diff options
Diffstat (limited to 'drivers/usb/media')
50 files changed, 40294 insertions, 0 deletions
diff --git a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig new file mode 100644 index 000000000000..21232ee2974c --- /dev/null +++ b/drivers/usb/media/Kconfig | |||
@@ -0,0 +1,213 @@ | |||
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_IBMCAM | ||
57 | tristate "USB IBM (Xirlink) C-it Camera support" | ||
58 | depends on USB && VIDEO_DEV | ||
59 | ---help--- | ||
60 | Say Y here if you want to connect a IBM "C-It" camera, also known as | ||
61 | "Xirlink PC Camera" to your computer's USB port. For more | ||
62 | information, read <file:Documentation/usb/ibmcam.txt>. | ||
63 | |||
64 | This driver uses the Video For Linux API. You must enable | ||
65 | (Y or M in config) Video For Linux (under Character Devices) | ||
66 | to use this driver. Information on this API and pointers to | ||
67 | "v4l" programs may be found at | ||
68 | <file:Documentation/video4linux/API.html>. | ||
69 | |||
70 | To compile this driver as a module, choose M here: the | ||
71 | module will be called ibmcam. | ||
72 | |||
73 | This camera has several configuration options which | ||
74 | can be specified when you load the module. Read | ||
75 | <file:Documentation/usb/ibmcam.txt> to learn more. | ||
76 | |||
77 | config USB_KONICAWC | ||
78 | tristate "USB Konica Webcam support" | ||
79 | depends on USB && VIDEO_DEV | ||
80 | ---help--- | ||
81 | Say Y here if you want support for webcams based on a Konica | ||
82 | chipset. This is known to work with the Intel YC76 webcam. | ||
83 | |||
84 | This driver uses the Video For Linux API. You must enable | ||
85 | (Y or M in config) Video For Linux (under Character Devices) | ||
86 | to use this driver. Information on this API and pointers to | ||
87 | "v4l" programs may be found at | ||
88 | <file:Documentation/video4linux/API.html>. | ||
89 | |||
90 | To compile this driver as a module, choose M here: the | ||
91 | module will be called konicawc. | ||
92 | |||
93 | config USB_OV511 | ||
94 | tristate "USB OV511 Camera support" | ||
95 | depends on USB && VIDEO_DEV | ||
96 | ---help--- | ||
97 | Say Y here if you want to connect this type of camera to your | ||
98 | computer's USB port. See <file:Documentation/usb/ov511.txt> for more | ||
99 | information and for a list of supported cameras. | ||
100 | |||
101 | This driver uses the Video For Linux API. You must say Y or M to | ||
102 | "Video For Linux" (under Character Devices) to use this driver. | ||
103 | Information on this API and pointers to "v4l" programs may be found | ||
104 | at <file:Documentation/video4linux/API.html>. | ||
105 | |||
106 | To compile this driver as a module, choose M here: the | ||
107 | module will be called ov511. | ||
108 | |||
109 | config USB_SE401 | ||
110 | tristate "USB SE401 Camera support" | ||
111 | depends on USB && VIDEO_DEV | ||
112 | ---help--- | ||
113 | Say Y here if you want to connect this type of camera to your | ||
114 | computer's USB port. See <file:Documentation/usb/se401.txt> for more | ||
115 | information and for a list of supported cameras. | ||
116 | |||
117 | This driver uses the Video For Linux API. You must say Y or M to | ||
118 | "Video For Linux" (under Multimedia Devices) to use this driver. | ||
119 | Information on this API and pointers to "v4l" programs may be found | ||
120 | at <file:Documentation/video4linux/API.html>. | ||
121 | |||
122 | To compile this driver as a module, choose M here: the | ||
123 | module will be called se401. | ||
124 | |||
125 | config USB_SN9C102 | ||
126 | tristate "USB SN9C10x PC Camera Controller support" | ||
127 | depends on USB && VIDEO_DEV | ||
128 | ---help--- | ||
129 | Say Y here if you want support for cameras based on SONiX SN9C101, | ||
130 | SN9C102 or SN9C103 PC Camera Controllers. | ||
131 | |||
132 | See <file:Documentation/usb/sn9c102.txt> for more informations. | ||
133 | |||
134 | This driver uses the Video For Linux API. You must say Y or M to | ||
135 | "Video For Linux" to use this driver. | ||
136 | |||
137 | To compile this driver as a module, choose M here: the | ||
138 | module will be called sn9c102. | ||
139 | |||
140 | config USB_STV680 | ||
141 | tristate "USB STV680 (Pencam) Camera support" | ||
142 | depends on USB && VIDEO_DEV | ||
143 | ---help--- | ||
144 | Say Y here if you want to connect this type of camera to your | ||
145 | computer's USB port. This includes the Pencam line of cameras. | ||
146 | See <file:Documentation/usb/stv680.txt> for more information and for | ||
147 | a list of supported cameras. | ||
148 | |||
149 | This driver uses the Video For Linux API. You must say Y or M to | ||
150 | "Video For Linux" (under Multimedia Devices) to use this driver. | ||
151 | Information on this API and pointers to "v4l" programs may be found | ||
152 | at <file:Documentation/video4linux/API.html>. | ||
153 | |||
154 | To compile this driver as a module, choose M here: the | ||
155 | module will be called stv680. | ||
156 | |||
157 | config USB_W9968CF | ||
158 | tristate "USB W996[87]CF JPEG Dual Mode Camera support" | ||
159 | depends on USB && VIDEO_DEV && I2C && VIDEO_OVCAMCHIP | ||
160 | ---help--- | ||
161 | Say Y here if you want support for cameras based on OV681 or | ||
162 | Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips. | ||
163 | |||
164 | This driver has an optional plugin, which is distributed as a | ||
165 | separate module only (released under GPL). It allows to use higher | ||
166 | resolutions and framerates, but cannot be included in the official | ||
167 | Linux kernel for performance purposes. | ||
168 | |||
169 | See <file:Documentation/usb/w9968cf.txt> for more informations. | ||
170 | |||
171 | This driver uses the Video For Linux and the I2C APIs. It needs the | ||
172 | OmniVision Camera Chip support as well. You must say Y or M to | ||
173 | "Video For Linux", "I2C Support" and "OmniVision Camera Chip | ||
174 | support" to use this driver. | ||
175 | |||
176 | To compile this driver as a module, choose M here: the | ||
177 | module will be called w9968cf. | ||
178 | |||
179 | config USB_PWC | ||
180 | tristate "USB Philips Cameras" | ||
181 | depends on USB && VIDEO_DEV | ||
182 | ---help--- | ||
183 | Say Y or M here if you want to use one of these Philips & OEM | ||
184 | webcams: | ||
185 | * Philips PCA645, PCA646 | ||
186 | * Philips PCVC675, PCVC680, PCVC690 | ||
187 | * Philips PCVC720/40, PCVC730, PCVC740, PCVC750 | ||
188 | * Askey VC010 | ||
189 | * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' | ||
190 | and 'Orbit'/'Sphere' | ||
191 | * Samsung MPC-C10, MPC-C30 | ||
192 | * Creative Webcam 5, Pro Ex | ||
193 | * SOTEC Afina Eye | ||
194 | * Visionite VCS-UC300, VCS-UM100 | ||
195 | |||
196 | The PCA635, PCVC665 and PCVC720/20 are not supported by this driver | ||
197 | and never will be, but the 665 and 720/20 are supported by other | ||
198 | drivers. | ||
199 | |||
200 | See <file:Documentation/usb/philips.txt> for more information and | ||
201 | installation instructions. | ||
202 | |||
203 | The built-in microphone is enabled by selecting USB Audio support. | ||
204 | |||
205 | This driver uses the Video For Linux API. You must say Y or M to | ||
206 | "Video For Linux" (under Character Devices) to use this driver. | ||
207 | Information on this API and pointers to "v4l" programs may be found | ||
208 | at <file:Documentation/video4linux/API.html>. | ||
209 | |||
210 | To compile this driver as a module, choose M here: the | ||
211 | module will be called pwc. | ||
212 | |||
213 | |||
diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile new file mode 100644 index 000000000000..2b76df7005fe --- /dev/null +++ b/drivers/usb/media/Makefile | |||
@@ -0,0 +1,17 @@ | |||
1 | # | ||
2 | # Makefile for USB Media drivers | ||
3 | # | ||
4 | |||
5 | sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o | ||
6 | |||
7 | obj-$(CONFIG_USB_DABUSB) += dabusb.o | ||
8 | obj-$(CONFIG_USB_DSBR) += dsbr100.o | ||
9 | obj-$(CONFIG_USB_IBMCAM) += ibmcam.o usbvideo.o ultracam.o | ||
10 | obj-$(CONFIG_USB_KONICAWC) += konicawc.o usbvideo.o | ||
11 | obj-$(CONFIG_USB_OV511) += ov511.o | ||
12 | obj-$(CONFIG_USB_SE401) += se401.o | ||
13 | obj-$(CONFIG_USB_SN9C102) += sn9c102.o | ||
14 | obj-$(CONFIG_USB_STV680) += stv680.o | ||
15 | obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o | ||
16 | obj-$(CONFIG_USB_W9968CF) += w9968cf.o | ||
17 | obj-$(CONFIG_USB_PWC) += pwc/ | ||
diff --git a/drivers/usb/media/dabfirmware.h b/drivers/usb/media/dabfirmware.h new file mode 100644 index 000000000000..d14d803566a3 --- /dev/null +++ b/drivers/usb/media/dabfirmware.h | |||
@@ -0,0 +1,1408 @@ | |||
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 new file mode 100644 index 000000000000..8823297d2191 --- /dev/null +++ b/drivers/usb/media/dabusb.c | |||
@@ -0,0 +1,877 @@ | |||
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 | |||
42 | #include "dabusb.h" | ||
43 | #include "dabfirmware.h" | ||
44 | |||
45 | /* | ||
46 | * Version Information | ||
47 | */ | ||
48 | #define DRIVER_VERSION "v1.54" | ||
49 | #define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de" | ||
50 | #define DRIVER_DESC "DAB-USB Interface Driver for Linux (c)1999" | ||
51 | |||
52 | /* --------------------------------------------------------------------- */ | ||
53 | |||
54 | #ifdef CONFIG_USB_DYNAMIC_MINORS | ||
55 | #define NRDABUSB 256 | ||
56 | #else | ||
57 | #define NRDABUSB 4 | ||
58 | #endif | ||
59 | |||
60 | /*-------------------------------------------------------------------*/ | ||
61 | |||
62 | static dabusb_t dabusb[NRDABUSB]; | ||
63 | static int buffers = 256; | ||
64 | static struct usb_driver dabusb_driver; | ||
65 | |||
66 | /*-------------------------------------------------------------------*/ | ||
67 | |||
68 | static int dabusb_add_buf_tail (pdabusb_t s, struct list_head *dst, struct list_head *src) | ||
69 | { | ||
70 | unsigned long flags; | ||
71 | struct list_head *tmp; | ||
72 | int ret = 0; | ||
73 | |||
74 | spin_lock_irqsave (&s->lock, flags); | ||
75 | |||
76 | if (list_empty (src)) { | ||
77 | // no elements in source buffer | ||
78 | ret = -1; | ||
79 | goto err; | ||
80 | } | ||
81 | tmp = src->next; | ||
82 | list_move_tail (tmp, dst); | ||
83 | |||
84 | err: spin_unlock_irqrestore (&s->lock, flags); | ||
85 | return ret; | ||
86 | } | ||
87 | /*-------------------------------------------------------------------*/ | ||
88 | #ifdef DEBUG | ||
89 | static void dump_urb (struct urb *urb) | ||
90 | { | ||
91 | dbg("urb :%p", urb); | ||
92 | dbg("dev :%p", urb->dev); | ||
93 | dbg("pipe :%08X", urb->pipe); | ||
94 | dbg("status :%d", urb->status); | ||
95 | dbg("transfer_flags :%08X", urb->transfer_flags); | ||
96 | dbg("transfer_buffer :%p", urb->transfer_buffer); | ||
97 | dbg("transfer_buffer_length:%d", urb->transfer_buffer_length); | ||
98 | dbg("actual_length :%d", urb->actual_length); | ||
99 | dbg("setup_packet :%p", urb->setup_packet); | ||
100 | dbg("start_frame :%d", urb->start_frame); | ||
101 | dbg("number_of_packets :%d", urb->number_of_packets); | ||
102 | dbg("interval :%d", urb->interval); | ||
103 | dbg("error_count :%d", urb->error_count); | ||
104 | dbg("context :%p", urb->context); | ||
105 | dbg("complete :%p", urb->complete); | ||
106 | } | ||
107 | #endif | ||
108 | /*-------------------------------------------------------------------*/ | ||
109 | static int dabusb_cancel_queue (pdabusb_t s, struct list_head *q) | ||
110 | { | ||
111 | unsigned long flags; | ||
112 | pbuff_t b; | ||
113 | |||
114 | dbg("dabusb_cancel_queue"); | ||
115 | |||
116 | spin_lock_irqsave (&s->lock, flags); | ||
117 | |||
118 | list_for_each_entry(b, q, buff_list) { | ||
119 | #ifdef DEBUG | ||
120 | dump_urb(b->purb); | ||
121 | #endif | ||
122 | usb_unlink_urb (b->purb); | ||
123 | } | ||
124 | spin_unlock_irqrestore (&s->lock, flags); | ||
125 | return 0; | ||
126 | } | ||
127 | /*-------------------------------------------------------------------*/ | ||
128 | static int dabusb_free_queue (struct list_head *q) | ||
129 | { | ||
130 | struct list_head *tmp; | ||
131 | struct list_head *p; | ||
132 | pbuff_t b; | ||
133 | |||
134 | dbg("dabusb_free_queue"); | ||
135 | for (p = q->next; p != q;) { | ||
136 | b = list_entry (p, buff_t, buff_list); | ||
137 | |||
138 | #ifdef DEBUG | ||
139 | dump_urb(b->purb); | ||
140 | #endif | ||
141 | if (b->purb->transfer_buffer) | ||
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) kmalloc (sizeof (buff_t), GFP_KERNEL); | ||
222 | if (!b) { | ||
223 | err("kmalloc(sizeof(buff_t))==NULL"); | ||
224 | goto err; | ||
225 | } | ||
226 | memset (b, 0, sizeof (buff_t)); | ||
227 | b->s = s; | ||
228 | b->purb = usb_alloc_urb(packets, GFP_KERNEL); | ||
229 | if (!b->purb) { | ||
230 | err("usb_alloc_urb == NULL"); | ||
231 | kfree (b); | ||
232 | goto err; | ||
233 | } | ||
234 | |||
235 | b->purb->transfer_buffer = kmalloc (transfer_buffer_length, GFP_KERNEL); | ||
236 | if (!b->purb->transfer_buffer) { | ||
237 | kfree (b->purb); | ||
238 | kfree (b); | ||
239 | err("kmalloc(%d)==NULL", transfer_buffer_length); | ||
240 | goto err; | ||
241 | } | ||
242 | |||
243 | b->purb->transfer_buffer_length = transfer_buffer_length; | ||
244 | b->purb->number_of_packets = packets; | ||
245 | b->purb->complete = dabusb_iso_complete; | ||
246 | b->purb->context = b; | ||
247 | b->purb->dev = s->usbdev; | ||
248 | b->purb->pipe = pipe; | ||
249 | b->purb->transfer_flags = URB_ISO_ASAP; | ||
250 | |||
251 | for (i = 0; i < packets; i++) { | ||
252 | b->purb->iso_frame_desc[i].offset = i * pipesize; | ||
253 | b->purb->iso_frame_desc[i].length = pipesize; | ||
254 | } | ||
255 | |||
256 | buffers += transfer_buffer_length; | ||
257 | list_add_tail (&b->buff_list, &s->free_buff_list); | ||
258 | } | ||
259 | s->got_mem = buffers; | ||
260 | |||
261 | return 0; | ||
262 | |||
263 | err: | ||
264 | dabusb_free_buffers (s); | ||
265 | return -ENOMEM; | ||
266 | } | ||
267 | /*-------------------------------------------------------------------*/ | ||
268 | static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb) | ||
269 | { | ||
270 | int ret; | ||
271 | unsigned int pipe; | ||
272 | int actual_length; | ||
273 | |||
274 | dbg("dabusb_bulk"); | ||
275 | |||
276 | if (!pb->pipe) | ||
277 | pipe = usb_rcvbulkpipe (s->usbdev, 2); | ||
278 | else | ||
279 | pipe = usb_sndbulkpipe (s->usbdev, 2); | ||
280 | |||
281 | ret=usb_bulk_msg(s->usbdev, pipe, pb->data, pb->size, &actual_length, 100); | ||
282 | if(ret<0) { | ||
283 | err("dabusb: usb_bulk_msg failed(%d)",ret); | ||
284 | |||
285 | if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) { | ||
286 | err("set_interface failed"); | ||
287 | return -EINVAL; | ||
288 | } | ||
289 | |||
290 | } | ||
291 | |||
292 | if( ret == -EPIPE ) { | ||
293 | warn("CLEAR_FEATURE request to remove STALL condition."); | ||
294 | if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe))) | ||
295 | err("request failed"); | ||
296 | } | ||
297 | |||
298 | pb->size = actual_length; | ||
299 | return ret; | ||
300 | } | ||
301 | /* --------------------------------------------------------------------- */ | ||
302 | static int dabusb_writemem (pdabusb_t s, int pos, unsigned char *data, int len) | ||
303 | { | ||
304 | int ret; | ||
305 | unsigned char *transfer_buffer = kmalloc (len, GFP_KERNEL); | ||
306 | |||
307 | if (!transfer_buffer) { | ||
308 | err("dabusb_writemem: kmalloc(%d) failed.", len); | ||
309 | return -ENOMEM; | ||
310 | } | ||
311 | |||
312 | memcpy (transfer_buffer, data, len); | ||
313 | |||
314 | ret=usb_control_msg(s->usbdev, usb_sndctrlpipe( s->usbdev, 0 ), 0xa0, 0x40, pos, 0, transfer_buffer, len, 300); | ||
315 | |||
316 | kfree (transfer_buffer); | ||
317 | return ret; | ||
318 | } | ||
319 | /* --------------------------------------------------------------------- */ | ||
320 | static int dabusb_8051_reset (pdabusb_t s, unsigned char reset_bit) | ||
321 | { | ||
322 | dbg("dabusb_8051_reset: %d",reset_bit); | ||
323 | return dabusb_writemem (s, CPUCS_REG, &reset_bit, 1); | ||
324 | } | ||
325 | /* --------------------------------------------------------------------- */ | ||
326 | static int dabusb_loadmem (pdabusb_t s, const char *fname) | ||
327 | { | ||
328 | int ret; | ||
329 | PINTEL_HEX_RECORD ptr = firmware; | ||
330 | |||
331 | dbg("Enter dabusb_loadmem (internal)"); | ||
332 | |||
333 | ret = dabusb_8051_reset (s, 1); | ||
334 | while (ptr->Type == 0) { | ||
335 | |||
336 | dbg("dabusb_writemem: %04X %p %d)", ptr->Address, ptr->Data, ptr->Length); | ||
337 | |||
338 | ret = dabusb_writemem (s, ptr->Address, ptr->Data, ptr->Length); | ||
339 | if (ret < 0) { | ||
340 | err("dabusb_writemem failed (%d %04X %p %d)", ret, ptr->Address, ptr->Data, ptr->Length); | ||
341 | break; | ||
342 | } | ||
343 | ptr++; | ||
344 | } | ||
345 | ret = dabusb_8051_reset (s, 0); | ||
346 | |||
347 | dbg("dabusb_loadmem: exit"); | ||
348 | |||
349 | return ret; | ||
350 | } | ||
351 | /* --------------------------------------------------------------------- */ | ||
352 | static int dabusb_fpga_clear (pdabusb_t s, pbulk_transfer_t b) | ||
353 | { | ||
354 | b->size = 4; | ||
355 | b->data[0] = 0x2a; | ||
356 | b->data[1] = 0; | ||
357 | b->data[2] = 0; | ||
358 | b->data[3] = 0; | ||
359 | |||
360 | dbg("dabusb_fpga_clear"); | ||
361 | |||
362 | return dabusb_bulk (s, b); | ||
363 | } | ||
364 | /* --------------------------------------------------------------------- */ | ||
365 | static int dabusb_fpga_init (pdabusb_t s, pbulk_transfer_t b) | ||
366 | { | ||
367 | b->size = 4; | ||
368 | b->data[0] = 0x2c; | ||
369 | b->data[1] = 0; | ||
370 | b->data[2] = 0; | ||
371 | b->data[3] = 0; | ||
372 | |||
373 | dbg("dabusb_fpga_init"); | ||
374 | |||
375 | return dabusb_bulk (s, b); | ||
376 | } | ||
377 | /* --------------------------------------------------------------------- */ | ||
378 | static int dabusb_fpga_download (pdabusb_t s, const char *fname) | ||
379 | { | ||
380 | pbulk_transfer_t b = kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL); | ||
381 | unsigned int blen, n; | ||
382 | int ret; | ||
383 | unsigned char *buf = bitstream; | ||
384 | |||
385 | dbg("Enter dabusb_fpga_download (internal)"); | ||
386 | |||
387 | if (!b) { | ||
388 | err("kmalloc(sizeof(bulk_transfer_t))==NULL"); | ||
389 | return -ENOMEM; | ||
390 | } | ||
391 | |||
392 | b->pipe = 1; | ||
393 | ret = dabusb_fpga_clear (s, b); | ||
394 | mdelay (10); | ||
395 | blen = buf[73] + (buf[72] << 8); | ||
396 | |||
397 | dbg("Bitstream len: %i", blen); | ||
398 | |||
399 | b->data[0] = 0x2b; | ||
400 | b->data[1] = 0; | ||
401 | b->data[2] = 0; | ||
402 | b->data[3] = 60; | ||
403 | |||
404 | for (n = 0; n <= blen + 60; n += 60) { | ||
405 | // some cclks for startup | ||
406 | b->size = 64; | ||
407 | memcpy (b->data + 4, buf + 74 + n, 60); | ||
408 | ret = dabusb_bulk (s, b); | ||
409 | if (ret < 0) { | ||
410 | err("dabusb_bulk failed."); | ||
411 | break; | ||
412 | } | ||
413 | mdelay (1); | ||
414 | } | ||
415 | |||
416 | ret = dabusb_fpga_init (s, b); | ||
417 | kfree (b); | ||
418 | |||
419 | dbg("exit dabusb_fpga_download"); | ||
420 | |||
421 | return ret; | ||
422 | } | ||
423 | |||
424 | static int dabusb_stop (pdabusb_t s) | ||
425 | { | ||
426 | dbg("dabusb_stop"); | ||
427 | |||
428 | s->state = _stopped; | ||
429 | dabusb_cancel_queue (s, &s->rec_buff_list); | ||
430 | |||
431 | dbg("pending_io: %d", s->pending_io.counter); | ||
432 | |||
433 | s->pending_io.counter = 0; | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static int dabusb_startrek (pdabusb_t s) | ||
438 | { | ||
439 | if (!s->got_mem && s->state != _started) { | ||
440 | |||
441 | dbg("dabusb_startrek"); | ||
442 | |||
443 | if (dabusb_alloc_buffers (s) < 0) | ||
444 | return -ENOMEM; | ||
445 | dabusb_stop (s); | ||
446 | s->state = _started; | ||
447 | s->readptr = 0; | ||
448 | } | ||
449 | |||
450 | if (!list_empty (&s->free_buff_list)) { | ||
451 | pbuff_t end; | ||
452 | int ret; | ||
453 | |||
454 | while (!dabusb_add_buf_tail (s, &s->rec_buff_list, &s->free_buff_list)) { | ||
455 | |||
456 | dbg("submitting: end:%p s->rec_buff_list:%p", s->rec_buff_list.prev, &s->rec_buff_list); | ||
457 | |||
458 | end = list_entry (s->rec_buff_list.prev, buff_t, buff_list); | ||
459 | |||
460 | ret = usb_submit_urb (end->purb, GFP_KERNEL); | ||
461 | if (ret) { | ||
462 | err("usb_submit_urb returned:%d", ret); | ||
463 | if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list)) | ||
464 | err("startrek: dabusb_add_buf_tail failed"); | ||
465 | break; | ||
466 | } | ||
467 | else | ||
468 | atomic_inc (&s->pending_io); | ||
469 | } | ||
470 | dbg("pending_io: %d",s->pending_io.counter); | ||
471 | } | ||
472 | |||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, loff_t * ppos) | ||
477 | { | ||
478 | pdabusb_t s = (pdabusb_t) file->private_data; | ||
479 | unsigned long flags; | ||
480 | unsigned ret = 0; | ||
481 | int rem; | ||
482 | int cnt; | ||
483 | pbuff_t b; | ||
484 | struct urb *purb = NULL; | ||
485 | |||
486 | dbg("dabusb_read"); | ||
487 | |||
488 | if (*ppos) | ||
489 | return -ESPIPE; | ||
490 | |||
491 | if (s->remove_pending) | ||
492 | return -EIO; | ||
493 | |||
494 | |||
495 | if (!s->usbdev) | ||
496 | return -EIO; | ||
497 | |||
498 | while (count > 0) { | ||
499 | dabusb_startrek (s); | ||
500 | |||
501 | spin_lock_irqsave (&s->lock, flags); | ||
502 | |||
503 | if (list_empty (&s->rec_buff_list)) { | ||
504 | |||
505 | spin_unlock_irqrestore(&s->lock, flags); | ||
506 | |||
507 | err("error: rec_buf_list is empty"); | ||
508 | goto err; | ||
509 | } | ||
510 | |||
511 | b = list_entry (s->rec_buff_list.next, buff_t, buff_list); | ||
512 | purb = b->purb; | ||
513 | |||
514 | spin_unlock_irqrestore(&s->lock, flags); | ||
515 | |||
516 | if (purb->status == -EINPROGRESS) { | ||
517 | if (file->f_flags & O_NONBLOCK) // return nonblocking | ||
518 | { | ||
519 | if (!ret) | ||
520 | ret = -EAGAIN; | ||
521 | goto err; | ||
522 | } | ||
523 | |||
524 | interruptible_sleep_on (&s->wait); | ||
525 | |||
526 | if (signal_pending (current)) { | ||
527 | if (!ret) | ||
528 | ret = -ERESTARTSYS; | ||
529 | goto err; | ||
530 | } | ||
531 | |||
532 | spin_lock_irqsave (&s->lock, flags); | ||
533 | |||
534 | if (list_empty (&s->rec_buff_list)) { | ||
535 | spin_unlock_irqrestore(&s->lock, flags); | ||
536 | err("error: still no buffer available."); | ||
537 | goto err; | ||
538 | } | ||
539 | spin_unlock_irqrestore(&s->lock, flags); | ||
540 | s->readptr = 0; | ||
541 | } | ||
542 | if (s->remove_pending) { | ||
543 | ret = -EIO; | ||
544 | goto err; | ||
545 | } | ||
546 | |||
547 | rem = purb->actual_length - s->readptr; // set remaining bytes to copy | ||
548 | |||
549 | if (count >= rem) | ||
550 | cnt = rem; | ||
551 | else | ||
552 | cnt = count; | ||
553 | |||
554 | dbg("copy_to_user:%p %p %d",buf, purb->transfer_buffer + s->readptr, cnt); | ||
555 | |||
556 | if (copy_to_user (buf, purb->transfer_buffer + s->readptr, cnt)) { | ||
557 | err("read: copy_to_user failed"); | ||
558 | if (!ret) | ||
559 | ret = -EFAULT; | ||
560 | goto err; | ||
561 | } | ||
562 | |||
563 | s->readptr += cnt; | ||
564 | count -= cnt; | ||
565 | buf += cnt; | ||
566 | ret += cnt; | ||
567 | |||
568 | if (s->readptr == purb->actual_length) { | ||
569 | // finished, take next buffer | ||
570 | if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list)) | ||
571 | err("read: dabusb_add_buf_tail failed"); | ||
572 | s->readptr = 0; | ||
573 | } | ||
574 | } | ||
575 | err: //up(&s->mutex); | ||
576 | return ret; | ||
577 | } | ||
578 | |||
579 | static int dabusb_open (struct inode *inode, struct file *file) | ||
580 | { | ||
581 | int devnum = iminor(inode); | ||
582 | pdabusb_t s; | ||
583 | |||
584 | if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB)) | ||
585 | return -EIO; | ||
586 | |||
587 | s = &dabusb[devnum - DABUSB_MINOR]; | ||
588 | |||
589 | dbg("dabusb_open"); | ||
590 | down (&s->mutex); | ||
591 | |||
592 | while (!s->usbdev || s->opened) { | ||
593 | up (&s->mutex); | ||
594 | |||
595 | if (file->f_flags & O_NONBLOCK) { | ||
596 | return -EBUSY; | ||
597 | } | ||
598 | msleep_interruptible(500); | ||
599 | |||
600 | if (signal_pending (current)) { | ||
601 | return -EAGAIN; | ||
602 | } | ||
603 | down (&s->mutex); | ||
604 | } | ||
605 | if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) { | ||
606 | up(&s->mutex); | ||
607 | err("set_interface failed"); | ||
608 | return -EINVAL; | ||
609 | } | ||
610 | s->opened = 1; | ||
611 | up (&s->mutex); | ||
612 | |||
613 | file->f_pos = 0; | ||
614 | file->private_data = s; | ||
615 | |||
616 | return nonseekable_open(inode, file); | ||
617 | } | ||
618 | |||
619 | static int dabusb_release (struct inode *inode, struct file *file) | ||
620 | { | ||
621 | pdabusb_t s = (pdabusb_t) file->private_data; | ||
622 | |||
623 | dbg("dabusb_release"); | ||
624 | |||
625 | down (&s->mutex); | ||
626 | dabusb_stop (s); | ||
627 | dabusb_free_buffers (s); | ||
628 | up (&s->mutex); | ||
629 | |||
630 | if (!s->remove_pending) { | ||
631 | if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) | ||
632 | err("set_interface failed"); | ||
633 | } | ||
634 | else | ||
635 | wake_up (&s->remove_ok); | ||
636 | |||
637 | s->opened = 0; | ||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
642 | { | ||
643 | pdabusb_t s = (pdabusb_t) file->private_data; | ||
644 | pbulk_transfer_t pbulk; | ||
645 | int ret = 0; | ||
646 | int version = DABUSB_VERSION; | ||
647 | |||
648 | dbg("dabusb_ioctl"); | ||
649 | |||
650 | if (s->remove_pending) | ||
651 | return -EIO; | ||
652 | |||
653 | down (&s->mutex); | ||
654 | |||
655 | if (!s->usbdev) { | ||
656 | up (&s->mutex); | ||
657 | return -EIO; | ||
658 | } | ||
659 | |||
660 | switch (cmd) { | ||
661 | |||
662 | case IOCTL_DAB_BULK: | ||
663 | pbulk = (pbulk_transfer_t) kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL); | ||
664 | |||
665 | if (!pbulk) { | ||
666 | ret = -ENOMEM; | ||
667 | break; | ||
668 | } | ||
669 | |||
670 | if (copy_from_user (pbulk, (void __user *) arg, sizeof (bulk_transfer_t))) { | ||
671 | ret = -EFAULT; | ||
672 | kfree (pbulk); | ||
673 | break; | ||
674 | } | ||
675 | |||
676 | ret=dabusb_bulk (s, pbulk); | ||
677 | if(ret==0) | ||
678 | if (copy_to_user((void __user *)arg, pbulk, | ||
679 | sizeof(bulk_transfer_t))) | ||
680 | ret = -EFAULT; | ||
681 | kfree (pbulk); | ||
682 | break; | ||
683 | |||
684 | case IOCTL_DAB_OVERRUNS: | ||
685 | ret = put_user (s->overruns, (unsigned int __user *) arg); | ||
686 | break; | ||
687 | |||
688 | case IOCTL_DAB_VERSION: | ||
689 | ret = put_user (version, (unsigned int __user *) arg); | ||
690 | break; | ||
691 | |||
692 | default: | ||
693 | ret = -ENOIOCTLCMD; | ||
694 | break; | ||
695 | } | ||
696 | up (&s->mutex); | ||
697 | return ret; | ||
698 | } | ||
699 | |||
700 | static struct file_operations dabusb_fops = | ||
701 | { | ||
702 | .owner = THIS_MODULE, | ||
703 | .llseek = no_llseek, | ||
704 | .read = dabusb_read, | ||
705 | .ioctl = dabusb_ioctl, | ||
706 | .open = dabusb_open, | ||
707 | .release = dabusb_release, | ||
708 | }; | ||
709 | |||
710 | static struct usb_class_driver dabusb_class = { | ||
711 | .name = "usb/dabusb%d", | ||
712 | .fops = &dabusb_fops, | ||
713 | .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, | ||
714 | .minor_base = DABUSB_MINOR, | ||
715 | }; | ||
716 | |||
717 | |||
718 | /* --------------------------------------------------------------------- */ | ||
719 | static int dabusb_probe (struct usb_interface *intf, | ||
720 | const struct usb_device_id *id) | ||
721 | { | ||
722 | struct usb_device *usbdev = interface_to_usbdev(intf); | ||
723 | int retval; | ||
724 | pdabusb_t s; | ||
725 | |||
726 | dbg("dabusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d", | ||
727 | le16_to_cpu(usbdev->descriptor.idVendor), | ||
728 | le16_to_cpu(usbdev->descriptor.idProduct), | ||
729 | intf->altsetting->desc.bInterfaceNumber); | ||
730 | |||
731 | /* We don't handle multiple configurations */ | ||
732 | if (usbdev->descriptor.bNumConfigurations != 1) | ||
733 | return -ENODEV; | ||
734 | |||
735 | if (intf->altsetting->desc.bInterfaceNumber != _DABUSB_IF && | ||
736 | le16_to_cpu(usbdev->descriptor.idProduct) == 0x9999) | ||
737 | return -ENODEV; | ||
738 | |||
739 | |||
740 | |||
741 | s = &dabusb[intf->minor]; | ||
742 | |||
743 | down (&s->mutex); | ||
744 | s->remove_pending = 0; | ||
745 | s->usbdev = usbdev; | ||
746 | s->devnum = intf->minor; | ||
747 | |||
748 | if (usb_reset_configuration (usbdev) < 0) { | ||
749 | err("reset_configuration failed"); | ||
750 | goto reject; | ||
751 | } | ||
752 | if (le16_to_cpu(usbdev->descriptor.idProduct) == 0x2131) { | ||
753 | dabusb_loadmem (s, NULL); | ||
754 | goto reject; | ||
755 | } | ||
756 | else { | ||
757 | dabusb_fpga_download (s, NULL); | ||
758 | |||
759 | if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) { | ||
760 | err("set_interface failed"); | ||
761 | goto reject; | ||
762 | } | ||
763 | } | ||
764 | dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber); | ||
765 | usb_set_intfdata (intf, s); | ||
766 | up (&s->mutex); | ||
767 | |||
768 | retval = usb_register_dev(intf, &dabusb_class); | ||
769 | if (retval) { | ||
770 | usb_set_intfdata (intf, NULL); | ||
771 | return -ENOMEM; | ||
772 | } | ||
773 | |||
774 | return 0; | ||
775 | |||
776 | reject: | ||
777 | up (&s->mutex); | ||
778 | s->usbdev = NULL; | ||
779 | return -ENODEV; | ||
780 | } | ||
781 | |||
782 | static void dabusb_disconnect (struct usb_interface *intf) | ||
783 | { | ||
784 | wait_queue_t __wait; | ||
785 | pdabusb_t s = usb_get_intfdata (intf); | ||
786 | |||
787 | dbg("dabusb_disconnect"); | ||
788 | |||
789 | init_waitqueue_entry(&__wait, current); | ||
790 | |||
791 | usb_set_intfdata (intf, NULL); | ||
792 | if (s) { | ||
793 | usb_deregister_dev (intf, &dabusb_class); | ||
794 | s->remove_pending = 1; | ||
795 | wake_up (&s->wait); | ||
796 | add_wait_queue(&s->remove_ok, &__wait); | ||
797 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
798 | if (s->state == _started) | ||
799 | schedule(); | ||
800 | current->state = TASK_RUNNING; | ||
801 | remove_wait_queue(&s->remove_ok, &__wait); | ||
802 | |||
803 | s->usbdev = NULL; | ||
804 | s->overruns = 0; | ||
805 | } | ||
806 | } | ||
807 | |||
808 | static struct usb_device_id dabusb_ids [] = { | ||
809 | // { USB_DEVICE(0x0547, 0x2131) }, /* An2131 chip, no boot ROM */ | ||
810 | { USB_DEVICE(0x0547, 0x9999) }, | ||
811 | { } /* Terminating entry */ | ||
812 | }; | ||
813 | |||
814 | MODULE_DEVICE_TABLE (usb, dabusb_ids); | ||
815 | |||
816 | static struct usb_driver dabusb_driver = { | ||
817 | .owner = THIS_MODULE, | ||
818 | .name = "dabusb", | ||
819 | .probe = dabusb_probe, | ||
820 | .disconnect = dabusb_disconnect, | ||
821 | .id_table = dabusb_ids, | ||
822 | }; | ||
823 | |||
824 | /* --------------------------------------------------------------------- */ | ||
825 | |||
826 | static int __init dabusb_init (void) | ||
827 | { | ||
828 | int retval; | ||
829 | unsigned u; | ||
830 | |||
831 | /* initialize struct */ | ||
832 | for (u = 0; u < NRDABUSB; u++) { | ||
833 | pdabusb_t s = &dabusb[u]; | ||
834 | memset (s, 0, sizeof (dabusb_t)); | ||
835 | init_MUTEX (&s->mutex); | ||
836 | s->usbdev = NULL; | ||
837 | s->total_buffer_size = buffers; | ||
838 | init_waitqueue_head (&s->wait); | ||
839 | init_waitqueue_head (&s->remove_ok); | ||
840 | spin_lock_init (&s->lock); | ||
841 | INIT_LIST_HEAD (&s->free_buff_list); | ||
842 | INIT_LIST_HEAD (&s->rec_buff_list); | ||
843 | } | ||
844 | |||
845 | /* register misc device */ | ||
846 | retval = usb_register(&dabusb_driver); | ||
847 | if (retval) | ||
848 | goto out; | ||
849 | |||
850 | dbg("dabusb_init: driver registered"); | ||
851 | |||
852 | info(DRIVER_VERSION ":" DRIVER_DESC); | ||
853 | |||
854 | out: | ||
855 | return retval; | ||
856 | } | ||
857 | |||
858 | static void __exit dabusb_cleanup (void) | ||
859 | { | ||
860 | dbg("dabusb_cleanup"); | ||
861 | |||
862 | usb_deregister (&dabusb_driver); | ||
863 | } | ||
864 | |||
865 | /* --------------------------------------------------------------------- */ | ||
866 | |||
867 | MODULE_AUTHOR( DRIVER_AUTHOR ); | ||
868 | MODULE_DESCRIPTION( DRIVER_DESC ); | ||
869 | MODULE_LICENSE("GPL"); | ||
870 | |||
871 | module_param(buffers, int, 0); | ||
872 | MODULE_PARM_DESC (buffers, "Number of buffers (default=256)"); | ||
873 | |||
874 | module_init (dabusb_init); | ||
875 | module_exit (dabusb_cleanup); | ||
876 | |||
877 | /* --------------------------------------------------------------------- */ | ||
diff --git a/drivers/usb/media/dabusb.h b/drivers/usb/media/dabusb.h new file mode 100644 index 000000000000..10b666e43abc --- /dev/null +++ b/drivers/usb/media/dabusb.h | |||
@@ -0,0 +1,85 @@ | |||
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 semaphore 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 new file mode 100644 index 000000000000..7503f5b96f59 --- /dev/null +++ b/drivers/usb/media/dsbr100.c | |||
@@ -0,0 +1,429 @@ | |||
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 | .llseek = no_llseek, | ||
131 | }; | ||
132 | |||
133 | /* V4L interface */ | ||
134 | static struct video_device dsbr100_videodev_template= | ||
135 | { | ||
136 | .owner = THIS_MODULE, | ||
137 | .name = "D-Link DSB-R 100", | ||
138 | .type = VID_TYPE_TUNER, | ||
139 | .hardware = VID_HARDWARE_AZTECH, | ||
140 | .fops = &usb_dsbr100_fops, | ||
141 | .release = video_device_release, | ||
142 | }; | ||
143 | |||
144 | static struct usb_device_id usb_dsbr100_device_table [] = { | ||
145 | { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) }, | ||
146 | { } /* Terminating entry */ | ||
147 | }; | ||
148 | |||
149 | MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table); | ||
150 | |||
151 | /* USB subsystem interface */ | ||
152 | static struct usb_driver usb_dsbr100_driver = { | ||
153 | .owner = THIS_MODULE, | ||
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/ibmcam.c b/drivers/usb/media/ibmcam.c new file mode 100644 index 000000000000..ba41fc7b95c2 --- /dev/null +++ b/drivers/usb/media/ibmcam.c | |||
@@ -0,0 +1,3932 @@ | |||
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 < (sizeof(initData)/sizeof(initData[0])); 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 new file mode 100644 index 000000000000..08521a2b4f3d --- /dev/null +++ b/drivers/usb/media/konicawc.c | |||
@@ -0,0 +1,947 @@ | |||
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 | |||
20 | #include "usbvideo.h" | ||
21 | |||
22 | #define MAX_BRIGHTNESS 108 | ||
23 | #define MAX_CONTRAST 108 | ||
24 | #define MAX_SATURATION 108 | ||
25 | #define MAX_SHARPNESS 108 | ||
26 | #define MAX_WHITEBAL 372 | ||
27 | #define MAX_SPEED 6 | ||
28 | |||
29 | |||
30 | #define MAX_CAMERAS 1 | ||
31 | |||
32 | #define DRIVER_VERSION "v1.4" | ||
33 | #define DRIVER_DESC "Konica Webcam driver" | ||
34 | |||
35 | enum ctrl_req { | ||
36 | SetWhitebal = 0x01, | ||
37 | SetBrightness = 0x02, | ||
38 | SetSharpness = 0x03, | ||
39 | SetContrast = 0x04, | ||
40 | SetSaturation = 0x05, | ||
41 | }; | ||
42 | |||
43 | |||
44 | enum frame_sizes { | ||
45 | SIZE_160X120 = 0, | ||
46 | SIZE_160X136 = 1, | ||
47 | SIZE_176X144 = 2, | ||
48 | SIZE_320X240 = 3, | ||
49 | |||
50 | }; | ||
51 | |||
52 | #define MAX_FRAME_SIZE SIZE_320X240 | ||
53 | |||
54 | static struct usbvideo *cams; | ||
55 | |||
56 | #ifdef CONFIG_USB_DEBUG | ||
57 | static int debug; | ||
58 | #define DEBUG(n, format, arg...) \ | ||
59 | if (n <= debug) { \ | ||
60 | printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \ | ||
61 | } | ||
62 | #else | ||
63 | #define DEBUG(n, arg...) | ||
64 | static const int debug = 0; | ||
65 | #endif | ||
66 | |||
67 | |||
68 | /* Some default values for initial camera settings, | ||
69 | can be set by modprobe */ | ||
70 | |||
71 | static int size; | ||
72 | static int speed = 6; /* Speed (fps) 0 (slowest) to 6 (fastest) */ | ||
73 | static int brightness = MAX_BRIGHTNESS/2; | ||
74 | static int contrast = MAX_CONTRAST/2; | ||
75 | static int saturation = MAX_SATURATION/2; | ||
76 | static int sharpness = MAX_SHARPNESS/2; | ||
77 | static int whitebal = 3*(MAX_WHITEBAL/4); | ||
78 | |||
79 | static int spd_to_iface[] = { 1, 0, 3, 2, 4, 5, 6 }; | ||
80 | |||
81 | /* These FPS speeds are from the windows config box. They are | ||
82 | * indexed on size (0-2) and speed (0-6). Divide by 3 to get the | ||
83 | * real fps. | ||
84 | */ | ||
85 | |||
86 | static int spd_to_fps[][7] = { { 24, 40, 48, 60, 72, 80, 100 }, | ||
87 | { 24, 40, 48, 60, 72, 80, 100 }, | ||
88 | { 18, 30, 36, 45, 54, 60, 75 }, | ||
89 | { 6, 10, 12, 15, 18, 21, 25 } }; | ||
90 | |||
91 | struct cam_size { | ||
92 | u16 width; | ||
93 | u16 height; | ||
94 | u8 cmd; | ||
95 | }; | ||
96 | |||
97 | static struct cam_size camera_sizes[] = { { 160, 120, 0x7 }, | ||
98 | { 160, 136, 0xa }, | ||
99 | { 176, 144, 0x4 }, | ||
100 | { 320, 240, 0x5 } }; | ||
101 | |||
102 | struct konicawc { | ||
103 | u8 brightness; /* camera uses 0 - 9, x11 for real value */ | ||
104 | u8 contrast; /* as above */ | ||
105 | u8 saturation; /* as above */ | ||
106 | u8 sharpness; /* as above */ | ||
107 | u8 white_bal; /* 0 - 33, x11 for real value */ | ||
108 | u8 speed; /* Stored as 0 - 6, used as index in spd_to_* (above) */ | ||
109 | u8 size; /* Frame Size */ | ||
110 | int height; | ||
111 | int width; | ||
112 | struct urb *sts_urb[USBVIDEO_NUMSBUF]; | ||
113 | u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC]; | ||
114 | struct urb *last_data_urb; | ||
115 | int lastframe; | ||
116 | int cur_frame_size; /* number of bytes in current frame size */ | ||
117 | int maxline; /* number of lines per frame */ | ||
118 | int yplanesz; /* Number of bytes in the Y plane */ | ||
119 | unsigned int buttonsts:1; | ||
120 | #ifdef CONFIG_INPUT | ||
121 | struct input_dev input; | ||
122 | char input_physname[64]; | ||
123 | #endif | ||
124 | }; | ||
125 | |||
126 | |||
127 | #define konicawc_set_misc(uvd, req, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, req, value, index, NULL, 0) | ||
128 | #define konicawc_get_misc(uvd, req, value, index, buf, sz) konicawc_ctrl_msg(uvd, USB_DIR_IN, req, value, index, buf, sz) | ||
129 | #define konicawc_set_value(uvd, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0) | ||
130 | |||
131 | |||
132 | static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len) | ||
133 | { | ||
134 | int retval = usb_control_msg(uvd->dev, | ||
135 | dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0), | ||
136 | request, 0x40 | dir, value, index, buf, len, 1000); | ||
137 | return retval < 0 ? retval : 0; | ||
138 | } | ||
139 | |||
140 | |||
141 | static inline void konicawc_camera_on(struct uvd *uvd) | ||
142 | { | ||
143 | DEBUG(0, "camera on"); | ||
144 | konicawc_set_misc(uvd, 0x2, 1, 0x0b); | ||
145 | } | ||
146 | |||
147 | |||
148 | static inline void konicawc_camera_off(struct uvd *uvd) | ||
149 | { | ||
150 | DEBUG(0, "camera off"); | ||
151 | konicawc_set_misc(uvd, 0x2, 0, 0x0b); | ||
152 | } | ||
153 | |||
154 | |||
155 | static void konicawc_set_camera_size(struct uvd *uvd) | ||
156 | { | ||
157 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
158 | |||
159 | konicawc_set_misc(uvd, 0x2, camera_sizes[cam->size].cmd, 0x08); | ||
160 | cam->width = camera_sizes[cam->size].width; | ||
161 | cam->height = camera_sizes[cam->size].height; | ||
162 | cam->yplanesz = cam->height * cam->width; | ||
163 | cam->cur_frame_size = (cam->yplanesz * 3) / 2; | ||
164 | cam->maxline = cam->yplanesz / 256; | ||
165 | uvd->videosize = VIDEOSIZE(cam->width, cam->height); | ||
166 | } | ||
167 | |||
168 | |||
169 | static int konicawc_setup_on_open(struct uvd *uvd) | ||
170 | { | ||
171 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
172 | |||
173 | DEBUG(1, "setting brightness to %d (%d)", cam->brightness, | ||
174 | cam->brightness * 11); | ||
175 | konicawc_set_value(uvd, cam->brightness, SetBrightness); | ||
176 | DEBUG(1, "setting white balance to %d (%d)", cam->white_bal, | ||
177 | cam->white_bal * 11); | ||
178 | konicawc_set_value(uvd, cam->white_bal, SetWhitebal); | ||
179 | DEBUG(1, "setting contrast to %d (%d)", cam->contrast, | ||
180 | cam->contrast * 11); | ||
181 | konicawc_set_value(uvd, cam->contrast, SetContrast); | ||
182 | DEBUG(1, "setting saturation to %d (%d)", cam->saturation, | ||
183 | cam->saturation * 11); | ||
184 | konicawc_set_value(uvd, cam->saturation, SetSaturation); | ||
185 | DEBUG(1, "setting sharpness to %d (%d)", cam->sharpness, | ||
186 | cam->sharpness * 11); | ||
187 | konicawc_set_value(uvd, cam->sharpness, SetSharpness); | ||
188 | konicawc_set_camera_size(uvd); | ||
189 | cam->lastframe = -2; | ||
190 | cam->buttonsts = 0; | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | |||
195 | static void konicawc_adjust_picture(struct uvd *uvd) | ||
196 | { | ||
197 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
198 | |||
199 | konicawc_camera_off(uvd); | ||
200 | DEBUG(1, "new brightness: %d", uvd->vpic.brightness); | ||
201 | uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness; | ||
202 | if(cam->brightness != uvd->vpic.brightness / 11) { | ||
203 | cam->brightness = uvd->vpic.brightness / 11; | ||
204 | DEBUG(1, "setting brightness to %d (%d)", cam->brightness, | ||
205 | cam->brightness * 11); | ||
206 | konicawc_set_value(uvd, cam->brightness, SetBrightness); | ||
207 | } | ||
208 | |||
209 | DEBUG(1, "new contrast: %d", uvd->vpic.contrast); | ||
210 | uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast; | ||
211 | if(cam->contrast != uvd->vpic.contrast / 11) { | ||
212 | cam->contrast = uvd->vpic.contrast / 11; | ||
213 | DEBUG(1, "setting contrast to %d (%d)", cam->contrast, | ||
214 | cam->contrast * 11); | ||
215 | konicawc_set_value(uvd, cam->contrast, SetContrast); | ||
216 | } | ||
217 | konicawc_camera_on(uvd); | ||
218 | } | ||
219 | |||
220 | |||
221 | static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb) | ||
222 | { | ||
223 | char *cdata; | ||
224 | int i, totlen = 0; | ||
225 | unsigned char *status = stsurb->transfer_buffer; | ||
226 | int keep = 0, discard = 0, bad = 0; | ||
227 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
228 | |||
229 | for (i = 0; i < dataurb->number_of_packets; i++) { | ||
230 | int button = cam->buttonsts; | ||
231 | unsigned char sts; | ||
232 | int n = dataurb->iso_frame_desc[i].actual_length; | ||
233 | int st = dataurb->iso_frame_desc[i].status; | ||
234 | cdata = dataurb->transfer_buffer + | ||
235 | dataurb->iso_frame_desc[i].offset; | ||
236 | |||
237 | /* Detect and ignore errored packets */ | ||
238 | if (st < 0) { | ||
239 | DEBUG(1, "Data error: packet=%d. len=%d. status=%d.", | ||
240 | i, n, st); | ||
241 | uvd->stats.iso_err_count++; | ||
242 | continue; | ||
243 | } | ||
244 | |||
245 | /* Detect and ignore empty packets */ | ||
246 | if (n <= 0) { | ||
247 | uvd->stats.iso_skip_count++; | ||
248 | continue; | ||
249 | } | ||
250 | |||
251 | /* See what the status data said about the packet */ | ||
252 | sts = *(status+stsurb->iso_frame_desc[i].offset); | ||
253 | |||
254 | /* sts: 0x80-0xff: frame start with frame number (ie 0-7f) | ||
255 | * otherwise: | ||
256 | * bit 0 0: keep packet | ||
257 | * 1: drop packet (padding data) | ||
258 | * | ||
259 | * bit 4 0 button not clicked | ||
260 | * 1 button clicked | ||
261 | * button is used to `take a picture' (in software) | ||
262 | */ | ||
263 | |||
264 | if(sts < 0x80) { | ||
265 | button = !!(sts & 0x40); | ||
266 | sts &= ~0x40; | ||
267 | } | ||
268 | |||
269 | /* work out the button status, but don't do | ||
270 | anything with it for now */ | ||
271 | |||
272 | if(button != cam->buttonsts) { | ||
273 | DEBUG(2, "button: %sclicked", button ? "" : "un"); | ||
274 | cam->buttonsts = button; | ||
275 | #ifdef CONFIG_INPUT | ||
276 | input_report_key(&cam->input, BTN_0, cam->buttonsts); | ||
277 | input_sync(&cam->input); | ||
278 | #endif | ||
279 | } | ||
280 | |||
281 | if(sts == 0x01) { /* drop frame */ | ||
282 | discard++; | ||
283 | continue; | ||
284 | } | ||
285 | |||
286 | if((sts > 0x01) && (sts < 0x80)) { | ||
287 | info("unknown status %2.2x", sts); | ||
288 | bad++; | ||
289 | continue; | ||
290 | } | ||
291 | if(!sts && cam->lastframe == -2) { | ||
292 | DEBUG(2, "dropping frame looking for image start"); | ||
293 | continue; | ||
294 | } | ||
295 | |||
296 | keep++; | ||
297 | if(sts & 0x80) { /* frame start */ | ||
298 | unsigned char marker[] = { 0, 0xff, 0, 0x00 }; | ||
299 | |||
300 | if(cam->lastframe == -2) { | ||
301 | DEBUG(2, "found initial image"); | ||
302 | cam->lastframe = -1; | ||
303 | } | ||
304 | |||
305 | marker[3] = sts & 0x7F; | ||
306 | RingQueue_Enqueue(&uvd->dp, marker, 4); | ||
307 | totlen += 4; | ||
308 | } | ||
309 | |||
310 | totlen += n; /* Little local accounting */ | ||
311 | RingQueue_Enqueue(&uvd->dp, cdata, n); | ||
312 | } | ||
313 | DEBUG(8, "finished: keep = %d discard = %d bad = %d added %d bytes", | ||
314 | keep, discard, bad, totlen); | ||
315 | return totlen; | ||
316 | } | ||
317 | |||
318 | |||
319 | static void resubmit_urb(struct uvd *uvd, struct urb *urb) | ||
320 | { | ||
321 | int i, ret; | ||
322 | for (i = 0; i < FRAMES_PER_DESC; i++) { | ||
323 | urb->iso_frame_desc[i].status = 0; | ||
324 | } | ||
325 | urb->dev = uvd->dev; | ||
326 | urb->status = 0; | ||
327 | ret = usb_submit_urb(urb, GFP_ATOMIC); | ||
328 | DEBUG(3, "submitting urb of length %d", urb->transfer_buffer_length); | ||
329 | if(ret) | ||
330 | err("usb_submit_urb error (%d)", ret); | ||
331 | |||
332 | } | ||
333 | |||
334 | |||
335 | static void konicawc_isoc_irq(struct urb *urb, struct pt_regs *regs) | ||
336 | { | ||
337 | struct uvd *uvd = urb->context; | ||
338 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
339 | |||
340 | /* We don't want to do anything if we are about to be removed! */ | ||
341 | if (!CAMERA_IS_OPERATIONAL(uvd)) | ||
342 | return; | ||
343 | |||
344 | if (!uvd->streaming) { | ||
345 | DEBUG(1, "Not streaming, but interrupt!"); | ||
346 | return; | ||
347 | } | ||
348 | |||
349 | DEBUG(3, "got frame %d len = %d buflen =%d", urb->start_frame, urb->actual_length, urb->transfer_buffer_length); | ||
350 | |||
351 | uvd->stats.urb_count++; | ||
352 | |||
353 | if (urb->transfer_buffer_length > 32) { | ||
354 | cam->last_data_urb = urb; | ||
355 | return; | ||
356 | } | ||
357 | /* Copy the data received into ring queue */ | ||
358 | if(cam->last_data_urb) { | ||
359 | int len = 0; | ||
360 | if(urb->start_frame != cam->last_data_urb->start_frame) | ||
361 | err("Lost sync on frames"); | ||
362 | else if (!urb->status && !cam->last_data_urb->status) | ||
363 | len = konicawc_compress_iso(uvd, cam->last_data_urb, urb); | ||
364 | |||
365 | resubmit_urb(uvd, cam->last_data_urb); | ||
366 | resubmit_urb(uvd, urb); | ||
367 | cam->last_data_urb = NULL; | ||
368 | uvd->stats.urb_length = len; | ||
369 | uvd->stats.data_count += len; | ||
370 | if(len) | ||
371 | RingQueue_WakeUpInterruptible(&uvd->dp); | ||
372 | return; | ||
373 | } | ||
374 | return; | ||
375 | } | ||
376 | |||
377 | |||
378 | static int konicawc_start_data(struct uvd *uvd) | ||
379 | { | ||
380 | struct usb_device *dev = uvd->dev; | ||
381 | int i, errFlag; | ||
382 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
383 | int pktsz; | ||
384 | struct usb_interface *intf; | ||
385 | struct usb_host_interface *interface = NULL; | ||
386 | |||
387 | intf = usb_ifnum_to_if(dev, uvd->iface); | ||
388 | if (intf) | ||
389 | interface = usb_altnum_to_altsetting(intf, | ||
390 | spd_to_iface[cam->speed]); | ||
391 | if (!interface) | ||
392 | return -ENXIO; | ||
393 | pktsz = le16_to_cpu(interface->endpoint[1].desc.wMaxPacketSize); | ||
394 | DEBUG(1, "pktsz = %d", pktsz); | ||
395 | if (!CAMERA_IS_OPERATIONAL(uvd)) { | ||
396 | err("Camera is not operational"); | ||
397 | return -EFAULT; | ||
398 | } | ||
399 | uvd->curframe = -1; | ||
400 | konicawc_camera_on(uvd); | ||
401 | /* Alternate interface 1 is is the biggest frame size */ | ||
402 | i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive); | ||
403 | if (i < 0) { | ||
404 | err("usb_set_interface error"); | ||
405 | uvd->last_error = i; | ||
406 | return -EBUSY; | ||
407 | } | ||
408 | |||
409 | /* We double buffer the Iso lists */ | ||
410 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
411 | int j, k; | ||
412 | struct urb *urb = uvd->sbuf[i].urb; | ||
413 | urb->dev = dev; | ||
414 | urb->context = uvd; | ||
415 | urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp); | ||
416 | urb->interval = 1; | ||
417 | urb->transfer_flags = URB_ISO_ASAP; | ||
418 | urb->transfer_buffer = uvd->sbuf[i].data; | ||
419 | urb->complete = konicawc_isoc_irq; | ||
420 | urb->number_of_packets = FRAMES_PER_DESC; | ||
421 | urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC; | ||
422 | for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) { | ||
423 | urb->iso_frame_desc[j].offset = k; | ||
424 | urb->iso_frame_desc[j].length = pktsz; | ||
425 | } | ||
426 | |||
427 | urb = cam->sts_urb[i]; | ||
428 | urb->dev = dev; | ||
429 | urb->context = uvd; | ||
430 | urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1); | ||
431 | urb->interval = 1; | ||
432 | urb->transfer_flags = URB_ISO_ASAP; | ||
433 | urb->transfer_buffer = cam->sts_buf[i]; | ||
434 | urb->complete = konicawc_isoc_irq; | ||
435 | urb->number_of_packets = FRAMES_PER_DESC; | ||
436 | urb->transfer_buffer_length = FRAMES_PER_DESC; | ||
437 | for (j=0; j < FRAMES_PER_DESC; j++) { | ||
438 | urb->iso_frame_desc[j].offset = j; | ||
439 | urb->iso_frame_desc[j].length = 1; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | cam->last_data_urb = NULL; | ||
444 | |||
445 | /* Submit all URBs */ | ||
446 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
447 | errFlag = usb_submit_urb(cam->sts_urb[i], GFP_KERNEL); | ||
448 | if (errFlag) | ||
449 | err("usb_submit_isoc(%d) ret %d", i, errFlag); | ||
450 | |||
451 | errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL); | ||
452 | if (errFlag) | ||
453 | err ("usb_submit_isoc(%d) ret %d", i, errFlag); | ||
454 | } | ||
455 | |||
456 | uvd->streaming = 1; | ||
457 | DEBUG(1, "streaming=1 video_endp=$%02x", uvd->video_endp); | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | |||
462 | static void konicawc_stop_data(struct uvd *uvd) | ||
463 | { | ||
464 | int i, j; | ||
465 | struct konicawc *cam; | ||
466 | |||
467 | if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL)) | ||
468 | return; | ||
469 | |||
470 | konicawc_camera_off(uvd); | ||
471 | uvd->streaming = 0; | ||
472 | cam = (struct konicawc *)uvd->user_data; | ||
473 | cam->last_data_urb = NULL; | ||
474 | |||
475 | /* Unschedule all of the iso td's */ | ||
476 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
477 | usb_kill_urb(uvd->sbuf[i].urb); | ||
478 | usb_kill_urb(cam->sts_urb[i]); | ||
479 | } | ||
480 | |||
481 | if (!uvd->remove_pending) { | ||
482 | /* Set packet size to 0 */ | ||
483 | j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive); | ||
484 | if (j < 0) { | ||
485 | err("usb_set_interface() error %d.", j); | ||
486 | uvd->last_error = j; | ||
487 | } | ||
488 | } | ||
489 | } | ||
490 | |||
491 | |||
492 | static void konicawc_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame) | ||
493 | { | ||
494 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
495 | int maxline = cam->maxline; | ||
496 | int yplanesz = cam->yplanesz; | ||
497 | |||
498 | assert(frame != NULL); | ||
499 | |||
500 | DEBUG(5, "maxline = %d yplanesz = %d", maxline, yplanesz); | ||
501 | DEBUG(3, "Frame state = %d", frame->scanstate); | ||
502 | |||
503 | if(frame->scanstate == ScanState_Scanning) { | ||
504 | int drop = 0; | ||
505 | int curframe; | ||
506 | int fdrops = 0; | ||
507 | DEBUG(3, "Searching for marker, queue len = %d", RingQueue_GetLength(&uvd->dp)); | ||
508 | while(RingQueue_GetLength(&uvd->dp) >= 4) { | ||
509 | if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && | ||
510 | (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) && | ||
511 | (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) && | ||
512 | (RING_QUEUE_PEEK(&uvd->dp, 3) < 0x80)) { | ||
513 | curframe = RING_QUEUE_PEEK(&uvd->dp, 3); | ||
514 | if(cam->lastframe >= 0) { | ||
515 | fdrops = (0x80 + curframe - cam->lastframe) & 0x7F; | ||
516 | fdrops--; | ||
517 | if(fdrops) { | ||
518 | info("Dropped %d frames (%d -> %d)", fdrops, | ||
519 | cam->lastframe, curframe); | ||
520 | } | ||
521 | } | ||
522 | cam->lastframe = curframe; | ||
523 | frame->curline = 0; | ||
524 | frame->scanstate = ScanState_Lines; | ||
525 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4); | ||
526 | break; | ||
527 | } | ||
528 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); | ||
529 | drop++; | ||
530 | } | ||
531 | if(drop) | ||
532 | DEBUG(2, "dropped %d bytes looking for new frame", drop); | ||
533 | } | ||
534 | |||
535 | if(frame->scanstate == ScanState_Scanning) | ||
536 | return; | ||
537 | |||
538 | /* Try to move data from queue into frame buffer | ||
539 | * We get data in blocks of 384 bytes made up of: | ||
540 | * 256 Y, 64 U, 64 V. | ||
541 | * This needs to be written out as a Y plane, a U plane and a V plane. | ||
542 | */ | ||
543 | |||
544 | while ( frame->curline < maxline && (RingQueue_GetLength(&uvd->dp) >= 384)) { | ||
545 | /* Y */ | ||
546 | RingQueue_Dequeue(&uvd->dp, frame->data + (frame->curline * 256), 256); | ||
547 | /* U */ | ||
548 | RingQueue_Dequeue(&uvd->dp, frame->data + yplanesz + (frame->curline * 64), 64); | ||
549 | /* V */ | ||
550 | RingQueue_Dequeue(&uvd->dp, frame->data + (5 * yplanesz)/4 + (frame->curline * 64), 64); | ||
551 | frame->seqRead_Length += 384; | ||
552 | frame->curline++; | ||
553 | } | ||
554 | /* See if we filled the frame */ | ||
555 | if (frame->curline == maxline) { | ||
556 | DEBUG(5, "got whole frame"); | ||
557 | |||
558 | frame->frameState = FrameState_Done_Hold; | ||
559 | frame->curline = 0; | ||
560 | uvd->curframe = -1; | ||
561 | uvd->stats.frame_num++; | ||
562 | } | ||
563 | } | ||
564 | |||
565 | |||
566 | static int konicawc_find_fps(int size, int fps) | ||
567 | { | ||
568 | int i; | ||
569 | |||
570 | fps *= 3; | ||
571 | DEBUG(1, "konica_find_fps: size = %d fps = %d", size, fps); | ||
572 | if(fps <= spd_to_fps[size][0]) | ||
573 | return 0; | ||
574 | |||
575 | if(fps >= spd_to_fps[size][MAX_SPEED]) | ||
576 | return MAX_SPEED; | ||
577 | |||
578 | for(i = 0; i < MAX_SPEED; i++) { | ||
579 | if((fps >= spd_to_fps[size][i]) && (fps <= spd_to_fps[size][i+1])) { | ||
580 | DEBUG(2, "fps %d between %d and %d", fps, i, i+1); | ||
581 | if( (fps - spd_to_fps[size][i]) < (spd_to_fps[size][i+1] - fps)) | ||
582 | return i; | ||
583 | else | ||
584 | return i+1; | ||
585 | } | ||
586 | } | ||
587 | return MAX_SPEED+1; | ||
588 | } | ||
589 | |||
590 | |||
591 | static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw) | ||
592 | { | ||
593 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
594 | int newspeed = cam->speed; | ||
595 | int newsize; | ||
596 | int x = vw->width; | ||
597 | int y = vw->height; | ||
598 | int fps = vw->flags; | ||
599 | |||
600 | if(x > 0 && y > 0) { | ||
601 | DEBUG(2, "trying to find size %d,%d", x, y); | ||
602 | for(newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) { | ||
603 | if((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y)) | ||
604 | break; | ||
605 | } | ||
606 | } else { | ||
607 | newsize = cam->size; | ||
608 | } | ||
609 | |||
610 | if(newsize > MAX_FRAME_SIZE) { | ||
611 | DEBUG(1, "couldn't find size %d,%d", x, y); | ||
612 | return -EINVAL; | ||
613 | } | ||
614 | |||
615 | if(fps > 0) { | ||
616 | DEBUG(1, "trying to set fps to %d", fps); | ||
617 | newspeed = konicawc_find_fps(newsize, fps); | ||
618 | DEBUG(1, "find_fps returned %d (%d)", newspeed, spd_to_fps[newsize][newspeed]); | ||
619 | } | ||
620 | |||
621 | if(newspeed > MAX_SPEED) | ||
622 | return -EINVAL; | ||
623 | |||
624 | DEBUG(1, "setting size to %d speed to %d", newsize, newspeed); | ||
625 | if((newsize == cam->size) && (newspeed == cam->speed)) { | ||
626 | DEBUG(1, "Nothing to do"); | ||
627 | return 0; | ||
628 | } | ||
629 | DEBUG(0, "setting to %dx%d @ %d fps", camera_sizes[newsize].width, | ||
630 | camera_sizes[newsize].height, spd_to_fps[newsize][newspeed]/3); | ||
631 | |||
632 | konicawc_stop_data(uvd); | ||
633 | uvd->ifaceAltActive = spd_to_iface[newspeed]; | ||
634 | DEBUG(1, "new interface = %d", uvd->ifaceAltActive); | ||
635 | cam->speed = newspeed; | ||
636 | |||
637 | if(cam->size != newsize) { | ||
638 | cam->size = newsize; | ||
639 | konicawc_set_camera_size(uvd); | ||
640 | } | ||
641 | |||
642 | /* Flush the input queue and clear any current frame in progress */ | ||
643 | |||
644 | RingQueue_Flush(&uvd->dp); | ||
645 | cam->lastframe = -2; | ||
646 | if(uvd->curframe != -1) { | ||
647 | uvd->frame[uvd->curframe].curline = 0; | ||
648 | uvd->frame[uvd->curframe].seqRead_Length = 0; | ||
649 | uvd->frame[uvd->curframe].seqRead_Index = 0; | ||
650 | } | ||
651 | |||
652 | konicawc_start_data(uvd); | ||
653 | return 0; | ||
654 | } | ||
655 | |||
656 | |||
657 | static int konicawc_calculate_fps(struct uvd *uvd) | ||
658 | { | ||
659 | struct konicawc *cam = uvd->user_data; | ||
660 | return spd_to_fps[cam->size][cam->speed]/3; | ||
661 | } | ||
662 | |||
663 | |||
664 | static void konicawc_configure_video(struct uvd *uvd) | ||
665 | { | ||
666 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
667 | u8 buf[2]; | ||
668 | |||
669 | memset(&uvd->vpic, 0, sizeof(uvd->vpic)); | ||
670 | memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old)); | ||
671 | |||
672 | RESTRICT_TO_RANGE(brightness, 0, MAX_BRIGHTNESS); | ||
673 | RESTRICT_TO_RANGE(contrast, 0, MAX_CONTRAST); | ||
674 | RESTRICT_TO_RANGE(saturation, 0, MAX_SATURATION); | ||
675 | RESTRICT_TO_RANGE(sharpness, 0, MAX_SHARPNESS); | ||
676 | RESTRICT_TO_RANGE(whitebal, 0, MAX_WHITEBAL); | ||
677 | |||
678 | cam->brightness = brightness / 11; | ||
679 | cam->contrast = contrast / 11; | ||
680 | cam->saturation = saturation / 11; | ||
681 | cam->sharpness = sharpness / 11; | ||
682 | cam->white_bal = whitebal / 11; | ||
683 | |||
684 | uvd->vpic.colour = 108; | ||
685 | uvd->vpic.hue = 108; | ||
686 | uvd->vpic.brightness = brightness; | ||
687 | uvd->vpic.contrast = contrast; | ||
688 | uvd->vpic.whiteness = whitebal; | ||
689 | uvd->vpic.depth = 6; | ||
690 | uvd->vpic.palette = VIDEO_PALETTE_YUV420P; | ||
691 | |||
692 | memset(&uvd->vcap, 0, sizeof(uvd->vcap)); | ||
693 | strcpy(uvd->vcap.name, "Konica Webcam"); | ||
694 | uvd->vcap.type = VID_TYPE_CAPTURE; | ||
695 | uvd->vcap.channels = 1; | ||
696 | uvd->vcap.audios = 0; | ||
697 | uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width; | ||
698 | uvd->vcap.minheight = camera_sizes[SIZE_160X120].height; | ||
699 | uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width; | ||
700 | uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height; | ||
701 | |||
702 | memset(&uvd->vchan, 0, sizeof(uvd->vchan)); | ||
703 | uvd->vchan.flags = 0 ; | ||
704 | uvd->vchan.tuners = 0; | ||
705 | uvd->vchan.channel = 0; | ||
706 | uvd->vchan.type = VIDEO_TYPE_CAMERA; | ||
707 | strcpy(uvd->vchan.name, "Camera"); | ||
708 | |||
709 | /* Talk to device */ | ||
710 | DEBUG(1, "device init"); | ||
711 | if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2)) | ||
712 | DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]); | ||
713 | if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2)) | ||
714 | DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]); | ||
715 | if(konicawc_set_misc(uvd, 0x2, 0, 0xd)) | ||
716 | DEBUG(2, "2,0,d failed"); | ||
717 | DEBUG(1, "setting initial values"); | ||
718 | } | ||
719 | |||
720 | |||
721 | static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id *devid) | ||
722 | { | ||
723 | struct usb_device *dev = interface_to_usbdev(intf); | ||
724 | struct uvd *uvd = NULL; | ||
725 | int ix, i, nas; | ||
726 | int actInterface=-1, inactInterface=-1, maxPS=0; | ||
727 | unsigned char video_ep = 0; | ||
728 | |||
729 | DEBUG(1, "konicawc_probe(%p)", intf); | ||
730 | |||
731 | /* We don't handle multi-config cameras */ | ||
732 | if (dev->descriptor.bNumConfigurations != 1) | ||
733 | return -ENODEV; | ||
734 | |||
735 | info("Konica Webcam (rev. 0x%04x)", le16_to_cpu(dev->descriptor.bcdDevice)); | ||
736 | RESTRICT_TO_RANGE(speed, 0, MAX_SPEED); | ||
737 | |||
738 | /* Validate found interface: must have one ISO endpoint */ | ||
739 | nas = intf->num_altsetting; | ||
740 | if (nas != 8) { | ||
741 | err("Incorrect number of alternate settings (%d) for this camera!", nas); | ||
742 | return -ENODEV; | ||
743 | } | ||
744 | /* Validate all alternate settings */ | ||
745 | for (ix=0; ix < nas; ix++) { | ||
746 | const struct usb_host_interface *interface; | ||
747 | const struct usb_endpoint_descriptor *endpoint; | ||
748 | |||
749 | interface = &intf->altsetting[ix]; | ||
750 | i = interface->desc.bAlternateSetting; | ||
751 | if (interface->desc.bNumEndpoints != 2) { | ||
752 | err("Interface %d. has %u. endpoints!", | ||
753 | interface->desc.bInterfaceNumber, | ||
754 | (unsigned)(interface->desc.bNumEndpoints)); | ||
755 | return -ENODEV; | ||
756 | } | ||
757 | endpoint = &interface->endpoint[1].desc; | ||
758 | DEBUG(1, "found endpoint: addr: 0x%2.2x maxps = 0x%4.4x", | ||
759 | endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize)); | ||
760 | if (video_ep == 0) | ||
761 | video_ep = endpoint->bEndpointAddress; | ||
762 | else if (video_ep != endpoint->bEndpointAddress) { | ||
763 | err("Alternate settings have different endpoint addresses!"); | ||
764 | return -ENODEV; | ||
765 | } | ||
766 | if ((endpoint->bmAttributes & 0x03) != 0x01) { | ||
767 | err("Interface %d. has non-ISO endpoint!", | ||
768 | interface->desc.bInterfaceNumber); | ||
769 | return -ENODEV; | ||
770 | } | ||
771 | if ((endpoint->bEndpointAddress & 0x80) == 0) { | ||
772 | err("Interface %d. has ISO OUT endpoint!", | ||
773 | interface->desc.bInterfaceNumber); | ||
774 | return -ENODEV; | ||
775 | } | ||
776 | if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) { | ||
777 | if (inactInterface < 0) | ||
778 | inactInterface = i; | ||
779 | else { | ||
780 | err("More than one inactive alt. setting!"); | ||
781 | return -ENODEV; | ||
782 | } | ||
783 | } else { | ||
784 | if (i == spd_to_iface[speed]) { | ||
785 | /* This one is the requested one */ | ||
786 | actInterface = i; | ||
787 | } | ||
788 | } | ||
789 | if (le16_to_cpu(endpoint->wMaxPacketSize) > maxPS) | ||
790 | maxPS = le16_to_cpu(endpoint->wMaxPacketSize); | ||
791 | } | ||
792 | if(actInterface == -1) { | ||
793 | err("Cant find required endpoint"); | ||
794 | return -ENODEV; | ||
795 | } | ||
796 | |||
797 | DEBUG(1, "Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS); | ||
798 | |||
799 | uvd = usbvideo_AllocateDevice(cams); | ||
800 | if (uvd != NULL) { | ||
801 | struct konicawc *cam = (struct konicawc *)(uvd->user_data); | ||
802 | /* Here uvd is a fully allocated uvd object */ | ||
803 | for(i = 0; i < USBVIDEO_NUMSBUF; i++) { | ||
804 | cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); | ||
805 | if(cam->sts_urb[i] == NULL) { | ||
806 | while(i--) { | ||
807 | usb_free_urb(cam->sts_urb[i]); | ||
808 | } | ||
809 | err("can't allocate urbs"); | ||
810 | return -ENOMEM; | ||
811 | } | ||
812 | } | ||
813 | cam->speed = speed; | ||
814 | RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240); | ||
815 | cam->width = camera_sizes[size].width; | ||
816 | cam->height = camera_sizes[size].height; | ||
817 | cam->size = size; | ||
818 | |||
819 | uvd->flags = 0; | ||
820 | uvd->debug = debug; | ||
821 | uvd->dev = dev; | ||
822 | uvd->iface = intf->altsetting->desc.bInterfaceNumber; | ||
823 | uvd->ifaceAltInactive = inactInterface; | ||
824 | uvd->ifaceAltActive = actInterface; | ||
825 | uvd->video_endp = video_ep; | ||
826 | uvd->iso_packet_len = maxPS; | ||
827 | uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P; | ||
828 | uvd->defaultPalette = VIDEO_PALETTE_YUV420P; | ||
829 | uvd->canvas = VIDEOSIZE(320, 240); | ||
830 | uvd->videosize = VIDEOSIZE(cam->width, cam->height); | ||
831 | |||
832 | /* Initialize konicawc specific data */ | ||
833 | konicawc_configure_video(uvd); | ||
834 | |||
835 | i = usbvideo_RegisterVideoDevice(uvd); | ||
836 | uvd->max_frame_size = (320 * 240 * 3)/2; | ||
837 | if (i != 0) { | ||
838 | err("usbvideo_RegisterVideoDevice() failed."); | ||
839 | uvd = NULL; | ||
840 | } | ||
841 | #ifdef CONFIG_INPUT | ||
842 | /* Register input device for button */ | ||
843 | memset(&cam->input, 0, sizeof(struct input_dev)); | ||
844 | cam->input.name = "Konicawc snapshot button"; | ||
845 | cam->input.private = cam; | ||
846 | cam->input.evbit[0] = BIT(EV_KEY); | ||
847 | cam->input.keybit[LONG(BTN_0)] = BIT(BTN_0); | ||
848 | cam->input.id.bustype = BUS_USB; | ||
849 | cam->input.id.vendor = le16_to_cpu(dev->descriptor.idVendor); | ||
850 | cam->input.id.product = le16_to_cpu(dev->descriptor.idProduct); | ||
851 | cam->input.id.version = le16_to_cpu(dev->descriptor.bcdDevice); | ||
852 | input_register_device(&cam->input); | ||
853 | |||
854 | usb_make_path(dev, cam->input_physname, 56); | ||
855 | strcat(cam->input_physname, "/input0"); | ||
856 | cam->input.phys = cam->input_physname; | ||
857 | info("konicawc: %s on %s\n", cam->input.name, cam->input.phys); | ||
858 | #endif | ||
859 | } | ||
860 | |||
861 | if (uvd) { | ||
862 | usb_set_intfdata (intf, uvd); | ||
863 | return 0; | ||
864 | } | ||
865 | return -EIO; | ||
866 | } | ||
867 | |||
868 | |||
869 | static void konicawc_free_uvd(struct uvd *uvd) | ||
870 | { | ||
871 | int i; | ||
872 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
873 | |||
874 | #ifdef CONFIG_INPUT | ||
875 | input_unregister_device(&cam->input); | ||
876 | #endif | ||
877 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
878 | usb_free_urb(cam->sts_urb[i]); | ||
879 | cam->sts_urb[i] = NULL; | ||
880 | } | ||
881 | } | ||
882 | |||
883 | |||
884 | static struct usb_device_id id_table[] = { | ||
885 | { USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */ | ||
886 | { } /* Terminating entry */ | ||
887 | }; | ||
888 | |||
889 | |||
890 | static int __init konicawc_init(void) | ||
891 | { | ||
892 | struct usbvideo_cb cbTbl; | ||
893 | info(DRIVER_DESC " " DRIVER_VERSION); | ||
894 | memset(&cbTbl, 0, sizeof(cbTbl)); | ||
895 | cbTbl.probe = konicawc_probe; | ||
896 | cbTbl.setupOnOpen = konicawc_setup_on_open; | ||
897 | cbTbl.processData = konicawc_process_isoc; | ||
898 | cbTbl.getFPS = konicawc_calculate_fps; | ||
899 | cbTbl.setVideoMode = konicawc_set_video_mode; | ||
900 | cbTbl.startDataPump = konicawc_start_data; | ||
901 | cbTbl.stopDataPump = konicawc_stop_data; | ||
902 | cbTbl.adjustPicture = konicawc_adjust_picture; | ||
903 | cbTbl.userFree = konicawc_free_uvd; | ||
904 | return usbvideo_register( | ||
905 | &cams, | ||
906 | MAX_CAMERAS, | ||
907 | sizeof(struct konicawc), | ||
908 | "konicawc", | ||
909 | &cbTbl, | ||
910 | THIS_MODULE, | ||
911 | id_table); | ||
912 | } | ||
913 | |||
914 | |||
915 | static void __exit konicawc_cleanup(void) | ||
916 | { | ||
917 | usbvideo_Deregister(&cams); | ||
918 | } | ||
919 | |||
920 | |||
921 | MODULE_DEVICE_TABLE(usb, id_table); | ||
922 | |||
923 | MODULE_LICENSE("GPL"); | ||
924 | MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>"); | ||
925 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
926 | module_param(speed, int, 0); | ||
927 | MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)"); | ||
928 | module_param(size, int, 0); | ||
929 | MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240"); | ||
930 | module_param(brightness, int, 0); | ||
931 | MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108"); | ||
932 | module_param(contrast, int, 0); | ||
933 | MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108"); | ||
934 | module_param(saturation, int, 0); | ||
935 | MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108"); | ||
936 | module_param(sharpness, int, 0); | ||
937 | MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108"); | ||
938 | module_param(whitebal, int, 0); | ||
939 | MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363"); | ||
940 | |||
941 | #ifdef CONFIG_USB_DEBUG | ||
942 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
943 | MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); | ||
944 | #endif | ||
945 | |||
946 | module_init(konicawc_init); | ||
947 | module_exit(konicawc_cleanup); | ||
diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c new file mode 100644 index 000000000000..0fd7ffed3a98 --- /dev/null +++ b/drivers/usb/media/ov511.c | |||
@@ -0,0 +1,6131 @@ | |||
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 | static struct ov51x_decomp_ops *ov511_decomp_ops; | ||
208 | static struct ov51x_decomp_ops *ov511_mmx_decomp_ops; | ||
209 | static struct ov51x_decomp_ops *ov518_decomp_ops; | ||
210 | static struct ov51x_decomp_ops *ov518_mmx_decomp_ops; | ||
211 | |||
212 | /* Number of times to retry a failed I2C transaction. Increase this if you | ||
213 | * are getting "Failed to read sensor ID..." */ | ||
214 | static int i2c_detect_tries = 5; | ||
215 | |||
216 | /* MMX support is present in kernel and CPU. Checked upon decomp module load. */ | ||
217 | #if defined(__i386__) || defined(__x86_64__) | ||
218 | #define ov51x_mmx_available (cpu_has_mmx) | ||
219 | #else | ||
220 | #define ov51x_mmx_available (0) | ||
221 | #endif | ||
222 | |||
223 | static struct usb_device_id device_table [] = { | ||
224 | { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) }, | ||
225 | { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) }, | ||
226 | { USB_DEVICE(VEND_OMNIVISION, PROD_OV518) }, | ||
227 | { USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) }, | ||
228 | { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) }, | ||
229 | { } /* Terminating entry */ | ||
230 | }; | ||
231 | |||
232 | MODULE_DEVICE_TABLE (usb, device_table); | ||
233 | |||
234 | static unsigned char yQuanTable511[] = OV511_YQUANTABLE; | ||
235 | static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE; | ||
236 | static unsigned char yQuanTable518[] = OV518_YQUANTABLE; | ||
237 | static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE; | ||
238 | |||
239 | /********************************************************************** | ||
240 | * Symbolic Names | ||
241 | **********************************************************************/ | ||
242 | |||
243 | /* Known OV511-based cameras */ | ||
244 | static struct symbolic_list camlist[] = { | ||
245 | { 0, "Generic Camera (no ID)" }, | ||
246 | { 1, "Mustek WCam 3X" }, | ||
247 | { 3, "D-Link DSB-C300" }, | ||
248 | { 4, "Generic OV511/OV7610" }, | ||
249 | { 5, "Puretek PT-6007" }, | ||
250 | { 6, "Lifeview USB Life TV (NTSC)" }, | ||
251 | { 21, "Creative Labs WebCam 3" }, | ||
252 | { 22, "Lifeview USB Life TV (PAL D/K+B/G)" }, | ||
253 | { 36, "Koala-Cam" }, | ||
254 | { 38, "Lifeview USB Life TV (PAL)" }, | ||
255 | { 41, "Samsung Anycam MPC-M10" }, | ||
256 | { 43, "Mtekvision Zeca MV402" }, | ||
257 | { 46, "Suma eON" }, | ||
258 | { 70, "Lifeview USB Life TV (PAL/SECAM)" }, | ||
259 | { 100, "Lifeview RoboCam" }, | ||
260 | { 102, "AverMedia InterCam Elite" }, | ||
261 | { 112, "MediaForte MV300" }, /* or OV7110 evaluation kit */ | ||
262 | { 134, "Ezonics EZCam II" }, | ||
263 | { 192, "Webeye 2000B" }, | ||
264 | { 253, "Alpha Vision Tech. AlphaCam SE" }, | ||
265 | { -1, NULL } | ||
266 | }; | ||
267 | |||
268 | /* Video4Linux1 Palettes */ | ||
269 | static struct symbolic_list v4l1_plist[] = { | ||
270 | { VIDEO_PALETTE_GREY, "GREY" }, | ||
271 | { VIDEO_PALETTE_HI240, "HI240" }, | ||
272 | { VIDEO_PALETTE_RGB565, "RGB565" }, | ||
273 | { VIDEO_PALETTE_RGB24, "RGB24" }, | ||
274 | { VIDEO_PALETTE_RGB32, "RGB32" }, | ||
275 | { VIDEO_PALETTE_RGB555, "RGB555" }, | ||
276 | { VIDEO_PALETTE_YUV422, "YUV422" }, | ||
277 | { VIDEO_PALETTE_YUYV, "YUYV" }, | ||
278 | { VIDEO_PALETTE_UYVY, "UYVY" }, | ||
279 | { VIDEO_PALETTE_YUV420, "YUV420" }, | ||
280 | { VIDEO_PALETTE_YUV411, "YUV411" }, | ||
281 | { VIDEO_PALETTE_RAW, "RAW" }, | ||
282 | { VIDEO_PALETTE_YUV422P,"YUV422P" }, | ||
283 | { VIDEO_PALETTE_YUV411P,"YUV411P" }, | ||
284 | { VIDEO_PALETTE_YUV420P,"YUV420P" }, | ||
285 | { VIDEO_PALETTE_YUV410P,"YUV410P" }, | ||
286 | { -1, NULL } | ||
287 | }; | ||
288 | |||
289 | static struct symbolic_list brglist[] = { | ||
290 | { BRG_OV511, "OV511" }, | ||
291 | { BRG_OV511PLUS, "OV511+" }, | ||
292 | { BRG_OV518, "OV518" }, | ||
293 | { BRG_OV518PLUS, "OV518+" }, | ||
294 | { -1, NULL } | ||
295 | }; | ||
296 | |||
297 | static struct symbolic_list senlist[] = { | ||
298 | { SEN_OV76BE, "OV76BE" }, | ||
299 | { SEN_OV7610, "OV7610" }, | ||
300 | { SEN_OV7620, "OV7620" }, | ||
301 | { SEN_OV7620AE, "OV7620AE" }, | ||
302 | { SEN_OV6620, "OV6620" }, | ||
303 | { SEN_OV6630, "OV6630" }, | ||
304 | { SEN_OV6630AE, "OV6630AE" }, | ||
305 | { SEN_OV6630AF, "OV6630AF" }, | ||
306 | { SEN_OV8600, "OV8600" }, | ||
307 | { SEN_KS0127, "KS0127" }, | ||
308 | { SEN_KS0127B, "KS0127B" }, | ||
309 | { SEN_SAA7111A, "SAA7111A" }, | ||
310 | { -1, NULL } | ||
311 | }; | ||
312 | |||
313 | /* URB error codes: */ | ||
314 | static struct symbolic_list urb_errlist[] = { | ||
315 | { -ENOSR, "Buffer error (overrun)" }, | ||
316 | { -EPIPE, "Stalled (device not responding)" }, | ||
317 | { -EOVERFLOW, "Babble (bad cable?)" }, | ||
318 | { -EPROTO, "Bit-stuff error (bad cable?)" }, | ||
319 | { -EILSEQ, "CRC/Timeout" }, | ||
320 | { -ETIMEDOUT, "NAK (device does not respond)" }, | ||
321 | { -1, NULL } | ||
322 | }; | ||
323 | |||
324 | /********************************************************************** | ||
325 | * Memory management | ||
326 | **********************************************************************/ | ||
327 | static void * | ||
328 | rvmalloc(unsigned long size) | ||
329 | { | ||
330 | void *mem; | ||
331 | unsigned long adr; | ||
332 | |||
333 | size = PAGE_ALIGN(size); | ||
334 | mem = vmalloc_32(size); | ||
335 | if (!mem) | ||
336 | return NULL; | ||
337 | |||
338 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
339 | adr = (unsigned long) mem; | ||
340 | while (size > 0) { | ||
341 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
342 | adr += PAGE_SIZE; | ||
343 | size -= PAGE_SIZE; | ||
344 | } | ||
345 | |||
346 | return mem; | ||
347 | } | ||
348 | |||
349 | static void | ||
350 | rvfree(void *mem, unsigned long size) | ||
351 | { | ||
352 | unsigned long adr; | ||
353 | |||
354 | if (!mem) | ||
355 | return; | ||
356 | |||
357 | adr = (unsigned long) mem; | ||
358 | while ((long) size > 0) { | ||
359 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
360 | adr += PAGE_SIZE; | ||
361 | size -= PAGE_SIZE; | ||
362 | } | ||
363 | vfree(mem); | ||
364 | } | ||
365 | |||
366 | /********************************************************************** | ||
367 | * | ||
368 | * Register I/O | ||
369 | * | ||
370 | **********************************************************************/ | ||
371 | |||
372 | /* Write an OV51x register */ | ||
373 | static int | ||
374 | reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) | ||
375 | { | ||
376 | int rc; | ||
377 | |||
378 | PDEBUG(5, "0x%02X:0x%02X", reg, value); | ||
379 | |||
380 | down(&ov->cbuf_lock); | ||
381 | ov->cbuf[0] = value; | ||
382 | rc = usb_control_msg(ov->dev, | ||
383 | usb_sndctrlpipe(ov->dev, 0), | ||
384 | (ov->bclass == BCL_OV518)?1:2 /* REG_IO */, | ||
385 | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
386 | 0, (__u16)reg, &ov->cbuf[0], 1, 1000); | ||
387 | up(&ov->cbuf_lock); | ||
388 | |||
389 | if (rc < 0) | ||
390 | err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc)); | ||
391 | |||
392 | return rc; | ||
393 | } | ||
394 | |||
395 | /* Read from an OV51x register */ | ||
396 | /* returns: negative is error, pos or zero is data */ | ||
397 | static int | ||
398 | reg_r(struct usb_ov511 *ov, unsigned char reg) | ||
399 | { | ||
400 | int rc; | ||
401 | |||
402 | down(&ov->cbuf_lock); | ||
403 | rc = usb_control_msg(ov->dev, | ||
404 | usb_rcvctrlpipe(ov->dev, 0), | ||
405 | (ov->bclass == BCL_OV518)?1:3 /* REG_IO */, | ||
406 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
407 | 0, (__u16)reg, &ov->cbuf[0], 1, 1000); | ||
408 | |||
409 | if (rc < 0) { | ||
410 | err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc)); | ||
411 | } else { | ||
412 | rc = ov->cbuf[0]; | ||
413 | PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]); | ||
414 | } | ||
415 | |||
416 | up(&ov->cbuf_lock); | ||
417 | |||
418 | return rc; | ||
419 | } | ||
420 | |||
421 | /* | ||
422 | * Writes bits at positions specified by mask to an OV51x reg. Bits that are in | ||
423 | * the same position as 1's in "mask" are cleared and set to "value". Bits | ||
424 | * that are in the same position as 0's in "mask" are preserved, regardless | ||
425 | * of their respective state in "value". | ||
426 | */ | ||
427 | static int | ||
428 | reg_w_mask(struct usb_ov511 *ov, | ||
429 | unsigned char reg, | ||
430 | unsigned char value, | ||
431 | unsigned char mask) | ||
432 | { | ||
433 | int ret; | ||
434 | unsigned char oldval, newval; | ||
435 | |||
436 | ret = reg_r(ov, reg); | ||
437 | if (ret < 0) | ||
438 | return ret; | ||
439 | |||
440 | oldval = (unsigned char) ret; | ||
441 | oldval &= (~mask); /* Clear the masked bits */ | ||
442 | value &= mask; /* Enforce mask on value */ | ||
443 | newval = oldval | value; /* Set the desired bits */ | ||
444 | |||
445 | return (reg_w(ov, reg, newval)); | ||
446 | } | ||
447 | |||
448 | /* | ||
449 | * Writes multiple (n) byte value to a single register. Only valid with certain | ||
450 | * registers (0x30 and 0xc4 - 0xce). | ||
451 | */ | ||
452 | static int | ||
453 | ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n) | ||
454 | { | ||
455 | int rc; | ||
456 | |||
457 | PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n); | ||
458 | |||
459 | down(&ov->cbuf_lock); | ||
460 | |||
461 | *((__le32 *)ov->cbuf) = __cpu_to_le32(val); | ||
462 | |||
463 | rc = usb_control_msg(ov->dev, | ||
464 | usb_sndctrlpipe(ov->dev, 0), | ||
465 | 1 /* REG_IO */, | ||
466 | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
467 | 0, (__u16)reg, ov->cbuf, n, 1000); | ||
468 | up(&ov->cbuf_lock); | ||
469 | |||
470 | if (rc < 0) | ||
471 | err("reg write multiple: error %d: %s", rc, | ||
472 | symbolic(urb_errlist, rc)); | ||
473 | |||
474 | return rc; | ||
475 | } | ||
476 | |||
477 | static int | ||
478 | ov511_upload_quan_tables(struct usb_ov511 *ov) | ||
479 | { | ||
480 | unsigned char *pYTable = yQuanTable511; | ||
481 | unsigned char *pUVTable = uvQuanTable511; | ||
482 | unsigned char val0, val1; | ||
483 | int i, rc, reg = R511_COMP_LUT_BEGIN; | ||
484 | |||
485 | PDEBUG(4, "Uploading quantization tables"); | ||
486 | |||
487 | for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) { | ||
488 | if (ENABLE_Y_QUANTABLE) { | ||
489 | val0 = *pYTable++; | ||
490 | val1 = *pYTable++; | ||
491 | val0 &= 0x0f; | ||
492 | val1 &= 0x0f; | ||
493 | val0 |= val1 << 4; | ||
494 | rc = reg_w(ov, reg, val0); | ||
495 | if (rc < 0) | ||
496 | return rc; | ||
497 | } | ||
498 | |||
499 | if (ENABLE_UV_QUANTABLE) { | ||
500 | val0 = *pUVTable++; | ||
501 | val1 = *pUVTable++; | ||
502 | val0 &= 0x0f; | ||
503 | val1 &= 0x0f; | ||
504 | val0 |= val1 << 4; | ||
505 | rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0); | ||
506 | if (rc < 0) | ||
507 | return rc; | ||
508 | } | ||
509 | |||
510 | reg++; | ||
511 | } | ||
512 | |||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | /* OV518 quantization tables are 8x4 (instead of 8x8) */ | ||
517 | static int | ||
518 | ov518_upload_quan_tables(struct usb_ov511 *ov) | ||
519 | { | ||
520 | unsigned char *pYTable = yQuanTable518; | ||
521 | unsigned char *pUVTable = uvQuanTable518; | ||
522 | unsigned char val0, val1; | ||
523 | int i, rc, reg = R511_COMP_LUT_BEGIN; | ||
524 | |||
525 | PDEBUG(4, "Uploading quantization tables"); | ||
526 | |||
527 | for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) { | ||
528 | if (ENABLE_Y_QUANTABLE) { | ||
529 | val0 = *pYTable++; | ||
530 | val1 = *pYTable++; | ||
531 | val0 &= 0x0f; | ||
532 | val1 &= 0x0f; | ||
533 | val0 |= val1 << 4; | ||
534 | rc = reg_w(ov, reg, val0); | ||
535 | if (rc < 0) | ||
536 | return rc; | ||
537 | } | ||
538 | |||
539 | if (ENABLE_UV_QUANTABLE) { | ||
540 | val0 = *pUVTable++; | ||
541 | val1 = *pUVTable++; | ||
542 | val0 &= 0x0f; | ||
543 | val1 &= 0x0f; | ||
544 | val0 |= val1 << 4; | ||
545 | rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0); | ||
546 | if (rc < 0) | ||
547 | return rc; | ||
548 | } | ||
549 | |||
550 | reg++; | ||
551 | } | ||
552 | |||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | static int | ||
557 | ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type) | ||
558 | { | ||
559 | int rc; | ||
560 | |||
561 | /* Setting bit 0 not allowed on 518/518Plus */ | ||
562 | if (ov->bclass == BCL_OV518) | ||
563 | reset_type &= 0xfe; | ||
564 | |||
565 | PDEBUG(4, "Reset: type=0x%02X", reset_type); | ||
566 | |||
567 | rc = reg_w(ov, R51x_SYS_RESET, reset_type); | ||
568 | rc = reg_w(ov, R51x_SYS_RESET, 0); | ||
569 | |||
570 | if (rc < 0) | ||
571 | err("reset: command failed"); | ||
572 | |||
573 | return rc; | ||
574 | } | ||
575 | |||
576 | /********************************************************************** | ||
577 | * | ||
578 | * Low-level I2C I/O functions | ||
579 | * | ||
580 | **********************************************************************/ | ||
581 | |||
582 | /* NOTE: Do not call this function directly! | ||
583 | * The OV518 I2C I/O procedure is different, hence, this function. | ||
584 | * This is normally only called from i2c_w(). Note that this function | ||
585 | * always succeeds regardless of whether the sensor is present and working. | ||
586 | */ | ||
587 | static int | ||
588 | ov518_i2c_write_internal(struct usb_ov511 *ov, | ||
589 | unsigned char reg, | ||
590 | unsigned char value) | ||
591 | { | ||
592 | int rc; | ||
593 | |||
594 | PDEBUG(5, "0x%02X:0x%02X", reg, value); | ||
595 | |||
596 | /* Select camera register */ | ||
597 | rc = reg_w(ov, R51x_I2C_SADDR_3, reg); | ||
598 | if (rc < 0) | ||
599 | return rc; | ||
600 | |||
601 | /* Write "value" to I2C data port of OV511 */ | ||
602 | rc = reg_w(ov, R51x_I2C_DATA, value); | ||
603 | if (rc < 0) | ||
604 | return rc; | ||
605 | |||
606 | /* Initiate 3-byte write cycle */ | ||
607 | rc = reg_w(ov, R518_I2C_CTL, 0x01); | ||
608 | if (rc < 0) | ||
609 | return rc; | ||
610 | |||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | /* NOTE: Do not call this function directly! */ | ||
615 | static int | ||
616 | ov511_i2c_write_internal(struct usb_ov511 *ov, | ||
617 | unsigned char reg, | ||
618 | unsigned char value) | ||
619 | { | ||
620 | int rc, retries; | ||
621 | |||
622 | PDEBUG(5, "0x%02X:0x%02X", reg, value); | ||
623 | |||
624 | /* Three byte write cycle */ | ||
625 | for (retries = OV511_I2C_RETRIES; ; ) { | ||
626 | /* Select camera register */ | ||
627 | rc = reg_w(ov, R51x_I2C_SADDR_3, reg); | ||
628 | if (rc < 0) | ||
629 | break; | ||
630 | |||
631 | /* Write "value" to I2C data port of OV511 */ | ||
632 | rc = reg_w(ov, R51x_I2C_DATA, value); | ||
633 | if (rc < 0) | ||
634 | break; | ||
635 | |||
636 | /* Initiate 3-byte write cycle */ | ||
637 | rc = reg_w(ov, R511_I2C_CTL, 0x01); | ||
638 | if (rc < 0) | ||
639 | break; | ||
640 | |||
641 | /* Retry until idle */ | ||
642 | do | ||
643 | rc = reg_r(ov, R511_I2C_CTL); | ||
644 | while (rc > 0 && ((rc&1) == 0)); | ||
645 | if (rc < 0) | ||
646 | break; | ||
647 | |||
648 | /* Ack? */ | ||
649 | if ((rc&2) == 0) { | ||
650 | rc = 0; | ||
651 | break; | ||
652 | } | ||
653 | #if 0 | ||
654 | /* I2C abort */ | ||
655 | reg_w(ov, R511_I2C_CTL, 0x10); | ||
656 | #endif | ||
657 | if (--retries < 0) { | ||
658 | err("i2c write retries exhausted"); | ||
659 | rc = -1; | ||
660 | break; | ||
661 | } | ||
662 | } | ||
663 | |||
664 | return rc; | ||
665 | } | ||
666 | |||
667 | /* NOTE: Do not call this function directly! | ||
668 | * The OV518 I2C I/O procedure is different, hence, this function. | ||
669 | * This is normally only called from i2c_r(). Note that this function | ||
670 | * always succeeds regardless of whether the sensor is present and working. | ||
671 | */ | ||
672 | static int | ||
673 | ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) | ||
674 | { | ||
675 | int rc, value; | ||
676 | |||
677 | /* Select camera register */ | ||
678 | rc = reg_w(ov, R51x_I2C_SADDR_2, reg); | ||
679 | if (rc < 0) | ||
680 | return rc; | ||
681 | |||
682 | /* Initiate 2-byte write cycle */ | ||
683 | rc = reg_w(ov, R518_I2C_CTL, 0x03); | ||
684 | if (rc < 0) | ||
685 | return rc; | ||
686 | |||
687 | /* Initiate 2-byte read cycle */ | ||
688 | rc = reg_w(ov, R518_I2C_CTL, 0x05); | ||
689 | if (rc < 0) | ||
690 | return rc; | ||
691 | |||
692 | value = reg_r(ov, R51x_I2C_DATA); | ||
693 | |||
694 | PDEBUG(5, "0x%02X:0x%02X", reg, value); | ||
695 | |||
696 | return value; | ||
697 | } | ||
698 | |||
699 | /* NOTE: Do not call this function directly! | ||
700 | * returns: negative is error, pos or zero is data */ | ||
701 | static int | ||
702 | ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) | ||
703 | { | ||
704 | int rc, value, retries; | ||
705 | |||
706 | /* Two byte write cycle */ | ||
707 | for (retries = OV511_I2C_RETRIES; ; ) { | ||
708 | /* Select camera register */ | ||
709 | rc = reg_w(ov, R51x_I2C_SADDR_2, reg); | ||
710 | if (rc < 0) | ||
711 | return rc; | ||
712 | |||
713 | /* Initiate 2-byte write cycle */ | ||
714 | rc = reg_w(ov, R511_I2C_CTL, 0x03); | ||
715 | if (rc < 0) | ||
716 | return rc; | ||
717 | |||
718 | /* Retry until idle */ | ||
719 | do | ||
720 | rc = reg_r(ov, R511_I2C_CTL); | ||
721 | while (rc > 0 && ((rc&1) == 0)); | ||
722 | if (rc < 0) | ||
723 | return rc; | ||
724 | |||
725 | if ((rc&2) == 0) /* Ack? */ | ||
726 | break; | ||
727 | |||
728 | /* I2C abort */ | ||
729 | reg_w(ov, R511_I2C_CTL, 0x10); | ||
730 | |||
731 | if (--retries < 0) { | ||
732 | err("i2c write retries exhausted"); | ||
733 | return -1; | ||
734 | } | ||
735 | } | ||
736 | |||
737 | /* Two byte read cycle */ | ||
738 | for (retries = OV511_I2C_RETRIES; ; ) { | ||
739 | /* Initiate 2-byte read cycle */ | ||
740 | rc = reg_w(ov, R511_I2C_CTL, 0x05); | ||
741 | if (rc < 0) | ||
742 | return rc; | ||
743 | |||
744 | /* Retry until idle */ | ||
745 | do | ||
746 | rc = reg_r(ov, R511_I2C_CTL); | ||
747 | while (rc > 0 && ((rc&1) == 0)); | ||
748 | if (rc < 0) | ||
749 | return rc; | ||
750 | |||
751 | if ((rc&2) == 0) /* Ack? */ | ||
752 | break; | ||
753 | |||
754 | /* I2C abort */ | ||
755 | rc = reg_w(ov, R511_I2C_CTL, 0x10); | ||
756 | if (rc < 0) | ||
757 | return rc; | ||
758 | |||
759 | if (--retries < 0) { | ||
760 | err("i2c read retries exhausted"); | ||
761 | return -1; | ||
762 | } | ||
763 | } | ||
764 | |||
765 | value = reg_r(ov, R51x_I2C_DATA); | ||
766 | |||
767 | PDEBUG(5, "0x%02X:0x%02X", reg, value); | ||
768 | |||
769 | /* This is needed to make i2c_w() work */ | ||
770 | rc = reg_w(ov, R511_I2C_CTL, 0x05); | ||
771 | if (rc < 0) | ||
772 | return rc; | ||
773 | |||
774 | return value; | ||
775 | } | ||
776 | |||
777 | /* returns: negative is error, pos or zero is data */ | ||
778 | static int | ||
779 | i2c_r(struct usb_ov511 *ov, unsigned char reg) | ||
780 | { | ||
781 | int rc; | ||
782 | |||
783 | down(&ov->i2c_lock); | ||
784 | |||
785 | if (ov->bclass == BCL_OV518) | ||
786 | rc = ov518_i2c_read_internal(ov, reg); | ||
787 | else | ||
788 | rc = ov511_i2c_read_internal(ov, reg); | ||
789 | |||
790 | up(&ov->i2c_lock); | ||
791 | |||
792 | return rc; | ||
793 | } | ||
794 | |||
795 | static int | ||
796 | i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) | ||
797 | { | ||
798 | int rc; | ||
799 | |||
800 | down(&ov->i2c_lock); | ||
801 | |||
802 | if (ov->bclass == BCL_OV518) | ||
803 | rc = ov518_i2c_write_internal(ov, reg, value); | ||
804 | else | ||
805 | rc = ov511_i2c_write_internal(ov, reg, value); | ||
806 | |||
807 | up(&ov->i2c_lock); | ||
808 | |||
809 | return rc; | ||
810 | } | ||
811 | |||
812 | /* Do not call this function directly! */ | ||
813 | static int | ||
814 | ov51x_i2c_write_mask_internal(struct usb_ov511 *ov, | ||
815 | unsigned char reg, | ||
816 | unsigned char value, | ||
817 | unsigned char mask) | ||
818 | { | ||
819 | int rc; | ||
820 | unsigned char oldval, newval; | ||
821 | |||
822 | if (mask == 0xff) { | ||
823 | newval = value; | ||
824 | } else { | ||
825 | if (ov->bclass == BCL_OV518) | ||
826 | rc = ov518_i2c_read_internal(ov, reg); | ||
827 | else | ||
828 | rc = ov511_i2c_read_internal(ov, reg); | ||
829 | if (rc < 0) | ||
830 | return rc; | ||
831 | |||
832 | oldval = (unsigned char) rc; | ||
833 | oldval &= (~mask); /* Clear the masked bits */ | ||
834 | value &= mask; /* Enforce mask on value */ | ||
835 | newval = oldval | value; /* Set the desired bits */ | ||
836 | } | ||
837 | |||
838 | if (ov->bclass == BCL_OV518) | ||
839 | return (ov518_i2c_write_internal(ov, reg, newval)); | ||
840 | else | ||
841 | return (ov511_i2c_write_internal(ov, reg, newval)); | ||
842 | } | ||
843 | |||
844 | /* Writes bits at positions specified by mask to an I2C reg. Bits that are in | ||
845 | * the same position as 1's in "mask" are cleared and set to "value". Bits | ||
846 | * that are in the same position as 0's in "mask" are preserved, regardless | ||
847 | * of their respective state in "value". | ||
848 | */ | ||
849 | static int | ||
850 | i2c_w_mask(struct usb_ov511 *ov, | ||
851 | unsigned char reg, | ||
852 | unsigned char value, | ||
853 | unsigned char mask) | ||
854 | { | ||
855 | int rc; | ||
856 | |||
857 | down(&ov->i2c_lock); | ||
858 | rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); | ||
859 | up(&ov->i2c_lock); | ||
860 | |||
861 | return rc; | ||
862 | } | ||
863 | |||
864 | /* Set the read and write slave IDs. The "slave" argument is the write slave, | ||
865 | * and the read slave will be set to (slave + 1). ov->i2c_lock should be held | ||
866 | * when calling this. This should not be called from outside the i2c I/O | ||
867 | * functions. | ||
868 | */ | ||
869 | static int | ||
870 | i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave) | ||
871 | { | ||
872 | int rc; | ||
873 | |||
874 | rc = reg_w(ov, R51x_I2C_W_SID, slave); | ||
875 | if (rc < 0) | ||
876 | return rc; | ||
877 | |||
878 | rc = reg_w(ov, R51x_I2C_R_SID, slave + 1); | ||
879 | if (rc < 0) | ||
880 | return rc; | ||
881 | |||
882 | return 0; | ||
883 | } | ||
884 | |||
885 | /* Write to a specific I2C slave ID and register, using the specified mask */ | ||
886 | static int | ||
887 | i2c_w_slave(struct usb_ov511 *ov, | ||
888 | unsigned char slave, | ||
889 | unsigned char reg, | ||
890 | unsigned char value, | ||
891 | unsigned char mask) | ||
892 | { | ||
893 | int rc = 0; | ||
894 | |||
895 | down(&ov->i2c_lock); | ||
896 | |||
897 | /* Set new slave IDs */ | ||
898 | rc = i2c_set_slave_internal(ov, slave); | ||
899 | if (rc < 0) | ||
900 | goto out; | ||
901 | |||
902 | rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); | ||
903 | |||
904 | out: | ||
905 | /* Restore primary IDs */ | ||
906 | if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) | ||
907 | err("Couldn't restore primary I2C slave"); | ||
908 | |||
909 | up(&ov->i2c_lock); | ||
910 | return rc; | ||
911 | } | ||
912 | |||
913 | /* Read from a specific I2C slave ID and register */ | ||
914 | static int | ||
915 | i2c_r_slave(struct usb_ov511 *ov, | ||
916 | unsigned char slave, | ||
917 | unsigned char reg) | ||
918 | { | ||
919 | int rc; | ||
920 | |||
921 | down(&ov->i2c_lock); | ||
922 | |||
923 | /* Set new slave IDs */ | ||
924 | rc = i2c_set_slave_internal(ov, slave); | ||
925 | if (rc < 0) | ||
926 | goto out; | ||
927 | |||
928 | if (ov->bclass == BCL_OV518) | ||
929 | rc = ov518_i2c_read_internal(ov, reg); | ||
930 | else | ||
931 | rc = ov511_i2c_read_internal(ov, reg); | ||
932 | |||
933 | out: | ||
934 | /* Restore primary IDs */ | ||
935 | if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) | ||
936 | err("Couldn't restore primary I2C slave"); | ||
937 | |||
938 | up(&ov->i2c_lock); | ||
939 | return rc; | ||
940 | } | ||
941 | |||
942 | /* Sets I2C read and write slave IDs. Returns <0 for error */ | ||
943 | static int | ||
944 | ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid) | ||
945 | { | ||
946 | int rc; | ||
947 | |||
948 | down(&ov->i2c_lock); | ||
949 | |||
950 | rc = i2c_set_slave_internal(ov, sid); | ||
951 | if (rc < 0) | ||
952 | goto out; | ||
953 | |||
954 | // FIXME: Is this actually necessary? | ||
955 | rc = ov51x_reset(ov, OV511_RESET_NOREGS); | ||
956 | out: | ||
957 | up(&ov->i2c_lock); | ||
958 | return rc; | ||
959 | } | ||
960 | |||
961 | static int | ||
962 | write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals) | ||
963 | { | ||
964 | int rc; | ||
965 | |||
966 | while (pRegvals->bus != OV511_DONE_BUS) { | ||
967 | if (pRegvals->bus == OV511_REG_BUS) { | ||
968 | if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0) | ||
969 | return rc; | ||
970 | } else if (pRegvals->bus == OV511_I2C_BUS) { | ||
971 | if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0) | ||
972 | return rc; | ||
973 | } else { | ||
974 | err("Bad regval array"); | ||
975 | return -1; | ||
976 | } | ||
977 | pRegvals++; | ||
978 | } | ||
979 | return 0; | ||
980 | } | ||
981 | |||
982 | #ifdef OV511_DEBUG | ||
983 | static void | ||
984 | dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn) | ||
985 | { | ||
986 | int i, rc; | ||
987 | |||
988 | for (i = reg1; i <= regn; i++) { | ||
989 | rc = i2c_r(ov, i); | ||
990 | info("Sensor[0x%02X] = 0x%02X", i, rc); | ||
991 | } | ||
992 | } | ||
993 | |||
994 | static void | ||
995 | dump_i2c_regs(struct usb_ov511 *ov) | ||
996 | { | ||
997 | info("I2C REGS"); | ||
998 | dump_i2c_range(ov, 0x00, 0x7C); | ||
999 | } | ||
1000 | |||
1001 | static void | ||
1002 | dump_reg_range(struct usb_ov511 *ov, int reg1, int regn) | ||
1003 | { | ||
1004 | int i, rc; | ||
1005 | |||
1006 | for (i = reg1; i <= regn; i++) { | ||
1007 | rc = reg_r(ov, i); | ||
1008 | info("OV511[0x%02X] = 0x%02X", i, rc); | ||
1009 | } | ||
1010 | } | ||
1011 | |||
1012 | static void | ||
1013 | ov511_dump_regs(struct usb_ov511 *ov) | ||
1014 | { | ||
1015 | info("CAMERA INTERFACE REGS"); | ||
1016 | dump_reg_range(ov, 0x10, 0x1f); | ||
1017 | info("DRAM INTERFACE REGS"); | ||
1018 | dump_reg_range(ov, 0x20, 0x23); | ||
1019 | info("ISO FIFO REGS"); | ||
1020 | dump_reg_range(ov, 0x30, 0x31); | ||
1021 | info("PIO REGS"); | ||
1022 | dump_reg_range(ov, 0x38, 0x39); | ||
1023 | dump_reg_range(ov, 0x3e, 0x3e); | ||
1024 | info("I2C REGS"); | ||
1025 | dump_reg_range(ov, 0x40, 0x49); | ||
1026 | info("SYSTEM CONTROL REGS"); | ||
1027 | dump_reg_range(ov, 0x50, 0x55); | ||
1028 | dump_reg_range(ov, 0x5e, 0x5f); | ||
1029 | info("OmniCE REGS"); | ||
1030 | dump_reg_range(ov, 0x70, 0x79); | ||
1031 | /* NOTE: Quantization tables are not readable. You will get the value | ||
1032 | * in reg. 0x79 for every table register */ | ||
1033 | dump_reg_range(ov, 0x80, 0x9f); | ||
1034 | dump_reg_range(ov, 0xa0, 0xbf); | ||
1035 | |||
1036 | } | ||
1037 | |||
1038 | static void | ||
1039 | ov518_dump_regs(struct usb_ov511 *ov) | ||
1040 | { | ||
1041 | info("VIDEO MODE REGS"); | ||
1042 | dump_reg_range(ov, 0x20, 0x2f); | ||
1043 | info("DATA PUMP AND SNAPSHOT REGS"); | ||
1044 | dump_reg_range(ov, 0x30, 0x3f); | ||
1045 | info("I2C REGS"); | ||
1046 | dump_reg_range(ov, 0x40, 0x4f); | ||
1047 | info("SYSTEM CONTROL AND VENDOR REGS"); | ||
1048 | dump_reg_range(ov, 0x50, 0x5f); | ||
1049 | info("60 - 6F"); | ||
1050 | dump_reg_range(ov, 0x60, 0x6f); | ||
1051 | info("70 - 7F"); | ||
1052 | dump_reg_range(ov, 0x70, 0x7f); | ||
1053 | info("Y QUANTIZATION TABLE"); | ||
1054 | dump_reg_range(ov, 0x80, 0x8f); | ||
1055 | info("UV QUANTIZATION TABLE"); | ||
1056 | dump_reg_range(ov, 0x90, 0x9f); | ||
1057 | info("A0 - BF"); | ||
1058 | dump_reg_range(ov, 0xa0, 0xbf); | ||
1059 | info("CBR"); | ||
1060 | dump_reg_range(ov, 0xc0, 0xcf); | ||
1061 | } | ||
1062 | #endif | ||
1063 | |||
1064 | /*****************************************************************************/ | ||
1065 | |||
1066 | /* Temporarily stops OV511 from functioning. Must do this before changing | ||
1067 | * registers while the camera is streaming */ | ||
1068 | static inline int | ||
1069 | ov51x_stop(struct usb_ov511 *ov) | ||
1070 | { | ||
1071 | PDEBUG(4, "stopping"); | ||
1072 | ov->stopped = 1; | ||
1073 | if (ov->bclass == BCL_OV518) | ||
1074 | return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a)); | ||
1075 | else | ||
1076 | return (reg_w(ov, R51x_SYS_RESET, 0x3d)); | ||
1077 | } | ||
1078 | |||
1079 | /* Restarts OV511 after ov511_stop() is called. Has no effect if it is not | ||
1080 | * actually stopped (for performance). */ | ||
1081 | static inline int | ||
1082 | ov51x_restart(struct usb_ov511 *ov) | ||
1083 | { | ||
1084 | if (ov->stopped) { | ||
1085 | PDEBUG(4, "restarting"); | ||
1086 | ov->stopped = 0; | ||
1087 | |||
1088 | /* Reinitialize the stream */ | ||
1089 | if (ov->bclass == BCL_OV518) | ||
1090 | reg_w(ov, 0x2f, 0x80); | ||
1091 | |||
1092 | return (reg_w(ov, R51x_SYS_RESET, 0x00)); | ||
1093 | } | ||
1094 | |||
1095 | return 0; | ||
1096 | } | ||
1097 | |||
1098 | /* Sleeps until no frames are active. Returns !0 if got signal */ | ||
1099 | static int | ||
1100 | ov51x_wait_frames_inactive(struct usb_ov511 *ov) | ||
1101 | { | ||
1102 | return wait_event_interruptible(ov->wq, ov->curframe < 0); | ||
1103 | } | ||
1104 | |||
1105 | /* Resets the hardware snapshot button */ | ||
1106 | static void | ||
1107 | ov51x_clear_snapshot(struct usb_ov511 *ov) | ||
1108 | { | ||
1109 | if (ov->bclass == BCL_OV511) { | ||
1110 | reg_w(ov, R51x_SYS_SNAP, 0x00); | ||
1111 | reg_w(ov, R51x_SYS_SNAP, 0x02); | ||
1112 | reg_w(ov, R51x_SYS_SNAP, 0x00); | ||
1113 | } else if (ov->bclass == BCL_OV518) { | ||
1114 | warn("snapshot reset not supported yet on OV518(+)"); | ||
1115 | } else { | ||
1116 | err("clear snap: invalid bridge type"); | ||
1117 | } | ||
1118 | } | ||
1119 | |||
1120 | #if 0 | ||
1121 | /* Checks the status of the snapshot button. Returns 1 if it was pressed since | ||
1122 | * it was last cleared, and zero in all other cases (including errors) */ | ||
1123 | static int | ||
1124 | ov51x_check_snapshot(struct usb_ov511 *ov) | ||
1125 | { | ||
1126 | int ret, status = 0; | ||
1127 | |||
1128 | if (ov->bclass == BCL_OV511) { | ||
1129 | ret = reg_r(ov, R51x_SYS_SNAP); | ||
1130 | if (ret < 0) { | ||
1131 | err("Error checking snspshot status (%d)", ret); | ||
1132 | } else if (ret & 0x08) { | ||
1133 | status = 1; | ||
1134 | } | ||
1135 | } else if (ov->bclass == BCL_OV518) { | ||
1136 | warn("snapshot check not supported yet on OV518(+)"); | ||
1137 | } else { | ||
1138 | err("check snap: invalid bridge type"); | ||
1139 | } | ||
1140 | |||
1141 | return status; | ||
1142 | } | ||
1143 | #endif | ||
1144 | |||
1145 | /* This does an initial reset of an OmniVision sensor and ensures that I2C | ||
1146 | * is synchronized. Returns <0 for failure. | ||
1147 | */ | ||
1148 | static int | ||
1149 | init_ov_sensor(struct usb_ov511 *ov) | ||
1150 | { | ||
1151 | int i, success; | ||
1152 | |||
1153 | /* Reset the sensor */ | ||
1154 | if (i2c_w(ov, 0x12, 0x80) < 0) | ||
1155 | return -EIO; | ||
1156 | |||
1157 | /* Wait for it to initialize */ | ||
1158 | msleep(150); | ||
1159 | |||
1160 | for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { | ||
1161 | if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && | ||
1162 | (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { | ||
1163 | success = 1; | ||
1164 | continue; | ||
1165 | } | ||
1166 | |||
1167 | /* Reset the sensor */ | ||
1168 | if (i2c_w(ov, 0x12, 0x80) < 0) | ||
1169 | return -EIO; | ||
1170 | /* Wait for it to initialize */ | ||
1171 | msleep(150); | ||
1172 | /* Dummy read to sync I2C */ | ||
1173 | if (i2c_r(ov, 0x00) < 0) | ||
1174 | return -EIO; | ||
1175 | } | ||
1176 | |||
1177 | if (!success) | ||
1178 | return -EIO; | ||
1179 | |||
1180 | PDEBUG(1, "I2C synced in %d attempt(s)", i); | ||
1181 | |||
1182 | return 0; | ||
1183 | } | ||
1184 | |||
1185 | static int | ||
1186 | ov511_set_packet_size(struct usb_ov511 *ov, int size) | ||
1187 | { | ||
1188 | int alt, mult; | ||
1189 | |||
1190 | if (ov51x_stop(ov) < 0) | ||
1191 | return -EIO; | ||
1192 | |||
1193 | mult = size >> 5; | ||
1194 | |||
1195 | if (ov->bridge == BRG_OV511) { | ||
1196 | if (size == 0) | ||
1197 | alt = OV511_ALT_SIZE_0; | ||
1198 | else if (size == 257) | ||
1199 | alt = OV511_ALT_SIZE_257; | ||
1200 | else if (size == 513) | ||
1201 | alt = OV511_ALT_SIZE_513; | ||
1202 | else if (size == 769) | ||
1203 | alt = OV511_ALT_SIZE_769; | ||
1204 | else if (size == 993) | ||
1205 | alt = OV511_ALT_SIZE_993; | ||
1206 | else { | ||
1207 | err("Set packet size: invalid size (%d)", size); | ||
1208 | return -EINVAL; | ||
1209 | } | ||
1210 | } else if (ov->bridge == BRG_OV511PLUS) { | ||
1211 | if (size == 0) | ||
1212 | alt = OV511PLUS_ALT_SIZE_0; | ||
1213 | else if (size == 33) | ||
1214 | alt = OV511PLUS_ALT_SIZE_33; | ||
1215 | else if (size == 129) | ||
1216 | alt = OV511PLUS_ALT_SIZE_129; | ||
1217 | else if (size == 257) | ||
1218 | alt = OV511PLUS_ALT_SIZE_257; | ||
1219 | else if (size == 385) | ||
1220 | alt = OV511PLUS_ALT_SIZE_385; | ||
1221 | else if (size == 513) | ||
1222 | alt = OV511PLUS_ALT_SIZE_513; | ||
1223 | else if (size == 769) | ||
1224 | alt = OV511PLUS_ALT_SIZE_769; | ||
1225 | else if (size == 961) | ||
1226 | alt = OV511PLUS_ALT_SIZE_961; | ||
1227 | else { | ||
1228 | err("Set packet size: invalid size (%d)", size); | ||
1229 | return -EINVAL; | ||
1230 | } | ||
1231 | } else { | ||
1232 | err("Set packet size: Invalid bridge type"); | ||
1233 | return -EINVAL; | ||
1234 | } | ||
1235 | |||
1236 | PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt); | ||
1237 | |||
1238 | if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0) | ||
1239 | return -EIO; | ||
1240 | |||
1241 | if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { | ||
1242 | err("Set packet size: set interface error"); | ||
1243 | return -EBUSY; | ||
1244 | } | ||
1245 | |||
1246 | if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) | ||
1247 | return -EIO; | ||
1248 | |||
1249 | ov->packet_size = size; | ||
1250 | |||
1251 | if (ov51x_restart(ov) < 0) | ||
1252 | return -EIO; | ||
1253 | |||
1254 | return 0; | ||
1255 | } | ||
1256 | |||
1257 | /* Note: Unlike the OV511/OV511+, the size argument does NOT include the | ||
1258 | * optional packet number byte. The actual size *is* stored in ov->packet_size, | ||
1259 | * though. */ | ||
1260 | static int | ||
1261 | ov518_set_packet_size(struct usb_ov511 *ov, int size) | ||
1262 | { | ||
1263 | int alt; | ||
1264 | |||
1265 | if (ov51x_stop(ov) < 0) | ||
1266 | return -EIO; | ||
1267 | |||
1268 | if (ov->bclass == BCL_OV518) { | ||
1269 | if (size == 0) | ||
1270 | alt = OV518_ALT_SIZE_0; | ||
1271 | else if (size == 128) | ||
1272 | alt = OV518_ALT_SIZE_128; | ||
1273 | else if (size == 256) | ||
1274 | alt = OV518_ALT_SIZE_256; | ||
1275 | else if (size == 384) | ||
1276 | alt = OV518_ALT_SIZE_384; | ||
1277 | else if (size == 512) | ||
1278 | alt = OV518_ALT_SIZE_512; | ||
1279 | else if (size == 640) | ||
1280 | alt = OV518_ALT_SIZE_640; | ||
1281 | else if (size == 768) | ||
1282 | alt = OV518_ALT_SIZE_768; | ||
1283 | else if (size == 896) | ||
1284 | alt = OV518_ALT_SIZE_896; | ||
1285 | else { | ||
1286 | err("Set packet size: invalid size (%d)", size); | ||
1287 | return -EINVAL; | ||
1288 | } | ||
1289 | } else { | ||
1290 | err("Set packet size: Invalid bridge type"); | ||
1291 | return -EINVAL; | ||
1292 | } | ||
1293 | |||
1294 | PDEBUG(3, "%d, alt=%d", size, alt); | ||
1295 | |||
1296 | ov->packet_size = size; | ||
1297 | if (size > 0) { | ||
1298 | /* Program ISO FIFO size reg (packet number isn't included) */ | ||
1299 | ov518_reg_w32(ov, 0x30, size, 2); | ||
1300 | |||
1301 | if (ov->packet_numbering) | ||
1302 | ++ov->packet_size; | ||
1303 | } | ||
1304 | |||
1305 | if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { | ||
1306 | err("Set packet size: set interface error"); | ||
1307 | return -EBUSY; | ||
1308 | } | ||
1309 | |||
1310 | /* Initialize the stream */ | ||
1311 | if (reg_w(ov, 0x2f, 0x80) < 0) | ||
1312 | return -EIO; | ||
1313 | |||
1314 | if (ov51x_restart(ov) < 0) | ||
1315 | return -EIO; | ||
1316 | |||
1317 | if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) | ||
1318 | return -EIO; | ||
1319 | |||
1320 | return 0; | ||
1321 | } | ||
1322 | |||
1323 | /* Upload compression params and quantization tables. Returns 0 for success. */ | ||
1324 | static int | ||
1325 | ov511_init_compression(struct usb_ov511 *ov) | ||
1326 | { | ||
1327 | int rc = 0; | ||
1328 | |||
1329 | if (!ov->compress_inited) { | ||
1330 | reg_w(ov, 0x70, phy); | ||
1331 | reg_w(ov, 0x71, phuv); | ||
1332 | reg_w(ov, 0x72, pvy); | ||
1333 | reg_w(ov, 0x73, pvuv); | ||
1334 | reg_w(ov, 0x74, qhy); | ||
1335 | reg_w(ov, 0x75, qhuv); | ||
1336 | reg_w(ov, 0x76, qvy); | ||
1337 | reg_w(ov, 0x77, qvuv); | ||
1338 | |||
1339 | if (ov511_upload_quan_tables(ov) < 0) { | ||
1340 | err("Error uploading quantization tables"); | ||
1341 | rc = -EIO; | ||
1342 | goto out; | ||
1343 | } | ||
1344 | } | ||
1345 | |||
1346 | ov->compress_inited = 1; | ||
1347 | out: | ||
1348 | return rc; | ||
1349 | } | ||
1350 | |||
1351 | /* Upload compression params and quantization tables. Returns 0 for success. */ | ||
1352 | static int | ||
1353 | ov518_init_compression(struct usb_ov511 *ov) | ||
1354 | { | ||
1355 | int rc = 0; | ||
1356 | |||
1357 | if (!ov->compress_inited) { | ||
1358 | if (ov518_upload_quan_tables(ov) < 0) { | ||
1359 | err("Error uploading quantization tables"); | ||
1360 | rc = -EIO; | ||
1361 | goto out; | ||
1362 | } | ||
1363 | } | ||
1364 | |||
1365 | ov->compress_inited = 1; | ||
1366 | out: | ||
1367 | return rc; | ||
1368 | } | ||
1369 | |||
1370 | /* -------------------------------------------------------------------------- */ | ||
1371 | |||
1372 | /* Sets sensor's contrast setting to "val" */ | ||
1373 | static int | ||
1374 | sensor_set_contrast(struct usb_ov511 *ov, unsigned short val) | ||
1375 | { | ||
1376 | int rc; | ||
1377 | |||
1378 | PDEBUG(3, "%d", val); | ||
1379 | |||
1380 | if (ov->stop_during_set) | ||
1381 | if (ov51x_stop(ov) < 0) | ||
1382 | return -EIO; | ||
1383 | |||
1384 | switch (ov->sensor) { | ||
1385 | case SEN_OV7610: | ||
1386 | case SEN_OV6620: | ||
1387 | { | ||
1388 | rc = i2c_w(ov, OV7610_REG_CNT, val >> 8); | ||
1389 | if (rc < 0) | ||
1390 | goto out; | ||
1391 | break; | ||
1392 | } | ||
1393 | case SEN_OV6630: | ||
1394 | { | ||
1395 | rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f); | ||
1396 | if (rc < 0) | ||
1397 | goto out; | ||
1398 | break; | ||
1399 | } | ||
1400 | case SEN_OV7620: | ||
1401 | { | ||
1402 | unsigned char ctab[] = { | ||
1403 | 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57, | ||
1404 | 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff | ||
1405 | }; | ||
1406 | |||
1407 | /* Use Y gamma control instead. Bit 0 enables it. */ | ||
1408 | rc = i2c_w(ov, 0x64, ctab[val>>12]); | ||
1409 | if (rc < 0) | ||
1410 | goto out; | ||
1411 | break; | ||
1412 | } | ||
1413 | case SEN_SAA7111A: | ||
1414 | { | ||
1415 | rc = i2c_w(ov, 0x0b, val >> 9); | ||
1416 | if (rc < 0) | ||
1417 | goto out; | ||
1418 | break; | ||
1419 | } | ||
1420 | default: | ||
1421 | { | ||
1422 | PDEBUG(3, "Unsupported with this sensor"); | ||
1423 | rc = -EPERM; | ||
1424 | goto out; | ||
1425 | } | ||
1426 | } | ||
1427 | |||
1428 | rc = 0; /* Success */ | ||
1429 | ov->contrast = val; | ||
1430 | out: | ||
1431 | if (ov51x_restart(ov) < 0) | ||
1432 | return -EIO; | ||
1433 | |||
1434 | return rc; | ||
1435 | } | ||
1436 | |||
1437 | /* Gets sensor's contrast setting */ | ||
1438 | static int | ||
1439 | sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val) | ||
1440 | { | ||
1441 | int rc; | ||
1442 | |||
1443 | switch (ov->sensor) { | ||
1444 | case SEN_OV7610: | ||
1445 | case SEN_OV6620: | ||
1446 | rc = i2c_r(ov, OV7610_REG_CNT); | ||
1447 | if (rc < 0) | ||
1448 | return rc; | ||
1449 | else | ||
1450 | *val = rc << 8; | ||
1451 | break; | ||
1452 | case SEN_OV6630: | ||
1453 | rc = i2c_r(ov, OV7610_REG_CNT); | ||
1454 | if (rc < 0) | ||
1455 | return rc; | ||
1456 | else | ||
1457 | *val = rc << 12; | ||
1458 | break; | ||
1459 | case SEN_OV7620: | ||
1460 | /* Use Y gamma reg instead. Bit 0 is the enable bit. */ | ||
1461 | rc = i2c_r(ov, 0x64); | ||
1462 | if (rc < 0) | ||
1463 | return rc; | ||
1464 | else | ||
1465 | *val = (rc & 0xfe) << 8; | ||
1466 | break; | ||
1467 | case SEN_SAA7111A: | ||
1468 | *val = ov->contrast; | ||
1469 | break; | ||
1470 | default: | ||
1471 | PDEBUG(3, "Unsupported with this sensor"); | ||
1472 | return -EPERM; | ||
1473 | } | ||
1474 | |||
1475 | PDEBUG(3, "%d", *val); | ||
1476 | ov->contrast = *val; | ||
1477 | |||
1478 | return 0; | ||
1479 | } | ||
1480 | |||
1481 | /* -------------------------------------------------------------------------- */ | ||
1482 | |||
1483 | /* Sets sensor's brightness setting to "val" */ | ||
1484 | static int | ||
1485 | sensor_set_brightness(struct usb_ov511 *ov, unsigned short val) | ||
1486 | { | ||
1487 | int rc; | ||
1488 | |||
1489 | PDEBUG(4, "%d", val); | ||
1490 | |||
1491 | if (ov->stop_during_set) | ||
1492 | if (ov51x_stop(ov) < 0) | ||
1493 | return -EIO; | ||
1494 | |||
1495 | switch (ov->sensor) { | ||
1496 | case SEN_OV7610: | ||
1497 | case SEN_OV76BE: | ||
1498 | case SEN_OV6620: | ||
1499 | case SEN_OV6630: | ||
1500 | rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); | ||
1501 | if (rc < 0) | ||
1502 | goto out; | ||
1503 | break; | ||
1504 | case SEN_OV7620: | ||
1505 | /* 7620 doesn't like manual changes when in auto mode */ | ||
1506 | if (!ov->auto_brt) { | ||
1507 | rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); | ||
1508 | if (rc < 0) | ||
1509 | goto out; | ||
1510 | } | ||
1511 | break; | ||
1512 | case SEN_SAA7111A: | ||
1513 | rc = i2c_w(ov, 0x0a, val >> 8); | ||
1514 | if (rc < 0) | ||
1515 | goto out; | ||
1516 | break; | ||
1517 | default: | ||
1518 | PDEBUG(3, "Unsupported with this sensor"); | ||
1519 | rc = -EPERM; | ||
1520 | goto out; | ||
1521 | } | ||
1522 | |||
1523 | rc = 0; /* Success */ | ||
1524 | ov->brightness = val; | ||
1525 | out: | ||
1526 | if (ov51x_restart(ov) < 0) | ||
1527 | return -EIO; | ||
1528 | |||
1529 | return rc; | ||
1530 | } | ||
1531 | |||
1532 | /* Gets sensor's brightness setting */ | ||
1533 | static int | ||
1534 | sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val) | ||
1535 | { | ||
1536 | int rc; | ||
1537 | |||
1538 | switch (ov->sensor) { | ||
1539 | case SEN_OV7610: | ||
1540 | case SEN_OV76BE: | ||
1541 | case SEN_OV7620: | ||
1542 | case SEN_OV6620: | ||
1543 | case SEN_OV6630: | ||
1544 | rc = i2c_r(ov, OV7610_REG_BRT); | ||
1545 | if (rc < 0) | ||
1546 | return rc; | ||
1547 | else | ||
1548 | *val = rc << 8; | ||
1549 | break; | ||
1550 | case SEN_SAA7111A: | ||
1551 | *val = ov->brightness; | ||
1552 | break; | ||
1553 | default: | ||
1554 | PDEBUG(3, "Unsupported with this sensor"); | ||
1555 | return -EPERM; | ||
1556 | } | ||
1557 | |||
1558 | PDEBUG(3, "%d", *val); | ||
1559 | ov->brightness = *val; | ||
1560 | |||
1561 | return 0; | ||
1562 | } | ||
1563 | |||
1564 | /* -------------------------------------------------------------------------- */ | ||
1565 | |||
1566 | /* Sets sensor's saturation (color intensity) setting to "val" */ | ||
1567 | static int | ||
1568 | sensor_set_saturation(struct usb_ov511 *ov, unsigned short val) | ||
1569 | { | ||
1570 | int rc; | ||
1571 | |||
1572 | PDEBUG(3, "%d", val); | ||
1573 | |||
1574 | if (ov->stop_during_set) | ||
1575 | if (ov51x_stop(ov) < 0) | ||
1576 | return -EIO; | ||
1577 | |||
1578 | switch (ov->sensor) { | ||
1579 | case SEN_OV7610: | ||
1580 | case SEN_OV76BE: | ||
1581 | case SEN_OV6620: | ||
1582 | case SEN_OV6630: | ||
1583 | rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); | ||
1584 | if (rc < 0) | ||
1585 | goto out; | ||
1586 | break; | ||
1587 | case SEN_OV7620: | ||
1588 | // /* Use UV gamma control instead. Bits 0 & 7 are reserved. */ | ||
1589 | // rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e); | ||
1590 | // if (rc < 0) | ||
1591 | // goto out; | ||
1592 | rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); | ||
1593 | if (rc < 0) | ||
1594 | goto out; | ||
1595 | break; | ||
1596 | case SEN_SAA7111A: | ||
1597 | rc = i2c_w(ov, 0x0c, val >> 9); | ||
1598 | if (rc < 0) | ||
1599 | goto out; | ||
1600 | break; | ||
1601 | default: | ||
1602 | PDEBUG(3, "Unsupported with this sensor"); | ||
1603 | rc = -EPERM; | ||
1604 | goto out; | ||
1605 | } | ||
1606 | |||
1607 | rc = 0; /* Success */ | ||
1608 | ov->colour = val; | ||
1609 | out: | ||
1610 | if (ov51x_restart(ov) < 0) | ||
1611 | return -EIO; | ||
1612 | |||
1613 | return rc; | ||
1614 | } | ||
1615 | |||
1616 | /* Gets sensor's saturation (color intensity) setting */ | ||
1617 | static int | ||
1618 | sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val) | ||
1619 | { | ||
1620 | int rc; | ||
1621 | |||
1622 | switch (ov->sensor) { | ||
1623 | case SEN_OV7610: | ||
1624 | case SEN_OV76BE: | ||
1625 | case SEN_OV6620: | ||
1626 | case SEN_OV6630: | ||
1627 | rc = i2c_r(ov, OV7610_REG_SAT); | ||
1628 | if (rc < 0) | ||
1629 | return rc; | ||
1630 | else | ||
1631 | *val = rc << 8; | ||
1632 | break; | ||
1633 | case SEN_OV7620: | ||
1634 | // /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */ | ||
1635 | // rc = i2c_r(ov, 0x62); | ||
1636 | // if (rc < 0) | ||
1637 | // return rc; | ||
1638 | // else | ||
1639 | // *val = (rc & 0x7e) << 9; | ||
1640 | rc = i2c_r(ov, OV7610_REG_SAT); | ||
1641 | if (rc < 0) | ||
1642 | return rc; | ||
1643 | else | ||
1644 | *val = rc << 8; | ||
1645 | break; | ||
1646 | case SEN_SAA7111A: | ||
1647 | *val = ov->colour; | ||
1648 | break; | ||
1649 | default: | ||
1650 | PDEBUG(3, "Unsupported with this sensor"); | ||
1651 | return -EPERM; | ||
1652 | } | ||
1653 | |||
1654 | PDEBUG(3, "%d", *val); | ||
1655 | ov->colour = *val; | ||
1656 | |||
1657 | return 0; | ||
1658 | } | ||
1659 | |||
1660 | /* -------------------------------------------------------------------------- */ | ||
1661 | |||
1662 | /* Sets sensor's hue (red/blue balance) setting to "val" */ | ||
1663 | static int | ||
1664 | sensor_set_hue(struct usb_ov511 *ov, unsigned short val) | ||
1665 | { | ||
1666 | int rc; | ||
1667 | |||
1668 | PDEBUG(3, "%d", val); | ||
1669 | |||
1670 | if (ov->stop_during_set) | ||
1671 | if (ov51x_stop(ov) < 0) | ||
1672 | return -EIO; | ||
1673 | |||
1674 | switch (ov->sensor) { | ||
1675 | case SEN_OV7610: | ||
1676 | case SEN_OV6620: | ||
1677 | case SEN_OV6630: | ||
1678 | rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8)); | ||
1679 | if (rc < 0) | ||
1680 | goto out; | ||
1681 | |||
1682 | rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8); | ||
1683 | if (rc < 0) | ||
1684 | goto out; | ||
1685 | break; | ||
1686 | case SEN_OV7620: | ||
1687 | // Hue control is causing problems. I will enable it once it's fixed. | ||
1688 | #if 0 | ||
1689 | rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb); | ||
1690 | if (rc < 0) | ||
1691 | goto out; | ||
1692 | |||
1693 | rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb); | ||
1694 | if (rc < 0) | ||
1695 | goto out; | ||
1696 | #endif | ||
1697 | break; | ||
1698 | case SEN_SAA7111A: | ||
1699 | rc = i2c_w(ov, 0x0d, (val + 32768) >> 8); | ||
1700 | if (rc < 0) | ||
1701 | goto out; | ||
1702 | break; | ||
1703 | default: | ||
1704 | PDEBUG(3, "Unsupported with this sensor"); | ||
1705 | rc = -EPERM; | ||
1706 | goto out; | ||
1707 | } | ||
1708 | |||
1709 | rc = 0; /* Success */ | ||
1710 | ov->hue = val; | ||
1711 | out: | ||
1712 | if (ov51x_restart(ov) < 0) | ||
1713 | return -EIO; | ||
1714 | |||
1715 | return rc; | ||
1716 | } | ||
1717 | |||
1718 | /* Gets sensor's hue (red/blue balance) setting */ | ||
1719 | static int | ||
1720 | sensor_get_hue(struct usb_ov511 *ov, unsigned short *val) | ||
1721 | { | ||
1722 | int rc; | ||
1723 | |||
1724 | switch (ov->sensor) { | ||
1725 | case SEN_OV7610: | ||
1726 | case SEN_OV6620: | ||
1727 | case SEN_OV6630: | ||
1728 | rc = i2c_r(ov, OV7610_REG_BLUE); | ||
1729 | if (rc < 0) | ||
1730 | return rc; | ||
1731 | else | ||
1732 | *val = rc << 8; | ||
1733 | break; | ||
1734 | case SEN_OV7620: | ||
1735 | rc = i2c_r(ov, 0x7a); | ||
1736 | if (rc < 0) | ||
1737 | return rc; | ||
1738 | else | ||
1739 | *val = rc << 8; | ||
1740 | break; | ||
1741 | case SEN_SAA7111A: | ||
1742 | *val = ov->hue; | ||
1743 | break; | ||
1744 | default: | ||
1745 | PDEBUG(3, "Unsupported with this sensor"); | ||
1746 | return -EPERM; | ||
1747 | } | ||
1748 | |||
1749 | PDEBUG(3, "%d", *val); | ||
1750 | ov->hue = *val; | ||
1751 | |||
1752 | return 0; | ||
1753 | } | ||
1754 | |||
1755 | /* -------------------------------------------------------------------------- */ | ||
1756 | |||
1757 | static int | ||
1758 | sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p) | ||
1759 | { | ||
1760 | int rc; | ||
1761 | |||
1762 | PDEBUG(4, "sensor_set_picture"); | ||
1763 | |||
1764 | ov->whiteness = p->whiteness; | ||
1765 | |||
1766 | /* Don't return error if a setting is unsupported, or rest of settings | ||
1767 | * will not be performed */ | ||
1768 | |||
1769 | rc = sensor_set_contrast(ov, p->contrast); | ||
1770 | if (FATAL_ERROR(rc)) | ||
1771 | return rc; | ||
1772 | |||
1773 | rc = sensor_set_brightness(ov, p->brightness); | ||
1774 | if (FATAL_ERROR(rc)) | ||
1775 | return rc; | ||
1776 | |||
1777 | rc = sensor_set_saturation(ov, p->colour); | ||
1778 | if (FATAL_ERROR(rc)) | ||
1779 | return rc; | ||
1780 | |||
1781 | rc = sensor_set_hue(ov, p->hue); | ||
1782 | if (FATAL_ERROR(rc)) | ||
1783 | return rc; | ||
1784 | |||
1785 | return 0; | ||
1786 | } | ||
1787 | |||
1788 | static int | ||
1789 | sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p) | ||
1790 | { | ||
1791 | int rc; | ||
1792 | |||
1793 | PDEBUG(4, "sensor_get_picture"); | ||
1794 | |||
1795 | /* Don't return error if a setting is unsupported, or rest of settings | ||
1796 | * will not be performed */ | ||
1797 | |||
1798 | rc = sensor_get_contrast(ov, &(p->contrast)); | ||
1799 | if (FATAL_ERROR(rc)) | ||
1800 | return rc; | ||
1801 | |||
1802 | rc = sensor_get_brightness(ov, &(p->brightness)); | ||
1803 | if (FATAL_ERROR(rc)) | ||
1804 | return rc; | ||
1805 | |||
1806 | rc = sensor_get_saturation(ov, &(p->colour)); | ||
1807 | if (FATAL_ERROR(rc)) | ||
1808 | return rc; | ||
1809 | |||
1810 | rc = sensor_get_hue(ov, &(p->hue)); | ||
1811 | if (FATAL_ERROR(rc)) | ||
1812 | return rc; | ||
1813 | |||
1814 | p->whiteness = 105 << 8; | ||
1815 | |||
1816 | return 0; | ||
1817 | } | ||
1818 | |||
1819 | #if 0 | ||
1820 | // FIXME: Exposure range is only 0x00-0x7f in interlace mode | ||
1821 | /* Sets current exposure for sensor. This only has an effect if auto-exposure | ||
1822 | * is off */ | ||
1823 | static inline int | ||
1824 | sensor_set_exposure(struct usb_ov511 *ov, unsigned char val) | ||
1825 | { | ||
1826 | int rc; | ||
1827 | |||
1828 | PDEBUG(3, "%d", val); | ||
1829 | |||
1830 | if (ov->stop_during_set) | ||
1831 | if (ov51x_stop(ov) < 0) | ||
1832 | return -EIO; | ||
1833 | |||
1834 | switch (ov->sensor) { | ||
1835 | case SEN_OV6620: | ||
1836 | case SEN_OV6630: | ||
1837 | case SEN_OV7610: | ||
1838 | case SEN_OV7620: | ||
1839 | case SEN_OV76BE: | ||
1840 | case SEN_OV8600: | ||
1841 | rc = i2c_w(ov, 0x10, val); | ||
1842 | if (rc < 0) | ||
1843 | goto out; | ||
1844 | |||
1845 | break; | ||
1846 | case SEN_KS0127: | ||
1847 | case SEN_KS0127B: | ||
1848 | case SEN_SAA7111A: | ||
1849 | PDEBUG(3, "Unsupported with this sensor"); | ||
1850 | return -EPERM; | ||
1851 | default: | ||
1852 | err("Sensor not supported for set_exposure"); | ||
1853 | return -EINVAL; | ||
1854 | } | ||
1855 | |||
1856 | rc = 0; /* Success */ | ||
1857 | ov->exposure = val; | ||
1858 | out: | ||
1859 | if (ov51x_restart(ov) < 0) | ||
1860 | return -EIO; | ||
1861 | |||
1862 | return rc; | ||
1863 | } | ||
1864 | #endif | ||
1865 | |||
1866 | /* Gets current exposure level from sensor, regardless of whether it is under | ||
1867 | * manual control. */ | ||
1868 | static int | ||
1869 | sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val) | ||
1870 | { | ||
1871 | int rc; | ||
1872 | |||
1873 | switch (ov->sensor) { | ||
1874 | case SEN_OV7610: | ||
1875 | case SEN_OV6620: | ||
1876 | case SEN_OV6630: | ||
1877 | case SEN_OV7620: | ||
1878 | case SEN_OV76BE: | ||
1879 | case SEN_OV8600: | ||
1880 | rc = i2c_r(ov, 0x10); | ||
1881 | if (rc < 0) | ||
1882 | return rc; | ||
1883 | else | ||
1884 | *val = rc; | ||
1885 | break; | ||
1886 | case SEN_KS0127: | ||
1887 | case SEN_KS0127B: | ||
1888 | case SEN_SAA7111A: | ||
1889 | val = NULL; | ||
1890 | PDEBUG(3, "Unsupported with this sensor"); | ||
1891 | return -EPERM; | ||
1892 | default: | ||
1893 | err("Sensor not supported for get_exposure"); | ||
1894 | return -EINVAL; | ||
1895 | } | ||
1896 | |||
1897 | PDEBUG(3, "%d", *val); | ||
1898 | ov->exposure = *val; | ||
1899 | |||
1900 | return 0; | ||
1901 | } | ||
1902 | |||
1903 | /* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */ | ||
1904 | static void | ||
1905 | ov51x_led_control(struct usb_ov511 *ov, int enable) | ||
1906 | { | ||
1907 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
1908 | |||
1909 | if (ov->bridge == BRG_OV511PLUS) | ||
1910 | reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0); | ||
1911 | else if (ov->bclass == BCL_OV518) | ||
1912 | reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02); | ||
1913 | |||
1914 | return; | ||
1915 | } | ||
1916 | |||
1917 | /* Matches the sensor's internal frame rate to the lighting frequency. | ||
1918 | * Valid frequencies are: | ||
1919 | * 50 - 50Hz, for European and Asian lighting | ||
1920 | * 60 - 60Hz, for American lighting | ||
1921 | * | ||
1922 | * Tested with: OV7610, OV7620, OV76BE, OV6620 | ||
1923 | * Unsupported: KS0127, KS0127B, SAA7111A | ||
1924 | * Returns: 0 for success | ||
1925 | */ | ||
1926 | static int | ||
1927 | sensor_set_light_freq(struct usb_ov511 *ov, int freq) | ||
1928 | { | ||
1929 | int sixty; | ||
1930 | |||
1931 | PDEBUG(4, "%d Hz", freq); | ||
1932 | |||
1933 | if (freq == 60) | ||
1934 | sixty = 1; | ||
1935 | else if (freq == 50) | ||
1936 | sixty = 0; | ||
1937 | else { | ||
1938 | err("Invalid light freq (%d Hz)", freq); | ||
1939 | return -EINVAL; | ||
1940 | } | ||
1941 | |||
1942 | switch (ov->sensor) { | ||
1943 | case SEN_OV7610: | ||
1944 | i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); | ||
1945 | i2c_w(ov, 0x2b, sixty?0x00:0xac); | ||
1946 | i2c_w_mask(ov, 0x13, 0x10, 0x10); | ||
1947 | i2c_w_mask(ov, 0x13, 0x00, 0x10); | ||
1948 | break; | ||
1949 | case SEN_OV7620: | ||
1950 | case SEN_OV76BE: | ||
1951 | case SEN_OV8600: | ||
1952 | i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); | ||
1953 | i2c_w(ov, 0x2b, sixty?0x00:0xac); | ||
1954 | i2c_w_mask(ov, 0x76, 0x01, 0x01); | ||
1955 | break; | ||
1956 | case SEN_OV6620: | ||
1957 | case SEN_OV6630: | ||
1958 | i2c_w(ov, 0x2b, sixty?0xa8:0x28); | ||
1959 | i2c_w(ov, 0x2a, sixty?0x84:0xa4); | ||
1960 | break; | ||
1961 | case SEN_KS0127: | ||
1962 | case SEN_KS0127B: | ||
1963 | case SEN_SAA7111A: | ||
1964 | PDEBUG(5, "Unsupported with this sensor"); | ||
1965 | return -EPERM; | ||
1966 | default: | ||
1967 | err("Sensor not supported for set_light_freq"); | ||
1968 | return -EINVAL; | ||
1969 | } | ||
1970 | |||
1971 | ov->lightfreq = freq; | ||
1972 | |||
1973 | return 0; | ||
1974 | } | ||
1975 | |||
1976 | /* If enable is true, turn on the sensor's banding filter, otherwise turn it | ||
1977 | * off. This filter tries to reduce the pattern of horizontal light/dark bands | ||
1978 | * caused by some (usually fluorescent) lighting. The light frequency must be | ||
1979 | * set either before or after enabling it with ov51x_set_light_freq(). | ||
1980 | * | ||
1981 | * Tested with: OV7610, OV7620, OV76BE, OV6620. | ||
1982 | * Unsupported: KS0127, KS0127B, SAA7111A | ||
1983 | * Returns: 0 for success | ||
1984 | */ | ||
1985 | static int | ||
1986 | sensor_set_banding_filter(struct usb_ov511 *ov, int enable) | ||
1987 | { | ||
1988 | int rc; | ||
1989 | |||
1990 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
1991 | |||
1992 | if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B | ||
1993 | || ov->sensor == SEN_SAA7111A) { | ||
1994 | PDEBUG(5, "Unsupported with this sensor"); | ||
1995 | return -EPERM; | ||
1996 | } | ||
1997 | |||
1998 | rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04); | ||
1999 | if (rc < 0) | ||
2000 | return rc; | ||
2001 | |||
2002 | ov->bandfilt = enable; | ||
2003 | |||
2004 | return 0; | ||
2005 | } | ||
2006 | |||
2007 | /* If enable is true, turn on the sensor's auto brightness control, otherwise | ||
2008 | * turn it off. | ||
2009 | * | ||
2010 | * Unsupported: KS0127, KS0127B, SAA7111A | ||
2011 | * Returns: 0 for success | ||
2012 | */ | ||
2013 | static int | ||
2014 | sensor_set_auto_brightness(struct usb_ov511 *ov, int enable) | ||
2015 | { | ||
2016 | int rc; | ||
2017 | |||
2018 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
2019 | |||
2020 | if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B | ||
2021 | || ov->sensor == SEN_SAA7111A) { | ||
2022 | PDEBUG(5, "Unsupported with this sensor"); | ||
2023 | return -EPERM; | ||
2024 | } | ||
2025 | |||
2026 | rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10); | ||
2027 | if (rc < 0) | ||
2028 | return rc; | ||
2029 | |||
2030 | ov->auto_brt = enable; | ||
2031 | |||
2032 | return 0; | ||
2033 | } | ||
2034 | |||
2035 | /* If enable is true, turn on the sensor's auto exposure control, otherwise | ||
2036 | * turn it off. | ||
2037 | * | ||
2038 | * Unsupported: KS0127, KS0127B, SAA7111A | ||
2039 | * Returns: 0 for success | ||
2040 | */ | ||
2041 | static int | ||
2042 | sensor_set_auto_exposure(struct usb_ov511 *ov, int enable) | ||
2043 | { | ||
2044 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
2045 | |||
2046 | switch (ov->sensor) { | ||
2047 | case SEN_OV7610: | ||
2048 | i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80); | ||
2049 | break; | ||
2050 | case SEN_OV6620: | ||
2051 | case SEN_OV7620: | ||
2052 | case SEN_OV76BE: | ||
2053 | case SEN_OV8600: | ||
2054 | i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01); | ||
2055 | break; | ||
2056 | case SEN_OV6630: | ||
2057 | i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10); | ||
2058 | break; | ||
2059 | case SEN_KS0127: | ||
2060 | case SEN_KS0127B: | ||
2061 | case SEN_SAA7111A: | ||
2062 | PDEBUG(5, "Unsupported with this sensor"); | ||
2063 | return -EPERM; | ||
2064 | default: | ||
2065 | err("Sensor not supported for set_auto_exposure"); | ||
2066 | return -EINVAL; | ||
2067 | } | ||
2068 | |||
2069 | ov->auto_exp = enable; | ||
2070 | |||
2071 | return 0; | ||
2072 | } | ||
2073 | |||
2074 | /* Modifies the sensor's exposure algorithm to allow proper exposure of objects | ||
2075 | * that are illuminated from behind. | ||
2076 | * | ||
2077 | * Tested with: OV6620, OV7620 | ||
2078 | * Unsupported: OV7610, OV76BE, KS0127, KS0127B, SAA7111A | ||
2079 | * Returns: 0 for success | ||
2080 | */ | ||
2081 | static int | ||
2082 | sensor_set_backlight(struct usb_ov511 *ov, int enable) | ||
2083 | { | ||
2084 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
2085 | |||
2086 | switch (ov->sensor) { | ||
2087 | case SEN_OV7620: | ||
2088 | case SEN_OV8600: | ||
2089 | i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0); | ||
2090 | i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); | ||
2091 | i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); | ||
2092 | break; | ||
2093 | case SEN_OV6620: | ||
2094 | i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0); | ||
2095 | i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); | ||
2096 | i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80); | ||
2097 | break; | ||
2098 | case SEN_OV6630: | ||
2099 | i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0); | ||
2100 | i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); | ||
2101 | i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); | ||
2102 | break; | ||
2103 | case SEN_OV7610: | ||
2104 | case SEN_OV76BE: | ||
2105 | case SEN_KS0127: | ||
2106 | case SEN_KS0127B: | ||
2107 | case SEN_SAA7111A: | ||
2108 | PDEBUG(5, "Unsupported with this sensor"); | ||
2109 | return -EPERM; | ||
2110 | default: | ||
2111 | err("Sensor not supported for set_backlight"); | ||
2112 | return -EINVAL; | ||
2113 | } | ||
2114 | |||
2115 | ov->backlight = enable; | ||
2116 | |||
2117 | return 0; | ||
2118 | } | ||
2119 | |||
2120 | static int | ||
2121 | sensor_set_mirror(struct usb_ov511 *ov, int enable) | ||
2122 | { | ||
2123 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
2124 | |||
2125 | switch (ov->sensor) { | ||
2126 | case SEN_OV6620: | ||
2127 | case SEN_OV6630: | ||
2128 | case SEN_OV7610: | ||
2129 | case SEN_OV7620: | ||
2130 | case SEN_OV76BE: | ||
2131 | case SEN_OV8600: | ||
2132 | i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40); | ||
2133 | break; | ||
2134 | case SEN_KS0127: | ||
2135 | case SEN_KS0127B: | ||
2136 | case SEN_SAA7111A: | ||
2137 | PDEBUG(5, "Unsupported with this sensor"); | ||
2138 | return -EPERM; | ||
2139 | default: | ||
2140 | err("Sensor not supported for set_mirror"); | ||
2141 | return -EINVAL; | ||
2142 | } | ||
2143 | |||
2144 | ov->mirror = enable; | ||
2145 | |||
2146 | return 0; | ||
2147 | } | ||
2148 | |||
2149 | /* Returns number of bits per pixel (regardless of where they are located; | ||
2150 | * planar or not), or zero for unsupported format. | ||
2151 | */ | ||
2152 | static inline int | ||
2153 | get_depth(int palette) | ||
2154 | { | ||
2155 | switch (palette) { | ||
2156 | case VIDEO_PALETTE_GREY: return 8; | ||
2157 | case VIDEO_PALETTE_YUV420: return 12; | ||
2158 | case VIDEO_PALETTE_YUV420P: return 12; /* Planar */ | ||
2159 | default: return 0; /* Invalid format */ | ||
2160 | } | ||
2161 | } | ||
2162 | |||
2163 | /* Bytes per frame. Used by read(). Return of 0 indicates error */ | ||
2164 | static inline long int | ||
2165 | get_frame_length(struct ov511_frame *frame) | ||
2166 | { | ||
2167 | if (!frame) | ||
2168 | return 0; | ||
2169 | else | ||
2170 | return ((frame->width * frame->height | ||
2171 | * get_depth(frame->format)) >> 3); | ||
2172 | } | ||
2173 | |||
2174 | static int | ||
2175 | mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height, | ||
2176 | int mode, int sub_flag, int qvga) | ||
2177 | { | ||
2178 | int clock; | ||
2179 | |||
2180 | /******** Mode (VGA/QVGA) and sensor specific regs ********/ | ||
2181 | |||
2182 | switch (ov->sensor) { | ||
2183 | case SEN_OV7610: | ||
2184 | i2c_w(ov, 0x14, qvga?0x24:0x04); | ||
2185 | // FIXME: Does this improve the image quality or frame rate? | ||
2186 | #if 0 | ||
2187 | i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); | ||
2188 | i2c_w(ov, 0x24, 0x10); | ||
2189 | i2c_w(ov, 0x25, qvga?0x40:0x8a); | ||
2190 | i2c_w(ov, 0x2f, qvga?0x30:0xb0); | ||
2191 | i2c_w(ov, 0x35, qvga?0x1c:0x9c); | ||
2192 | #endif | ||
2193 | break; | ||
2194 | case SEN_OV7620: | ||
2195 | // i2c_w(ov, 0x2b, 0x00); | ||
2196 | i2c_w(ov, 0x14, qvga?0xa4:0x84); | ||
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?0xf0:0x90, 0xf0); | ||
2202 | i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); | ||
2203 | break; | ||
2204 | case SEN_OV76BE: | ||
2205 | // i2c_w(ov, 0x2b, 0x00); | ||
2206 | i2c_w(ov, 0x14, qvga?0xa4:0x84); | ||
2207 | // FIXME: Enable this once 7620AE uses 7620 initial settings | ||
2208 | #if 0 | ||
2209 | i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); | ||
2210 | i2c_w(ov, 0x24, qvga?0x20:0x3a); | ||
2211 | i2c_w(ov, 0x25, qvga?0x30:0x60); | ||
2212 | i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); | ||
2213 | i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0); | ||
2214 | i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); | ||
2215 | #endif | ||
2216 | break; | ||
2217 | case SEN_OV6620: | ||
2218 | i2c_w(ov, 0x14, qvga?0x24:0x04); | ||
2219 | break; | ||
2220 | case SEN_OV6630: | ||
2221 | i2c_w(ov, 0x14, qvga?0xa0:0x80); | ||
2222 | break; | ||
2223 | default: | ||
2224 | err("Invalid sensor"); | ||
2225 | return -EINVAL; | ||
2226 | } | ||
2227 | |||
2228 | /******** Palette-specific regs ********/ | ||
2229 | |||
2230 | if (mode == VIDEO_PALETTE_GREY) { | ||
2231 | if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { | ||
2232 | /* these aren't valid on the OV6620/OV7620/6630? */ | ||
2233 | i2c_w_mask(ov, 0x0e, 0x40, 0x40); | ||
2234 | } | ||
2235 | |||
2236 | if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518 | ||
2237 | && ov518_color) { | ||
2238 | i2c_w_mask(ov, 0x12, 0x00, 0x10); | ||
2239 | i2c_w_mask(ov, 0x13, 0x00, 0x20); | ||
2240 | } else { | ||
2241 | i2c_w_mask(ov, 0x13, 0x20, 0x20); | ||
2242 | } | ||
2243 | } else { | ||
2244 | if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { | ||
2245 | /* not valid on the OV6620/OV7620/6630? */ | ||
2246 | i2c_w_mask(ov, 0x0e, 0x00, 0x40); | ||
2247 | } | ||
2248 | |||
2249 | /* The OV518 needs special treatment. Although both the OV518 | ||
2250 | * and the OV6630 support a 16-bit video bus, only the 8 bit Y | ||
2251 | * bus is actually used. The UV bus is tied to ground. | ||
2252 | * Therefore, the OV6630 needs to be in 8-bit multiplexed | ||
2253 | * output mode */ | ||
2254 | |||
2255 | if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518 | ||
2256 | && ov518_color) { | ||
2257 | i2c_w_mask(ov, 0x12, 0x10, 0x10); | ||
2258 | i2c_w_mask(ov, 0x13, 0x20, 0x20); | ||
2259 | } else { | ||
2260 | i2c_w_mask(ov, 0x13, 0x00, 0x20); | ||
2261 | } | ||
2262 | } | ||
2263 | |||
2264 | /******** Clock programming ********/ | ||
2265 | |||
2266 | /* The OV6620 needs special handling. This prevents the | ||
2267 | * severe banding that normally occurs */ | ||
2268 | if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) | ||
2269 | { | ||
2270 | /* Clock down */ | ||
2271 | |||
2272 | i2c_w(ov, 0x2a, 0x04); | ||
2273 | |||
2274 | if (ov->compress) { | ||
2275 | // clock = 0; /* This ensures the highest frame rate */ | ||
2276 | clock = 3; | ||
2277 | } else if (clockdiv == -1) { /* If user didn't override it */ | ||
2278 | clock = 3; /* Gives better exposure time */ | ||
2279 | } else { | ||
2280 | clock = clockdiv; | ||
2281 | } | ||
2282 | |||
2283 | PDEBUG(4, "Setting clock divisor to %d", clock); | ||
2284 | |||
2285 | i2c_w(ov, 0x11, clock); | ||
2286 | |||
2287 | i2c_w(ov, 0x2a, 0x84); | ||
2288 | /* This next setting is critical. It seems to improve | ||
2289 | * the gain or the contrast. The "reserved" bits seem | ||
2290 | * to have some effect in this case. */ | ||
2291 | i2c_w(ov, 0x2d, 0x85); | ||
2292 | } | ||
2293 | else | ||
2294 | { | ||
2295 | if (ov->compress) { | ||
2296 | clock = 1; /* This ensures the highest frame rate */ | ||
2297 | } else if (clockdiv == -1) { /* If user didn't override it */ | ||
2298 | /* Calculate and set the clock divisor */ | ||
2299 | clock = ((sub_flag ? ov->subw * ov->subh | ||
2300 | : width * height) | ||
2301 | * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2) | ||
2302 | / 66000; | ||
2303 | } else { | ||
2304 | clock = clockdiv; | ||
2305 | } | ||
2306 | |||
2307 | PDEBUG(4, "Setting clock divisor to %d", clock); | ||
2308 | |||
2309 | i2c_w(ov, 0x11, clock); | ||
2310 | } | ||
2311 | |||
2312 | /******** Special Features ********/ | ||
2313 | |||
2314 | if (framedrop >= 0) | ||
2315 | i2c_w(ov, 0x16, framedrop); | ||
2316 | |||
2317 | /* Test Pattern */ | ||
2318 | i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02); | ||
2319 | |||
2320 | /* Enable auto white balance */ | ||
2321 | i2c_w_mask(ov, 0x12, 0x04, 0x04); | ||
2322 | |||
2323 | // This will go away as soon as ov51x_mode_init_sensor_regs() | ||
2324 | // is fully tested. | ||
2325 | /* 7620/6620/6630? don't have register 0x35, so play it safe */ | ||
2326 | if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { | ||
2327 | if (width == 640 && height == 480) | ||
2328 | i2c_w(ov, 0x35, 0x9e); | ||
2329 | else | ||
2330 | i2c_w(ov, 0x35, 0x1e); | ||
2331 | } | ||
2332 | |||
2333 | return 0; | ||
2334 | } | ||
2335 | |||
2336 | static int | ||
2337 | set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode, | ||
2338 | int sub_flag) | ||
2339 | { | ||
2340 | int ret; | ||
2341 | int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize; | ||
2342 | int hoffset, voffset, hwscale = 0, vwscale = 0; | ||
2343 | |||
2344 | /* The different sensor ICs handle setting up of window differently. | ||
2345 | * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */ | ||
2346 | switch (ov->sensor) { | ||
2347 | case SEN_OV7610: | ||
2348 | case SEN_OV76BE: | ||
2349 | hwsbase = 0x38; | ||
2350 | hwebase = 0x3a; | ||
2351 | vwsbase = vwebase = 0x05; | ||
2352 | break; | ||
2353 | case SEN_OV6620: | ||
2354 | case SEN_OV6630: | ||
2355 | hwsbase = 0x38; | ||
2356 | hwebase = 0x3a; | ||
2357 | vwsbase = 0x05; | ||
2358 | vwebase = 0x06; | ||
2359 | break; | ||
2360 | case SEN_OV7620: | ||
2361 | hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */ | ||
2362 | hwebase = 0x2f; | ||
2363 | vwsbase = vwebase = 0x05; | ||
2364 | break; | ||
2365 | default: | ||
2366 | err("Invalid sensor"); | ||
2367 | return -EINVAL; | ||
2368 | } | ||
2369 | |||
2370 | if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) { | ||
2371 | /* Note: OV518(+) does downsample on its own) */ | ||
2372 | if ((width > 176 && height > 144) | ||
2373 | || ov->bclass == BCL_OV518) { /* CIF */ | ||
2374 | ret = mode_init_ov_sensor_regs(ov, width, height, | ||
2375 | mode, sub_flag, 0); | ||
2376 | if (ret < 0) | ||
2377 | return ret; | ||
2378 | hwscale = 1; | ||
2379 | vwscale = 1; /* The datasheet says 0; it's wrong */ | ||
2380 | hwsize = 352; | ||
2381 | vwsize = 288; | ||
2382 | } else if (width > 176 || height > 144) { | ||
2383 | err("Illegal dimensions"); | ||
2384 | return -EINVAL; | ||
2385 | } else { /* QCIF */ | ||
2386 | ret = mode_init_ov_sensor_regs(ov, width, height, | ||
2387 | mode, sub_flag, 1); | ||
2388 | if (ret < 0) | ||
2389 | return ret; | ||
2390 | hwsize = 176; | ||
2391 | vwsize = 144; | ||
2392 | } | ||
2393 | } else { | ||
2394 | if (width > 320 && height > 240) { /* VGA */ | ||
2395 | ret = mode_init_ov_sensor_regs(ov, width, height, | ||
2396 | mode, sub_flag, 0); | ||
2397 | if (ret < 0) | ||
2398 | return ret; | ||
2399 | hwscale = 2; | ||
2400 | vwscale = 1; | ||
2401 | hwsize = 640; | ||
2402 | vwsize = 480; | ||
2403 | } else if (width > 320 || height > 240) { | ||
2404 | err("Illegal dimensions"); | ||
2405 | return -EINVAL; | ||
2406 | } else { /* QVGA */ | ||
2407 | ret = mode_init_ov_sensor_regs(ov, width, height, | ||
2408 | mode, sub_flag, 1); | ||
2409 | if (ret < 0) | ||
2410 | return ret; | ||
2411 | hwscale = 1; | ||
2412 | hwsize = 320; | ||
2413 | vwsize = 240; | ||
2414 | } | ||
2415 | } | ||
2416 | |||
2417 | /* Center the window */ | ||
2418 | hoffset = ((hwsize - width) / 2) >> hwscale; | ||
2419 | voffset = ((vwsize - height) / 2) >> vwscale; | ||
2420 | |||
2421 | /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */ | ||
2422 | if (sub_flag) { | ||
2423 | i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale)); | ||
2424 | i2c_w(ov, 0x18, hwebase+((ov->subx+ov->subw)>>hwscale)); | ||
2425 | i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale)); | ||
2426 | i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale)); | ||
2427 | } else { | ||
2428 | i2c_w(ov, 0x17, hwsbase + hoffset); | ||
2429 | i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale)); | ||
2430 | i2c_w(ov, 0x19, vwsbase + voffset); | ||
2431 | i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale)); | ||
2432 | } | ||
2433 | |||
2434 | #ifdef OV511_DEBUG | ||
2435 | if (dump_sensor) | ||
2436 | dump_i2c_regs(ov); | ||
2437 | #endif | ||
2438 | |||
2439 | return 0; | ||
2440 | } | ||
2441 | |||
2442 | /* Set up the OV511/OV511+ with the given image parameters. | ||
2443 | * | ||
2444 | * Do not put any sensor-specific code in here (including I2C I/O functions) | ||
2445 | */ | ||
2446 | static int | ||
2447 | ov511_mode_init_regs(struct usb_ov511 *ov, | ||
2448 | int width, int height, int mode, int sub_flag) | ||
2449 | { | ||
2450 | int hsegs, vsegs; | ||
2451 | |||
2452 | if (sub_flag) { | ||
2453 | width = ov->subw; | ||
2454 | height = ov->subh; | ||
2455 | } | ||
2456 | |||
2457 | PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", | ||
2458 | width, height, mode, sub_flag); | ||
2459 | |||
2460 | // FIXME: This should be moved to a 7111a-specific function once | ||
2461 | // subcapture is dealt with properly | ||
2462 | if (ov->sensor == SEN_SAA7111A) { | ||
2463 | if (width == 320 && height == 240) { | ||
2464 | /* No need to do anything special */ | ||
2465 | } else if (width == 640 && height == 480) { | ||
2466 | /* Set the OV511 up as 320x480, but keep the | ||
2467 | * V4L resolution as 640x480 */ | ||
2468 | width = 320; | ||
2469 | } else { | ||
2470 | err("SAA7111A only allows 320x240 or 640x480"); | ||
2471 | return -EINVAL; | ||
2472 | } | ||
2473 | } | ||
2474 | |||
2475 | /* Make sure width and height are a multiple of 8 */ | ||
2476 | if (width % 8 || height % 8) { | ||
2477 | err("Invalid size (%d, %d) (mode = %d)", width, height, mode); | ||
2478 | return -EINVAL; | ||
2479 | } | ||
2480 | |||
2481 | if (width < ov->minwidth || height < ov->minheight) { | ||
2482 | err("Requested dimensions are too small"); | ||
2483 | return -EINVAL; | ||
2484 | } | ||
2485 | |||
2486 | if (ov51x_stop(ov) < 0) | ||
2487 | return -EIO; | ||
2488 | |||
2489 | if (mode == VIDEO_PALETTE_GREY) { | ||
2490 | reg_w(ov, R511_CAM_UV_EN, 0x00); | ||
2491 | reg_w(ov, R511_SNAP_UV_EN, 0x00); | ||
2492 | reg_w(ov, R511_SNAP_OPTS, 0x01); | ||
2493 | } else { | ||
2494 | reg_w(ov, R511_CAM_UV_EN, 0x01); | ||
2495 | reg_w(ov, R511_SNAP_UV_EN, 0x01); | ||
2496 | reg_w(ov, R511_SNAP_OPTS, 0x03); | ||
2497 | } | ||
2498 | |||
2499 | /* Here I'm assuming that snapshot size == image size. | ||
2500 | * I hope that's always true. --claudio | ||
2501 | */ | ||
2502 | hsegs = (width >> 3) - 1; | ||
2503 | vsegs = (height >> 3) - 1; | ||
2504 | |||
2505 | reg_w(ov, R511_CAM_PXCNT, hsegs); | ||
2506 | reg_w(ov, R511_CAM_LNCNT, vsegs); | ||
2507 | reg_w(ov, R511_CAM_PXDIV, 0x00); | ||
2508 | reg_w(ov, R511_CAM_LNDIV, 0x00); | ||
2509 | |||
2510 | /* YUV420, low pass filter on */ | ||
2511 | reg_w(ov, R511_CAM_OPTS, 0x03); | ||
2512 | |||
2513 | /* Snapshot additions */ | ||
2514 | reg_w(ov, R511_SNAP_PXCNT, hsegs); | ||
2515 | reg_w(ov, R511_SNAP_LNCNT, vsegs); | ||
2516 | reg_w(ov, R511_SNAP_PXDIV, 0x00); | ||
2517 | reg_w(ov, R511_SNAP_LNDIV, 0x00); | ||
2518 | |||
2519 | if (ov->compress) { | ||
2520 | /* Enable Y and UV quantization and compression */ | ||
2521 | reg_w(ov, R511_COMP_EN, 0x07); | ||
2522 | reg_w(ov, R511_COMP_LUT_EN, 0x03); | ||
2523 | ov51x_reset(ov, OV511_RESET_OMNICE); | ||
2524 | } | ||
2525 | |||
2526 | if (ov51x_restart(ov) < 0) | ||
2527 | return -EIO; | ||
2528 | |||
2529 | return 0; | ||
2530 | } | ||
2531 | |||
2532 | /* Sets up the OV518/OV518+ with the given image parameters | ||
2533 | * | ||
2534 | * OV518 needs a completely different approach, until we can figure out what | ||
2535 | * the individual registers do. Also, only 15 FPS is supported now. | ||
2536 | * | ||
2537 | * Do not put any sensor-specific code in here (including I2C I/O functions) | ||
2538 | */ | ||
2539 | static int | ||
2540 | ov518_mode_init_regs(struct usb_ov511 *ov, | ||
2541 | int width, int height, int mode, int sub_flag) | ||
2542 | { | ||
2543 | int hsegs, vsegs, hi_res; | ||
2544 | |||
2545 | if (sub_flag) { | ||
2546 | width = ov->subw; | ||
2547 | height = ov->subh; | ||
2548 | } | ||
2549 | |||
2550 | PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", | ||
2551 | width, height, mode, sub_flag); | ||
2552 | |||
2553 | if (width % 16 || height % 8) { | ||
2554 | err("Invalid size (%d, %d)", width, height); | ||
2555 | return -EINVAL; | ||
2556 | } | ||
2557 | |||
2558 | if (width < ov->minwidth || height < ov->minheight) { | ||
2559 | err("Requested dimensions are too small"); | ||
2560 | return -EINVAL; | ||
2561 | } | ||
2562 | |||
2563 | if (width >= 320 && height >= 240) { | ||
2564 | hi_res = 1; | ||
2565 | } else if (width >= 320 || height >= 240) { | ||
2566 | err("Invalid width/height combination (%d, %d)", width, height); | ||
2567 | return -EINVAL; | ||
2568 | } else { | ||
2569 | hi_res = 0; | ||
2570 | } | ||
2571 | |||
2572 | if (ov51x_stop(ov) < 0) | ||
2573 | return -EIO; | ||
2574 | |||
2575 | /******** Set the mode ********/ | ||
2576 | |||
2577 | reg_w(ov, 0x2b, 0); | ||
2578 | reg_w(ov, 0x2c, 0); | ||
2579 | reg_w(ov, 0x2d, 0); | ||
2580 | reg_w(ov, 0x2e, 0); | ||
2581 | reg_w(ov, 0x3b, 0); | ||
2582 | reg_w(ov, 0x3c, 0); | ||
2583 | reg_w(ov, 0x3d, 0); | ||
2584 | reg_w(ov, 0x3e, 0); | ||
2585 | |||
2586 | if (ov->bridge == BRG_OV518 && ov518_color) { | ||
2587 | /* OV518 needs U and V swapped */ | ||
2588 | i2c_w_mask(ov, 0x15, 0x00, 0x01); | ||
2589 | |||
2590 | if (mode == VIDEO_PALETTE_GREY) { | ||
2591 | /* Set 16-bit input format (UV data are ignored) */ | ||
2592 | reg_w_mask(ov, 0x20, 0x00, 0x08); | ||
2593 | |||
2594 | /* Set 8-bit (4:0:0) output format */ | ||
2595 | reg_w_mask(ov, 0x28, 0x00, 0xf0); | ||
2596 | reg_w_mask(ov, 0x38, 0x00, 0xf0); | ||
2597 | } else { | ||
2598 | /* Set 8-bit (YVYU) input format */ | ||
2599 | reg_w_mask(ov, 0x20, 0x08, 0x08); | ||
2600 | |||
2601 | /* Set 12-bit (4:2:0) output format */ | ||
2602 | reg_w_mask(ov, 0x28, 0x80, 0xf0); | ||
2603 | reg_w_mask(ov, 0x38, 0x80, 0xf0); | ||
2604 | } | ||
2605 | } else { | ||
2606 | reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); | ||
2607 | reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); | ||
2608 | } | ||
2609 | |||
2610 | hsegs = width / 16; | ||
2611 | vsegs = height / 4; | ||
2612 | |||
2613 | reg_w(ov, 0x29, hsegs); | ||
2614 | reg_w(ov, 0x2a, vsegs); | ||
2615 | |||
2616 | reg_w(ov, 0x39, hsegs); | ||
2617 | reg_w(ov, 0x3a, vsegs); | ||
2618 | |||
2619 | /* Windows driver does this here; who knows why */ | ||
2620 | reg_w(ov, 0x2f, 0x80); | ||
2621 | |||
2622 | /******** Set the framerate (to 15 FPS) ********/ | ||
2623 | |||
2624 | /* Mode independent, but framerate dependent, regs */ | ||
2625 | reg_w(ov, 0x51, 0x02); /* Clock divider; lower==faster */ | ||
2626 | reg_w(ov, 0x22, 0x18); | ||
2627 | reg_w(ov, 0x23, 0xff); | ||
2628 | |||
2629 | if (ov->bridge == BRG_OV518PLUS) | ||
2630 | reg_w(ov, 0x21, 0x19); | ||
2631 | else | ||
2632 | reg_w(ov, 0x71, 0x19); /* Compression-related? */ | ||
2633 | |||
2634 | // FIXME: Sensor-specific | ||
2635 | /* Bit 5 is what matters here. Of course, it is "reserved" */ | ||
2636 | i2c_w(ov, 0x54, 0x23); | ||
2637 | |||
2638 | reg_w(ov, 0x2f, 0x80); | ||
2639 | |||
2640 | if (ov->bridge == BRG_OV518PLUS) { | ||
2641 | reg_w(ov, 0x24, 0x94); | ||
2642 | reg_w(ov, 0x25, 0x90); | ||
2643 | ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */ | ||
2644 | ov518_reg_w32(ov, 0xc6, 540, 2); /* 21ch */ | ||
2645 | ov518_reg_w32(ov, 0xc7, 540, 2); /* 21ch */ | ||
2646 | ov518_reg_w32(ov, 0xc8, 108, 2); /* 6ch */ | ||
2647 | ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */ | ||
2648 | ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */ | ||
2649 | ov518_reg_w32(ov, 0xcc, 2400, 2); /* 960h */ | ||
2650 | ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */ | ||
2651 | ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */ | ||
2652 | } else { | ||
2653 | reg_w(ov, 0x24, 0x9f); | ||
2654 | reg_w(ov, 0x25, 0x90); | ||
2655 | ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */ | ||
2656 | ov518_reg_w32(ov, 0xc6, 500, 2); /* 1f4h */ | ||
2657 | ov518_reg_w32(ov, 0xc7, 500, 2); /* 1f4h */ | ||
2658 | ov518_reg_w32(ov, 0xc8, 142, 2); /* 8eh */ | ||
2659 | ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */ | ||
2660 | ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */ | ||
2661 | ov518_reg_w32(ov, 0xcc, 2000, 2); /* 7d0h */ | ||
2662 | ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */ | ||
2663 | ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */ | ||
2664 | } | ||
2665 | |||
2666 | reg_w(ov, 0x2f, 0x80); | ||
2667 | |||
2668 | if (ov51x_restart(ov) < 0) | ||
2669 | return -EIO; | ||
2670 | |||
2671 | /* Reset it just for good measure */ | ||
2672 | if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) | ||
2673 | return -EIO; | ||
2674 | |||
2675 | return 0; | ||
2676 | } | ||
2677 | |||
2678 | /* This is a wrapper around the OV511, OV518, and sensor specific functions */ | ||
2679 | static int | ||
2680 | mode_init_regs(struct usb_ov511 *ov, | ||
2681 | int width, int height, int mode, int sub_flag) | ||
2682 | { | ||
2683 | int rc = 0; | ||
2684 | |||
2685 | if (!ov || !ov->dev) | ||
2686 | return -EFAULT; | ||
2687 | |||
2688 | if (ov->bclass == BCL_OV518) { | ||
2689 | rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag); | ||
2690 | } else { | ||
2691 | rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag); | ||
2692 | } | ||
2693 | |||
2694 | if (FATAL_ERROR(rc)) | ||
2695 | return rc; | ||
2696 | |||
2697 | switch (ov->sensor) { | ||
2698 | case SEN_OV7610: | ||
2699 | case SEN_OV7620: | ||
2700 | case SEN_OV76BE: | ||
2701 | case SEN_OV8600: | ||
2702 | case SEN_OV6620: | ||
2703 | case SEN_OV6630: | ||
2704 | rc = set_ov_sensor_window(ov, width, height, mode, sub_flag); | ||
2705 | break; | ||
2706 | case SEN_KS0127: | ||
2707 | case SEN_KS0127B: | ||
2708 | err("KS0127-series decoders not supported yet"); | ||
2709 | rc = -EINVAL; | ||
2710 | break; | ||
2711 | case SEN_SAA7111A: | ||
2712 | // rc = mode_init_saa_sensor_regs(ov, width, height, mode, | ||
2713 | // sub_flag); | ||
2714 | |||
2715 | PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f)); | ||
2716 | break; | ||
2717 | default: | ||
2718 | err("Unknown sensor"); | ||
2719 | rc = -EINVAL; | ||
2720 | } | ||
2721 | |||
2722 | if (FATAL_ERROR(rc)) | ||
2723 | return rc; | ||
2724 | |||
2725 | /* Sensor-independent settings */ | ||
2726 | rc = sensor_set_auto_brightness(ov, ov->auto_brt); | ||
2727 | if (FATAL_ERROR(rc)) | ||
2728 | return rc; | ||
2729 | |||
2730 | rc = sensor_set_auto_exposure(ov, ov->auto_exp); | ||
2731 | if (FATAL_ERROR(rc)) | ||
2732 | return rc; | ||
2733 | |||
2734 | rc = sensor_set_banding_filter(ov, bandingfilter); | ||
2735 | if (FATAL_ERROR(rc)) | ||
2736 | return rc; | ||
2737 | |||
2738 | if (ov->lightfreq) { | ||
2739 | rc = sensor_set_light_freq(ov, lightfreq); | ||
2740 | if (FATAL_ERROR(rc)) | ||
2741 | return rc; | ||
2742 | } | ||
2743 | |||
2744 | rc = sensor_set_backlight(ov, ov->backlight); | ||
2745 | if (FATAL_ERROR(rc)) | ||
2746 | return rc; | ||
2747 | |||
2748 | rc = sensor_set_mirror(ov, ov->mirror); | ||
2749 | if (FATAL_ERROR(rc)) | ||
2750 | return rc; | ||
2751 | |||
2752 | return 0; | ||
2753 | } | ||
2754 | |||
2755 | /* This sets the default image parameters. This is useful for apps that use | ||
2756 | * read() and do not set these. | ||
2757 | */ | ||
2758 | static int | ||
2759 | ov51x_set_default_params(struct usb_ov511 *ov) | ||
2760 | { | ||
2761 | int i; | ||
2762 | |||
2763 | /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used | ||
2764 | * (using read() instead). */ | ||
2765 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
2766 | ov->frame[i].width = ov->maxwidth; | ||
2767 | ov->frame[i].height = ov->maxheight; | ||
2768 | ov->frame[i].bytes_read = 0; | ||
2769 | if (force_palette) | ||
2770 | ov->frame[i].format = force_palette; | ||
2771 | else | ||
2772 | ov->frame[i].format = VIDEO_PALETTE_YUV420; | ||
2773 | |||
2774 | ov->frame[i].depth = get_depth(ov->frame[i].format); | ||
2775 | } | ||
2776 | |||
2777 | PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight, | ||
2778 | symbolic(v4l1_plist, ov->frame[0].format)); | ||
2779 | |||
2780 | /* Initialize to max width/height, YUV420 or RGB24 (if supported) */ | ||
2781 | if (mode_init_regs(ov, ov->maxwidth, ov->maxheight, | ||
2782 | ov->frame[0].format, 0) < 0) | ||
2783 | return -EINVAL; | ||
2784 | |||
2785 | return 0; | ||
2786 | } | ||
2787 | |||
2788 | /********************************************************************** | ||
2789 | * | ||
2790 | * Video decoder stuff | ||
2791 | * | ||
2792 | **********************************************************************/ | ||
2793 | |||
2794 | /* Set analog input port of decoder */ | ||
2795 | static int | ||
2796 | decoder_set_input(struct usb_ov511 *ov, int input) | ||
2797 | { | ||
2798 | PDEBUG(4, "port %d", input); | ||
2799 | |||
2800 | switch (ov->sensor) { | ||
2801 | case SEN_SAA7111A: | ||
2802 | { | ||
2803 | /* Select mode */ | ||
2804 | i2c_w_mask(ov, 0x02, input, 0x07); | ||
2805 | /* Bypass chrominance trap for modes 4..7 */ | ||
2806 | i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80); | ||
2807 | break; | ||
2808 | } | ||
2809 | default: | ||
2810 | return -EINVAL; | ||
2811 | } | ||
2812 | |||
2813 | return 0; | ||
2814 | } | ||
2815 | |||
2816 | /* Get ASCII name of video input */ | ||
2817 | static int | ||
2818 | decoder_get_input_name(struct usb_ov511 *ov, int input, char *name) | ||
2819 | { | ||
2820 | switch (ov->sensor) { | ||
2821 | case SEN_SAA7111A: | ||
2822 | { | ||
2823 | if (input < 0 || input > 7) | ||
2824 | return -EINVAL; | ||
2825 | else if (input < 4) | ||
2826 | sprintf(name, "CVBS-%d", input); | ||
2827 | else // if (input < 8) | ||
2828 | sprintf(name, "S-Video-%d", input - 4); | ||
2829 | break; | ||
2830 | } | ||
2831 | default: | ||
2832 | sprintf(name, "%s", "Camera"); | ||
2833 | } | ||
2834 | |||
2835 | return 0; | ||
2836 | } | ||
2837 | |||
2838 | /* Set norm (NTSC, PAL, SECAM, AUTO) */ | ||
2839 | static int | ||
2840 | decoder_set_norm(struct usb_ov511 *ov, int norm) | ||
2841 | { | ||
2842 | PDEBUG(4, "%d", norm); | ||
2843 | |||
2844 | switch (ov->sensor) { | ||
2845 | case SEN_SAA7111A: | ||
2846 | { | ||
2847 | int reg_8, reg_e; | ||
2848 | |||
2849 | if (norm == VIDEO_MODE_NTSC) { | ||
2850 | reg_8 = 0x40; /* 60 Hz */ | ||
2851 | reg_e = 0x00; /* NTSC M / PAL BGHI */ | ||
2852 | } else if (norm == VIDEO_MODE_PAL) { | ||
2853 | reg_8 = 0x00; /* 50 Hz */ | ||
2854 | reg_e = 0x00; /* NTSC M / PAL BGHI */ | ||
2855 | } else if (norm == VIDEO_MODE_AUTO) { | ||
2856 | reg_8 = 0x80; /* Auto field detect */ | ||
2857 | reg_e = 0x00; /* NTSC M / PAL BGHI */ | ||
2858 | } else if (norm == VIDEO_MODE_SECAM) { | ||
2859 | reg_8 = 0x00; /* 50 Hz */ | ||
2860 | reg_e = 0x50; /* SECAM / PAL 4.43 */ | ||
2861 | } else { | ||
2862 | return -EINVAL; | ||
2863 | } | ||
2864 | |||
2865 | i2c_w_mask(ov, 0x08, reg_8, 0xc0); | ||
2866 | i2c_w_mask(ov, 0x0e, reg_e, 0x70); | ||
2867 | break; | ||
2868 | } | ||
2869 | default: | ||
2870 | return -EINVAL; | ||
2871 | } | ||
2872 | |||
2873 | return 0; | ||
2874 | } | ||
2875 | |||
2876 | /********************************************************************** | ||
2877 | * | ||
2878 | * Raw data parsing | ||
2879 | * | ||
2880 | **********************************************************************/ | ||
2881 | |||
2882 | /* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the | ||
2883 | * image at pOut is specified by w. | ||
2884 | */ | ||
2885 | static inline void | ||
2886 | make_8x8(unsigned char *pIn, unsigned char *pOut, int w) | ||
2887 | { | ||
2888 | unsigned char *pOut1 = pOut; | ||
2889 | int x, y; | ||
2890 | |||
2891 | for (y = 0; y < 8; y++) { | ||
2892 | pOut1 = pOut; | ||
2893 | for (x = 0; x < 8; x++) { | ||
2894 | *pOut1++ = *pIn++; | ||
2895 | } | ||
2896 | pOut += w; | ||
2897 | } | ||
2898 | } | ||
2899 | |||
2900 | /* | ||
2901 | * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments. | ||
2902 | * The segments represent 4 squares of 8x8 pixels as follows: | ||
2903 | * | ||
2904 | * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 | ||
2905 | * 8 9 ... 15 72 73 ... 79 200 201 ... 207 | ||
2906 | * ... ... ... | ||
2907 | * 56 57 ... 63 120 121 ... 127 248 249 ... 255 | ||
2908 | * | ||
2909 | */ | ||
2910 | static void | ||
2911 | yuv400raw_to_yuv400p(struct ov511_frame *frame, | ||
2912 | unsigned char *pIn0, unsigned char *pOut0) | ||
2913 | { | ||
2914 | int x, y; | ||
2915 | unsigned char *pIn, *pOut, *pOutLine; | ||
2916 | |||
2917 | /* Copy Y */ | ||
2918 | pIn = pIn0; | ||
2919 | pOutLine = pOut0; | ||
2920 | for (y = 0; y < frame->rawheight - 1; y += 8) { | ||
2921 | pOut = pOutLine; | ||
2922 | for (x = 0; x < frame->rawwidth - 1; x += 8) { | ||
2923 | make_8x8(pIn, pOut, frame->rawwidth); | ||
2924 | pIn += 64; | ||
2925 | pOut += 8; | ||
2926 | } | ||
2927 | pOutLine += 8 * frame->rawwidth; | ||
2928 | } | ||
2929 | } | ||
2930 | |||
2931 | /* | ||
2932 | * For YUV 4:2:0 images, the data show up in 384 byte segments. | ||
2933 | * The first 64 bytes of each segment are U, the next 64 are V. The U and | ||
2934 | * V are arranged as follows: | ||
2935 | * | ||
2936 | * 0 1 ... 7 | ||
2937 | * 8 9 ... 15 | ||
2938 | * ... | ||
2939 | * 56 57 ... 63 | ||
2940 | * | ||
2941 | * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block). | ||
2942 | * | ||
2943 | * The next 256 bytes are full resolution Y data and represent 4 squares | ||
2944 | * of 8x8 pixels as follows: | ||
2945 | * | ||
2946 | * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 | ||
2947 | * 8 9 ... 15 72 73 ... 79 200 201 ... 207 | ||
2948 | * ... ... ... | ||
2949 | * 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255 | ||
2950 | * | ||
2951 | * Note that the U and V data in one segment represent a 16 x 16 pixel | ||
2952 | * area, but the Y data represent a 32 x 8 pixel area. If the width is not an | ||
2953 | * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the | ||
2954 | * next horizontal stripe. | ||
2955 | * | ||
2956 | * If dumppix module param is set, _parse_data just dumps the incoming segments, | ||
2957 | * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480 | ||
2958 | * this puts the data on the standard output and can be analyzed with the | ||
2959 | * parseppm.c utility I wrote. That's a much faster way for figuring out how | ||
2960 | * these data are scrambled. | ||
2961 | */ | ||
2962 | |||
2963 | /* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0. | ||
2964 | * | ||
2965 | * FIXME: Currently only handles width and height that are multiples of 16 | ||
2966 | */ | ||
2967 | static void | ||
2968 | yuv420raw_to_yuv420p(struct ov511_frame *frame, | ||
2969 | unsigned char *pIn0, unsigned char *pOut0) | ||
2970 | { | ||
2971 | int k, x, y; | ||
2972 | unsigned char *pIn, *pOut, *pOutLine; | ||
2973 | const unsigned int a = frame->rawwidth * frame->rawheight; | ||
2974 | const unsigned int w = frame->rawwidth / 2; | ||
2975 | |||
2976 | /* Copy U and V */ | ||
2977 | pIn = pIn0; | ||
2978 | pOutLine = pOut0 + a; | ||
2979 | for (y = 0; y < frame->rawheight - 1; y += 16) { | ||
2980 | pOut = pOutLine; | ||
2981 | for (x = 0; x < frame->rawwidth - 1; x += 16) { | ||
2982 | make_8x8(pIn, pOut, w); | ||
2983 | make_8x8(pIn + 64, pOut + a/4, w); | ||
2984 | pIn += 384; | ||
2985 | pOut += 8; | ||
2986 | } | ||
2987 | pOutLine += 8 * w; | ||
2988 | } | ||
2989 | |||
2990 | /* Copy Y */ | ||
2991 | pIn = pIn0 + 128; | ||
2992 | pOutLine = pOut0; | ||
2993 | k = 0; | ||
2994 | for (y = 0; y < frame->rawheight - 1; y += 8) { | ||
2995 | pOut = pOutLine; | ||
2996 | for (x = 0; x < frame->rawwidth - 1; x += 8) { | ||
2997 | make_8x8(pIn, pOut, frame->rawwidth); | ||
2998 | pIn += 64; | ||
2999 | pOut += 8; | ||
3000 | if ((++k) > 3) { | ||
3001 | k = 0; | ||
3002 | pIn += 128; | ||
3003 | } | ||
3004 | } | ||
3005 | pOutLine += 8 * frame->rawwidth; | ||
3006 | } | ||
3007 | } | ||
3008 | |||
3009 | /********************************************************************** | ||
3010 | * | ||
3011 | * Decompression | ||
3012 | * | ||
3013 | **********************************************************************/ | ||
3014 | |||
3015 | /* Chooses a decompression module, locks it, and sets ov->decomp_ops | ||
3016 | * accordingly. Returns -ENXIO if decompressor is not available, otherwise | ||
3017 | * returns 0 if no other error. | ||
3018 | */ | ||
3019 | static int | ||
3020 | request_decompressor(struct usb_ov511 *ov) | ||
3021 | { | ||
3022 | if (!ov) | ||
3023 | return -ENODEV; | ||
3024 | |||
3025 | if (ov->decomp_ops) { | ||
3026 | err("ERROR: Decompressor already requested!"); | ||
3027 | return -EINVAL; | ||
3028 | } | ||
3029 | |||
3030 | lock_kernel(); | ||
3031 | |||
3032 | /* Try to get MMX, and fall back on no-MMX if necessary */ | ||
3033 | if (ov->bclass == BCL_OV511) { | ||
3034 | if (ov511_mmx_decomp_ops) { | ||
3035 | PDEBUG(3, "Using OV511 MMX decompressor"); | ||
3036 | ov->decomp_ops = ov511_mmx_decomp_ops; | ||
3037 | } else if (ov511_decomp_ops) { | ||
3038 | PDEBUG(3, "Using OV511 decompressor"); | ||
3039 | ov->decomp_ops = ov511_decomp_ops; | ||
3040 | } else { | ||
3041 | err("No decompressor available"); | ||
3042 | } | ||
3043 | } else if (ov->bclass == BCL_OV518) { | ||
3044 | if (ov518_mmx_decomp_ops) { | ||
3045 | PDEBUG(3, "Using OV518 MMX decompressor"); | ||
3046 | ov->decomp_ops = ov518_mmx_decomp_ops; | ||
3047 | } else if (ov518_decomp_ops) { | ||
3048 | PDEBUG(3, "Using OV518 decompressor"); | ||
3049 | ov->decomp_ops = ov518_decomp_ops; | ||
3050 | } else { | ||
3051 | err("No decompressor available"); | ||
3052 | } | ||
3053 | } else { | ||
3054 | err("Unknown bridge"); | ||
3055 | } | ||
3056 | |||
3057 | if (!ov->decomp_ops) | ||
3058 | goto nosys; | ||
3059 | |||
3060 | if (!ov->decomp_ops->owner) { | ||
3061 | ov->decomp_ops = NULL; | ||
3062 | goto nosys; | ||
3063 | } | ||
3064 | |||
3065 | if (!try_module_get(ov->decomp_ops->owner)) | ||
3066 | goto nosys; | ||
3067 | |||
3068 | unlock_kernel(); | ||
3069 | return 0; | ||
3070 | |||
3071 | nosys: | ||
3072 | unlock_kernel(); | ||
3073 | return -ENOSYS; | ||
3074 | } | ||
3075 | |||
3076 | /* Unlocks decompression module and nulls ov->decomp_ops. Safe to call even | ||
3077 | * if ov->decomp_ops is NULL. | ||
3078 | */ | ||
3079 | static void | ||
3080 | release_decompressor(struct usb_ov511 *ov) | ||
3081 | { | ||
3082 | int released = 0; /* Did we actually do anything? */ | ||
3083 | |||
3084 | if (!ov) | ||
3085 | return; | ||
3086 | |||
3087 | lock_kernel(); | ||
3088 | |||
3089 | if (ov->decomp_ops) { | ||
3090 | module_put(ov->decomp_ops->owner); | ||
3091 | released = 1; | ||
3092 | } | ||
3093 | |||
3094 | ov->decomp_ops = NULL; | ||
3095 | |||
3096 | unlock_kernel(); | ||
3097 | |||
3098 | if (released) | ||
3099 | PDEBUG(3, "Decompressor released"); | ||
3100 | } | ||
3101 | |||
3102 | static void | ||
3103 | decompress(struct usb_ov511 *ov, struct ov511_frame *frame, | ||
3104 | unsigned char *pIn0, unsigned char *pOut0) | ||
3105 | { | ||
3106 | if (!ov->decomp_ops) | ||
3107 | if (request_decompressor(ov)) | ||
3108 | return; | ||
3109 | |||
3110 | PDEBUG(4, "Decompressing %d bytes", frame->bytes_recvd); | ||
3111 | |||
3112 | if (frame->format == VIDEO_PALETTE_GREY | ||
3113 | && ov->decomp_ops->decomp_400) { | ||
3114 | int ret = ov->decomp_ops->decomp_400( | ||
3115 | pIn0, | ||
3116 | pOut0, | ||
3117 | frame->compbuf, | ||
3118 | frame->rawwidth, | ||
3119 | frame->rawheight, | ||
3120 | frame->bytes_recvd); | ||
3121 | PDEBUG(4, "DEBUG: decomp_400 returned %d", ret); | ||
3122 | } else if (frame->format != VIDEO_PALETTE_GREY | ||
3123 | && ov->decomp_ops->decomp_420) { | ||
3124 | int ret = ov->decomp_ops->decomp_420( | ||
3125 | pIn0, | ||
3126 | pOut0, | ||
3127 | frame->compbuf, | ||
3128 | frame->rawwidth, | ||
3129 | frame->rawheight, | ||
3130 | frame->bytes_recvd); | ||
3131 | PDEBUG(4, "DEBUG: decomp_420 returned %d", ret); | ||
3132 | } else { | ||
3133 | err("Decompressor does not support this format"); | ||
3134 | } | ||
3135 | } | ||
3136 | |||
3137 | /********************************************************************** | ||
3138 | * | ||
3139 | * Format conversion | ||
3140 | * | ||
3141 | **********************************************************************/ | ||
3142 | |||
3143 | /* Fuses even and odd fields together, and doubles width. | ||
3144 | * INPUT: an odd field followed by an even field at pIn0, in YUV planar format | ||
3145 | * OUTPUT: a normal YUV planar image, with correct aspect ratio | ||
3146 | */ | ||
3147 | static void | ||
3148 | deinterlace(struct ov511_frame *frame, int rawformat, | ||
3149 | unsigned char *pIn0, unsigned char *pOut0) | ||
3150 | { | ||
3151 | const int fieldheight = frame->rawheight / 2; | ||
3152 | const int fieldpix = fieldheight * frame->rawwidth; | ||
3153 | const int w = frame->width; | ||
3154 | int x, y; | ||
3155 | unsigned char *pInEven, *pInOdd, *pOut; | ||
3156 | |||
3157 | PDEBUG(5, "fieldheight=%d", fieldheight); | ||
3158 | |||
3159 | if (frame->rawheight != frame->height) { | ||
3160 | err("invalid height"); | ||
3161 | return; | ||
3162 | } | ||
3163 | |||
3164 | if ((frame->rawwidth * 2) != frame->width) { | ||
3165 | err("invalid width"); | ||
3166 | return; | ||
3167 | } | ||
3168 | |||
3169 | /* Y */ | ||
3170 | pInOdd = pIn0; | ||
3171 | pInEven = pInOdd + fieldpix; | ||
3172 | pOut = pOut0; | ||
3173 | for (y = 0; y < fieldheight; y++) { | ||
3174 | for (x = 0; x < frame->rawwidth; x++) { | ||
3175 | *pOut = *pInEven; | ||
3176 | *(pOut+1) = *pInEven++; | ||
3177 | *(pOut+w) = *pInOdd; | ||
3178 | *(pOut+w+1) = *pInOdd++; | ||
3179 | pOut += 2; | ||
3180 | } | ||
3181 | pOut += w; | ||
3182 | } | ||
3183 | |||
3184 | if (rawformat == RAWFMT_YUV420) { | ||
3185 | /* U */ | ||
3186 | pInOdd = pIn0 + fieldpix * 2; | ||
3187 | pInEven = pInOdd + fieldpix / 4; | ||
3188 | for (y = 0; y < fieldheight / 2; y++) { | ||
3189 | for (x = 0; x < frame->rawwidth / 2; x++) { | ||
3190 | *pOut = *pInEven; | ||
3191 | *(pOut+1) = *pInEven++; | ||
3192 | *(pOut+w/2) = *pInOdd; | ||
3193 | *(pOut+w/2+1) = *pInOdd++; | ||
3194 | pOut += 2; | ||
3195 | } | ||
3196 | pOut += w/2; | ||
3197 | } | ||
3198 | /* V */ | ||
3199 | pInOdd = pIn0 + fieldpix * 2 + fieldpix / 2; | ||
3200 | pInEven = pInOdd + fieldpix / 4; | ||
3201 | for (y = 0; y < fieldheight / 2; y++) { | ||
3202 | for (x = 0; x < frame->rawwidth / 2; x++) { | ||
3203 | *pOut = *pInEven; | ||
3204 | *(pOut+1) = *pInEven++; | ||
3205 | *(pOut+w/2) = *pInOdd; | ||
3206 | *(pOut+w/2+1) = *pInOdd++; | ||
3207 | pOut += 2; | ||
3208 | } | ||
3209 | pOut += w/2; | ||
3210 | } | ||
3211 | } | ||
3212 | } | ||
3213 | |||
3214 | static void | ||
3215 | ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame) | ||
3216 | { | ||
3217 | /* Deinterlace frame, if necessary */ | ||
3218 | if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) { | ||
3219 | if (frame->compressed) | ||
3220 | decompress(ov, frame, frame->rawdata, | ||
3221 | frame->tempdata); | ||
3222 | else | ||
3223 | yuv400raw_to_yuv400p(frame, frame->rawdata, | ||
3224 | frame->tempdata); | ||
3225 | |||
3226 | deinterlace(frame, RAWFMT_YUV400, frame->tempdata, | ||
3227 | frame->data); | ||
3228 | } else { | ||
3229 | if (frame->compressed) | ||
3230 | decompress(ov, frame, frame->rawdata, | ||
3231 | frame->data); | ||
3232 | else | ||
3233 | yuv400raw_to_yuv400p(frame, frame->rawdata, | ||
3234 | frame->data); | ||
3235 | } | ||
3236 | } | ||
3237 | |||
3238 | /* Process raw YUV420 data into standard YUV420P */ | ||
3239 | static void | ||
3240 | ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame) | ||
3241 | { | ||
3242 | /* Deinterlace frame, if necessary */ | ||
3243 | if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) { | ||
3244 | if (frame->compressed) | ||
3245 | decompress(ov, frame, frame->rawdata, frame->tempdata); | ||
3246 | else | ||
3247 | yuv420raw_to_yuv420p(frame, frame->rawdata, | ||
3248 | frame->tempdata); | ||
3249 | |||
3250 | deinterlace(frame, RAWFMT_YUV420, frame->tempdata, | ||
3251 | frame->data); | ||
3252 | } else { | ||
3253 | if (frame->compressed) | ||
3254 | decompress(ov, frame, frame->rawdata, frame->data); | ||
3255 | else | ||
3256 | yuv420raw_to_yuv420p(frame, frame->rawdata, | ||
3257 | frame->data); | ||
3258 | } | ||
3259 | } | ||
3260 | |||
3261 | /* Post-processes the specified frame. This consists of: | ||
3262 | * 1. Decompress frame, if necessary | ||
3263 | * 2. Deinterlace frame and scale to proper size, if necessary | ||
3264 | * 3. Convert from YUV planar to destination format, if necessary | ||
3265 | * 4. Fix the RGB offset, if necessary | ||
3266 | */ | ||
3267 | static void | ||
3268 | ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame) | ||
3269 | { | ||
3270 | if (dumppix) { | ||
3271 | memset(frame->data, 0, | ||
3272 | MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); | ||
3273 | PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd); | ||
3274 | memcpy(frame->data, frame->rawdata, frame->bytes_recvd); | ||
3275 | } else { | ||
3276 | switch (frame->format) { | ||
3277 | case VIDEO_PALETTE_GREY: | ||
3278 | ov51x_postprocess_grey(ov, frame); | ||
3279 | break; | ||
3280 | case VIDEO_PALETTE_YUV420: | ||
3281 | case VIDEO_PALETTE_YUV420P: | ||
3282 | ov51x_postprocess_yuv420(ov, frame); | ||
3283 | break; | ||
3284 | default: | ||
3285 | err("Cannot convert data to %s", | ||
3286 | symbolic(v4l1_plist, frame->format)); | ||
3287 | } | ||
3288 | } | ||
3289 | } | ||
3290 | |||
3291 | /********************************************************************** | ||
3292 | * | ||
3293 | * OV51x data transfer, IRQ handler | ||
3294 | * | ||
3295 | **********************************************************************/ | ||
3296 | |||
3297 | static inline void | ||
3298 | ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n) | ||
3299 | { | ||
3300 | int num, offset; | ||
3301 | int pnum = in[ov->packet_size - 1]; /* Get packet number */ | ||
3302 | int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight); | ||
3303 | struct ov511_frame *frame = &ov->frame[ov->curframe]; | ||
3304 | struct timeval *ts; | ||
3305 | |||
3306 | /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th | ||
3307 | * byte non-zero. The EOF packet has image width/height in the | ||
3308 | * 10th and 11th bytes. The 9th byte is given as follows: | ||
3309 | * | ||
3310 | * bit 7: EOF | ||
3311 | * 6: compression enabled | ||
3312 | * 5: 422/420/400 modes | ||
3313 | * 4: 422/420/400 modes | ||
3314 | * 3: 1 | ||
3315 | * 2: snapshot button on | ||
3316 | * 1: snapshot frame | ||
3317 | * 0: even/odd field | ||
3318 | */ | ||
3319 | |||
3320 | if (printph) { | ||
3321 | info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", | ||
3322 | pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6], | ||
3323 | in[7], in[8], in[9], in[10], in[11]); | ||
3324 | } | ||
3325 | |||
3326 | /* Check for SOF/EOF packet */ | ||
3327 | if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) || | ||
3328 | (~in[8] & 0x08)) | ||
3329 | goto check_middle; | ||
3330 | |||
3331 | /* Frame end */ | ||
3332 | if (in[8] & 0x80) { | ||
3333 | ts = (struct timeval *)(frame->data | ||
3334 | + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); | ||
3335 | do_gettimeofday(ts); | ||
3336 | |||
3337 | /* Get the actual frame size from the EOF header */ | ||
3338 | frame->rawwidth = ((int)(in[9]) + 1) * 8; | ||
3339 | frame->rawheight = ((int)(in[10]) + 1) * 8; | ||
3340 | |||
3341 | PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d", | ||
3342 | ov->curframe, pnum, frame->rawwidth, frame->rawheight, | ||
3343 | frame->bytes_recvd); | ||
3344 | |||
3345 | /* Validate the header data */ | ||
3346 | RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); | ||
3347 | RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, | ||
3348 | ov->maxheight); | ||
3349 | |||
3350 | /* Don't allow byte count to exceed buffer size */ | ||
3351 | RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw); | ||
3352 | |||
3353 | if (frame->scanstate == STATE_LINES) { | ||
3354 | int nextf; | ||
3355 | |||
3356 | frame->grabstate = FRAME_DONE; | ||
3357 | wake_up_interruptible(&frame->wq); | ||
3358 | |||
3359 | /* If next frame is ready or grabbing, | ||
3360 | * point to it */ | ||
3361 | nextf = (ov->curframe + 1) % OV511_NUMFRAMES; | ||
3362 | if (ov->frame[nextf].grabstate == FRAME_READY | ||
3363 | || ov->frame[nextf].grabstate == FRAME_GRABBING) { | ||
3364 | ov->curframe = nextf; | ||
3365 | ov->frame[nextf].scanstate = STATE_SCANNING; | ||
3366 | } else { | ||
3367 | if (frame->grabstate == FRAME_DONE) { | ||
3368 | PDEBUG(4, "** Frame done **"); | ||
3369 | } else { | ||
3370 | PDEBUG(4, "Frame not ready? state = %d", | ||
3371 | ov->frame[nextf].grabstate); | ||
3372 | } | ||
3373 | |||
3374 | ov->curframe = -1; | ||
3375 | } | ||
3376 | } else { | ||
3377 | PDEBUG(5, "Frame done, but not scanning"); | ||
3378 | } | ||
3379 | /* Image corruption caused by misplaced frame->segment = 0 | ||
3380 | * fixed by carlosf@conectiva.com.br | ||
3381 | */ | ||
3382 | } else { | ||
3383 | /* Frame start */ | ||
3384 | PDEBUG(4, "Frame start, framenum = %d", ov->curframe); | ||
3385 | |||
3386 | /* Check to see if it's a snapshot frame */ | ||
3387 | /* FIXME?? Should the snapshot reset go here? Performance? */ | ||
3388 | if (in[8] & 0x02) { | ||
3389 | frame->snapshot = 1; | ||
3390 | PDEBUG(3, "snapshot detected"); | ||
3391 | } | ||
3392 | |||
3393 | frame->scanstate = STATE_LINES; | ||
3394 | frame->bytes_recvd = 0; | ||
3395 | frame->compressed = in[8] & 0x40; | ||
3396 | } | ||
3397 | |||
3398 | check_middle: | ||
3399 | /* Are we in a frame? */ | ||
3400 | if (frame->scanstate != STATE_LINES) { | ||
3401 | PDEBUG(5, "Not in a frame; packet skipped"); | ||
3402 | return; | ||
3403 | } | ||
3404 | |||
3405 | /* If frame start, skip header */ | ||
3406 | if (frame->bytes_recvd == 0) | ||
3407 | offset = 9; | ||
3408 | else | ||
3409 | offset = 0; | ||
3410 | |||
3411 | num = n - offset - 1; | ||
3412 | |||
3413 | /* Dump all data exactly as received */ | ||
3414 | if (dumppix == 2) { | ||
3415 | frame->bytes_recvd += n - 1; | ||
3416 | if (frame->bytes_recvd <= max_raw) | ||
3417 | memcpy(frame->rawdata + frame->bytes_recvd - (n - 1), | ||
3418 | in, n - 1); | ||
3419 | else | ||
3420 | PDEBUG(3, "Raw data buffer overrun!! (%d)", | ||
3421 | frame->bytes_recvd - max_raw); | ||
3422 | } else if (!frame->compressed && !remove_zeros) { | ||
3423 | frame->bytes_recvd += num; | ||
3424 | if (frame->bytes_recvd <= max_raw) | ||
3425 | memcpy(frame->rawdata + frame->bytes_recvd - num, | ||
3426 | in + offset, num); | ||
3427 | else | ||
3428 | PDEBUG(3, "Raw data buffer overrun!! (%d)", | ||
3429 | frame->bytes_recvd - max_raw); | ||
3430 | } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */ | ||
3431 | int b, read = 0, allzero, copied = 0; | ||
3432 | if (offset) { | ||
3433 | frame->bytes_recvd += 32 - offset; // Bytes out | ||
3434 | memcpy(frame->rawdata, in + offset, 32 - offset); | ||
3435 | read += 32; | ||
3436 | } | ||
3437 | |||
3438 | while (read < n - 1) { | ||
3439 | allzero = 1; | ||
3440 | for (b = 0; b < 32; b++) { | ||
3441 | if (in[read + b]) { | ||
3442 | allzero = 0; | ||
3443 | break; | ||
3444 | } | ||
3445 | } | ||
3446 | |||
3447 | if (allzero) { | ||
3448 | /* Don't copy it */ | ||
3449 | } else { | ||
3450 | if (frame->bytes_recvd + copied + 32 <= max_raw) | ||
3451 | { | ||
3452 | memcpy(frame->rawdata | ||
3453 | + frame->bytes_recvd + copied, | ||
3454 | in + read, 32); | ||
3455 | copied += 32; | ||
3456 | } else { | ||
3457 | PDEBUG(3, "Raw data buffer overrun!!"); | ||
3458 | } | ||
3459 | } | ||
3460 | read += 32; | ||
3461 | } | ||
3462 | |||
3463 | frame->bytes_recvd += copied; | ||
3464 | } | ||
3465 | } | ||
3466 | |||
3467 | static inline void | ||
3468 | ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n) | ||
3469 | { | ||
3470 | int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight); | ||
3471 | struct ov511_frame *frame = &ov->frame[ov->curframe]; | ||
3472 | struct timeval *ts; | ||
3473 | |||
3474 | /* Don't copy the packet number byte */ | ||
3475 | if (ov->packet_numbering) | ||
3476 | --n; | ||
3477 | |||
3478 | /* A false positive here is likely, until OVT gives me | ||
3479 | * the definitive SOF/EOF format */ | ||
3480 | if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) { | ||
3481 | if (printph) { | ||
3482 | info("ph: %2x %2x %2x %2x %2x %2x %2x %2x", in[0], | ||
3483 | in[1], in[2], in[3], in[4], in[5], in[6], in[7]); | ||
3484 | } | ||
3485 | |||
3486 | if (frame->scanstate == STATE_LINES) { | ||
3487 | PDEBUG(4, "Detected frame end/start"); | ||
3488 | goto eof; | ||
3489 | } else { //scanstate == STATE_SCANNING | ||
3490 | /* Frame start */ | ||
3491 | PDEBUG(4, "Frame start, framenum = %d", ov->curframe); | ||
3492 | goto sof; | ||
3493 | } | ||
3494 | } else { | ||
3495 | goto check_middle; | ||
3496 | } | ||
3497 | |||
3498 | eof: | ||
3499 | ts = (struct timeval *)(frame->data | ||
3500 | + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); | ||
3501 | do_gettimeofday(ts); | ||
3502 | |||
3503 | PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d", | ||
3504 | ov->curframe, | ||
3505 | (int)(in[9]), (int)(in[10]), frame->bytes_recvd); | ||
3506 | |||
3507 | // FIXME: Since we don't know the header formats yet, | ||
3508 | // there is no way to know what the actual image size is | ||
3509 | frame->rawwidth = frame->width; | ||
3510 | frame->rawheight = frame->height; | ||
3511 | |||
3512 | /* Validate the header data */ | ||
3513 | RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); | ||
3514 | RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight); | ||
3515 | |||
3516 | /* Don't allow byte count to exceed buffer size */ | ||
3517 | RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw); | ||
3518 | |||
3519 | if (frame->scanstate == STATE_LINES) { | ||
3520 | int nextf; | ||
3521 | |||
3522 | frame->grabstate = FRAME_DONE; | ||
3523 | wake_up_interruptible(&frame->wq); | ||
3524 | |||
3525 | /* If next frame is ready or grabbing, | ||
3526 | * point to it */ | ||
3527 | nextf = (ov->curframe + 1) % OV511_NUMFRAMES; | ||
3528 | if (ov->frame[nextf].grabstate == FRAME_READY | ||
3529 | || ov->frame[nextf].grabstate == FRAME_GRABBING) { | ||
3530 | ov->curframe = nextf; | ||
3531 | ov->frame[nextf].scanstate = STATE_SCANNING; | ||
3532 | frame = &ov->frame[nextf]; | ||
3533 | } else { | ||
3534 | if (frame->grabstate == FRAME_DONE) { | ||
3535 | PDEBUG(4, "** Frame done **"); | ||
3536 | } else { | ||
3537 | PDEBUG(4, "Frame not ready? state = %d", | ||
3538 | ov->frame[nextf].grabstate); | ||
3539 | } | ||
3540 | |||
3541 | ov->curframe = -1; | ||
3542 | PDEBUG(4, "SOF dropped (no active frame)"); | ||
3543 | return; /* Nowhere to store this frame */ | ||
3544 | } | ||
3545 | } | ||
3546 | sof: | ||
3547 | PDEBUG(4, "Starting capture on frame %d", frame->framenum); | ||
3548 | |||
3549 | // Snapshot not reverse-engineered yet. | ||
3550 | #if 0 | ||
3551 | /* Check to see if it's a snapshot frame */ | ||
3552 | /* FIXME?? Should the snapshot reset go here? Performance? */ | ||
3553 | if (in[8] & 0x02) { | ||
3554 | frame->snapshot = 1; | ||
3555 | PDEBUG(3, "snapshot detected"); | ||
3556 | } | ||
3557 | #endif | ||
3558 | frame->scanstate = STATE_LINES; | ||
3559 | frame->bytes_recvd = 0; | ||
3560 | frame->compressed = 1; | ||
3561 | |||
3562 | check_middle: | ||
3563 | /* Are we in a frame? */ | ||
3564 | if (frame->scanstate != STATE_LINES) { | ||
3565 | PDEBUG(4, "scanstate: no SOF yet"); | ||
3566 | return; | ||
3567 | } | ||
3568 | |||
3569 | /* Dump all data exactly as received */ | ||
3570 | if (dumppix == 2) { | ||
3571 | frame->bytes_recvd += n; | ||
3572 | if (frame->bytes_recvd <= max_raw) | ||
3573 | memcpy(frame->rawdata + frame->bytes_recvd - n, in, n); | ||
3574 | else | ||
3575 | PDEBUG(3, "Raw data buffer overrun!! (%d)", | ||
3576 | frame->bytes_recvd - max_raw); | ||
3577 | } else { | ||
3578 | /* All incoming data are divided into 8-byte segments. If the | ||
3579 | * segment contains all zero bytes, it must be skipped. These | ||
3580 | * zero-segments allow the OV518 to mainain a constant data rate | ||
3581 | * regardless of the effectiveness of the compression. Segments | ||
3582 | * are aligned relative to the beginning of each isochronous | ||
3583 | * packet. The first segment in each image is a header (the | ||
3584 | * decompressor skips it later). | ||
3585 | */ | ||
3586 | |||
3587 | int b, read = 0, allzero, copied = 0; | ||
3588 | |||
3589 | while (read < n) { | ||
3590 | allzero = 1; | ||
3591 | for (b = 0; b < 8; b++) { | ||
3592 | if (in[read + b]) { | ||
3593 | allzero = 0; | ||
3594 | break; | ||
3595 | } | ||
3596 | } | ||
3597 | |||
3598 | if (allzero) { | ||
3599 | /* Don't copy it */ | ||
3600 | } else { | ||
3601 | if (frame->bytes_recvd + copied + 8 <= max_raw) | ||
3602 | { | ||
3603 | memcpy(frame->rawdata | ||
3604 | + frame->bytes_recvd + copied, | ||
3605 | in + read, 8); | ||
3606 | copied += 8; | ||
3607 | } else { | ||
3608 | PDEBUG(3, "Raw data buffer overrun!!"); | ||
3609 | } | ||
3610 | } | ||
3611 | read += 8; | ||
3612 | } | ||
3613 | frame->bytes_recvd += copied; | ||
3614 | } | ||
3615 | } | ||
3616 | |||
3617 | static void | ||
3618 | ov51x_isoc_irq(struct urb *urb, struct pt_regs *regs) | ||
3619 | { | ||
3620 | int i; | ||
3621 | struct usb_ov511 *ov; | ||
3622 | struct ov511_sbuf *sbuf; | ||
3623 | |||
3624 | if (!urb->context) { | ||
3625 | PDEBUG(4, "no context"); | ||
3626 | return; | ||
3627 | } | ||
3628 | |||
3629 | sbuf = urb->context; | ||
3630 | ov = sbuf->ov; | ||
3631 | |||
3632 | if (!ov || !ov->dev || !ov->user) { | ||
3633 | PDEBUG(4, "no device, or not open"); | ||
3634 | return; | ||
3635 | } | ||
3636 | |||
3637 | if (!ov->streaming) { | ||
3638 | PDEBUG(4, "hmmm... not streaming, but got interrupt"); | ||
3639 | return; | ||
3640 | } | ||
3641 | |||
3642 | if (urb->status == -ENOENT || urb->status == -ECONNRESET) { | ||
3643 | PDEBUG(4, "URB unlinked"); | ||
3644 | return; | ||
3645 | } | ||
3646 | |||
3647 | if (urb->status != -EINPROGRESS && urb->status != 0) { | ||
3648 | err("ERROR: urb->status=%d: %s", urb->status, | ||
3649 | symbolic(urb_errlist, urb->status)); | ||
3650 | } | ||
3651 | |||
3652 | /* Copy the data received into our frame buffer */ | ||
3653 | PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n, | ||
3654 | urb->number_of_packets); | ||
3655 | for (i = 0; i < urb->number_of_packets; i++) { | ||
3656 | /* Warning: Don't call *_move_data() if no frame active! */ | ||
3657 | if (ov->curframe >= 0) { | ||
3658 | int n = urb->iso_frame_desc[i].actual_length; | ||
3659 | int st = urb->iso_frame_desc[i].status; | ||
3660 | unsigned char *cdata; | ||
3661 | |||
3662 | urb->iso_frame_desc[i].actual_length = 0; | ||
3663 | urb->iso_frame_desc[i].status = 0; | ||
3664 | |||
3665 | cdata = urb->transfer_buffer | ||
3666 | + urb->iso_frame_desc[i].offset; | ||
3667 | |||
3668 | if (!n) { | ||
3669 | PDEBUG(4, "Zero-length packet"); | ||
3670 | continue; | ||
3671 | } | ||
3672 | |||
3673 | if (st) | ||
3674 | PDEBUG(2, "data error: [%d] len=%d, status=%d", | ||
3675 | i, n, st); | ||
3676 | |||
3677 | if (ov->bclass == BCL_OV511) | ||
3678 | ov511_move_data(ov, cdata, n); | ||
3679 | else if (ov->bclass == BCL_OV518) | ||
3680 | ov518_move_data(ov, cdata, n); | ||
3681 | else | ||
3682 | err("Unknown bridge device (%d)", ov->bridge); | ||
3683 | |||
3684 | } else if (waitqueue_active(&ov->wq)) { | ||
3685 | wake_up_interruptible(&ov->wq); | ||
3686 | } | ||
3687 | } | ||
3688 | |||
3689 | /* Resubmit this URB */ | ||
3690 | urb->dev = ov->dev; | ||
3691 | if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0) | ||
3692 | err("usb_submit_urb() ret %d", i); | ||
3693 | |||
3694 | return; | ||
3695 | } | ||
3696 | |||
3697 | /**************************************************************************** | ||
3698 | * | ||
3699 | * Stream initialization and termination | ||
3700 | * | ||
3701 | ***************************************************************************/ | ||
3702 | |||
3703 | static int | ||
3704 | ov51x_init_isoc(struct usb_ov511 *ov) | ||
3705 | { | ||
3706 | struct urb *urb; | ||
3707 | int fx, err, n, size; | ||
3708 | |||
3709 | PDEBUG(3, "*** Initializing capture ***"); | ||
3710 | |||
3711 | ov->curframe = -1; | ||
3712 | |||
3713 | if (ov->bridge == BRG_OV511) { | ||
3714 | if (cams == 1) | ||
3715 | size = 993; | ||
3716 | else if (cams == 2) | ||
3717 | size = 513; | ||
3718 | else if (cams == 3 || cams == 4) | ||
3719 | size = 257; | ||
3720 | else { | ||
3721 | err("\"cams\" parameter too high!"); | ||
3722 | return -1; | ||
3723 | } | ||
3724 | } else if (ov->bridge == BRG_OV511PLUS) { | ||
3725 | if (cams == 1) | ||
3726 | size = 961; | ||
3727 | else if (cams == 2) | ||
3728 | size = 513; | ||
3729 | else if (cams == 3 || cams == 4) | ||
3730 | size = 257; | ||
3731 | else if (cams >= 5 && cams <= 8) | ||
3732 | size = 129; | ||
3733 | else if (cams >= 9 && cams <= 31) | ||
3734 | size = 33; | ||
3735 | else { | ||
3736 | err("\"cams\" parameter too high!"); | ||
3737 | return -1; | ||
3738 | } | ||
3739 | } else if (ov->bclass == BCL_OV518) { | ||
3740 | if (cams == 1) | ||
3741 | size = 896; | ||
3742 | else if (cams == 2) | ||
3743 | size = 512; | ||
3744 | else if (cams == 3 || cams == 4) | ||
3745 | size = 256; | ||
3746 | else if (cams >= 5 && cams <= 8) | ||
3747 | size = 128; | ||
3748 | else { | ||
3749 | err("\"cams\" parameter too high!"); | ||
3750 | return -1; | ||
3751 | } | ||
3752 | } else { | ||
3753 | err("invalid bridge type"); | ||
3754 | return -1; | ||
3755 | } | ||
3756 | |||
3757 | // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now | ||
3758 | if (ov->bclass == BCL_OV518) { | ||
3759 | if (packetsize == -1) { | ||
3760 | ov518_set_packet_size(ov, 640); | ||
3761 | } else { | ||
3762 | info("Forcing packet size to %d", packetsize); | ||
3763 | ov518_set_packet_size(ov, packetsize); | ||
3764 | } | ||
3765 | } else { | ||
3766 | if (packetsize == -1) { | ||
3767 | ov511_set_packet_size(ov, size); | ||
3768 | } else { | ||
3769 | info("Forcing packet size to %d", packetsize); | ||
3770 | ov511_set_packet_size(ov, packetsize); | ||
3771 | } | ||
3772 | } | ||
3773 | |||
3774 | for (n = 0; n < OV511_NUMSBUF; n++) { | ||
3775 | urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); | ||
3776 | if (!urb) { | ||
3777 | err("init isoc: usb_alloc_urb ret. NULL"); | ||
3778 | return -ENOMEM; | ||
3779 | } | ||
3780 | ov->sbuf[n].urb = urb; | ||
3781 | urb->dev = ov->dev; | ||
3782 | urb->context = &ov->sbuf[n]; | ||
3783 | urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS); | ||
3784 | urb->transfer_flags = URB_ISO_ASAP; | ||
3785 | urb->transfer_buffer = ov->sbuf[n].data; | ||
3786 | urb->complete = ov51x_isoc_irq; | ||
3787 | urb->number_of_packets = FRAMES_PER_DESC; | ||
3788 | urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC; | ||
3789 | urb->interval = 1; | ||
3790 | for (fx = 0; fx < FRAMES_PER_DESC; fx++) { | ||
3791 | urb->iso_frame_desc[fx].offset = ov->packet_size * fx; | ||
3792 | urb->iso_frame_desc[fx].length = ov->packet_size; | ||
3793 | } | ||
3794 | } | ||
3795 | |||
3796 | ov->streaming = 1; | ||
3797 | |||
3798 | for (n = 0; n < OV511_NUMSBUF; n++) { | ||
3799 | ov->sbuf[n].urb->dev = ov->dev; | ||
3800 | err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL); | ||
3801 | if (err) { | ||
3802 | err("init isoc: usb_submit_urb(%d) ret %d", n, err); | ||
3803 | return err; | ||
3804 | } | ||
3805 | } | ||
3806 | |||
3807 | return 0; | ||
3808 | } | ||
3809 | |||
3810 | static void | ||
3811 | ov51x_unlink_isoc(struct usb_ov511 *ov) | ||
3812 | { | ||
3813 | int n; | ||
3814 | |||
3815 | /* Unschedule all of the iso td's */ | ||
3816 | for (n = OV511_NUMSBUF - 1; n >= 0; n--) { | ||
3817 | if (ov->sbuf[n].urb) { | ||
3818 | usb_kill_urb(ov->sbuf[n].urb); | ||
3819 | usb_free_urb(ov->sbuf[n].urb); | ||
3820 | ov->sbuf[n].urb = NULL; | ||
3821 | } | ||
3822 | } | ||
3823 | } | ||
3824 | |||
3825 | static void | ||
3826 | ov51x_stop_isoc(struct usb_ov511 *ov) | ||
3827 | { | ||
3828 | if (!ov->streaming || !ov->dev) | ||
3829 | return; | ||
3830 | |||
3831 | PDEBUG(3, "*** Stopping capture ***"); | ||
3832 | |||
3833 | if (ov->bclass == BCL_OV518) | ||
3834 | ov518_set_packet_size(ov, 0); | ||
3835 | else | ||
3836 | ov511_set_packet_size(ov, 0); | ||
3837 | |||
3838 | ov->streaming = 0; | ||
3839 | |||
3840 | ov51x_unlink_isoc(ov); | ||
3841 | } | ||
3842 | |||
3843 | static int | ||
3844 | ov51x_new_frame(struct usb_ov511 *ov, int framenum) | ||
3845 | { | ||
3846 | struct ov511_frame *frame; | ||
3847 | int newnum; | ||
3848 | |||
3849 | PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum); | ||
3850 | |||
3851 | if (!ov->dev) | ||
3852 | return -1; | ||
3853 | |||
3854 | /* If we're not grabbing a frame right now and the other frame is */ | ||
3855 | /* ready to be grabbed into, then use it instead */ | ||
3856 | if (ov->curframe == -1) { | ||
3857 | newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES; | ||
3858 | if (ov->frame[newnum].grabstate == FRAME_READY) | ||
3859 | framenum = newnum; | ||
3860 | } else | ||
3861 | return 0; | ||
3862 | |||
3863 | frame = &ov->frame[framenum]; | ||
3864 | |||
3865 | PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum, | ||
3866 | frame->width, frame->height); | ||
3867 | |||
3868 | frame->grabstate = FRAME_GRABBING; | ||
3869 | frame->scanstate = STATE_SCANNING; | ||
3870 | frame->snapshot = 0; | ||
3871 | |||
3872 | ov->curframe = framenum; | ||
3873 | |||
3874 | /* Make sure it's not too big */ | ||
3875 | if (frame->width > ov->maxwidth) | ||
3876 | frame->width = ov->maxwidth; | ||
3877 | |||
3878 | frame->width &= ~7L; /* Multiple of 8 */ | ||
3879 | |||
3880 | if (frame->height > ov->maxheight) | ||
3881 | frame->height = ov->maxheight; | ||
3882 | |||
3883 | frame->height &= ~3L; /* Multiple of 4 */ | ||
3884 | |||
3885 | return 0; | ||
3886 | } | ||
3887 | |||
3888 | /**************************************************************************** | ||
3889 | * | ||
3890 | * Buffer management | ||
3891 | * | ||
3892 | ***************************************************************************/ | ||
3893 | |||
3894 | /* | ||
3895 | * - You must acquire buf_lock before entering this function. | ||
3896 | * - Because this code will free any non-null pointer, you must be sure to null | ||
3897 | * them if you explicitly free them somewhere else! | ||
3898 | */ | ||
3899 | static void | ||
3900 | ov51x_do_dealloc(struct usb_ov511 *ov) | ||
3901 | { | ||
3902 | int i; | ||
3903 | PDEBUG(4, "entered"); | ||
3904 | |||
3905 | if (ov->fbuf) { | ||
3906 | rvfree(ov->fbuf, OV511_NUMFRAMES | ||
3907 | * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); | ||
3908 | ov->fbuf = NULL; | ||
3909 | } | ||
3910 | |||
3911 | vfree(ov->rawfbuf); | ||
3912 | ov->rawfbuf = NULL; | ||
3913 | |||
3914 | vfree(ov->tempfbuf); | ||
3915 | ov->tempfbuf = NULL; | ||
3916 | |||
3917 | for (i = 0; i < OV511_NUMSBUF; i++) { | ||
3918 | if (ov->sbuf[i].data) { | ||
3919 | kfree(ov->sbuf[i].data); | ||
3920 | ov->sbuf[i].data = NULL; | ||
3921 | } | ||
3922 | } | ||
3923 | |||
3924 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
3925 | ov->frame[i].data = NULL; | ||
3926 | ov->frame[i].rawdata = NULL; | ||
3927 | ov->frame[i].tempdata = NULL; | ||
3928 | if (ov->frame[i].compbuf) { | ||
3929 | free_page((unsigned long) ov->frame[i].compbuf); | ||
3930 | ov->frame[i].compbuf = NULL; | ||
3931 | } | ||
3932 | } | ||
3933 | |||
3934 | PDEBUG(4, "buffer memory deallocated"); | ||
3935 | ov->buf_state = BUF_NOT_ALLOCATED; | ||
3936 | PDEBUG(4, "leaving"); | ||
3937 | } | ||
3938 | |||
3939 | static int | ||
3940 | ov51x_alloc(struct usb_ov511 *ov) | ||
3941 | { | ||
3942 | int i; | ||
3943 | const int w = ov->maxwidth; | ||
3944 | const int h = ov->maxheight; | ||
3945 | const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h); | ||
3946 | const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h); | ||
3947 | |||
3948 | PDEBUG(4, "entered"); | ||
3949 | down(&ov->buf_lock); | ||
3950 | |||
3951 | if (ov->buf_state == BUF_ALLOCATED) | ||
3952 | goto out; | ||
3953 | |||
3954 | ov->fbuf = rvmalloc(data_bufsize); | ||
3955 | if (!ov->fbuf) | ||
3956 | goto error; | ||
3957 | |||
3958 | ov->rawfbuf = vmalloc(raw_bufsize); | ||
3959 | if (!ov->rawfbuf) | ||
3960 | goto error; | ||
3961 | |||
3962 | memset(ov->rawfbuf, 0, raw_bufsize); | ||
3963 | |||
3964 | ov->tempfbuf = vmalloc(raw_bufsize); | ||
3965 | if (!ov->tempfbuf) | ||
3966 | goto error; | ||
3967 | |||
3968 | memset(ov->tempfbuf, 0, raw_bufsize); | ||
3969 | |||
3970 | for (i = 0; i < OV511_NUMSBUF; i++) { | ||
3971 | ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC * | ||
3972 | MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL); | ||
3973 | if (!ov->sbuf[i].data) | ||
3974 | goto error; | ||
3975 | |||
3976 | PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data); | ||
3977 | } | ||
3978 | |||
3979 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
3980 | ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h); | ||
3981 | ov->frame[i].rawdata = ov->rawfbuf | ||
3982 | + i * MAX_RAW_DATA_SIZE(w, h); | ||
3983 | ov->frame[i].tempdata = ov->tempfbuf | ||
3984 | + i * MAX_RAW_DATA_SIZE(w, h); | ||
3985 | |||
3986 | ov->frame[i].compbuf = | ||
3987 | (unsigned char *) __get_free_page(GFP_KERNEL); | ||
3988 | if (!ov->frame[i].compbuf) | ||
3989 | goto error; | ||
3990 | |||
3991 | PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data); | ||
3992 | } | ||
3993 | |||
3994 | ov->buf_state = BUF_ALLOCATED; | ||
3995 | out: | ||
3996 | up(&ov->buf_lock); | ||
3997 | PDEBUG(4, "leaving"); | ||
3998 | return 0; | ||
3999 | error: | ||
4000 | ov51x_do_dealloc(ov); | ||
4001 | up(&ov->buf_lock); | ||
4002 | PDEBUG(4, "errored"); | ||
4003 | return -ENOMEM; | ||
4004 | } | ||
4005 | |||
4006 | static void | ||
4007 | ov51x_dealloc(struct usb_ov511 *ov) | ||
4008 | { | ||
4009 | PDEBUG(4, "entered"); | ||
4010 | down(&ov->buf_lock); | ||
4011 | ov51x_do_dealloc(ov); | ||
4012 | up(&ov->buf_lock); | ||
4013 | PDEBUG(4, "leaving"); | ||
4014 | } | ||
4015 | |||
4016 | /**************************************************************************** | ||
4017 | * | ||
4018 | * V4L 1 API | ||
4019 | * | ||
4020 | ***************************************************************************/ | ||
4021 | |||
4022 | static int | ||
4023 | ov51x_v4l1_open(struct inode *inode, struct file *file) | ||
4024 | { | ||
4025 | struct video_device *vdev = video_devdata(file); | ||
4026 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
4027 | int err, i; | ||
4028 | |||
4029 | PDEBUG(4, "opening"); | ||
4030 | |||
4031 | down(&ov->lock); | ||
4032 | |||
4033 | err = -EBUSY; | ||
4034 | if (ov->user) | ||
4035 | goto out; | ||
4036 | |||
4037 | ov->sub_flag = 0; | ||
4038 | |||
4039 | /* In case app doesn't set them... */ | ||
4040 | err = ov51x_set_default_params(ov); | ||
4041 | if (err < 0) | ||
4042 | goto out; | ||
4043 | |||
4044 | /* Make sure frames are reset */ | ||
4045 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
4046 | ov->frame[i].grabstate = FRAME_UNUSED; | ||
4047 | ov->frame[i].bytes_read = 0; | ||
4048 | } | ||
4049 | |||
4050 | /* If compression is on, make sure now that a | ||
4051 | * decompressor can be loaded */ | ||
4052 | if (ov->compress && !ov->decomp_ops) { | ||
4053 | err = request_decompressor(ov); | ||
4054 | if (err && !dumppix) | ||
4055 | goto out; | ||
4056 | } | ||
4057 | |||
4058 | err = ov51x_alloc(ov); | ||
4059 | if (err < 0) | ||
4060 | goto out; | ||
4061 | |||
4062 | err = ov51x_init_isoc(ov); | ||
4063 | if (err) { | ||
4064 | ov51x_dealloc(ov); | ||
4065 | goto out; | ||
4066 | } | ||
4067 | |||
4068 | ov->user++; | ||
4069 | file->private_data = vdev; | ||
4070 | |||
4071 | if (ov->led_policy == LED_AUTO) | ||
4072 | ov51x_led_control(ov, 1); | ||
4073 | |||
4074 | out: | ||
4075 | up(&ov->lock); | ||
4076 | return err; | ||
4077 | } | ||
4078 | |||
4079 | static int | ||
4080 | ov51x_v4l1_close(struct inode *inode, struct file *file) | ||
4081 | { | ||
4082 | struct video_device *vdev = file->private_data; | ||
4083 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
4084 | |||
4085 | PDEBUG(4, "ov511_close"); | ||
4086 | |||
4087 | down(&ov->lock); | ||
4088 | |||
4089 | ov->user--; | ||
4090 | ov51x_stop_isoc(ov); | ||
4091 | |||
4092 | release_decompressor(ov); | ||
4093 | |||
4094 | if (ov->led_policy == LED_AUTO) | ||
4095 | ov51x_led_control(ov, 0); | ||
4096 | |||
4097 | if (ov->dev) | ||
4098 | ov51x_dealloc(ov); | ||
4099 | |||
4100 | up(&ov->lock); | ||
4101 | |||
4102 | /* Device unplugged while open. Only a minimum of unregistration is done | ||
4103 | * here; the disconnect callback already did the rest. */ | ||
4104 | if (!ov->dev) { | ||
4105 | down(&ov->cbuf_lock); | ||
4106 | kfree(ov->cbuf); | ||
4107 | ov->cbuf = NULL; | ||
4108 | up(&ov->cbuf_lock); | ||
4109 | |||
4110 | ov51x_dealloc(ov); | ||
4111 | kfree(ov); | ||
4112 | ov = NULL; | ||
4113 | } | ||
4114 | |||
4115 | file->private_data = NULL; | ||
4116 | return 0; | ||
4117 | } | ||
4118 | |||
4119 | /* Do not call this function directly! */ | ||
4120 | static int | ||
4121 | ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, | ||
4122 | unsigned int cmd, void *arg) | ||
4123 | { | ||
4124 | struct video_device *vdev = file->private_data; | ||
4125 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
4126 | PDEBUG(5, "IOCtl: 0x%X", cmd); | ||
4127 | |||
4128 | if (!ov->dev) | ||
4129 | return -EIO; | ||
4130 | |||
4131 | switch (cmd) { | ||
4132 | case VIDIOCGCAP: | ||
4133 | { | ||
4134 | struct video_capability *b = arg; | ||
4135 | |||
4136 | PDEBUG(4, "VIDIOCGCAP"); | ||
4137 | |||
4138 | memset(b, 0, sizeof(struct video_capability)); | ||
4139 | sprintf(b->name, "%s USB Camera", | ||
4140 | symbolic(brglist, ov->bridge)); | ||
4141 | b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; | ||
4142 | b->channels = ov->num_inputs; | ||
4143 | b->audios = 0; | ||
4144 | b->maxwidth = ov->maxwidth; | ||
4145 | b->maxheight = ov->maxheight; | ||
4146 | b->minwidth = ov->minwidth; | ||
4147 | b->minheight = ov->minheight; | ||
4148 | |||
4149 | return 0; | ||
4150 | } | ||
4151 | case VIDIOCGCHAN: | ||
4152 | { | ||
4153 | struct video_channel *v = arg; | ||
4154 | |||
4155 | PDEBUG(4, "VIDIOCGCHAN"); | ||
4156 | |||
4157 | if ((unsigned)(v->channel) >= ov->num_inputs) { | ||
4158 | err("Invalid channel (%d)", v->channel); | ||
4159 | return -EINVAL; | ||
4160 | } | ||
4161 | |||
4162 | v->norm = ov->norm; | ||
4163 | v->type = VIDEO_TYPE_CAMERA; | ||
4164 | v->flags = 0; | ||
4165 | // v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0; | ||
4166 | v->tuners = 0; | ||
4167 | decoder_get_input_name(ov, v->channel, v->name); | ||
4168 | |||
4169 | return 0; | ||
4170 | } | ||
4171 | case VIDIOCSCHAN: | ||
4172 | { | ||
4173 | struct video_channel *v = arg; | ||
4174 | int err; | ||
4175 | |||
4176 | PDEBUG(4, "VIDIOCSCHAN"); | ||
4177 | |||
4178 | /* Make sure it's not a camera */ | ||
4179 | if (!ov->has_decoder) { | ||
4180 | if (v->channel == 0) | ||
4181 | return 0; | ||
4182 | else | ||
4183 | return -EINVAL; | ||
4184 | } | ||
4185 | |||
4186 | if (v->norm != VIDEO_MODE_PAL && | ||
4187 | v->norm != VIDEO_MODE_NTSC && | ||
4188 | v->norm != VIDEO_MODE_SECAM && | ||
4189 | v->norm != VIDEO_MODE_AUTO) { | ||
4190 | err("Invalid norm (%d)", v->norm); | ||
4191 | return -EINVAL; | ||
4192 | } | ||
4193 | |||
4194 | if ((unsigned)(v->channel) >= ov->num_inputs) { | ||
4195 | err("Invalid channel (%d)", v->channel); | ||
4196 | return -EINVAL; | ||
4197 | } | ||
4198 | |||
4199 | err = decoder_set_input(ov, v->channel); | ||
4200 | if (err) | ||
4201 | return err; | ||
4202 | |||
4203 | err = decoder_set_norm(ov, v->norm); | ||
4204 | if (err) | ||
4205 | return err; | ||
4206 | |||
4207 | return 0; | ||
4208 | } | ||
4209 | case VIDIOCGPICT: | ||
4210 | { | ||
4211 | struct video_picture *p = arg; | ||
4212 | |||
4213 | PDEBUG(4, "VIDIOCGPICT"); | ||
4214 | |||
4215 | memset(p, 0, sizeof(struct video_picture)); | ||
4216 | if (sensor_get_picture(ov, p)) | ||
4217 | return -EIO; | ||
4218 | |||
4219 | /* Can we get these from frame[0]? -claudio? */ | ||
4220 | p->depth = ov->frame[0].depth; | ||
4221 | p->palette = ov->frame[0].format; | ||
4222 | |||
4223 | return 0; | ||
4224 | } | ||
4225 | case VIDIOCSPICT: | ||
4226 | { | ||
4227 | struct video_picture *p = arg; | ||
4228 | int i, rc; | ||
4229 | |||
4230 | PDEBUG(4, "VIDIOCSPICT"); | ||
4231 | |||
4232 | if (!get_depth(p->palette)) | ||
4233 | return -EINVAL; | ||
4234 | |||
4235 | if (sensor_set_picture(ov, p)) | ||
4236 | return -EIO; | ||
4237 | |||
4238 | if (force_palette && p->palette != force_palette) { | ||
4239 | info("Palette rejected (%s)", | ||
4240 | symbolic(v4l1_plist, p->palette)); | ||
4241 | return -EINVAL; | ||
4242 | } | ||
4243 | |||
4244 | // FIXME: Format should be independent of frames | ||
4245 | if (p->palette != ov->frame[0].format) { | ||
4246 | PDEBUG(4, "Detected format change"); | ||
4247 | |||
4248 | rc = ov51x_wait_frames_inactive(ov); | ||
4249 | if (rc) | ||
4250 | return rc; | ||
4251 | |||
4252 | mode_init_regs(ov, ov->frame[0].width, | ||
4253 | ov->frame[0].height, p->palette, ov->sub_flag); | ||
4254 | } | ||
4255 | |||
4256 | PDEBUG(4, "Setting depth=%d, palette=%s", | ||
4257 | p->depth, symbolic(v4l1_plist, p->palette)); | ||
4258 | |||
4259 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
4260 | ov->frame[i].depth = p->depth; | ||
4261 | ov->frame[i].format = p->palette; | ||
4262 | } | ||
4263 | |||
4264 | return 0; | ||
4265 | } | ||
4266 | case VIDIOCGCAPTURE: | ||
4267 | { | ||
4268 | int *vf = arg; | ||
4269 | |||
4270 | PDEBUG(4, "VIDIOCGCAPTURE"); | ||
4271 | |||
4272 | ov->sub_flag = *vf; | ||
4273 | return 0; | ||
4274 | } | ||
4275 | case VIDIOCSCAPTURE: | ||
4276 | { | ||
4277 | struct video_capture *vc = arg; | ||
4278 | |||
4279 | PDEBUG(4, "VIDIOCSCAPTURE"); | ||
4280 | |||
4281 | if (vc->flags) | ||
4282 | return -EINVAL; | ||
4283 | if (vc->decimation) | ||
4284 | return -EINVAL; | ||
4285 | |||
4286 | vc->x &= ~3L; | ||
4287 | vc->y &= ~1L; | ||
4288 | vc->y &= ~31L; | ||
4289 | |||
4290 | if (vc->width == 0) | ||
4291 | vc->width = 32; | ||
4292 | |||
4293 | vc->height /= 16; | ||
4294 | vc->height *= 16; | ||
4295 | if (vc->height == 0) | ||
4296 | vc->height = 16; | ||
4297 | |||
4298 | ov->subx = vc->x; | ||
4299 | ov->suby = vc->y; | ||
4300 | ov->subw = vc->width; | ||
4301 | ov->subh = vc->height; | ||
4302 | |||
4303 | return 0; | ||
4304 | } | ||
4305 | case VIDIOCSWIN: | ||
4306 | { | ||
4307 | struct video_window *vw = arg; | ||
4308 | int i, rc; | ||
4309 | |||
4310 | PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height); | ||
4311 | |||
4312 | #if 0 | ||
4313 | if (vw->flags) | ||
4314 | return -EINVAL; | ||
4315 | if (vw->clipcount) | ||
4316 | return -EINVAL; | ||
4317 | if (vw->height != ov->maxheight) | ||
4318 | return -EINVAL; | ||
4319 | if (vw->width != ov->maxwidth) | ||
4320 | return -EINVAL; | ||
4321 | #endif | ||
4322 | |||
4323 | rc = ov51x_wait_frames_inactive(ov); | ||
4324 | if (rc) | ||
4325 | return rc; | ||
4326 | |||
4327 | rc = mode_init_regs(ov, vw->width, vw->height, | ||
4328 | ov->frame[0].format, ov->sub_flag); | ||
4329 | if (rc < 0) | ||
4330 | return rc; | ||
4331 | |||
4332 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
4333 | ov->frame[i].width = vw->width; | ||
4334 | ov->frame[i].height = vw->height; | ||
4335 | } | ||
4336 | |||
4337 | return 0; | ||
4338 | } | ||
4339 | case VIDIOCGWIN: | ||
4340 | { | ||
4341 | struct video_window *vw = arg; | ||
4342 | |||
4343 | memset(vw, 0, sizeof(struct video_window)); | ||
4344 | vw->x = 0; /* FIXME */ | ||
4345 | vw->y = 0; | ||
4346 | vw->width = ov->frame[0].width; | ||
4347 | vw->height = ov->frame[0].height; | ||
4348 | vw->flags = 30; | ||
4349 | |||
4350 | PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height); | ||
4351 | |||
4352 | return 0; | ||
4353 | } | ||
4354 | case VIDIOCGMBUF: | ||
4355 | { | ||
4356 | struct video_mbuf *vm = arg; | ||
4357 | int i; | ||
4358 | |||
4359 | PDEBUG(4, "VIDIOCGMBUF"); | ||
4360 | |||
4361 | memset(vm, 0, sizeof(struct video_mbuf)); | ||
4362 | vm->size = OV511_NUMFRAMES | ||
4363 | * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); | ||
4364 | vm->frames = OV511_NUMFRAMES; | ||
4365 | |||
4366 | vm->offsets[0] = 0; | ||
4367 | for (i = 1; i < OV511_NUMFRAMES; i++) { | ||
4368 | vm->offsets[i] = vm->offsets[i-1] | ||
4369 | + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); | ||
4370 | } | ||
4371 | |||
4372 | return 0; | ||
4373 | } | ||
4374 | case VIDIOCMCAPTURE: | ||
4375 | { | ||
4376 | struct video_mmap *vm = arg; | ||
4377 | int rc, depth; | ||
4378 | unsigned int f = vm->frame; | ||
4379 | |||
4380 | PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width, | ||
4381 | vm->height, symbolic(v4l1_plist, vm->format)); | ||
4382 | |||
4383 | depth = get_depth(vm->format); | ||
4384 | if (!depth) { | ||
4385 | PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)", | ||
4386 | symbolic(v4l1_plist, vm->format)); | ||
4387 | return -EINVAL; | ||
4388 | } | ||
4389 | |||
4390 | if (f >= OV511_NUMFRAMES) { | ||
4391 | err("VIDIOCMCAPTURE: invalid frame (%d)", f); | ||
4392 | return -EINVAL; | ||
4393 | } | ||
4394 | |||
4395 | if (vm->width > ov->maxwidth | ||
4396 | || vm->height > ov->maxheight) { | ||
4397 | err("VIDIOCMCAPTURE: requested dimensions too big"); | ||
4398 | return -EINVAL; | ||
4399 | } | ||
4400 | |||
4401 | if (ov->frame[f].grabstate == FRAME_GRABBING) { | ||
4402 | PDEBUG(4, "VIDIOCMCAPTURE: already grabbing"); | ||
4403 | return -EBUSY; | ||
4404 | } | ||
4405 | |||
4406 | if (force_palette && (vm->format != force_palette)) { | ||
4407 | PDEBUG(2, "palette rejected (%s)", | ||
4408 | symbolic(v4l1_plist, vm->format)); | ||
4409 | return -EINVAL; | ||
4410 | } | ||
4411 | |||
4412 | if ((ov->frame[f].width != vm->width) || | ||
4413 | (ov->frame[f].height != vm->height) || | ||
4414 | (ov->frame[f].format != vm->format) || | ||
4415 | (ov->frame[f].sub_flag != ov->sub_flag) || | ||
4416 | (ov->frame[f].depth != depth)) { | ||
4417 | PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters"); | ||
4418 | |||
4419 | rc = ov51x_wait_frames_inactive(ov); | ||
4420 | if (rc) | ||
4421 | return rc; | ||
4422 | |||
4423 | rc = mode_init_regs(ov, vm->width, vm->height, | ||
4424 | vm->format, ov->sub_flag); | ||
4425 | #if 0 | ||
4426 | if (rc < 0) { | ||
4427 | PDEBUG(1, "Got error while initializing regs "); | ||
4428 | return ret; | ||
4429 | } | ||
4430 | #endif | ||
4431 | ov->frame[f].width = vm->width; | ||
4432 | ov->frame[f].height = vm->height; | ||
4433 | ov->frame[f].format = vm->format; | ||
4434 | ov->frame[f].sub_flag = ov->sub_flag; | ||
4435 | ov->frame[f].depth = depth; | ||
4436 | } | ||
4437 | |||
4438 | /* Mark it as ready */ | ||
4439 | ov->frame[f].grabstate = FRAME_READY; | ||
4440 | |||
4441 | PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f); | ||
4442 | |||
4443 | return ov51x_new_frame(ov, f); | ||
4444 | } | ||
4445 | case VIDIOCSYNC: | ||
4446 | { | ||
4447 | unsigned int fnum = *((unsigned int *) arg); | ||
4448 | struct ov511_frame *frame; | ||
4449 | int rc; | ||
4450 | |||
4451 | if (fnum >= OV511_NUMFRAMES) { | ||
4452 | err("VIDIOCSYNC: invalid frame (%d)", fnum); | ||
4453 | return -EINVAL; | ||
4454 | } | ||
4455 | |||
4456 | frame = &ov->frame[fnum]; | ||
4457 | |||
4458 | PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum, | ||
4459 | frame->grabstate); | ||
4460 | |||
4461 | switch (frame->grabstate) { | ||
4462 | case FRAME_UNUSED: | ||
4463 | return -EINVAL; | ||
4464 | case FRAME_READY: | ||
4465 | case FRAME_GRABBING: | ||
4466 | case FRAME_ERROR: | ||
4467 | redo: | ||
4468 | if (!ov->dev) | ||
4469 | return -EIO; | ||
4470 | |||
4471 | rc = wait_event_interruptible(frame->wq, | ||
4472 | (frame->grabstate == FRAME_DONE) | ||
4473 | || (frame->grabstate == FRAME_ERROR)); | ||
4474 | |||
4475 | if (rc) | ||
4476 | return rc; | ||
4477 | |||
4478 | if (frame->grabstate == FRAME_ERROR) { | ||
4479 | if ((rc = ov51x_new_frame(ov, fnum)) < 0) | ||
4480 | return rc; | ||
4481 | goto redo; | ||
4482 | } | ||
4483 | /* Fall through */ | ||
4484 | case FRAME_DONE: | ||
4485 | if (ov->snap_enabled && !frame->snapshot) { | ||
4486 | if ((rc = ov51x_new_frame(ov, fnum)) < 0) | ||
4487 | return rc; | ||
4488 | goto redo; | ||
4489 | } | ||
4490 | |||
4491 | frame->grabstate = FRAME_UNUSED; | ||
4492 | |||
4493 | /* Reset the hardware snapshot button */ | ||
4494 | /* FIXME - Is this the best place for this? */ | ||
4495 | if ((ov->snap_enabled) && (frame->snapshot)) { | ||
4496 | frame->snapshot = 0; | ||
4497 | ov51x_clear_snapshot(ov); | ||
4498 | } | ||
4499 | |||
4500 | /* Decompression, format conversion, etc... */ | ||
4501 | ov51x_postprocess(ov, frame); | ||
4502 | |||
4503 | break; | ||
4504 | } /* end switch */ | ||
4505 | |||
4506 | return 0; | ||
4507 | } | ||
4508 | case VIDIOCGFBUF: | ||
4509 | { | ||
4510 | struct video_buffer *vb = arg; | ||
4511 | |||
4512 | PDEBUG(4, "VIDIOCGFBUF"); | ||
4513 | |||
4514 | memset(vb, 0, sizeof(struct video_buffer)); | ||
4515 | |||
4516 | return 0; | ||
4517 | } | ||
4518 | case VIDIOCGUNIT: | ||
4519 | { | ||
4520 | struct video_unit *vu = arg; | ||
4521 | |||
4522 | PDEBUG(4, "VIDIOCGUNIT"); | ||
4523 | |||
4524 | memset(vu, 0, sizeof(struct video_unit)); | ||
4525 | |||
4526 | vu->video = ov->vdev->minor; | ||
4527 | vu->vbi = VIDEO_NO_UNIT; | ||
4528 | vu->radio = VIDEO_NO_UNIT; | ||
4529 | vu->audio = VIDEO_NO_UNIT; | ||
4530 | vu->teletext = VIDEO_NO_UNIT; | ||
4531 | |||
4532 | return 0; | ||
4533 | } | ||
4534 | case OV511IOC_WI2C: | ||
4535 | { | ||
4536 | struct ov511_i2c_struct *w = arg; | ||
4537 | |||
4538 | return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask); | ||
4539 | } | ||
4540 | case OV511IOC_RI2C: | ||
4541 | { | ||
4542 | struct ov511_i2c_struct *r = arg; | ||
4543 | int rc; | ||
4544 | |||
4545 | rc = i2c_r_slave(ov, r->slave, r->reg); | ||
4546 | if (rc < 0) | ||
4547 | return rc; | ||
4548 | |||
4549 | r->value = rc; | ||
4550 | return 0; | ||
4551 | } | ||
4552 | default: | ||
4553 | PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd); | ||
4554 | return -ENOIOCTLCMD; | ||
4555 | } /* end switch */ | ||
4556 | |||
4557 | return 0; | ||
4558 | } | ||
4559 | |||
4560 | static int | ||
4561 | ov51x_v4l1_ioctl(struct inode *inode, struct file *file, | ||
4562 | unsigned int cmd, unsigned long arg) | ||
4563 | { | ||
4564 | struct video_device *vdev = file->private_data; | ||
4565 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
4566 | int rc; | ||
4567 | |||
4568 | if (down_interruptible(&ov->lock)) | ||
4569 | return -EINTR; | ||
4570 | |||
4571 | rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal); | ||
4572 | |||
4573 | up(&ov->lock); | ||
4574 | return rc; | ||
4575 | } | ||
4576 | |||
4577 | static ssize_t | ||
4578 | ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos) | ||
4579 | { | ||
4580 | struct video_device *vdev = file->private_data; | ||
4581 | int noblock = file->f_flags&O_NONBLOCK; | ||
4582 | unsigned long count = cnt; | ||
4583 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
4584 | int i, rc = 0, frmx = -1; | ||
4585 | struct ov511_frame *frame; | ||
4586 | |||
4587 | if (down_interruptible(&ov->lock)) | ||
4588 | return -EINTR; | ||
4589 | |||
4590 | PDEBUG(4, "%ld bytes, noblock=%d", count, noblock); | ||
4591 | |||
4592 | if (!vdev || !buf) { | ||
4593 | rc = -EFAULT; | ||
4594 | goto error; | ||
4595 | } | ||
4596 | |||
4597 | if (!ov->dev) { | ||
4598 | rc = -EIO; | ||
4599 | goto error; | ||
4600 | } | ||
4601 | |||
4602 | // FIXME: Only supports two frames | ||
4603 | /* See if a frame is completed, then use it. */ | ||
4604 | if (ov->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ | ||
4605 | frmx = 0; | ||
4606 | else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ | ||
4607 | frmx = 1; | ||
4608 | |||
4609 | /* If nonblocking we return immediately */ | ||
4610 | if (noblock && (frmx == -1)) { | ||
4611 | rc = -EAGAIN; | ||
4612 | goto error; | ||
4613 | } | ||
4614 | |||
4615 | /* If no FRAME_DONE, look for a FRAME_GRABBING state. */ | ||
4616 | /* See if a frame is in process (grabbing), then use it. */ | ||
4617 | if (frmx == -1) { | ||
4618 | if (ov->frame[0].grabstate == FRAME_GRABBING) | ||
4619 | frmx = 0; | ||
4620 | else if (ov->frame[1].grabstate == FRAME_GRABBING) | ||
4621 | frmx = 1; | ||
4622 | } | ||
4623 | |||
4624 | /* If no frame is active, start one. */ | ||
4625 | if (frmx == -1) { | ||
4626 | if ((rc = ov51x_new_frame(ov, frmx = 0))) { | ||
4627 | err("read: ov51x_new_frame error"); | ||
4628 | goto error; | ||
4629 | } | ||
4630 | } | ||
4631 | |||
4632 | frame = &ov->frame[frmx]; | ||
4633 | |||
4634 | restart: | ||
4635 | if (!ov->dev) { | ||
4636 | rc = -EIO; | ||
4637 | goto error; | ||
4638 | } | ||
4639 | |||
4640 | /* Wait while we're grabbing the image */ | ||
4641 | PDEBUG(4, "Waiting image grabbing"); | ||
4642 | rc = wait_event_interruptible(frame->wq, | ||
4643 | (frame->grabstate == FRAME_DONE) | ||
4644 | || (frame->grabstate == FRAME_ERROR)); | ||
4645 | |||
4646 | if (rc) | ||
4647 | goto error; | ||
4648 | |||
4649 | PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate); | ||
4650 | PDEBUG(4, "bytes_recvd = %d", frame->bytes_recvd); | ||
4651 | |||
4652 | if (frame->grabstate == FRAME_ERROR) { | ||
4653 | frame->bytes_read = 0; | ||
4654 | err("** ick! ** Errored frame %d", ov->curframe); | ||
4655 | if (ov51x_new_frame(ov, frmx)) { | ||
4656 | err("read: ov51x_new_frame error"); | ||
4657 | goto error; | ||
4658 | } | ||
4659 | goto restart; | ||
4660 | } | ||
4661 | |||
4662 | |||
4663 | /* Repeat until we get a snapshot frame */ | ||
4664 | if (ov->snap_enabled) | ||
4665 | PDEBUG(4, "Waiting snapshot frame"); | ||
4666 | if (ov->snap_enabled && !frame->snapshot) { | ||
4667 | frame->bytes_read = 0; | ||
4668 | if ((rc = ov51x_new_frame(ov, frmx))) { | ||
4669 | err("read: ov51x_new_frame error"); | ||
4670 | goto error; | ||
4671 | } | ||
4672 | goto restart; | ||
4673 | } | ||
4674 | |||
4675 | /* Clear the snapshot */ | ||
4676 | if (ov->snap_enabled && frame->snapshot) { | ||
4677 | frame->snapshot = 0; | ||
4678 | ov51x_clear_snapshot(ov); | ||
4679 | } | ||
4680 | |||
4681 | /* Decompression, format conversion, etc... */ | ||
4682 | ov51x_postprocess(ov, frame); | ||
4683 | |||
4684 | PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx, | ||
4685 | frame->bytes_read, | ||
4686 | get_frame_length(frame)); | ||
4687 | |||
4688 | /* copy bytes to user space; we allow for partials reads */ | ||
4689 | // if ((count + frame->bytes_read) | ||
4690 | // > get_frame_length((struct ov511_frame *)frame)) | ||
4691 | // count = frame->scanlength - frame->bytes_read; | ||
4692 | |||
4693 | /* FIXME - count hardwired to be one frame... */ | ||
4694 | count = get_frame_length(frame); | ||
4695 | |||
4696 | PDEBUG(4, "Copy to user space: %ld bytes", count); | ||
4697 | if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) { | ||
4698 | PDEBUG(4, "Copy failed! %d bytes not copied", i); | ||
4699 | rc = -EFAULT; | ||
4700 | goto error; | ||
4701 | } | ||
4702 | |||
4703 | frame->bytes_read += count; | ||
4704 | PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld", | ||
4705 | count, frame->bytes_read); | ||
4706 | |||
4707 | /* If all data have been read... */ | ||
4708 | if (frame->bytes_read | ||
4709 | >= get_frame_length(frame)) { | ||
4710 | frame->bytes_read = 0; | ||
4711 | |||
4712 | // FIXME: Only supports two frames | ||
4713 | /* Mark it as available to be used again. */ | ||
4714 | ov->frame[frmx].grabstate = FRAME_UNUSED; | ||
4715 | if ((rc = ov51x_new_frame(ov, !frmx))) { | ||
4716 | err("ov51x_new_frame returned error"); | ||
4717 | goto error; | ||
4718 | } | ||
4719 | } | ||
4720 | |||
4721 | PDEBUG(4, "read finished, returning %ld (sweet)", count); | ||
4722 | |||
4723 | up(&ov->lock); | ||
4724 | return count; | ||
4725 | |||
4726 | error: | ||
4727 | up(&ov->lock); | ||
4728 | return rc; | ||
4729 | } | ||
4730 | |||
4731 | static int | ||
4732 | ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma) | ||
4733 | { | ||
4734 | struct video_device *vdev = file->private_data; | ||
4735 | unsigned long start = vma->vm_start; | ||
4736 | unsigned long size = vma->vm_end - vma->vm_start; | ||
4737 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
4738 | unsigned long page, pos; | ||
4739 | |||
4740 | if (ov->dev == NULL) | ||
4741 | return -EIO; | ||
4742 | |||
4743 | PDEBUG(4, "mmap: %ld (%lX) bytes", size, size); | ||
4744 | |||
4745 | if (size > (((OV511_NUMFRAMES | ||
4746 | * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight) | ||
4747 | + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))) | ||
4748 | return -EINVAL; | ||
4749 | |||
4750 | if (down_interruptible(&ov->lock)) | ||
4751 | return -EINTR; | ||
4752 | |||
4753 | pos = (unsigned long)ov->fbuf; | ||
4754 | while (size > 0) { | ||
4755 | page = vmalloc_to_pfn((void *)pos); | ||
4756 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { | ||
4757 | up(&ov->lock); | ||
4758 | return -EAGAIN; | ||
4759 | } | ||
4760 | start += PAGE_SIZE; | ||
4761 | pos += PAGE_SIZE; | ||
4762 | if (size > PAGE_SIZE) | ||
4763 | size -= PAGE_SIZE; | ||
4764 | else | ||
4765 | size = 0; | ||
4766 | } | ||
4767 | |||
4768 | up(&ov->lock); | ||
4769 | return 0; | ||
4770 | } | ||
4771 | |||
4772 | static struct file_operations ov511_fops = { | ||
4773 | .owner = THIS_MODULE, | ||
4774 | .open = ov51x_v4l1_open, | ||
4775 | .release = ov51x_v4l1_close, | ||
4776 | .read = ov51x_v4l1_read, | ||
4777 | .mmap = ov51x_v4l1_mmap, | ||
4778 | .ioctl = ov51x_v4l1_ioctl, | ||
4779 | .llseek = no_llseek, | ||
4780 | }; | ||
4781 | |||
4782 | static struct video_device vdev_template = { | ||
4783 | .owner = THIS_MODULE, | ||
4784 | .name = "OV511 USB Camera", | ||
4785 | .type = VID_TYPE_CAPTURE, | ||
4786 | .hardware = VID_HARDWARE_OV511, | ||
4787 | .fops = &ov511_fops, | ||
4788 | .release = video_device_release, | ||
4789 | .minor = -1, | ||
4790 | }; | ||
4791 | |||
4792 | /**************************************************************************** | ||
4793 | * | ||
4794 | * OV511 and sensor configuration | ||
4795 | * | ||
4796 | ***************************************************************************/ | ||
4797 | |||
4798 | /* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses | ||
4799 | * the same register settings as the OV7610, since they are very similar. | ||
4800 | */ | ||
4801 | static int | ||
4802 | ov7xx0_configure(struct usb_ov511 *ov) | ||
4803 | { | ||
4804 | int i, success; | ||
4805 | int rc; | ||
4806 | |||
4807 | /* Lawrence Glaister <lg@jfm.bc.ca> reports: | ||
4808 | * | ||
4809 | * Register 0x0f in the 7610 has the following effects: | ||
4810 | * | ||
4811 | * 0x85 (AEC method 1): Best overall, good contrast range | ||
4812 | * 0x45 (AEC method 2): Very overexposed | ||
4813 | * 0xa5 (spec sheet default): Ok, but the black level is | ||
4814 | * shifted resulting in loss of contrast | ||
4815 | * 0x05 (old driver setting): very overexposed, too much | ||
4816 | * contrast | ||
4817 | */ | ||
4818 | static struct ov511_regvals aRegvalsNorm7610[] = { | ||
4819 | { OV511_I2C_BUS, 0x10, 0xff }, | ||
4820 | { OV511_I2C_BUS, 0x16, 0x06 }, | ||
4821 | { OV511_I2C_BUS, 0x28, 0x24 }, | ||
4822 | { OV511_I2C_BUS, 0x2b, 0xac }, | ||
4823 | { OV511_I2C_BUS, 0x12, 0x00 }, | ||
4824 | { OV511_I2C_BUS, 0x38, 0x81 }, | ||
4825 | { OV511_I2C_BUS, 0x28, 0x24 }, /* 0c */ | ||
4826 | { OV511_I2C_BUS, 0x0f, 0x85 }, /* lg's setting */ | ||
4827 | { OV511_I2C_BUS, 0x15, 0x01 }, | ||
4828 | { OV511_I2C_BUS, 0x20, 0x1c }, | ||
4829 | { OV511_I2C_BUS, 0x23, 0x2a }, | ||
4830 | { OV511_I2C_BUS, 0x24, 0x10 }, | ||
4831 | { OV511_I2C_BUS, 0x25, 0x8a }, | ||
4832 | { OV511_I2C_BUS, 0x26, 0xa2 }, | ||
4833 | { OV511_I2C_BUS, 0x27, 0xc2 }, | ||
4834 | { OV511_I2C_BUS, 0x2a, 0x04 }, | ||
4835 | { OV511_I2C_BUS, 0x2c, 0xfe }, | ||
4836 | { OV511_I2C_BUS, 0x2d, 0x93 }, | ||
4837 | { OV511_I2C_BUS, 0x30, 0x71 }, | ||
4838 | { OV511_I2C_BUS, 0x31, 0x60 }, | ||
4839 | { OV511_I2C_BUS, 0x32, 0x26 }, | ||
4840 | { OV511_I2C_BUS, 0x33, 0x20 }, | ||
4841 | { OV511_I2C_BUS, 0x34, 0x48 }, | ||
4842 | { OV511_I2C_BUS, 0x12, 0x24 }, | ||
4843 | { OV511_I2C_BUS, 0x11, 0x01 }, | ||
4844 | { OV511_I2C_BUS, 0x0c, 0x24 }, | ||
4845 | { OV511_I2C_BUS, 0x0d, 0x24 }, | ||
4846 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
4847 | }; | ||
4848 | |||
4849 | static struct ov511_regvals aRegvalsNorm7620[] = { | ||
4850 | { OV511_I2C_BUS, 0x00, 0x00 }, | ||
4851 | { OV511_I2C_BUS, 0x01, 0x80 }, | ||
4852 | { OV511_I2C_BUS, 0x02, 0x80 }, | ||
4853 | { OV511_I2C_BUS, 0x03, 0xc0 }, | ||
4854 | { OV511_I2C_BUS, 0x06, 0x60 }, | ||
4855 | { OV511_I2C_BUS, 0x07, 0x00 }, | ||
4856 | { OV511_I2C_BUS, 0x0c, 0x24 }, | ||
4857 | { OV511_I2C_BUS, 0x0c, 0x24 }, | ||
4858 | { OV511_I2C_BUS, 0x0d, 0x24 }, | ||
4859 | { OV511_I2C_BUS, 0x11, 0x01 }, | ||
4860 | { OV511_I2C_BUS, 0x12, 0x24 }, | ||
4861 | { OV511_I2C_BUS, 0x13, 0x01 }, | ||
4862 | { OV511_I2C_BUS, 0x14, 0x84 }, | ||
4863 | { OV511_I2C_BUS, 0x15, 0x01 }, | ||
4864 | { OV511_I2C_BUS, 0x16, 0x03 }, | ||
4865 | { OV511_I2C_BUS, 0x17, 0x2f }, | ||
4866 | { OV511_I2C_BUS, 0x18, 0xcf }, | ||
4867 | { OV511_I2C_BUS, 0x19, 0x06 }, | ||
4868 | { OV511_I2C_BUS, 0x1a, 0xf5 }, | ||
4869 | { OV511_I2C_BUS, 0x1b, 0x00 }, | ||
4870 | { OV511_I2C_BUS, 0x20, 0x18 }, | ||
4871 | { OV511_I2C_BUS, 0x21, 0x80 }, | ||
4872 | { OV511_I2C_BUS, 0x22, 0x80 }, | ||
4873 | { OV511_I2C_BUS, 0x23, 0x00 }, | ||
4874 | { OV511_I2C_BUS, 0x26, 0xa2 }, | ||
4875 | { OV511_I2C_BUS, 0x27, 0xea }, | ||
4876 | { OV511_I2C_BUS, 0x28, 0x20 }, | ||
4877 | { OV511_I2C_BUS, 0x29, 0x00 }, | ||
4878 | { OV511_I2C_BUS, 0x2a, 0x10 }, | ||
4879 | { OV511_I2C_BUS, 0x2b, 0x00 }, | ||
4880 | { OV511_I2C_BUS, 0x2c, 0x88 }, | ||
4881 | { OV511_I2C_BUS, 0x2d, 0x91 }, | ||
4882 | { OV511_I2C_BUS, 0x2e, 0x80 }, | ||
4883 | { OV511_I2C_BUS, 0x2f, 0x44 }, | ||
4884 | { OV511_I2C_BUS, 0x60, 0x27 }, | ||
4885 | { OV511_I2C_BUS, 0x61, 0x02 }, | ||
4886 | { OV511_I2C_BUS, 0x62, 0x5f }, | ||
4887 | { OV511_I2C_BUS, 0x63, 0xd5 }, | ||
4888 | { OV511_I2C_BUS, 0x64, 0x57 }, | ||
4889 | { OV511_I2C_BUS, 0x65, 0x83 }, | ||
4890 | { OV511_I2C_BUS, 0x66, 0x55 }, | ||
4891 | { OV511_I2C_BUS, 0x67, 0x92 }, | ||
4892 | { OV511_I2C_BUS, 0x68, 0xcf }, | ||
4893 | { OV511_I2C_BUS, 0x69, 0x76 }, | ||
4894 | { OV511_I2C_BUS, 0x6a, 0x22 }, | ||
4895 | { OV511_I2C_BUS, 0x6b, 0x00 }, | ||
4896 | { OV511_I2C_BUS, 0x6c, 0x02 }, | ||
4897 | { OV511_I2C_BUS, 0x6d, 0x44 }, | ||
4898 | { OV511_I2C_BUS, 0x6e, 0x80 }, | ||
4899 | { OV511_I2C_BUS, 0x6f, 0x1d }, | ||
4900 | { OV511_I2C_BUS, 0x70, 0x8b }, | ||
4901 | { OV511_I2C_BUS, 0x71, 0x00 }, | ||
4902 | { OV511_I2C_BUS, 0x72, 0x14 }, | ||
4903 | { OV511_I2C_BUS, 0x73, 0x54 }, | ||
4904 | { OV511_I2C_BUS, 0x74, 0x00 }, | ||
4905 | { OV511_I2C_BUS, 0x75, 0x8e }, | ||
4906 | { OV511_I2C_BUS, 0x76, 0x00 }, | ||
4907 | { OV511_I2C_BUS, 0x77, 0xff }, | ||
4908 | { OV511_I2C_BUS, 0x78, 0x80 }, | ||
4909 | { OV511_I2C_BUS, 0x79, 0x80 }, | ||
4910 | { OV511_I2C_BUS, 0x7a, 0x80 }, | ||
4911 | { OV511_I2C_BUS, 0x7b, 0xe2 }, | ||
4912 | { OV511_I2C_BUS, 0x7c, 0x00 }, | ||
4913 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
4914 | }; | ||
4915 | |||
4916 | PDEBUG(4, "starting configuration"); | ||
4917 | |||
4918 | /* This looks redundant, but is necessary for WebCam 3 */ | ||
4919 | ov->primary_i2c_slave = OV7xx0_SID; | ||
4920 | if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) | ||
4921 | return -1; | ||
4922 | |||
4923 | if (init_ov_sensor(ov) >= 0) { | ||
4924 | PDEBUG(1, "OV7xx0 sensor initalized (method 1)"); | ||
4925 | } else { | ||
4926 | /* Reset the 76xx */ | ||
4927 | if (i2c_w(ov, 0x12, 0x80) < 0) | ||
4928 | return -1; | ||
4929 | |||
4930 | /* Wait for it to initialize */ | ||
4931 | msleep(150); | ||
4932 | |||
4933 | i = 0; | ||
4934 | success = 0; | ||
4935 | while (i <= i2c_detect_tries) { | ||
4936 | if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && | ||
4937 | (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { | ||
4938 | success = 1; | ||
4939 | break; | ||
4940 | } else { | ||
4941 | i++; | ||
4942 | } | ||
4943 | } | ||
4944 | |||
4945 | // Was (i == i2c_detect_tries) previously. This obviously used to always report | ||
4946 | // success. Whether anyone actually depended on that bug is unknown | ||
4947 | if ((i >= i2c_detect_tries) && (success == 0)) { | ||
4948 | err("Failed to read sensor ID. You might not have an"); | ||
4949 | err("OV7610/20, or it may be not responding. Report"); | ||
4950 | err("this to " EMAIL); | ||
4951 | err("This is only a warning. You can attempt to use"); | ||
4952 | err("your camera anyway"); | ||
4953 | // Only issue a warning for now | ||
4954 | // return -1; | ||
4955 | } else { | ||
4956 | PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1); | ||
4957 | } | ||
4958 | } | ||
4959 | |||
4960 | /* Detect sensor (sub)type */ | ||
4961 | rc = i2c_r(ov, OV7610_REG_COM_I); | ||
4962 | |||
4963 | if (rc < 0) { | ||
4964 | err("Error detecting sensor type"); | ||
4965 | return -1; | ||
4966 | } else if ((rc & 3) == 3) { | ||
4967 | info("Sensor is an OV7610"); | ||
4968 | ov->sensor = SEN_OV7610; | ||
4969 | } else if ((rc & 3) == 1) { | ||
4970 | /* I don't know what's different about the 76BE yet. */ | ||
4971 | if (i2c_r(ov, 0x15) & 1) | ||
4972 | info("Sensor is an OV7620AE"); | ||
4973 | else | ||
4974 | info("Sensor is an OV76BE"); | ||
4975 | |||
4976 | /* OV511+ will return all zero isoc data unless we | ||
4977 | * configure the sensor as a 7620. Someone needs to | ||
4978 | * find the exact reg. setting that causes this. */ | ||
4979 | if (ov->bridge == BRG_OV511PLUS) { | ||
4980 | info("Enabling 511+/7620AE workaround"); | ||
4981 | ov->sensor = SEN_OV7620; | ||
4982 | } else { | ||
4983 | ov->sensor = SEN_OV76BE; | ||
4984 | } | ||
4985 | } else if ((rc & 3) == 0) { | ||
4986 | info("Sensor is an OV7620"); | ||
4987 | ov->sensor = SEN_OV7620; | ||
4988 | } else { | ||
4989 | err("Unknown image sensor version: %d", rc & 3); | ||
4990 | return -1; | ||
4991 | } | ||
4992 | |||
4993 | if (ov->sensor == SEN_OV7620) { | ||
4994 | PDEBUG(4, "Writing 7620 registers"); | ||
4995 | if (write_regvals(ov, aRegvalsNorm7620)) | ||
4996 | return -1; | ||
4997 | } else { | ||
4998 | PDEBUG(4, "Writing 7610 registers"); | ||
4999 | if (write_regvals(ov, aRegvalsNorm7610)) | ||
5000 | return -1; | ||
5001 | } | ||
5002 | |||
5003 | /* Set sensor-specific vars */ | ||
5004 | ov->maxwidth = 640; | ||
5005 | ov->maxheight = 480; | ||
5006 | ov->minwidth = 64; | ||
5007 | ov->minheight = 48; | ||
5008 | |||
5009 | // FIXME: These do not match the actual settings yet | ||
5010 | ov->brightness = 0x80 << 8; | ||
5011 | ov->contrast = 0x80 << 8; | ||
5012 | ov->colour = 0x80 << 8; | ||
5013 | ov->hue = 0x80 << 8; | ||
5014 | |||
5015 | return 0; | ||
5016 | } | ||
5017 | |||
5018 | /* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */ | ||
5019 | static int | ||
5020 | ov6xx0_configure(struct usb_ov511 *ov) | ||
5021 | { | ||
5022 | int rc; | ||
5023 | |||
5024 | static struct ov511_regvals aRegvalsNorm6x20[] = { | ||
5025 | { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ | ||
5026 | { OV511_I2C_BUS, 0x11, 0x01 }, | ||
5027 | { OV511_I2C_BUS, 0x03, 0x60 }, | ||
5028 | { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ | ||
5029 | { OV511_I2C_BUS, 0x07, 0xa8 }, | ||
5030 | /* The ratio of 0x0c and 0x0d controls the white point */ | ||
5031 | { OV511_I2C_BUS, 0x0c, 0x24 }, | ||
5032 | { OV511_I2C_BUS, 0x0d, 0x24 }, | ||
5033 | { OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */ | ||
5034 | { OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */ | ||
5035 | { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */ | ||
5036 | { OV511_I2C_BUS, 0x14, 0x04 }, | ||
5037 | /* 0x16: 0x06 helps frame stability with moving objects */ | ||
5038 | { OV511_I2C_BUS, 0x16, 0x06 }, | ||
5039 | // { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */ | ||
5040 | { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ | ||
5041 | /* 0x28: 0x05 Selects RGB format if RGB on */ | ||
5042 | { OV511_I2C_BUS, 0x28, 0x05 }, | ||
5043 | { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ | ||
5044 | // { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ | ||
5045 | { OV511_I2C_BUS, 0x2d, 0x99 }, | ||
5046 | { OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Procesing Parameter */ | ||
5047 | { OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */ | ||
5048 | { OV511_I2C_BUS, 0x38, 0x8b }, | ||
5049 | { OV511_I2C_BUS, 0x39, 0x40 }, | ||
5050 | |||
5051 | { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */ | ||
5052 | { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */ | ||
5053 | { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */ | ||
5054 | |||
5055 | { OV511_I2C_BUS, 0x3d, 0x80 }, | ||
5056 | /* These next two registers (0x4a, 0x4b) are undocumented. They | ||
5057 | * control the color balance */ | ||
5058 | { OV511_I2C_BUS, 0x4a, 0x80 }, | ||
5059 | { OV511_I2C_BUS, 0x4b, 0x80 }, | ||
5060 | { OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */ | ||
5061 | { OV511_I2C_BUS, 0x4e, 0xc1 }, | ||
5062 | { OV511_I2C_BUS, 0x4f, 0x04 }, | ||
5063 | // Do 50-53 have any effect? | ||
5064 | // Toggle 0x12[2] off and on here? | ||
5065 | { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ | ||
5066 | }; | ||
5067 | |||
5068 | static struct ov511_regvals aRegvalsNorm6x30[] = { | ||
5069 | /*OK*/ { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ | ||
5070 | { OV511_I2C_BUS, 0x11, 0x00 }, | ||
5071 | /*OK*/ { OV511_I2C_BUS, 0x03, 0x60 }, | ||
5072 | /*0A?*/ { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ | ||
5073 | { OV511_I2C_BUS, 0x07, 0xa8 }, | ||
5074 | /* The ratio of 0x0c and 0x0d controls the white point */ | ||
5075 | /*OK*/ { OV511_I2C_BUS, 0x0c, 0x24 }, | ||
5076 | /*OK*/ { OV511_I2C_BUS, 0x0d, 0x24 }, | ||
5077 | /*A*/ { OV511_I2C_BUS, 0x0e, 0x20 }, | ||
5078 | // /*04?*/ { OV511_I2C_BUS, 0x14, 0x80 }, | ||
5079 | { OV511_I2C_BUS, 0x16, 0x03 }, | ||
5080 | // /*OK*/ { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */ | ||
5081 | // 21 & 22? The suggested values look wrong. Go with default | ||
5082 | /*A*/ { OV511_I2C_BUS, 0x23, 0xc0 }, | ||
5083 | /*A*/ { OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default | ||
5084 | // /*OK*/ { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ | ||
5085 | |||
5086 | /* 0x28: 0x05 Selects RGB format if RGB on */ | ||
5087 | // /*04?*/ { OV511_I2C_BUS, 0x28, 0x05 }, | ||
5088 | // /*04?*/ { OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus | ||
5089 | |||
5090 | /*OK*/ { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ | ||
5091 | // /*OK*/ { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ | ||
5092 | { OV511_I2C_BUS, 0x2d, 0x99 }, | ||
5093 | // /*A*/ { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620 | ||
5094 | // /*d2?*/ { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */ | ||
5095 | // /*8b?*/ { OV511_I2C_BUS, 0x38, 0x83 }, | ||
5096 | // /*40?*/ { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7 | ||
5097 | // { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */ | ||
5098 | // { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */ | ||
5099 | // { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */ | ||
5100 | { OV511_I2C_BUS, 0x3d, 0x80 }, | ||
5101 | // /*A*/ { OV511_I2C_BUS, 0x3f, 0x0e }, | ||
5102 | |||
5103 | /* These next two registers (0x4a, 0x4b) are undocumented. They | ||
5104 | * control the color balance */ | ||
5105 | // /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these | ||
5106 | // /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 }, | ||
5107 | { OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ | ||
5108 | /*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 }, | ||
5109 | |||
5110 | /* UV average mode, color killer: strongest */ | ||
5111 | { OV511_I2C_BUS, 0x4f, 0x07 }, | ||
5112 | |||
5113 | { OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */ | ||
5114 | { OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */ | ||
5115 | { OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */ | ||
5116 | { OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */ | ||
5117 | { OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */ | ||
5118 | // { OV511_I2C_BUS, 0x5c, 0x10 }, | ||
5119 | { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ | ||
5120 | }; | ||
5121 | |||
5122 | PDEBUG(4, "starting sensor configuration"); | ||
5123 | |||
5124 | if (init_ov_sensor(ov) < 0) { | ||
5125 | err("Failed to read sensor ID. You might not have an OV6xx0,"); | ||
5126 | err("or it may be not responding. Report this to " EMAIL); | ||
5127 | return -1; | ||
5128 | } else { | ||
5129 | PDEBUG(1, "OV6xx0 sensor detected"); | ||
5130 | } | ||
5131 | |||
5132 | /* Detect sensor (sub)type */ | ||
5133 | rc = i2c_r(ov, OV7610_REG_COM_I); | ||
5134 | |||
5135 | if (rc < 0) { | ||
5136 | err("Error detecting sensor type"); | ||
5137 | return -1; | ||
5138 | } | ||
5139 | |||
5140 | if ((rc & 3) == 0) { | ||
5141 | ov->sensor = SEN_OV6630; | ||
5142 | info("Sensor is an OV6630"); | ||
5143 | } else if ((rc & 3) == 1) { | ||
5144 | ov->sensor = SEN_OV6620; | ||
5145 | info("Sensor is an OV6620"); | ||
5146 | } else if ((rc & 3) == 2) { | ||
5147 | ov->sensor = SEN_OV6630; | ||
5148 | info("Sensor is an OV6630AE"); | ||
5149 | } else if ((rc & 3) == 3) { | ||
5150 | ov->sensor = SEN_OV6630; | ||
5151 | info("Sensor is an OV6630AF"); | ||
5152 | } | ||
5153 | |||
5154 | /* Set sensor-specific vars */ | ||
5155 | ov->maxwidth = 352; | ||
5156 | ov->maxheight = 288; | ||
5157 | ov->minwidth = 64; | ||
5158 | ov->minheight = 48; | ||
5159 | |||
5160 | // FIXME: These do not match the actual settings yet | ||
5161 | ov->brightness = 0x80 << 8; | ||
5162 | ov->contrast = 0x80 << 8; | ||
5163 | ov->colour = 0x80 << 8; | ||
5164 | ov->hue = 0x80 << 8; | ||
5165 | |||
5166 | if (ov->sensor == SEN_OV6620) { | ||
5167 | PDEBUG(4, "Writing 6x20 registers"); | ||
5168 | if (write_regvals(ov, aRegvalsNorm6x20)) | ||
5169 | return -1; | ||
5170 | } else { | ||
5171 | PDEBUG(4, "Writing 6x30 registers"); | ||
5172 | if (write_regvals(ov, aRegvalsNorm6x30)) | ||
5173 | return -1; | ||
5174 | } | ||
5175 | |||
5176 | return 0; | ||
5177 | } | ||
5178 | |||
5179 | /* This initializes the KS0127 and KS0127B video decoders. */ | ||
5180 | static int | ||
5181 | ks0127_configure(struct usb_ov511 *ov) | ||
5182 | { | ||
5183 | int rc; | ||
5184 | |||
5185 | // FIXME: I don't know how to sync or reset it yet | ||
5186 | #if 0 | ||
5187 | if (ov51x_init_ks_sensor(ov) < 0) { | ||
5188 | err("Failed to initialize the KS0127"); | ||
5189 | return -1; | ||
5190 | } else { | ||
5191 | PDEBUG(1, "KS012x(B) sensor detected"); | ||
5192 | } | ||
5193 | #endif | ||
5194 | |||
5195 | /* Detect decoder subtype */ | ||
5196 | rc = i2c_r(ov, 0x00); | ||
5197 | if (rc < 0) { | ||
5198 | err("Error detecting sensor type"); | ||
5199 | return -1; | ||
5200 | } else if (rc & 0x08) { | ||
5201 | rc = i2c_r(ov, 0x3d); | ||
5202 | if (rc < 0) { | ||
5203 | err("Error detecting sensor type"); | ||
5204 | return -1; | ||
5205 | } else if ((rc & 0x0f) == 0) { | ||
5206 | info("Sensor is a KS0127"); | ||
5207 | ov->sensor = SEN_KS0127; | ||
5208 | } else if ((rc & 0x0f) == 9) { | ||
5209 | info("Sensor is a KS0127B Rev. A"); | ||
5210 | ov->sensor = SEN_KS0127B; | ||
5211 | } | ||
5212 | } else { | ||
5213 | err("Error: Sensor is an unsupported KS0122"); | ||
5214 | return -1; | ||
5215 | } | ||
5216 | |||
5217 | /* Set sensor-specific vars */ | ||
5218 | ov->maxwidth = 640; | ||
5219 | ov->maxheight = 480; | ||
5220 | ov->minwidth = 64; | ||
5221 | ov->minheight = 48; | ||
5222 | |||
5223 | // FIXME: These do not match the actual settings yet | ||
5224 | ov->brightness = 0x80 << 8; | ||
5225 | ov->contrast = 0x80 << 8; | ||
5226 | ov->colour = 0x80 << 8; | ||
5227 | ov->hue = 0x80 << 8; | ||
5228 | |||
5229 | /* This device is not supported yet. Bail out now... */ | ||
5230 | err("This sensor is not supported yet."); | ||
5231 | return -1; | ||
5232 | |||
5233 | return 0; | ||
5234 | } | ||
5235 | |||
5236 | /* This initializes the SAA7111A video decoder. */ | ||
5237 | static int | ||
5238 | saa7111a_configure(struct usb_ov511 *ov) | ||
5239 | { | ||
5240 | int rc; | ||
5241 | |||
5242 | /* Since there is no register reset command, all registers must be | ||
5243 | * written, otherwise gives erratic results */ | ||
5244 | static struct ov511_regvals aRegvalsNormSAA7111A[] = { | ||
5245 | { OV511_I2C_BUS, 0x06, 0xce }, | ||
5246 | { OV511_I2C_BUS, 0x07, 0x00 }, | ||
5247 | { OV511_I2C_BUS, 0x10, 0x44 }, /* YUV422, 240/286 lines */ | ||
5248 | { OV511_I2C_BUS, 0x0e, 0x01 }, /* NTSC M or PAL BGHI */ | ||
5249 | { OV511_I2C_BUS, 0x00, 0x00 }, | ||
5250 | { OV511_I2C_BUS, 0x01, 0x00 }, | ||
5251 | { OV511_I2C_BUS, 0x03, 0x23 }, | ||
5252 | { OV511_I2C_BUS, 0x04, 0x00 }, | ||
5253 | { OV511_I2C_BUS, 0x05, 0x00 }, | ||
5254 | { OV511_I2C_BUS, 0x08, 0xc8 }, /* Auto field freq */ | ||
5255 | { OV511_I2C_BUS, 0x09, 0x01 }, /* Chrom. trap off, APER=0.25 */ | ||
5256 | { OV511_I2C_BUS, 0x0a, 0x80 }, /* BRIG=128 */ | ||
5257 | { OV511_I2C_BUS, 0x0b, 0x40 }, /* CONT=1.0 */ | ||
5258 | { OV511_I2C_BUS, 0x0c, 0x40 }, /* SATN=1.0 */ | ||
5259 | { OV511_I2C_BUS, 0x0d, 0x00 }, /* HUE=0 */ | ||
5260 | { OV511_I2C_BUS, 0x0f, 0x00 }, | ||
5261 | { OV511_I2C_BUS, 0x11, 0x0c }, | ||
5262 | { OV511_I2C_BUS, 0x12, 0x00 }, | ||
5263 | { OV511_I2C_BUS, 0x13, 0x00 }, | ||
5264 | { OV511_I2C_BUS, 0x14, 0x00 }, | ||
5265 | { OV511_I2C_BUS, 0x15, 0x00 }, | ||
5266 | { OV511_I2C_BUS, 0x16, 0x00 }, | ||
5267 | { OV511_I2C_BUS, 0x17, 0x00 }, | ||
5268 | { OV511_I2C_BUS, 0x02, 0xc0 }, /* Composite input 0 */ | ||
5269 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
5270 | }; | ||
5271 | |||
5272 | // FIXME: I don't know how to sync or reset it yet | ||
5273 | #if 0 | ||
5274 | if (ov51x_init_saa_sensor(ov) < 0) { | ||
5275 | err("Failed to initialize the SAA7111A"); | ||
5276 | return -1; | ||
5277 | } else { | ||
5278 | PDEBUG(1, "SAA7111A sensor detected"); | ||
5279 | } | ||
5280 | #endif | ||
5281 | |||
5282 | /* 640x480 not supported with PAL */ | ||
5283 | if (ov->pal) { | ||
5284 | ov->maxwidth = 320; | ||
5285 | ov->maxheight = 240; /* Even field only */ | ||
5286 | } else { | ||
5287 | ov->maxwidth = 640; | ||
5288 | ov->maxheight = 480; /* Even/Odd fields */ | ||
5289 | } | ||
5290 | |||
5291 | ov->minwidth = 320; | ||
5292 | ov->minheight = 240; /* Even field only */ | ||
5293 | |||
5294 | ov->has_decoder = 1; | ||
5295 | ov->num_inputs = 8; | ||
5296 | ov->norm = VIDEO_MODE_AUTO; | ||
5297 | ov->stop_during_set = 0; /* Decoder guarantees stable image */ | ||
5298 | |||
5299 | /* Decoder doesn't change these values, so we use these instead of | ||
5300 | * acutally reading the registers (which doesn't work) */ | ||
5301 | ov->brightness = 0x80 << 8; | ||
5302 | ov->contrast = 0x40 << 9; | ||
5303 | ov->colour = 0x40 << 9; | ||
5304 | ov->hue = 32768; | ||
5305 | |||
5306 | PDEBUG(4, "Writing SAA7111A registers"); | ||
5307 | if (write_regvals(ov, aRegvalsNormSAA7111A)) | ||
5308 | return -1; | ||
5309 | |||
5310 | /* Detect version of decoder. This must be done after writing the | ||
5311 | * initial regs or the decoder will lock up. */ | ||
5312 | rc = i2c_r(ov, 0x00); | ||
5313 | |||
5314 | if (rc < 0) { | ||
5315 | err("Error detecting sensor version"); | ||
5316 | return -1; | ||
5317 | } else { | ||
5318 | info("Sensor is an SAA7111A (version 0x%x)", rc); | ||
5319 | ov->sensor = SEN_SAA7111A; | ||
5320 | } | ||
5321 | |||
5322 | // FIXME: Fix this for OV518(+) | ||
5323 | /* Latch to negative edge of clock. Otherwise, we get incorrect | ||
5324 | * colors and jitter in the digital signal. */ | ||
5325 | if (ov->bclass == BCL_OV511) | ||
5326 | reg_w(ov, 0x11, 0x00); | ||
5327 | else | ||
5328 | warn("SAA7111A not yet supported with OV518/OV518+"); | ||
5329 | |||
5330 | return 0; | ||
5331 | } | ||
5332 | |||
5333 | /* This initializes the OV511/OV511+ and the sensor */ | ||
5334 | static int | ||
5335 | ov511_configure(struct usb_ov511 *ov) | ||
5336 | { | ||
5337 | static struct ov511_regvals aRegvalsInit511[] = { | ||
5338 | { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, | ||
5339 | { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, | ||
5340 | { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, | ||
5341 | { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, | ||
5342 | { OV511_REG_BUS, R51x_SYS_RESET, 0x3f }, | ||
5343 | { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, | ||
5344 | { OV511_REG_BUS, R51x_SYS_RESET, 0x3d }, | ||
5345 | { OV511_DONE_BUS, 0x0, 0x00}, | ||
5346 | }; | ||
5347 | |||
5348 | static struct ov511_regvals aRegvalsNorm511[] = { | ||
5349 | { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0x01 }, | ||
5350 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, | ||
5351 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, | ||
5352 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, | ||
5353 | { OV511_REG_BUS, R511_FIFO_OPTS, 0x1f }, | ||
5354 | { OV511_REG_BUS, R511_COMP_EN, 0x00 }, | ||
5355 | { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, | ||
5356 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
5357 | }; | ||
5358 | |||
5359 | static struct ov511_regvals aRegvalsNorm511Plus[] = { | ||
5360 | { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0xff }, | ||
5361 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, | ||
5362 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, | ||
5363 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, | ||
5364 | { OV511_REG_BUS, R511_FIFO_OPTS, 0xff }, | ||
5365 | { OV511_REG_BUS, R511_COMP_EN, 0x00 }, | ||
5366 | { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, | ||
5367 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
5368 | }; | ||
5369 | |||
5370 | PDEBUG(4, ""); | ||
5371 | |||
5372 | ov->customid = reg_r(ov, R511_SYS_CUST_ID); | ||
5373 | if (ov->customid < 0) { | ||
5374 | err("Unable to read camera bridge registers"); | ||
5375 | goto error; | ||
5376 | } | ||
5377 | |||
5378 | PDEBUG (1, "CustomID = %d", ov->customid); | ||
5379 | ov->desc = symbolic(camlist, ov->customid); | ||
5380 | info("model: %s", ov->desc); | ||
5381 | |||
5382 | if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) { | ||
5383 | err("Camera type (%d) not recognized", ov->customid); | ||
5384 | err("Please notify " EMAIL " of the name,"); | ||
5385 | err("manufacturer, model, and this number of your camera."); | ||
5386 | err("Also include the output of the detection process."); | ||
5387 | } | ||
5388 | |||
5389 | if (ov->customid == 70) /* USB Life TV (PAL/SECAM) */ | ||
5390 | ov->pal = 1; | ||
5391 | |||
5392 | if (write_regvals(ov, aRegvalsInit511)) | ||
5393 | goto error; | ||
5394 | |||
5395 | if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) | ||
5396 | ov51x_led_control(ov, 0); | ||
5397 | |||
5398 | /* The OV511+ has undocumented bits in the flow control register. | ||
5399 | * Setting it to 0xff fixes the corruption with moving objects. */ | ||
5400 | if (ov->bridge == BRG_OV511) { | ||
5401 | if (write_regvals(ov, aRegvalsNorm511)) | ||
5402 | goto error; | ||
5403 | } else if (ov->bridge == BRG_OV511PLUS) { | ||
5404 | if (write_regvals(ov, aRegvalsNorm511Plus)) | ||
5405 | goto error; | ||
5406 | } else { | ||
5407 | err("Invalid bridge"); | ||
5408 | } | ||
5409 | |||
5410 | if (ov511_init_compression(ov)) | ||
5411 | goto error; | ||
5412 | |||
5413 | ov->packet_numbering = 1; | ||
5414 | ov511_set_packet_size(ov, 0); | ||
5415 | |||
5416 | ov->snap_enabled = snapshot; | ||
5417 | |||
5418 | /* Test for 7xx0 */ | ||
5419 | PDEBUG(3, "Testing for 0V7xx0"); | ||
5420 | ov->primary_i2c_slave = OV7xx0_SID; | ||
5421 | if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) | ||
5422 | goto error; | ||
5423 | |||
5424 | if (i2c_w(ov, 0x12, 0x80) < 0) { | ||
5425 | /* Test for 6xx0 */ | ||
5426 | PDEBUG(3, "Testing for 0V6xx0"); | ||
5427 | ov->primary_i2c_slave = OV6xx0_SID; | ||
5428 | if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) | ||
5429 | goto error; | ||
5430 | |||
5431 | if (i2c_w(ov, 0x12, 0x80) < 0) { | ||
5432 | /* Test for 8xx0 */ | ||
5433 | PDEBUG(3, "Testing for 0V8xx0"); | ||
5434 | ov->primary_i2c_slave = OV8xx0_SID; | ||
5435 | if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) | ||
5436 | goto error; | ||
5437 | |||
5438 | if (i2c_w(ov, 0x12, 0x80) < 0) { | ||
5439 | /* Test for SAA7111A */ | ||
5440 | PDEBUG(3, "Testing for SAA7111A"); | ||
5441 | ov->primary_i2c_slave = SAA7111A_SID; | ||
5442 | if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0) | ||
5443 | goto error; | ||
5444 | |||
5445 | if (i2c_w(ov, 0x0d, 0x00) < 0) { | ||
5446 | /* Test for KS0127 */ | ||
5447 | PDEBUG(3, "Testing for KS0127"); | ||
5448 | ov->primary_i2c_slave = KS0127_SID; | ||
5449 | if (ov51x_set_slave_ids(ov, KS0127_SID) < 0) | ||
5450 | goto error; | ||
5451 | |||
5452 | if (i2c_w(ov, 0x10, 0x00) < 0) { | ||
5453 | err("Can't determine sensor slave IDs"); | ||
5454 | goto error; | ||
5455 | } else { | ||
5456 | if (ks0127_configure(ov) < 0) { | ||
5457 | err("Failed to configure KS0127"); | ||
5458 | goto error; | ||
5459 | } | ||
5460 | } | ||
5461 | } else { | ||
5462 | if (saa7111a_configure(ov) < 0) { | ||
5463 | err("Failed to configure SAA7111A"); | ||
5464 | goto error; | ||
5465 | } | ||
5466 | } | ||
5467 | } else { | ||
5468 | err("Detected unsupported OV8xx0 sensor"); | ||
5469 | goto error; | ||
5470 | } | ||
5471 | } else { | ||
5472 | if (ov6xx0_configure(ov) < 0) { | ||
5473 | err("Failed to configure OV6xx0"); | ||
5474 | goto error; | ||
5475 | } | ||
5476 | } | ||
5477 | } else { | ||
5478 | if (ov7xx0_configure(ov) < 0) { | ||
5479 | err("Failed to configure OV7xx0"); | ||
5480 | goto error; | ||
5481 | } | ||
5482 | } | ||
5483 | |||
5484 | return 0; | ||
5485 | |||
5486 | error: | ||
5487 | err("OV511 Config failed"); | ||
5488 | |||
5489 | return -EBUSY; | ||
5490 | } | ||
5491 | |||
5492 | /* This initializes the OV518/OV518+ and the sensor */ | ||
5493 | static int | ||
5494 | ov518_configure(struct usb_ov511 *ov) | ||
5495 | { | ||
5496 | /* For 518 and 518+ */ | ||
5497 | static struct ov511_regvals aRegvalsInit518[] = { | ||
5498 | { OV511_REG_BUS, R51x_SYS_RESET, 0x40 }, | ||
5499 | { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, | ||
5500 | { OV511_REG_BUS, R51x_SYS_RESET, 0x3e }, | ||
5501 | { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, | ||
5502 | { OV511_REG_BUS, R51x_SYS_RESET, 0x00 }, | ||
5503 | { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, | ||
5504 | { OV511_REG_BUS, 0x46, 0x00 }, | ||
5505 | { OV511_REG_BUS, 0x5d, 0x03 }, | ||
5506 | { OV511_DONE_BUS, 0x0, 0x00}, | ||
5507 | }; | ||
5508 | |||
5509 | static struct ov511_regvals aRegvalsNorm518[] = { | ||
5510 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */ | ||
5511 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */ | ||
5512 | { OV511_REG_BUS, 0x31, 0x0f }, | ||
5513 | { OV511_REG_BUS, 0x5d, 0x03 }, | ||
5514 | { OV511_REG_BUS, 0x24, 0x9f }, | ||
5515 | { OV511_REG_BUS, 0x25, 0x90 }, | ||
5516 | { OV511_REG_BUS, 0x20, 0x00 }, | ||
5517 | { OV511_REG_BUS, 0x51, 0x04 }, | ||
5518 | { OV511_REG_BUS, 0x71, 0x19 }, | ||
5519 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
5520 | }; | ||
5521 | |||
5522 | static struct ov511_regvals aRegvalsNorm518Plus[] = { | ||
5523 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */ | ||
5524 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */ | ||
5525 | { OV511_REG_BUS, 0x31, 0x0f }, | ||
5526 | { OV511_REG_BUS, 0x5d, 0x03 }, | ||
5527 | { OV511_REG_BUS, 0x24, 0x9f }, | ||
5528 | { OV511_REG_BUS, 0x25, 0x90 }, | ||
5529 | { OV511_REG_BUS, 0x20, 0x60 }, | ||
5530 | { OV511_REG_BUS, 0x51, 0x02 }, | ||
5531 | { OV511_REG_BUS, 0x71, 0x19 }, | ||
5532 | { OV511_REG_BUS, 0x40, 0xff }, | ||
5533 | { OV511_REG_BUS, 0x41, 0x42 }, | ||
5534 | { OV511_REG_BUS, 0x46, 0x00 }, | ||
5535 | { OV511_REG_BUS, 0x33, 0x04 }, | ||
5536 | { OV511_REG_BUS, 0x21, 0x19 }, | ||
5537 | { OV511_REG_BUS, 0x3f, 0x10 }, | ||
5538 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
5539 | }; | ||
5540 | |||
5541 | PDEBUG(4, ""); | ||
5542 | |||
5543 | /* First 5 bits of custom ID reg are a revision ID on OV518 */ | ||
5544 | info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID)); | ||
5545 | |||
5546 | /* Give it the default description */ | ||
5547 | ov->desc = symbolic(camlist, 0); | ||
5548 | |||
5549 | if (write_regvals(ov, aRegvalsInit518)) | ||
5550 | goto error; | ||
5551 | |||
5552 | /* Set LED GPIO pin to output mode */ | ||
5553 | if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0) | ||
5554 | goto error; | ||
5555 | |||
5556 | /* LED is off by default with OV518; have to explicitly turn it on */ | ||
5557 | if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) | ||
5558 | ov51x_led_control(ov, 0); | ||
5559 | else | ||
5560 | ov51x_led_control(ov, 1); | ||
5561 | |||
5562 | /* Don't require compression if dumppix is enabled; otherwise it's | ||
5563 | * required. OV518 has no uncompressed mode, to save RAM. */ | ||
5564 | if (!dumppix && !ov->compress) { | ||
5565 | ov->compress = 1; | ||
5566 | warn("Compression required with OV518...enabling"); | ||
5567 | } | ||
5568 | |||
5569 | if (ov->bridge == BRG_OV518) { | ||
5570 | if (write_regvals(ov, aRegvalsNorm518)) | ||
5571 | goto error; | ||
5572 | } else if (ov->bridge == BRG_OV518PLUS) { | ||
5573 | if (write_regvals(ov, aRegvalsNorm518Plus)) | ||
5574 | goto error; | ||
5575 | } else { | ||
5576 | err("Invalid bridge"); | ||
5577 | } | ||
5578 | |||
5579 | if (reg_w(ov, 0x2f, 0x80) < 0) | ||
5580 | goto error; | ||
5581 | |||
5582 | if (ov518_init_compression(ov)) | ||
5583 | goto error; | ||
5584 | |||
5585 | if (ov->bridge == BRG_OV518) | ||
5586 | { | ||
5587 | struct usb_interface *ifp; | ||
5588 | struct usb_host_interface *alt; | ||
5589 | __u16 mxps = 0; | ||
5590 | |||
5591 | ifp = usb_ifnum_to_if(ov->dev, 0); | ||
5592 | if (ifp) { | ||
5593 | alt = usb_altnum_to_altsetting(ifp, 7); | ||
5594 | if (alt) | ||
5595 | mxps = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); | ||
5596 | } | ||
5597 | |||
5598 | /* Some OV518s have packet numbering by default, some don't */ | ||
5599 | if (mxps == 897) | ||
5600 | ov->packet_numbering = 1; | ||
5601 | else | ||
5602 | ov->packet_numbering = 0; | ||
5603 | } else { | ||
5604 | /* OV518+ has packet numbering turned on by default */ | ||
5605 | ov->packet_numbering = 1; | ||
5606 | } | ||
5607 | |||
5608 | ov518_set_packet_size(ov, 0); | ||
5609 | |||
5610 | ov->snap_enabled = snapshot; | ||
5611 | |||
5612 | /* Test for 76xx */ | ||
5613 | ov->primary_i2c_slave = OV7xx0_SID; | ||
5614 | if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) | ||
5615 | goto error; | ||
5616 | |||
5617 | /* The OV518 must be more aggressive about sensor detection since | ||
5618 | * I2C write will never fail if the sensor is not present. We have | ||
5619 | * to try to initialize the sensor to detect its presence */ | ||
5620 | |||
5621 | if (init_ov_sensor(ov) < 0) { | ||
5622 | /* Test for 6xx0 */ | ||
5623 | ov->primary_i2c_slave = OV6xx0_SID; | ||
5624 | if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) | ||
5625 | goto error; | ||
5626 | |||
5627 | if (init_ov_sensor(ov) < 0) { | ||
5628 | /* Test for 8xx0 */ | ||
5629 | ov->primary_i2c_slave = OV8xx0_SID; | ||
5630 | if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) | ||
5631 | goto error; | ||
5632 | |||
5633 | if (init_ov_sensor(ov) < 0) { | ||
5634 | err("Can't determine sensor slave IDs"); | ||
5635 | goto error; | ||
5636 | } else { | ||
5637 | err("Detected unsupported OV8xx0 sensor"); | ||
5638 | goto error; | ||
5639 | } | ||
5640 | } else { | ||
5641 | if (ov6xx0_configure(ov) < 0) { | ||
5642 | err("Failed to configure OV6xx0"); | ||
5643 | goto error; | ||
5644 | } | ||
5645 | } | ||
5646 | } else { | ||
5647 | if (ov7xx0_configure(ov) < 0) { | ||
5648 | err("Failed to configure OV7xx0"); | ||
5649 | goto error; | ||
5650 | } | ||
5651 | } | ||
5652 | |||
5653 | ov->maxwidth = 352; | ||
5654 | ov->maxheight = 288; | ||
5655 | |||
5656 | // The OV518 cannot go as low as the sensor can | ||
5657 | ov->minwidth = 160; | ||
5658 | ov->minheight = 120; | ||
5659 | |||
5660 | return 0; | ||
5661 | |||
5662 | error: | ||
5663 | err("OV518 Config failed"); | ||
5664 | |||
5665 | return -EBUSY; | ||
5666 | } | ||
5667 | |||
5668 | /**************************************************************************** | ||
5669 | * sysfs | ||
5670 | ***************************************************************************/ | ||
5671 | |||
5672 | static inline struct usb_ov511 *cd_to_ov(struct class_device *cd) | ||
5673 | { | ||
5674 | struct video_device *vdev = to_video_device(cd); | ||
5675 | return video_get_drvdata(vdev); | ||
5676 | } | ||
5677 | |||
5678 | static ssize_t show_custom_id(struct class_device *cd, char *buf) | ||
5679 | { | ||
5680 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5681 | return sprintf(buf, "%d\n", ov->customid); | ||
5682 | } | ||
5683 | static CLASS_DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL); | ||
5684 | |||
5685 | static ssize_t show_model(struct class_device *cd, char *buf) | ||
5686 | { | ||
5687 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5688 | return sprintf(buf, "%s\n", ov->desc); | ||
5689 | } | ||
5690 | static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); | ||
5691 | |||
5692 | static ssize_t show_bridge(struct class_device *cd, char *buf) | ||
5693 | { | ||
5694 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5695 | return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge)); | ||
5696 | } | ||
5697 | static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL); | ||
5698 | |||
5699 | static ssize_t show_sensor(struct class_device *cd, char *buf) | ||
5700 | { | ||
5701 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5702 | return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor)); | ||
5703 | } | ||
5704 | static CLASS_DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL); | ||
5705 | |||
5706 | static ssize_t show_brightness(struct class_device *cd, char *buf) | ||
5707 | { | ||
5708 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5709 | unsigned short x; | ||
5710 | |||
5711 | if (!ov->dev) | ||
5712 | return -ENODEV; | ||
5713 | sensor_get_brightness(ov, &x); | ||
5714 | return sprintf(buf, "%d\n", x >> 8); | ||
5715 | } | ||
5716 | static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); | ||
5717 | |||
5718 | static ssize_t show_saturation(struct class_device *cd, char *buf) | ||
5719 | { | ||
5720 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5721 | unsigned short x; | ||
5722 | |||
5723 | if (!ov->dev) | ||
5724 | return -ENODEV; | ||
5725 | sensor_get_saturation(ov, &x); | ||
5726 | return sprintf(buf, "%d\n", x >> 8); | ||
5727 | } | ||
5728 | static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); | ||
5729 | |||
5730 | static ssize_t show_contrast(struct class_device *cd, char *buf) | ||
5731 | { | ||
5732 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5733 | unsigned short x; | ||
5734 | |||
5735 | if (!ov->dev) | ||
5736 | return -ENODEV; | ||
5737 | sensor_get_contrast(ov, &x); | ||
5738 | return sprintf(buf, "%d\n", x >> 8); | ||
5739 | } | ||
5740 | static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); | ||
5741 | |||
5742 | static ssize_t show_hue(struct class_device *cd, char *buf) | ||
5743 | { | ||
5744 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5745 | unsigned short x; | ||
5746 | |||
5747 | if (!ov->dev) | ||
5748 | return -ENODEV; | ||
5749 | sensor_get_hue(ov, &x); | ||
5750 | return sprintf(buf, "%d\n", x >> 8); | ||
5751 | } | ||
5752 | static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); | ||
5753 | |||
5754 | static ssize_t show_exposure(struct class_device *cd, char *buf) | ||
5755 | { | ||
5756 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5757 | unsigned char exp; | ||
5758 | |||
5759 | if (!ov->dev) | ||
5760 | return -ENODEV; | ||
5761 | sensor_get_exposure(ov, &exp); | ||
5762 | return sprintf(buf, "%d\n", exp >> 8); | ||
5763 | } | ||
5764 | static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); | ||
5765 | |||
5766 | static void ov_create_sysfs(struct video_device *vdev) | ||
5767 | { | ||
5768 | video_device_create_file(vdev, &class_device_attr_custom_id); | ||
5769 | video_device_create_file(vdev, &class_device_attr_model); | ||
5770 | video_device_create_file(vdev, &class_device_attr_bridge); | ||
5771 | video_device_create_file(vdev, &class_device_attr_sensor); | ||
5772 | video_device_create_file(vdev, &class_device_attr_brightness); | ||
5773 | video_device_create_file(vdev, &class_device_attr_saturation); | ||
5774 | video_device_create_file(vdev, &class_device_attr_contrast); | ||
5775 | video_device_create_file(vdev, &class_device_attr_hue); | ||
5776 | video_device_create_file(vdev, &class_device_attr_exposure); | ||
5777 | } | ||
5778 | |||
5779 | /**************************************************************************** | ||
5780 | * USB routines | ||
5781 | ***************************************************************************/ | ||
5782 | |||
5783 | static int | ||
5784 | ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
5785 | { | ||
5786 | struct usb_device *dev = interface_to_usbdev(intf); | ||
5787 | struct usb_interface_descriptor *idesc; | ||
5788 | struct usb_ov511 *ov; | ||
5789 | int i; | ||
5790 | |||
5791 | PDEBUG(1, "probing for device..."); | ||
5792 | |||
5793 | /* We don't handle multi-config cameras */ | ||
5794 | if (dev->descriptor.bNumConfigurations != 1) | ||
5795 | return -ENODEV; | ||
5796 | |||
5797 | idesc = &intf->cur_altsetting->desc; | ||
5798 | |||
5799 | if (idesc->bInterfaceClass != 0xFF) | ||
5800 | return -ENODEV; | ||
5801 | if (idesc->bInterfaceSubClass != 0x00) | ||
5802 | return -ENODEV; | ||
5803 | |||
5804 | if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) { | ||
5805 | err("couldn't kmalloc ov struct"); | ||
5806 | goto error_out; | ||
5807 | } | ||
5808 | |||
5809 | memset(ov, 0, sizeof(*ov)); | ||
5810 | |||
5811 | ov->dev = dev; | ||
5812 | ov->iface = idesc->bInterfaceNumber; | ||
5813 | ov->led_policy = led; | ||
5814 | ov->compress = compress; | ||
5815 | ov->lightfreq = lightfreq; | ||
5816 | ov->num_inputs = 1; /* Video decoder init functs. change this */ | ||
5817 | ov->stop_during_set = !fastset; | ||
5818 | ov->backlight = backlight; | ||
5819 | ov->mirror = mirror; | ||
5820 | ov->auto_brt = autobright; | ||
5821 | ov->auto_gain = autogain; | ||
5822 | ov->auto_exp = autoexp; | ||
5823 | |||
5824 | switch (le16_to_cpu(dev->descriptor.idProduct)) { | ||
5825 | case PROD_OV511: | ||
5826 | ov->bridge = BRG_OV511; | ||
5827 | ov->bclass = BCL_OV511; | ||
5828 | break; | ||
5829 | case PROD_OV511PLUS: | ||
5830 | ov->bridge = BRG_OV511PLUS; | ||
5831 | ov->bclass = BCL_OV511; | ||
5832 | break; | ||
5833 | case PROD_OV518: | ||
5834 | ov->bridge = BRG_OV518; | ||
5835 | ov->bclass = BCL_OV518; | ||
5836 | break; | ||
5837 | case PROD_OV518PLUS: | ||
5838 | ov->bridge = BRG_OV518PLUS; | ||
5839 | ov->bclass = BCL_OV518; | ||
5840 | break; | ||
5841 | case PROD_ME2CAM: | ||
5842 | if (le16_to_cpu(dev->descriptor.idVendor) != VEND_MATTEL) | ||
5843 | goto error; | ||
5844 | ov->bridge = BRG_OV511PLUS; | ||
5845 | ov->bclass = BCL_OV511; | ||
5846 | break; | ||
5847 | default: | ||
5848 | err("Unknown product ID 0x%04x", le16_to_cpu(dev->descriptor.idProduct)); | ||
5849 | goto error; | ||
5850 | } | ||
5851 | |||
5852 | info("USB %s video device found", symbolic(brglist, ov->bridge)); | ||
5853 | |||
5854 | init_waitqueue_head(&ov->wq); | ||
5855 | |||
5856 | init_MUTEX(&ov->lock); /* to 1 == available */ | ||
5857 | init_MUTEX(&ov->buf_lock); | ||
5858 | init_MUTEX(&ov->param_lock); | ||
5859 | init_MUTEX(&ov->i2c_lock); | ||
5860 | init_MUTEX(&ov->cbuf_lock); | ||
5861 | |||
5862 | ov->buf_state = BUF_NOT_ALLOCATED; | ||
5863 | |||
5864 | if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) { | ||
5865 | err("usb_make_path error"); | ||
5866 | goto error; | ||
5867 | } | ||
5868 | |||
5869 | /* Allocate control transfer buffer. */ | ||
5870 | /* Must be kmalloc()'ed, for DMA compatibility */ | ||
5871 | ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL); | ||
5872 | if (!ov->cbuf) | ||
5873 | goto error; | ||
5874 | |||
5875 | if (ov->bclass == BCL_OV518) { | ||
5876 | if (ov518_configure(ov) < 0) | ||
5877 | goto error; | ||
5878 | } else { | ||
5879 | if (ov511_configure(ov) < 0) | ||
5880 | goto error; | ||
5881 | } | ||
5882 | |||
5883 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
5884 | ov->frame[i].framenum = i; | ||
5885 | init_waitqueue_head(&ov->frame[i].wq); | ||
5886 | } | ||
5887 | |||
5888 | for (i = 0; i < OV511_NUMSBUF; i++) { | ||
5889 | ov->sbuf[i].ov = ov; | ||
5890 | spin_lock_init(&ov->sbuf[i].lock); | ||
5891 | ov->sbuf[i].n = i; | ||
5892 | } | ||
5893 | |||
5894 | /* Unnecessary? (This is done on open(). Need to make sure variables | ||
5895 | * are properly initialized without this before removing it, though). */ | ||
5896 | if (ov51x_set_default_params(ov) < 0) | ||
5897 | goto error; | ||
5898 | |||
5899 | #ifdef OV511_DEBUG | ||
5900 | if (dump_bridge) { | ||
5901 | if (ov->bclass == BCL_OV511) | ||
5902 | ov511_dump_regs(ov); | ||
5903 | else | ||
5904 | ov518_dump_regs(ov); | ||
5905 | } | ||
5906 | #endif | ||
5907 | |||
5908 | ov->vdev = video_device_alloc(); | ||
5909 | if (!ov->vdev) | ||
5910 | goto error; | ||
5911 | |||
5912 | memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev)); | ||
5913 | ov->vdev->dev = &dev->dev; | ||
5914 | video_set_drvdata(ov->vdev, ov); | ||
5915 | |||
5916 | for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) { | ||
5917 | /* Minor 0 cannot be specified; assume user wants autodetect */ | ||
5918 | if (unit_video[i] == 0) | ||
5919 | break; | ||
5920 | |||
5921 | if (video_register_device(ov->vdev, VFL_TYPE_GRABBER, | ||
5922 | unit_video[i]) >= 0) { | ||
5923 | break; | ||
5924 | } | ||
5925 | } | ||
5926 | |||
5927 | /* Use the next available one */ | ||
5928 | if ((ov->vdev->minor == -1) && | ||
5929 | video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1) < 0) { | ||
5930 | err("video_register_device failed"); | ||
5931 | goto error; | ||
5932 | } | ||
5933 | |||
5934 | info("Device at %s registered to minor %d", ov->usb_path, | ||
5935 | ov->vdev->minor); | ||
5936 | |||
5937 | usb_set_intfdata(intf, ov); | ||
5938 | ov_create_sysfs(ov->vdev); | ||
5939 | return 0; | ||
5940 | |||
5941 | error: | ||
5942 | if (ov->vdev) { | ||
5943 | if (-1 == ov->vdev->minor) | ||
5944 | video_device_release(ov->vdev); | ||
5945 | else | ||
5946 | video_unregister_device(ov->vdev); | ||
5947 | ov->vdev = NULL; | ||
5948 | } | ||
5949 | |||
5950 | if (ov->cbuf) { | ||
5951 | down(&ov->cbuf_lock); | ||
5952 | kfree(ov->cbuf); | ||
5953 | ov->cbuf = NULL; | ||
5954 | up(&ov->cbuf_lock); | ||
5955 | } | ||
5956 | |||
5957 | if (ov) { | ||
5958 | kfree(ov); | ||
5959 | ov = NULL; | ||
5960 | } | ||
5961 | |||
5962 | error_out: | ||
5963 | err("Camera initialization failed"); | ||
5964 | return -EIO; | ||
5965 | } | ||
5966 | |||
5967 | static void | ||
5968 | ov51x_disconnect(struct usb_interface *intf) | ||
5969 | { | ||
5970 | struct usb_ov511 *ov = usb_get_intfdata(intf); | ||
5971 | int n; | ||
5972 | |||
5973 | PDEBUG(3, ""); | ||
5974 | |||
5975 | usb_set_intfdata (intf, NULL); | ||
5976 | |||
5977 | if (!ov) | ||
5978 | return; | ||
5979 | |||
5980 | if (ov->vdev) | ||
5981 | video_unregister_device(ov->vdev); | ||
5982 | |||
5983 | for (n = 0; n < OV511_NUMFRAMES; n++) | ||
5984 | ov->frame[n].grabstate = FRAME_ERROR; | ||
5985 | |||
5986 | ov->curframe = -1; | ||
5987 | |||
5988 | /* This will cause the process to request another frame */ | ||
5989 | for (n = 0; n < OV511_NUMFRAMES; n++) | ||
5990 | wake_up_interruptible(&ov->frame[n].wq); | ||
5991 | |||
5992 | wake_up_interruptible(&ov->wq); | ||
5993 | |||
5994 | ov->streaming = 0; | ||
5995 | ov51x_unlink_isoc(ov); | ||
5996 | |||
5997 | ov->dev = NULL; | ||
5998 | |||
5999 | /* Free the memory */ | ||
6000 | if (ov && !ov->user) { | ||
6001 | down(&ov->cbuf_lock); | ||
6002 | kfree(ov->cbuf); | ||
6003 | ov->cbuf = NULL; | ||
6004 | up(&ov->cbuf_lock); | ||
6005 | |||
6006 | ov51x_dealloc(ov); | ||
6007 | kfree(ov); | ||
6008 | ov = NULL; | ||
6009 | } | ||
6010 | |||
6011 | PDEBUG(3, "Disconnect complete"); | ||
6012 | } | ||
6013 | |||
6014 | static struct usb_driver ov511_driver = { | ||
6015 | .owner = THIS_MODULE, | ||
6016 | .name = "ov511", | ||
6017 | .id_table = device_table, | ||
6018 | .probe = ov51x_probe, | ||
6019 | .disconnect = ov51x_disconnect | ||
6020 | }; | ||
6021 | |||
6022 | /**************************************************************************** | ||
6023 | * | ||
6024 | * Module routines | ||
6025 | * | ||
6026 | ***************************************************************************/ | ||
6027 | |||
6028 | /* Returns 0 for success */ | ||
6029 | int | ||
6030 | ov511_register_decomp_module(int ver, struct ov51x_decomp_ops *ops, int ov518, | ||
6031 | int mmx) | ||
6032 | { | ||
6033 | if (ver != DECOMP_INTERFACE_VER) { | ||
6034 | err("Decompression module has incompatible"); | ||
6035 | err("interface version %d", ver); | ||
6036 | err("Interface version %d is required", DECOMP_INTERFACE_VER); | ||
6037 | return -EINVAL; | ||
6038 | } | ||
6039 | |||
6040 | if (!ops) | ||
6041 | return -EFAULT; | ||
6042 | |||
6043 | if (mmx && !ov51x_mmx_available) { | ||
6044 | err("MMX not available on this system or kernel"); | ||
6045 | return -EINVAL; | ||
6046 | } | ||
6047 | |||
6048 | lock_kernel(); | ||
6049 | |||
6050 | if (ov518) { | ||
6051 | if (mmx) { | ||
6052 | if (ov518_mmx_decomp_ops) | ||
6053 | goto err_in_use; | ||
6054 | else | ||
6055 | ov518_mmx_decomp_ops = ops; | ||
6056 | } else { | ||
6057 | if (ov518_decomp_ops) | ||
6058 | goto err_in_use; | ||
6059 | else | ||
6060 | ov518_decomp_ops = ops; | ||
6061 | } | ||
6062 | } else { | ||
6063 | if (mmx) { | ||
6064 | if (ov511_mmx_decomp_ops) | ||
6065 | goto err_in_use; | ||
6066 | else | ||
6067 | ov511_mmx_decomp_ops = ops; | ||
6068 | } else { | ||
6069 | if (ov511_decomp_ops) | ||
6070 | goto err_in_use; | ||
6071 | else | ||
6072 | ov511_decomp_ops = ops; | ||
6073 | } | ||
6074 | } | ||
6075 | |||
6076 | unlock_kernel(); | ||
6077 | return 0; | ||
6078 | |||
6079 | err_in_use: | ||
6080 | unlock_kernel(); | ||
6081 | return -EBUSY; | ||
6082 | } | ||
6083 | |||
6084 | void | ||
6085 | ov511_deregister_decomp_module(int ov518, int mmx) | ||
6086 | { | ||
6087 | lock_kernel(); | ||
6088 | |||
6089 | if (ov518) { | ||
6090 | if (mmx) | ||
6091 | ov518_mmx_decomp_ops = NULL; | ||
6092 | else | ||
6093 | ov518_decomp_ops = NULL; | ||
6094 | } else { | ||
6095 | if (mmx) | ||
6096 | ov511_mmx_decomp_ops = NULL; | ||
6097 | else | ||
6098 | ov511_decomp_ops = NULL; | ||
6099 | } | ||
6100 | |||
6101 | unlock_kernel(); | ||
6102 | } | ||
6103 | |||
6104 | static int __init | ||
6105 | usb_ov511_init(void) | ||
6106 | { | ||
6107 | int retval; | ||
6108 | |||
6109 | retval = usb_register(&ov511_driver); | ||
6110 | if (retval) | ||
6111 | goto out; | ||
6112 | |||
6113 | info(DRIVER_VERSION " : " DRIVER_DESC); | ||
6114 | |||
6115 | out: | ||
6116 | return retval; | ||
6117 | } | ||
6118 | |||
6119 | static void __exit | ||
6120 | usb_ov511_exit(void) | ||
6121 | { | ||
6122 | usb_deregister(&ov511_driver); | ||
6123 | info("driver deregistered"); | ||
6124 | |||
6125 | } | ||
6126 | |||
6127 | module_init(usb_ov511_init); | ||
6128 | module_exit(usb_ov511_exit); | ||
6129 | |||
6130 | EXPORT_SYMBOL(ov511_register_decomp_module); | ||
6131 | EXPORT_SYMBOL(ov511_deregister_decomp_module); | ||
diff --git a/drivers/usb/media/ov511.h b/drivers/usb/media/ov511.h new file mode 100644 index 000000000000..086509a137c6 --- /dev/null +++ b/drivers/usb/media/ov511.h | |||
@@ -0,0 +1,569 @@ | |||
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 | |||
9 | #define OV511_DEBUG /* Turn on debug messages */ | ||
10 | |||
11 | #ifdef OV511_DEBUG | ||
12 | #define PDEBUG(level, fmt, args...) \ | ||
13 | if (debug >= (level)) info("[%s:%d] " fmt, \ | ||
14 | __FUNCTION__, __LINE__ , ## args) | ||
15 | #else | ||
16 | #define PDEBUG(level, fmt, args...) do {} while(0) | ||
17 | #endif | ||
18 | |||
19 | /* This macro restricts an int variable to an inclusive range */ | ||
20 | #define RESTRICT_TO_RANGE(v,mi,ma) { \ | ||
21 | if ((v) < (mi)) (v) = (mi); \ | ||
22 | else if ((v) > (ma)) (v) = (ma); \ | ||
23 | } | ||
24 | |||
25 | /* --------------------------------- */ | ||
26 | /* DEFINES FOR OV511 AND OTHER CHIPS */ | ||
27 | /* --------------------------------- */ | ||
28 | |||
29 | /* USB IDs */ | ||
30 | #define VEND_OMNIVISION 0x05A9 | ||
31 | #define PROD_OV511 0x0511 | ||
32 | #define PROD_OV511PLUS 0xA511 | ||
33 | #define PROD_OV518 0x0518 | ||
34 | #define PROD_OV518PLUS 0xA518 | ||
35 | |||
36 | #define VEND_MATTEL 0x0813 | ||
37 | #define PROD_ME2CAM 0x0002 | ||
38 | |||
39 | /* --------------------------------- */ | ||
40 | /* OV51x REGISTER MNEMONICS */ | ||
41 | /* --------------------------------- */ | ||
42 | |||
43 | /* Camera interface register numbers */ | ||
44 | #define R511_CAM_DELAY 0x10 | ||
45 | #define R511_CAM_EDGE 0x11 | ||
46 | #define R511_CAM_PXCNT 0x12 | ||
47 | #define R511_CAM_LNCNT 0x13 | ||
48 | #define R511_CAM_PXDIV 0x14 | ||
49 | #define R511_CAM_LNDIV 0x15 | ||
50 | #define R511_CAM_UV_EN 0x16 | ||
51 | #define R511_CAM_LINE_MODE 0x17 | ||
52 | #define R511_CAM_OPTS 0x18 | ||
53 | |||
54 | /* Snapshot mode camera interface register numbers */ | ||
55 | #define R511_SNAP_FRAME 0x19 | ||
56 | #define R511_SNAP_PXCNT 0x1A | ||
57 | #define R511_SNAP_LNCNT 0x1B | ||
58 | #define R511_SNAP_PXDIV 0x1C | ||
59 | #define R511_SNAP_LNDIV 0x1D | ||
60 | #define R511_SNAP_UV_EN 0x1E | ||
61 | #define R511_SNAP_OPTS 0x1F | ||
62 | |||
63 | /* DRAM register numbers */ | ||
64 | #define R511_DRAM_FLOW_CTL 0x20 | ||
65 | #define R511_DRAM_ARCP 0x21 | ||
66 | #define R511_DRAM_MRC 0x22 | ||
67 | #define R511_DRAM_RFC 0x23 | ||
68 | |||
69 | /* ISO FIFO register numbers */ | ||
70 | #define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */ | ||
71 | #define R511_FIFO_OPTS 0x31 | ||
72 | |||
73 | /* Parallel IO register numbers */ | ||
74 | #define R511_PIO_OPTS 0x38 | ||
75 | #define R511_PIO_DATA 0x39 | ||
76 | #define R511_PIO_BIST 0x3E | ||
77 | #define R518_GPIO_IN 0x55 /* OV518(+) only */ | ||
78 | #define R518_GPIO_OUT 0x56 /* OV518(+) only */ | ||
79 | #define R518_GPIO_CTL 0x57 /* OV518(+) only */ | ||
80 | #define R518_GPIO_PULSE_IN 0x58 /* OV518(+) only */ | ||
81 | #define R518_GPIO_PULSE_CLEAR 0x59 /* OV518(+) only */ | ||
82 | #define R518_GPIO_PULSE_POL 0x5a /* OV518(+) only */ | ||
83 | #define R518_GPIO_PULSE_EN 0x5b /* OV518(+) only */ | ||
84 | #define R518_GPIO_RESET 0x5c /* OV518(+) only */ | ||
85 | |||
86 | /* I2C registers */ | ||
87 | #define R511_I2C_CTL 0x40 | ||
88 | #define R518_I2C_CTL 0x47 /* OV518(+) only */ | ||
89 | #define R51x_I2C_W_SID 0x41 | ||
90 | #define R51x_I2C_SADDR_3 0x42 | ||
91 | #define R51x_I2C_SADDR_2 0x43 | ||
92 | #define R51x_I2C_R_SID 0x44 | ||
93 | #define R51x_I2C_DATA 0x45 | ||
94 | #define R51x_I2C_CLOCK 0x46 | ||
95 | #define R51x_I2C_TIMEOUT 0x47 | ||
96 | |||
97 | /* I2C snapshot registers */ | ||
98 | #define R511_SI2C_SADDR_3 0x48 | ||
99 | #define R511_SI2C_DATA 0x49 | ||
100 | |||
101 | /* System control registers */ | ||
102 | #define R51x_SYS_RESET 0x50 | ||
103 | /* Reset type definitions */ | ||
104 | #define OV511_RESET_UDC 0x01 | ||
105 | #define OV511_RESET_I2C 0x02 | ||
106 | #define OV511_RESET_FIFO 0x04 | ||
107 | #define OV511_RESET_OMNICE 0x08 | ||
108 | #define OV511_RESET_DRAM 0x10 | ||
109 | #define OV511_RESET_CAM_INT 0x20 | ||
110 | #define OV511_RESET_OV511 0x40 | ||
111 | #define OV511_RESET_NOREGS 0x3F /* All but OV511 & regs */ | ||
112 | #define OV511_RESET_ALL 0x7F | ||
113 | |||
114 | #define R511_SYS_CLOCK_DIV 0x51 | ||
115 | #define R51x_SYS_SNAP 0x52 | ||
116 | #define R51x_SYS_INIT 0x53 | ||
117 | #define R511_SYS_PWR_CLK 0x54 /* OV511+/OV518(+) only */ | ||
118 | #define R511_SYS_LED_CTL 0x55 /* OV511+ only */ | ||
119 | #define R511_SYS_USER 0x5E | ||
120 | #define R511_SYS_CUST_ID 0x5F | ||
121 | |||
122 | /* OmniCE (compression) registers */ | ||
123 | #define R511_COMP_PHY 0x70 | ||
124 | #define R511_COMP_PHUV 0x71 | ||
125 | #define R511_COMP_PVY 0x72 | ||
126 | #define R511_COMP_PVUV 0x73 | ||
127 | #define R511_COMP_QHY 0x74 | ||
128 | #define R511_COMP_QHUV 0x75 | ||
129 | #define R511_COMP_QVY 0x76 | ||
130 | #define R511_COMP_QVUV 0x77 | ||
131 | #define R511_COMP_EN 0x78 | ||
132 | #define R511_COMP_LUT_EN 0x79 | ||
133 | #define R511_COMP_LUT_BEGIN 0x80 | ||
134 | |||
135 | /* --------------------------------- */ | ||
136 | /* ALTERNATE NUMBERS */ | ||
137 | /* --------------------------------- */ | ||
138 | |||
139 | /* Alternate numbers for various max packet sizes (OV511 only) */ | ||
140 | #define OV511_ALT_SIZE_992 0 | ||
141 | #define OV511_ALT_SIZE_993 1 | ||
142 | #define OV511_ALT_SIZE_768 2 | ||
143 | #define OV511_ALT_SIZE_769 3 | ||
144 | #define OV511_ALT_SIZE_512 4 | ||
145 | #define OV511_ALT_SIZE_513 5 | ||
146 | #define OV511_ALT_SIZE_257 6 | ||
147 | #define OV511_ALT_SIZE_0 7 | ||
148 | |||
149 | /* Alternate numbers for various max packet sizes (OV511+ only) */ | ||
150 | #define OV511PLUS_ALT_SIZE_0 0 | ||
151 | #define OV511PLUS_ALT_SIZE_33 1 | ||
152 | #define OV511PLUS_ALT_SIZE_129 2 | ||
153 | #define OV511PLUS_ALT_SIZE_257 3 | ||
154 | #define OV511PLUS_ALT_SIZE_385 4 | ||
155 | #define OV511PLUS_ALT_SIZE_513 5 | ||
156 | #define OV511PLUS_ALT_SIZE_769 6 | ||
157 | #define OV511PLUS_ALT_SIZE_961 7 | ||
158 | |||
159 | /* Alternate numbers for various max packet sizes (OV518(+) only) */ | ||
160 | #define OV518_ALT_SIZE_0 0 | ||
161 | #define OV518_ALT_SIZE_128 1 | ||
162 | #define OV518_ALT_SIZE_256 2 | ||
163 | #define OV518_ALT_SIZE_384 3 | ||
164 | #define OV518_ALT_SIZE_512 4 | ||
165 | #define OV518_ALT_SIZE_640 5 | ||
166 | #define OV518_ALT_SIZE_768 6 | ||
167 | #define OV518_ALT_SIZE_896 7 | ||
168 | |||
169 | /* --------------------------------- */ | ||
170 | /* OV7610 REGISTER MNEMONICS */ | ||
171 | /* --------------------------------- */ | ||
172 | |||
173 | /* OV7610 registers */ | ||
174 | #define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */ | ||
175 | #define OV7610_REG_BLUE 0x01 /* blue channel balance */ | ||
176 | #define OV7610_REG_RED 0x02 /* red channel balance */ | ||
177 | #define OV7610_REG_SAT 0x03 /* saturation */ | ||
178 | /* 04 reserved */ | ||
179 | #define OV7610_REG_CNT 0x05 /* Y contrast */ | ||
180 | #define OV7610_REG_BRT 0x06 /* Y brightness */ | ||
181 | /* 08-0b reserved */ | ||
182 | #define OV7610_REG_BLUE_BIAS 0x0C /* blue channel bias (5:0) */ | ||
183 | #define OV7610_REG_RED_BIAS 0x0D /* read channel bias (5:0) */ | ||
184 | #define OV7610_REG_GAMMA_COEFF 0x0E /* gamma settings */ | ||
185 | #define OV7610_REG_WB_RANGE 0x0F /* AEC/ALC/S-AWB settings */ | ||
186 | #define OV7610_REG_EXP 0x10 /* manual exposure setting */ | ||
187 | #define OV7610_REG_CLOCK 0x11 /* polarity/clock prescaler */ | ||
188 | #define OV7610_REG_COM_A 0x12 /* misc common regs */ | ||
189 | #define OV7610_REG_COM_B 0x13 /* misc common regs */ | ||
190 | #define OV7610_REG_COM_C 0x14 /* misc common regs */ | ||
191 | #define OV7610_REG_COM_D 0x15 /* misc common regs */ | ||
192 | #define OV7610_REG_FIELD_DIVIDE 0x16 /* field interval/mode settings */ | ||
193 | #define OV7610_REG_HWIN_START 0x17 /* horizontal window start */ | ||
194 | #define OV7610_REG_HWIN_END 0x18 /* horizontal window end */ | ||
195 | #define OV7610_REG_VWIN_START 0x19 /* vertical window start */ | ||
196 | #define OV7610_REG_VWIN_END 0x1A /* vertical window end */ | ||
197 | #define OV7610_REG_PIXEL_SHIFT 0x1B /* pixel shift */ | ||
198 | #define OV7610_REG_ID_HIGH 0x1C /* manufacturer ID MSB */ | ||
199 | #define OV7610_REG_ID_LOW 0x1D /* manufacturer ID LSB */ | ||
200 | /* 0e-0f reserved */ | ||
201 | #define OV7610_REG_COM_E 0x20 /* misc common regs */ | ||
202 | #define OV7610_REG_YOFFSET 0x21 /* Y channel offset */ | ||
203 | #define OV7610_REG_UOFFSET 0x22 /* U channel offset */ | ||
204 | /* 23 reserved */ | ||
205 | #define OV7610_REG_ECW 0x24 /* Exposure white level for AEC */ | ||
206 | #define OV7610_REG_ECB 0x25 /* Exposure black level for AEC */ | ||
207 | #define OV7610_REG_COM_F 0x26 /* misc settings */ | ||
208 | #define OV7610_REG_COM_G 0x27 /* misc settings */ | ||
209 | #define OV7610_REG_COM_H 0x28 /* misc settings */ | ||
210 | #define OV7610_REG_COM_I 0x29 /* misc settings */ | ||
211 | #define OV7610_REG_FRAMERATE_H 0x2A /* frame rate MSB + misc */ | ||
212 | #define OV7610_REG_FRAMERATE_L 0x2B /* frame rate LSB */ | ||
213 | #define OV7610_REG_ALC 0x2C /* Auto Level Control settings */ | ||
214 | #define OV7610_REG_COM_J 0x2D /* misc settings */ | ||
215 | #define OV7610_REG_VOFFSET 0x2E /* V channel offset adjustment */ | ||
216 | #define OV7610_REG_ARRAY_BIAS 0x2F /* Array bias -- don't change */ | ||
217 | /* 30-32 reserved */ | ||
218 | #define OV7610_REG_YGAMMA 0x33 /* misc gamma settings (7:6) */ | ||
219 | #define OV7610_REG_BIAS_ADJUST 0x34 /* misc bias settings */ | ||
220 | #define OV7610_REG_COM_L 0x35 /* misc settings */ | ||
221 | /* 36-37 reserved */ | ||
222 | #define OV7610_REG_COM_K 0x38 /* misc registers */ | ||
223 | |||
224 | /* --------------------------------- */ | ||
225 | /* I2C ADDRESSES */ | ||
226 | /* --------------------------------- */ | ||
227 | |||
228 | #define OV7xx0_SID 0x42 | ||
229 | #define OV6xx0_SID 0xC0 | ||
230 | #define OV8xx0_SID 0xA0 | ||
231 | #define KS0127_SID 0xD8 | ||
232 | #define SAA7111A_SID 0x48 | ||
233 | |||
234 | /* --------------------------------- */ | ||
235 | /* MISCELLANEOUS DEFINES */ | ||
236 | /* --------------------------------- */ | ||
237 | |||
238 | #define I2C_CLOCK_PRESCALER 0x03 | ||
239 | |||
240 | #define FRAMES_PER_DESC 10 /* FIXME - What should this be? */ | ||
241 | #define MAX_FRAME_SIZE_PER_DESC 993 /* For statically allocated stuff */ | ||
242 | #define PIXELS_PER_SEG 256 /* Pixels per segment */ | ||
243 | |||
244 | #define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ | ||
245 | |||
246 | #define OV511_NUMFRAMES 2 | ||
247 | #if OV511_NUMFRAMES > VIDEO_MAX_FRAME | ||
248 | #error "OV511_NUMFRAMES is too high" | ||
249 | #endif | ||
250 | |||
251 | #define OV511_NUMSBUF 2 | ||
252 | |||
253 | /* Control transfers use up to 4 bytes */ | ||
254 | #define OV511_CBUF_SIZE 4 | ||
255 | |||
256 | /* Size of usb_make_path() buffer */ | ||
257 | #define OV511_USB_PATH_LEN 64 | ||
258 | |||
259 | /* Bridge types */ | ||
260 | enum { | ||
261 | BRG_UNKNOWN, | ||
262 | BRG_OV511, | ||
263 | BRG_OV511PLUS, | ||
264 | BRG_OV518, | ||
265 | BRG_OV518PLUS, | ||
266 | }; | ||
267 | |||
268 | /* Bridge classes */ | ||
269 | enum { | ||
270 | BCL_UNKNOWN, | ||
271 | BCL_OV511, | ||
272 | BCL_OV518, | ||
273 | }; | ||
274 | |||
275 | /* Sensor types */ | ||
276 | enum { | ||
277 | SEN_UNKNOWN, | ||
278 | SEN_OV76BE, | ||
279 | SEN_OV7610, | ||
280 | SEN_OV7620, | ||
281 | SEN_OV7620AE, | ||
282 | SEN_OV6620, | ||
283 | SEN_OV6630, | ||
284 | SEN_OV6630AE, | ||
285 | SEN_OV6630AF, | ||
286 | SEN_OV8600, | ||
287 | SEN_KS0127, | ||
288 | SEN_KS0127B, | ||
289 | SEN_SAA7111A, | ||
290 | }; | ||
291 | |||
292 | enum { | ||
293 | STATE_SCANNING, /* Scanning for start */ | ||
294 | STATE_HEADER, /* Parsing header */ | ||
295 | STATE_LINES, /* Parsing lines */ | ||
296 | }; | ||
297 | |||
298 | /* Buffer states */ | ||
299 | enum { | ||
300 | BUF_NOT_ALLOCATED, | ||
301 | BUF_ALLOCATED, | ||
302 | }; | ||
303 | |||
304 | /* --------- Definition of ioctl interface --------- */ | ||
305 | |||
306 | #define OV511_INTERFACE_VER 101 | ||
307 | |||
308 | /* LED options */ | ||
309 | enum { | ||
310 | LED_OFF, | ||
311 | LED_ON, | ||
312 | LED_AUTO, | ||
313 | }; | ||
314 | |||
315 | /* Raw frame formats */ | ||
316 | enum { | ||
317 | RAWFMT_INVALID, | ||
318 | RAWFMT_YUV400, | ||
319 | RAWFMT_YUV420, | ||
320 | RAWFMT_YUV422, | ||
321 | RAWFMT_GBR422, | ||
322 | }; | ||
323 | |||
324 | struct ov511_i2c_struct { | ||
325 | unsigned char slave; /* Write slave ID (read ID - 1) */ | ||
326 | unsigned char reg; /* Index of register */ | ||
327 | unsigned char value; /* User sets this w/ write, driver does w/ read */ | ||
328 | unsigned char mask; /* Bits to be changed. Not used with read ops */ | ||
329 | }; | ||
330 | |||
331 | /* ioctls */ | ||
332 | #define OV511IOC_WI2C _IOW('v', BASE_VIDIOCPRIVATE + 5, \ | ||
333 | struct ov511_i2c_struct) | ||
334 | #define OV511IOC_RI2C _IOWR('v', BASE_VIDIOCPRIVATE + 6, \ | ||
335 | struct ov511_i2c_struct) | ||
336 | /* ------------- End IOCTL interface -------------- */ | ||
337 | |||
338 | struct usb_ov511; /* Forward declaration */ | ||
339 | |||
340 | struct ov511_sbuf { | ||
341 | struct usb_ov511 *ov; | ||
342 | unsigned char *data; | ||
343 | struct urb *urb; | ||
344 | spinlock_t lock; | ||
345 | int n; | ||
346 | }; | ||
347 | |||
348 | enum { | ||
349 | FRAME_UNUSED, /* Unused (no MCAPTURE) */ | ||
350 | FRAME_READY, /* Ready to start grabbing */ | ||
351 | FRAME_GRABBING, /* In the process of being grabbed into */ | ||
352 | FRAME_DONE, /* Finished grabbing, but not been synced yet */ | ||
353 | FRAME_ERROR, /* Something bad happened while processing */ | ||
354 | }; | ||
355 | |||
356 | struct ov511_regvals { | ||
357 | enum { | ||
358 | OV511_DONE_BUS, | ||
359 | OV511_REG_BUS, | ||
360 | OV511_I2C_BUS, | ||
361 | } bus; | ||
362 | unsigned char reg; | ||
363 | unsigned char val; | ||
364 | }; | ||
365 | |||
366 | struct ov511_frame { | ||
367 | int framenum; /* Index of this frame */ | ||
368 | unsigned char *data; /* Frame buffer */ | ||
369 | unsigned char *tempdata; /* Temp buffer for multi-stage conversions */ | ||
370 | unsigned char *rawdata; /* Raw camera data buffer */ | ||
371 | unsigned char *compbuf; /* Temp buffer for decompressor */ | ||
372 | |||
373 | int depth; /* Bytes per pixel */ | ||
374 | int width; /* Width application is expecting */ | ||
375 | int height; /* Height application is expecting */ | ||
376 | |||
377 | int rawwidth; /* Actual width of frame sent from camera */ | ||
378 | int rawheight; /* Actual height of frame sent from camera */ | ||
379 | |||
380 | int sub_flag; /* Sub-capture mode for this frame? */ | ||
381 | unsigned int format; /* Format for this frame */ | ||
382 | int compressed; /* Is frame compressed? */ | ||
383 | |||
384 | volatile int grabstate; /* State of grabbing */ | ||
385 | int scanstate; /* State of scanning */ | ||
386 | |||
387 | int bytes_recvd; /* Number of image bytes received from camera */ | ||
388 | |||
389 | long bytes_read; /* Amount that has been read() */ | ||
390 | |||
391 | wait_queue_head_t wq; /* Processes waiting */ | ||
392 | |||
393 | int snapshot; /* True if frame was a snapshot */ | ||
394 | }; | ||
395 | |||
396 | #define DECOMP_INTERFACE_VER 4 | ||
397 | |||
398 | /* Compression module operations */ | ||
399 | struct ov51x_decomp_ops { | ||
400 | int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *, | ||
401 | int, int, int); | ||
402 | int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *, | ||
403 | int, int, int); | ||
404 | int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *, | ||
405 | int, int, int); | ||
406 | struct module *owner; | ||
407 | }; | ||
408 | |||
409 | struct usb_ov511 { | ||
410 | struct video_device *vdev; | ||
411 | struct usb_device *dev; | ||
412 | |||
413 | int customid; | ||
414 | char *desc; | ||
415 | unsigned char iface; | ||
416 | char usb_path[OV511_USB_PATH_LEN]; | ||
417 | |||
418 | /* Determined by sensor type */ | ||
419 | int maxwidth; | ||
420 | int maxheight; | ||
421 | int minwidth; | ||
422 | int minheight; | ||
423 | |||
424 | int brightness; | ||
425 | int colour; | ||
426 | int contrast; | ||
427 | int hue; | ||
428 | int whiteness; | ||
429 | int exposure; | ||
430 | int auto_brt; /* Auto brightness enabled flag */ | ||
431 | int auto_gain; /* Auto gain control enabled flag */ | ||
432 | int auto_exp; /* Auto exposure enabled flag */ | ||
433 | int backlight; /* Backlight exposure algorithm flag */ | ||
434 | int mirror; /* Image is reversed horizontally */ | ||
435 | |||
436 | int led_policy; /* LED: off|on|auto; OV511+ only */ | ||
437 | |||
438 | struct semaphore lock; /* Serializes user-accessible operations */ | ||
439 | int user; /* user count for exclusive use */ | ||
440 | |||
441 | int streaming; /* Are we streaming Isochronous? */ | ||
442 | int grabbing; /* Are we grabbing? */ | ||
443 | |||
444 | int compress; /* Should the next frame be compressed? */ | ||
445 | int compress_inited; /* Are compression params uploaded? */ | ||
446 | |||
447 | int lightfreq; /* Power (lighting) frequency */ | ||
448 | int bandfilt; /* Banding filter enabled flag */ | ||
449 | |||
450 | unsigned char *fbuf; /* Videodev buffer area */ | ||
451 | unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */ | ||
452 | unsigned char *rawfbuf; /* Raw camera data buffer area */ | ||
453 | |||
454 | int sub_flag; /* Pix Array subcapture on flag */ | ||
455 | int subx; /* Pix Array subcapture x offset */ | ||
456 | int suby; /* Pix Array subcapture y offset */ | ||
457 | int subw; /* Pix Array subcapture width */ | ||
458 | int subh; /* Pix Array subcapture height */ | ||
459 | |||
460 | int curframe; /* Current receiving sbuf */ | ||
461 | struct ov511_frame frame[OV511_NUMFRAMES]; | ||
462 | |||
463 | struct ov511_sbuf sbuf[OV511_NUMSBUF]; | ||
464 | |||
465 | wait_queue_head_t wq; /* Processes waiting */ | ||
466 | |||
467 | int snap_enabled; /* Snapshot mode enabled */ | ||
468 | |||
469 | int bridge; /* Type of bridge (BRG_*) */ | ||
470 | int bclass; /* Class of bridge (BCL_*) */ | ||
471 | int sensor; /* Type of image sensor chip (SEN_*) */ | ||
472 | |||
473 | int packet_size; /* Frame size per isoc desc */ | ||
474 | int packet_numbering; /* Is ISO frame numbering enabled? */ | ||
475 | |||
476 | struct semaphore param_lock; /* params lock for this camera */ | ||
477 | |||
478 | /* Framebuffer/sbuf management */ | ||
479 | int buf_state; | ||
480 | struct semaphore buf_lock; | ||
481 | |||
482 | struct ov51x_decomp_ops *decomp_ops; | ||
483 | |||
484 | /* Stop streaming while changing picture settings */ | ||
485 | int stop_during_set; | ||
486 | |||
487 | int stopped; /* Streaming is temporarily paused */ | ||
488 | |||
489 | /* Video decoder stuff */ | ||
490 | int input; /* Composite, S-VIDEO, etc... */ | ||
491 | int num_inputs; /* Number of inputs */ | ||
492 | int norm; /* NTSC / PAL / SECAM */ | ||
493 | int has_decoder; /* Device has a video decoder */ | ||
494 | int pal; /* Device is designed for PAL resolution */ | ||
495 | |||
496 | /* I2C interface */ | ||
497 | struct semaphore i2c_lock; /* Protect I2C controller regs */ | ||
498 | unsigned char primary_i2c_slave; /* I2C write id of sensor */ | ||
499 | |||
500 | /* Control transaction stuff */ | ||
501 | unsigned char *cbuf; /* Buffer for payload */ | ||
502 | struct semaphore cbuf_lock; | ||
503 | }; | ||
504 | |||
505 | /* Used to represent a list of values and their respective symbolic names */ | ||
506 | struct symbolic_list { | ||
507 | int num; | ||
508 | char *name; | ||
509 | }; | ||
510 | |||
511 | #define NOT_DEFINED_STR "Unknown" | ||
512 | |||
513 | /* Returns the name of the matching element in the symbolic_list array. The | ||
514 | * end of the list must be marked with an element that has a NULL name. | ||
515 | */ | ||
516 | static inline char * | ||
517 | symbolic(struct symbolic_list list[], int num) | ||
518 | { | ||
519 | int i; | ||
520 | |||
521 | for (i = 0; list[i].name != NULL; i++) | ||
522 | if (list[i].num == num) | ||
523 | return (list[i].name); | ||
524 | |||
525 | return (NOT_DEFINED_STR); | ||
526 | } | ||
527 | |||
528 | /* Compression stuff */ | ||
529 | |||
530 | #define OV511_QUANTABLESIZE 64 | ||
531 | #define OV518_QUANTABLESIZE 32 | ||
532 | |||
533 | #define OV511_YQUANTABLE { \ | ||
534 | 0, 1, 1, 2, 2, 3, 3, 4, \ | ||
535 | 1, 1, 1, 2, 2, 3, 4, 4, \ | ||
536 | 1, 1, 2, 2, 3, 4, 4, 4, \ | ||
537 | 2, 2, 2, 3, 4, 4, 4, 4, \ | ||
538 | 2, 2, 3, 4, 4, 5, 5, 5, \ | ||
539 | 3, 3, 4, 4, 5, 5, 5, 5, \ | ||
540 | 3, 4, 4, 4, 5, 5, 5, 5, \ | ||
541 | 4, 4, 4, 4, 5, 5, 5, 5 \ | ||
542 | } | ||
543 | |||
544 | #define OV511_UVQUANTABLE { \ | ||
545 | 0, 2, 2, 3, 4, 4, 4, 4, \ | ||
546 | 2, 2, 2, 4, 4, 4, 4, 4, \ | ||
547 | 2, 2, 3, 4, 4, 4, 4, 4, \ | ||
548 | 3, 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 | 4, 4, 4, 4, 4, 4, 4, 4 \ | ||
553 | } | ||
554 | |||
555 | #define OV518_YQUANTABLE { \ | ||
556 | 5, 4, 5, 6, 6, 7, 7, 7, \ | ||
557 | 5, 5, 5, 5, 6, 7, 7, 7, \ | ||
558 | 6, 6, 6, 6, 7, 7, 7, 8, \ | ||
559 | 7, 7, 6, 7, 7, 7, 8, 8 \ | ||
560 | } | ||
561 | |||
562 | #define OV518_UVQUANTABLE { \ | ||
563 | 6, 6, 6, 7, 7, 7, 7, 7, \ | ||
564 | 6, 6, 6, 7, 7, 7, 7, 7, \ | ||
565 | 6, 6, 6, 7, 7, 7, 7, 8, \ | ||
566 | 7, 7, 7, 7, 7, 7, 8, 8 \ | ||
567 | } | ||
568 | |||
569 | #endif | ||
diff --git a/drivers/usb/media/pwc/ChangeLog b/drivers/usb/media/pwc/ChangeLog new file mode 100644 index 000000000000..b2eb71a9afb5 --- /dev/null +++ b/drivers/usb/media/pwc/ChangeLog | |||
@@ -0,0 +1,143 @@ | |||
1 | 9.0.2 | ||
2 | |||
3 | * Adding #ifdef to compile PWC before and after 2.6.5 | ||
4 | |||
5 | 9.0.1 | ||
6 | |||
7 | 9.0 | ||
8 | |||
9 | |||
10 | 8.12 | ||
11 | |||
12 | * Implement motorized pan/tilt feature for Logitech QuickCam Orbit/Spere. | ||
13 | |||
14 | 8.11.1 | ||
15 | |||
16 | * Fix for PCVC720/40, would not be able to set videomode | ||
17 | * Fix for Samsung MPC models, appearantly they are based on a newer chipset | ||
18 | |||
19 | 8.11 | ||
20 | |||
21 | * 20 dev_hints (per request) | ||
22 | * Hot unplugging should be better, no more dangling pointers or memory leaks | ||
23 | * Added reserved Logitech webcam IDs | ||
24 | * Device now remembers size & fps between close()/open() | ||
25 | * Removed palette stuff altogether | ||
26 | |||
27 | 8.10.1 | ||
28 | |||
29 | * Added IDs for PCVC720K/40 and Creative Labs Webcam Pro | ||
30 | |||
31 | 8.10 | ||
32 | |||
33 | * Fixed ID for QuickCam Notebook pro | ||
34 | * Added GREALSIZE ioctl() call | ||
35 | * Fixed bug in case PWCX was not loaded and invalid size was set | ||
36 | |||
37 | 8.9 | ||
38 | |||
39 | * Merging with kernel 2.5.49 | ||
40 | * Adding IDs for QuickCam Zoom & QuickCam Notebook | ||
41 | |||
42 | 8.8 | ||
43 | |||
44 | * Fixing 'leds' parameter | ||
45 | * Adding IDs for Logitech QuickCam Pro 4000 | ||
46 | * Making URB init/cleanup a little nicer | ||
47 | |||
48 | 8.7 | ||
49 | |||
50 | * Incorporating changes in ioctl() parameter passing | ||
51 | * Also changes to URB mechanism | ||
52 | |||
53 | 8.6 | ||
54 | |||
55 | * Added ID's for Visionite VCS UM100 and UC300 | ||
56 | * Removed YUV420-interlaced palette altogether (was confusing) | ||
57 | * Removed MIRROR stuff as it didn't work anyway | ||
58 | * Fixed a problem with the 'leds' parameter (wouldn't blink) | ||
59 | * Added ioctl()s for advanced features: 'extended' whitebalance ioctl()s, | ||
60 | CONTOUR, BACKLIGHT, FLICKER, DYNNOISE. | ||
61 | * VIDIOCGCAP.name now contains real camera model name instead of | ||
62 | 'Philips xxx webcam' | ||
63 | * Added PROBE ioctl (see previous point & API doc) | ||
64 | |||
65 | 8.5 | ||
66 | |||
67 | * Adding IDs for Creative Labs Webcam 5 | ||
68 | * Adding IDs for SOTEC CMS-001 webcam | ||
69 | * Solving possible hang in VIDIOCSYNC when unplugging the cam | ||
70 | * Forgot to return structure in VIDIOCPWCGAWB, oops | ||
71 | * Time interval for the LEDs are now in milliseconds | ||
72 | |||
73 | 8.4 | ||
74 | |||
75 | * Fixing power_save option for Vesta range | ||
76 | * Handling new error codes in ISOC callback | ||
77 | * Adding dev_hint module parameter, to specify /dev/videoX device nodes | ||
78 | |||
79 | 8.3 | ||
80 | |||
81 | * Adding Samsung C10 and C30 cameras | ||
82 | * Removing palette module parameter | ||
83 | * Fixed typo in ID of QuickCam 3000 Pro | ||
84 | * Adding LED settings (blinking while in use) for ToUCam cameras. | ||
85 | * Turns LED off when camera is not in use. | ||
86 | |||
87 | 8.2 | ||
88 | |||
89 | * Making module more silent when trace = 0 | ||
90 | * Adding QuickCam 3000 Pro IDs | ||
91 | * Chrominance control for the Vesta cameras | ||
92 | * Hopefully fixed problems on machines with BIGMEM and > 1GB of RAM | ||
93 | * Included Oliver Neukem's lock_kernel() patch | ||
94 | * Allocates less memory for image buffers | ||
95 | * Adds ioctl()s for the whitebalancing | ||
96 | |||
97 | 8.1 | ||
98 | |||
99 | * Adding support for 750 | ||
100 | * Adding V4L GAUDIO/SAUDIO/UNIT ioctl() calls | ||
101 | |||
102 | 8.0 | ||
103 | * 'damage control' after inclusion in 2.4.5. | ||
104 | * Changed wait-queue mechanism in read/mmap/poll according to the book. | ||
105 | * Included YUV420P palette. | ||
106 | * Changed interface to decompressor module. | ||
107 | * Cleaned up pwc structure a bit. | ||
108 | |||
109 | 7.0 | ||
110 | |||
111 | * Fixed bug in vcvt_420i_yuyv; extra variables on stack were misaligned. | ||
112 | * There is now a clear error message when an image size is selected that | ||
113 | is only supported using the decompressor, and the decompressor isn't | ||
114 | loaded. | ||
115 | * When the decompressor wasn't loaded, selecting large image size | ||
116 | would create skewed or double images. | ||
117 | |||
118 | 6.3 | ||
119 | |||
120 | * Introduced spinlocks for the buffer pointer manipulation; a number of | ||
121 | reports seem to suggest the down()/up() semaphores were the cause of | ||
122 | lockups, since they are not suitable for interrupt/user locking. | ||
123 | * Separated decompressor and core code into 2 modules. | ||
124 | |||
125 | 6.2 | ||
126 | |||
127 | * Non-integral image sizes are now padded with gray or black. | ||
128 | * Added SHUTTERSPEED ioctl(). | ||
129 | * Fixed buglet in VIDIOCPWCSAGC; the function would always return an error, | ||
130 | even though the call succeeded. | ||
131 | * Added hotplug support for 2.4.*. | ||
132 | * Memory: the 645/646 uses less memory now. | ||
133 | |||
134 | 6.1 | ||
135 | |||
136 | * VIDIOCSPICT returns -EINVAL with invalid palettes. | ||
137 | * Added saturation control. | ||
138 | * Split decompressors from rest. | ||
139 | * Fixed bug that would reset the framerate to the default framerate if | ||
140 | the rate field was set to 0 (which is not what I intended, nl. do not | ||
141 | change the framerate!). | ||
142 | * VIDIOCPWCSCQUAL (setting compression quality) now takes effect immediately. | ||
143 | * Workaround for a bug in the 730 sensor. | ||
diff --git a/drivers/usb/media/pwc/Makefile b/drivers/usb/media/pwc/Makefile new file mode 100644 index 000000000000..e0b41ed4407f --- /dev/null +++ b/drivers/usb/media/pwc/Makefile | |||
@@ -0,0 +1,20 @@ | |||
1 | ifneq ($(KERNELRELEASE),) | ||
2 | |||
3 | pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.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 new file mode 100644 index 000000000000..04a640d723ed --- /dev/null +++ b/drivers/usb/media/pwc/philips.txt | |||
@@ -0,0 +1,236 @@ | |||
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 new file mode 100644 index 000000000000..26aa914bc541 --- /dev/null +++ b/drivers/usb/media/pwc/pwc-ctrl.c | |||
@@ -0,0 +1,1630 @@ | |||
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 | #include <linux/version.h> | ||
45 | |||
46 | #include "pwc.h" | ||
47 | #include "pwc-ioctl.h" | ||
48 | #include "pwc-uncompress.h" | ||
49 | #include "pwc-kiara.h" | ||
50 | #include "pwc-timon.h" | ||
51 | #include "pwc-dec1.h" | ||
52 | #include "pwc-dec23.h" | ||
53 | |||
54 | /* Request types: video */ | ||
55 | #define SET_LUM_CTL 0x01 | ||
56 | #define GET_LUM_CTL 0x02 | ||
57 | #define SET_CHROM_CTL 0x03 | ||
58 | #define GET_CHROM_CTL 0x04 | ||
59 | #define SET_STATUS_CTL 0x05 | ||
60 | #define GET_STATUS_CTL 0x06 | ||
61 | #define SET_EP_STREAM_CTL 0x07 | ||
62 | #define GET_EP_STREAM_CTL 0x08 | ||
63 | #define SET_MPT_CTL 0x0D | ||
64 | #define GET_MPT_CTL 0x0E | ||
65 | |||
66 | /* Selectors for the Luminance controls [GS]ET_LUM_CTL */ | ||
67 | #define AGC_MODE_FORMATTER 0x2000 | ||
68 | #define PRESET_AGC_FORMATTER 0x2100 | ||
69 | #define SHUTTER_MODE_FORMATTER 0x2200 | ||
70 | #define PRESET_SHUTTER_FORMATTER 0x2300 | ||
71 | #define PRESET_CONTOUR_FORMATTER 0x2400 | ||
72 | #define AUTO_CONTOUR_FORMATTER 0x2500 | ||
73 | #define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600 | ||
74 | #define CONTRAST_FORMATTER 0x2700 | ||
75 | #define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800 | ||
76 | #define FLICKERLESS_MODE_FORMATTER 0x2900 | ||
77 | #define AE_CONTROL_SPEED 0x2A00 | ||
78 | #define BRIGHTNESS_FORMATTER 0x2B00 | ||
79 | #define GAMMA_FORMATTER 0x2C00 | ||
80 | |||
81 | /* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */ | ||
82 | #define WB_MODE_FORMATTER 0x1000 | ||
83 | #define AWB_CONTROL_SPEED_FORMATTER 0x1100 | ||
84 | #define AWB_CONTROL_DELAY_FORMATTER 0x1200 | ||
85 | #define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300 | ||
86 | #define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400 | ||
87 | #define COLOUR_MODE_FORMATTER 0x1500 | ||
88 | #define SATURATION_MODE_FORMATTER1 0x1600 | ||
89 | #define SATURATION_MODE_FORMATTER2 0x1700 | ||
90 | |||
91 | /* Selectors for the Status controls [GS]ET_STATUS_CTL */ | ||
92 | #define SAVE_USER_DEFAULTS_FORMATTER 0x0200 | ||
93 | #define RESTORE_USER_DEFAULTS_FORMATTER 0x0300 | ||
94 | #define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400 | ||
95 | #define READ_AGC_FORMATTER 0x0500 | ||
96 | #define READ_SHUTTER_FORMATTER 0x0600 | ||
97 | #define READ_RED_GAIN_FORMATTER 0x0700 | ||
98 | #define READ_BLUE_GAIN_FORMATTER 0x0800 | ||
99 | #define SENSOR_TYPE_FORMATTER1 0x0C00 | ||
100 | #define READ_RAW_Y_MEAN_FORMATTER 0x3100 | ||
101 | #define SET_POWER_SAVE_MODE_FORMATTER 0x3200 | ||
102 | #define MIRROR_IMAGE_FORMATTER 0x3300 | ||
103 | #define LED_FORMATTER 0x3400 | ||
104 | #define SENSOR_TYPE_FORMATTER2 0x3700 | ||
105 | |||
106 | /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ | ||
107 | #define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 | ||
108 | |||
109 | /* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */ | ||
110 | #define PT_RELATIVE_CONTROL_FORMATTER 0x01 | ||
111 | #define PT_RESET_CONTROL_FORMATTER 0x02 | ||
112 | #define PT_STATUS_FORMATTER 0x03 | ||
113 | |||
114 | static char *size2name[PSZ_MAX] = | ||
115 | { | ||
116 | "subQCIF", | ||
117 | "QSIF", | ||
118 | "QCIF", | ||
119 | "SIF", | ||
120 | "CIF", | ||
121 | "VGA", | ||
122 | }; | ||
123 | |||
124 | /********/ | ||
125 | |||
126 | /* Entries for the Nala (645/646) camera; the Nala doesn't have compression | ||
127 | preferences, so you either get compressed or non-compressed streams. | ||
128 | |||
129 | An alternate value of 0 means this mode is not available at all. | ||
130 | */ | ||
131 | |||
132 | struct Nala_table_entry { | ||
133 | char alternate; /* USB alternate setting */ | ||
134 | int compressed; /* Compressed yes/no */ | ||
135 | |||
136 | unsigned char mode[3]; /* precomputed mode table */ | ||
137 | }; | ||
138 | |||
139 | static struct Nala_table_entry Nala_table[PSZ_MAX][8] = | ||
140 | { | ||
141 | #include "pwc-nala.h" | ||
142 | }; | ||
143 | |||
144 | |||
145 | /****************************************************************************/ | ||
146 | |||
147 | |||
148 | #define SendControlMsg(request, value, buflen) \ | ||
149 | usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \ | ||
150 | request, \ | ||
151 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ | ||
152 | value, \ | ||
153 | pdev->vcinterface, \ | ||
154 | &buf, buflen, 500) | ||
155 | |||
156 | #define RecvControlMsg(request, value, buflen) \ | ||
157 | usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \ | ||
158 | request, \ | ||
159 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ | ||
160 | value, \ | ||
161 | pdev->vcinterface, \ | ||
162 | &buf, buflen, 500) | ||
163 | |||
164 | |||
165 | #if PWC_DEBUG | ||
166 | void pwc_hexdump(void *p, int len) | ||
167 | { | ||
168 | int i; | ||
169 | unsigned char *s; | ||
170 | char buf[100], *d; | ||
171 | |||
172 | s = (unsigned char *)p; | ||
173 | d = buf; | ||
174 | *d = '\0'; | ||
175 | Debug("Doing hexdump @ %p, %d bytes.\n", p, len); | ||
176 | for (i = 0; i < len; i++) { | ||
177 | d += sprintf(d, "%02X ", *s++); | ||
178 | if ((i & 0xF) == 0xF) { | ||
179 | Debug("%s\n", buf); | ||
180 | d = buf; | ||
181 | *d = '\0'; | ||
182 | } | ||
183 | } | ||
184 | if ((i & 0xF) != 0) | ||
185 | Debug("%s\n", buf); | ||
186 | } | ||
187 | #endif | ||
188 | |||
189 | static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen) | ||
190 | { | ||
191 | return usb_control_msg(udev, | ||
192 | usb_sndctrlpipe(udev, 0), | ||
193 | SET_EP_STREAM_CTL, | ||
194 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
195 | VIDEO_OUTPUT_CONTROL_FORMATTER, | ||
196 | index, | ||
197 | buf, buflen, 1000); | ||
198 | } | ||
199 | |||
200 | |||
201 | |||
202 | static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) | ||
203 | { | ||
204 | unsigned char buf[3]; | ||
205 | int ret, fps; | ||
206 | struct Nala_table_entry *pEntry; | ||
207 | int frames2frames[31] = | ||
208 | { /* closest match of framerate */ | ||
209 | 0, 0, 0, 0, 4, /* 0-4 */ | ||
210 | 5, 5, 7, 7, 10, /* 5-9 */ | ||
211 | 10, 10, 12, 12, 15, /* 10-14 */ | ||
212 | 15, 15, 15, 20, 20, /* 15-19 */ | ||
213 | 20, 20, 20, 24, 24, /* 20-24 */ | ||
214 | 24, 24, 24, 24, 24, /* 25-29 */ | ||
215 | 24 /* 30 */ | ||
216 | }; | ||
217 | int frames2table[31] = | ||
218 | { 0, 0, 0, 0, 0, /* 0-4 */ | ||
219 | 1, 1, 1, 2, 2, /* 5-9 */ | ||
220 | 3, 3, 4, 4, 4, /* 10-14 */ | ||
221 | 5, 5, 5, 5, 5, /* 15-19 */ | ||
222 | 6, 6, 6, 6, 7, /* 20-24 */ | ||
223 | 7, 7, 7, 7, 7, /* 25-29 */ | ||
224 | 7 /* 30 */ | ||
225 | }; | ||
226 | |||
227 | if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25) | ||
228 | return -EINVAL; | ||
229 | frames = frames2frames[frames]; | ||
230 | fps = frames2table[frames]; | ||
231 | pEntry = &Nala_table[size][fps]; | ||
232 | if (pEntry->alternate == 0) | ||
233 | return -EINVAL; | ||
234 | |||
235 | if (pEntry->compressed) | ||
236 | return -ENOENT; /* Not supported. */ | ||
237 | |||
238 | memcpy(buf, pEntry->mode, 3); | ||
239 | ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3); | ||
240 | if (ret < 0) { | ||
241 | Debug("Failed to send video command... %d\n", ret); | ||
242 | return ret; | ||
243 | } | ||
244 | if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW) | ||
245 | { | ||
246 | switch(pdev->type) { | ||
247 | case 645: | ||
248 | case 646: | ||
249 | pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); | ||
250 | break; | ||
251 | |||
252 | case 675: | ||
253 | case 680: | ||
254 | case 690: | ||
255 | case 720: | ||
256 | case 730: | ||
257 | case 740: | ||
258 | case 750: | ||
259 | pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); | ||
260 | break; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | pdev->cmd_len = 3; | ||
265 | memcpy(pdev->cmd_buf, buf, 3); | ||
266 | |||
267 | /* Set various parameters */ | ||
268 | pdev->vframes = frames; | ||
269 | pdev->vsize = size; | ||
270 | pdev->valternate = pEntry->alternate; | ||
271 | pdev->image = pwc_image_sizes[size]; | ||
272 | pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2; | ||
273 | if (pEntry->compressed) { | ||
274 | if (pdev->release < 5) { /* 4 fold compression */ | ||
275 | pdev->vbandlength = 528; | ||
276 | pdev->frame_size /= 4; | ||
277 | } | ||
278 | else { | ||
279 | pdev->vbandlength = 704; | ||
280 | pdev->frame_size /= 3; | ||
281 | } | ||
282 | } | ||
283 | else | ||
284 | pdev->vbandlength = 0; | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | |||
289 | static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) | ||
290 | { | ||
291 | unsigned char buf[13]; | ||
292 | const struct Timon_table_entry *pChoose; | ||
293 | int ret, fps; | ||
294 | |||
295 | if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) | ||
296 | return -EINVAL; | ||
297 | if (size == PSZ_VGA && frames > 15) | ||
298 | return -EINVAL; | ||
299 | fps = (frames / 5) - 1; | ||
300 | |||
301 | /* Find a supported framerate with progressively higher compression ratios | ||
302 | if the preferred ratio is not available. | ||
303 | */ | ||
304 | pChoose = NULL; | ||
305 | while (compression <= 3) { | ||
306 | pChoose = &Timon_table[size][fps][compression]; | ||
307 | if (pChoose->alternate != 0) | ||
308 | break; | ||
309 | compression++; | ||
310 | } | ||
311 | if (pChoose == NULL || pChoose->alternate == 0) | ||
312 | return -ENOENT; /* Not supported. */ | ||
313 | |||
314 | memcpy(buf, pChoose->mode, 13); | ||
315 | if (snapshot) | ||
316 | buf[0] |= 0x80; | ||
317 | ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13); | ||
318 | if (ret < 0) | ||
319 | return ret; | ||
320 | |||
321 | if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) | ||
322 | pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); | ||
323 | |||
324 | pdev->cmd_len = 13; | ||
325 | memcpy(pdev->cmd_buf, buf, 13); | ||
326 | |||
327 | /* Set various parameters */ | ||
328 | pdev->vframes = frames; | ||
329 | pdev->vsize = size; | ||
330 | pdev->vsnapshot = snapshot; | ||
331 | pdev->valternate = pChoose->alternate; | ||
332 | pdev->image = pwc_image_sizes[size]; | ||
333 | pdev->vbandlength = pChoose->bandlength; | ||
334 | if (pChoose->bandlength > 0) | ||
335 | pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; | ||
336 | else | ||
337 | pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; | ||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | |||
342 | static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) | ||
343 | { | ||
344 | const struct Kiara_table_entry *pChoose = NULL; | ||
345 | int fps, ret; | ||
346 | unsigned char buf[12]; | ||
347 | struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}; | ||
348 | |||
349 | if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) | ||
350 | return -EINVAL; | ||
351 | if (size == PSZ_VGA && frames > 15) | ||
352 | return -EINVAL; | ||
353 | fps = (frames / 5) - 1; | ||
354 | |||
355 | /* special case: VGA @ 5 fps and snapshot is raw bayer mode */ | ||
356 | if (size == PSZ_VGA && frames == 5 && snapshot) | ||
357 | { | ||
358 | /* Only available in case the raw palette is selected or | ||
359 | we have the decompressor available. This mode is | ||
360 | only available in compressed form | ||
361 | */ | ||
362 | if (pdev->vpalette == VIDEO_PALETTE_RAW) | ||
363 | { | ||
364 | Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette); | ||
365 | pChoose = &RawEntry; | ||
366 | } | ||
367 | else | ||
368 | { | ||
369 | Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n"); | ||
370 | } | ||
371 | } | ||
372 | else | ||
373 | { | ||
374 | /* Find a supported framerate with progressively higher compression ratios | ||
375 | if the preferred ratio is not available. | ||
376 | Skip this step when using RAW modes. | ||
377 | */ | ||
378 | while (compression <= 3) { | ||
379 | pChoose = &Kiara_table[size][fps][compression]; | ||
380 | if (pChoose->alternate != 0) | ||
381 | break; | ||
382 | compression++; | ||
383 | } | ||
384 | } | ||
385 | if (pChoose == NULL || pChoose->alternate == 0) | ||
386 | return -ENOENT; /* Not supported. */ | ||
387 | |||
388 | Debug("Using alternate setting %d.\n", pChoose->alternate); | ||
389 | |||
390 | /* usb_control_msg won't take staticly allocated arrays as argument?? */ | ||
391 | memcpy(buf, pChoose->mode, 12); | ||
392 | if (snapshot) | ||
393 | buf[0] |= 0x80; | ||
394 | |||
395 | /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ | ||
396 | ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12); | ||
397 | if (ret < 0) | ||
398 | return ret; | ||
399 | |||
400 | if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) | ||
401 | pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); | ||
402 | |||
403 | pdev->cmd_len = 12; | ||
404 | memcpy(pdev->cmd_buf, buf, 12); | ||
405 | /* All set and go */ | ||
406 | pdev->vframes = frames; | ||
407 | pdev->vsize = size; | ||
408 | pdev->vsnapshot = snapshot; | ||
409 | pdev->valternate = pChoose->alternate; | ||
410 | pdev->image = pwc_image_sizes[size]; | ||
411 | pdev->vbandlength = pChoose->bandlength; | ||
412 | if (pdev->vbandlength > 0) | ||
413 | pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4; | ||
414 | else | ||
415 | pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; | ||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | |||
420 | |||
421 | /** | ||
422 | @pdev: device structure | ||
423 | @width: viewport width | ||
424 | @height: viewport height | ||
425 | @frame: framerate, in fps | ||
426 | @compression: preferred compression ratio | ||
427 | @snapshot: snapshot mode or streaming | ||
428 | */ | ||
429 | int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot) | ||
430 | { | ||
431 | int ret, size; | ||
432 | |||
433 | Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette); | ||
434 | size = pwc_decode_size(pdev, width, height); | ||
435 | if (size < 0) { | ||
436 | Debug("Could not find suitable size.\n"); | ||
437 | return -ERANGE; | ||
438 | } | ||
439 | Debug("decode_size = %d.\n", size); | ||
440 | |||
441 | ret = -EINVAL; | ||
442 | switch(pdev->type) { | ||
443 | case 645: | ||
444 | case 646: | ||
445 | ret = set_video_mode_Nala(pdev, size, frames); | ||
446 | break; | ||
447 | |||
448 | case 675: | ||
449 | case 680: | ||
450 | case 690: | ||
451 | ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); | ||
452 | break; | ||
453 | |||
454 | case 720: | ||
455 | case 730: | ||
456 | case 740: | ||
457 | case 750: | ||
458 | ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); | ||
459 | break; | ||
460 | } | ||
461 | if (ret < 0) { | ||
462 | if (ret == -ENOENT) | ||
463 | Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames); | ||
464 | else { | ||
465 | Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); | ||
466 | } | ||
467 | return ret; | ||
468 | } | ||
469 | pdev->view.x = width; | ||
470 | pdev->view.y = height; | ||
471 | pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; | ||
472 | pwc_set_image_buffer_size(pdev); | ||
473 | 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); | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | |||
478 | void pwc_set_image_buffer_size(struct pwc_device *pdev) | ||
479 | { | ||
480 | int i, factor = 0, filler = 0; | ||
481 | |||
482 | /* for PALETTE_YUV420P */ | ||
483 | switch(pdev->vpalette) | ||
484 | { | ||
485 | case VIDEO_PALETTE_YUV420P: | ||
486 | factor = 6; | ||
487 | filler = 128; | ||
488 | break; | ||
489 | case VIDEO_PALETTE_RAW: | ||
490 | factor = 6; /* can be uncompressed YUV420P */ | ||
491 | filler = 0; | ||
492 | break; | ||
493 | } | ||
494 | |||
495 | /* Set sizes in bytes */ | ||
496 | pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; | ||
497 | pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; | ||
498 | |||
499 | /* Align offset, or you'll get some very weird results in | ||
500 | YUV420 mode... x must be multiple of 4 (to get the Y's in | ||
501 | place), and y even (or you'll mixup U & V). This is less of a | ||
502 | problem for YUV420P. | ||
503 | */ | ||
504 | pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; | ||
505 | pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; | ||
506 | |||
507 | /* Fill buffers with gray or black */ | ||
508 | for (i = 0; i < MAX_IMAGES; i++) { | ||
509 | if (pdev->image_ptr[i] != NULL) | ||
510 | memset(pdev->image_ptr[i], filler, pdev->view.size); | ||
511 | } | ||
512 | } | ||
513 | |||
514 | |||
515 | |||
516 | /* BRIGHTNESS */ | ||
517 | |||
518 | int pwc_get_brightness(struct pwc_device *pdev) | ||
519 | { | ||
520 | char buf; | ||
521 | int ret; | ||
522 | |||
523 | ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); | ||
524 | if (ret < 0) | ||
525 | return ret; | ||
526 | return buf << 9; | ||
527 | } | ||
528 | |||
529 | int pwc_set_brightness(struct pwc_device *pdev, int value) | ||
530 | { | ||
531 | char buf; | ||
532 | |||
533 | if (value < 0) | ||
534 | value = 0; | ||
535 | if (value > 0xffff) | ||
536 | value = 0xffff; | ||
537 | buf = (value >> 9) & 0x7f; | ||
538 | return SendControlMsg(SET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); | ||
539 | } | ||
540 | |||
541 | /* CONTRAST */ | ||
542 | |||
543 | int pwc_get_contrast(struct pwc_device *pdev) | ||
544 | { | ||
545 | char buf; | ||
546 | int ret; | ||
547 | |||
548 | ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1); | ||
549 | if (ret < 0) | ||
550 | return ret; | ||
551 | return buf << 10; | ||
552 | } | ||
553 | |||
554 | int pwc_set_contrast(struct pwc_device *pdev, int value) | ||
555 | { | ||
556 | char buf; | ||
557 | |||
558 | if (value < 0) | ||
559 | value = 0; | ||
560 | if (value > 0xffff) | ||
561 | value = 0xffff; | ||
562 | buf = (value >> 10) & 0x3f; | ||
563 | return SendControlMsg(SET_LUM_CTL, CONTRAST_FORMATTER, 1); | ||
564 | } | ||
565 | |||
566 | /* GAMMA */ | ||
567 | |||
568 | int pwc_get_gamma(struct pwc_device *pdev) | ||
569 | { | ||
570 | char buf; | ||
571 | int ret; | ||
572 | |||
573 | ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1); | ||
574 | if (ret < 0) | ||
575 | return ret; | ||
576 | return buf << 11; | ||
577 | } | ||
578 | |||
579 | int pwc_set_gamma(struct pwc_device *pdev, int value) | ||
580 | { | ||
581 | char buf; | ||
582 | |||
583 | if (value < 0) | ||
584 | value = 0; | ||
585 | if (value > 0xffff) | ||
586 | value = 0xffff; | ||
587 | buf = (value >> 11) & 0x1f; | ||
588 | return SendControlMsg(SET_LUM_CTL, GAMMA_FORMATTER, 1); | ||
589 | } | ||
590 | |||
591 | |||
592 | /* SATURATION */ | ||
593 | |||
594 | int pwc_get_saturation(struct pwc_device *pdev) | ||
595 | { | ||
596 | char buf; | ||
597 | int ret; | ||
598 | |||
599 | if (pdev->type < 675) | ||
600 | return -1; | ||
601 | ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); | ||
602 | if (ret < 0) | ||
603 | return ret; | ||
604 | return 32768 + buf * 327; | ||
605 | } | ||
606 | |||
607 | int pwc_set_saturation(struct pwc_device *pdev, int value) | ||
608 | { | ||
609 | char buf; | ||
610 | |||
611 | if (pdev->type < 675) | ||
612 | return -EINVAL; | ||
613 | if (value < 0) | ||
614 | value = 0; | ||
615 | if (value > 0xffff) | ||
616 | value = 0xffff; | ||
617 | /* saturation ranges from -100 to +100 */ | ||
618 | buf = (value - 32768) / 327; | ||
619 | return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); | ||
620 | } | ||
621 | |||
622 | /* AGC */ | ||
623 | |||
624 | static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value) | ||
625 | { | ||
626 | char buf; | ||
627 | int ret; | ||
628 | |||
629 | if (mode) | ||
630 | buf = 0x0; /* auto */ | ||
631 | else | ||
632 | buf = 0xff; /* fixed */ | ||
633 | |||
634 | ret = SendControlMsg(SET_LUM_CTL, AGC_MODE_FORMATTER, 1); | ||
635 | |||
636 | if (!mode && ret >= 0) { | ||
637 | if (value < 0) | ||
638 | value = 0; | ||
639 | if (value > 0xffff) | ||
640 | value = 0xffff; | ||
641 | buf = (value >> 10) & 0x3F; | ||
642 | ret = SendControlMsg(SET_LUM_CTL, PRESET_AGC_FORMATTER, 1); | ||
643 | } | ||
644 | if (ret < 0) | ||
645 | return ret; | ||
646 | return 0; | ||
647 | } | ||
648 | |||
649 | static inline int pwc_get_agc(struct pwc_device *pdev, int *value) | ||
650 | { | ||
651 | unsigned char buf; | ||
652 | int ret; | ||
653 | |||
654 | ret = RecvControlMsg(GET_LUM_CTL, AGC_MODE_FORMATTER, 1); | ||
655 | if (ret < 0) | ||
656 | return ret; | ||
657 | |||
658 | if (buf != 0) { /* fixed */ | ||
659 | ret = RecvControlMsg(GET_LUM_CTL, PRESET_AGC_FORMATTER, 1); | ||
660 | if (ret < 0) | ||
661 | return ret; | ||
662 | if (buf > 0x3F) | ||
663 | buf = 0x3F; | ||
664 | *value = (buf << 10); | ||
665 | } | ||
666 | else { /* auto */ | ||
667 | ret = RecvControlMsg(GET_STATUS_CTL, READ_AGC_FORMATTER, 1); | ||
668 | if (ret < 0) | ||
669 | return ret; | ||
670 | /* Gah... this value ranges from 0x00 ... 0x9F */ | ||
671 | if (buf > 0x9F) | ||
672 | buf = 0x9F; | ||
673 | *value = -(48 + buf * 409); | ||
674 | } | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value) | ||
680 | { | ||
681 | char buf[2]; | ||
682 | int speed, ret; | ||
683 | |||
684 | |||
685 | if (mode) | ||
686 | buf[0] = 0x0; /* auto */ | ||
687 | else | ||
688 | buf[0] = 0xff; /* fixed */ | ||
689 | |||
690 | ret = SendControlMsg(SET_LUM_CTL, SHUTTER_MODE_FORMATTER, 1); | ||
691 | |||
692 | if (!mode && ret >= 0) { | ||
693 | if (value < 0) | ||
694 | value = 0; | ||
695 | if (value > 0xffff) | ||
696 | value = 0xffff; | ||
697 | switch(pdev->type) { | ||
698 | case 675: | ||
699 | case 680: | ||
700 | case 690: | ||
701 | /* speed ranges from 0x0 to 0x290 (656) */ | ||
702 | speed = (value / 100); | ||
703 | buf[1] = speed >> 8; | ||
704 | buf[0] = speed & 0xff; | ||
705 | break; | ||
706 | case 720: | ||
707 | case 730: | ||
708 | case 740: | ||
709 | case 750: | ||
710 | /* speed seems to range from 0x0 to 0xff */ | ||
711 | buf[1] = 0; | ||
712 | buf[0] = value >> 8; | ||
713 | break; | ||
714 | } | ||
715 | |||
716 | ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2); | ||
717 | } | ||
718 | return ret; | ||
719 | } | ||
720 | |||
721 | |||
722 | /* POWER */ | ||
723 | |||
724 | int pwc_camera_power(struct pwc_device *pdev, int power) | ||
725 | { | ||
726 | char buf; | ||
727 | |||
728 | if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) | ||
729 | return 0; /* Not supported by Nala or Timon < release 6 */ | ||
730 | |||
731 | if (power) | ||
732 | buf = 0x00; /* active */ | ||
733 | else | ||
734 | buf = 0xFF; /* power save */ | ||
735 | return SendControlMsg(SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, 1); | ||
736 | } | ||
737 | |||
738 | |||
739 | |||
740 | /* private calls */ | ||
741 | |||
742 | static inline int pwc_restore_user(struct pwc_device *pdev) | ||
743 | { | ||
744 | char buf; /* dummy */ | ||
745 | return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0); | ||
746 | } | ||
747 | |||
748 | static inline int pwc_save_user(struct pwc_device *pdev) | ||
749 | { | ||
750 | char buf; /* dummy */ | ||
751 | return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0); | ||
752 | } | ||
753 | |||
754 | static inline int pwc_restore_factory(struct pwc_device *pdev) | ||
755 | { | ||
756 | char buf; /* dummy */ | ||
757 | return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0); | ||
758 | } | ||
759 | |||
760 | /* ************************************************* */ | ||
761 | /* Patch by Alvarado: (not in the original version */ | ||
762 | |||
763 | /* | ||
764 | * the camera recognizes modes from 0 to 4: | ||
765 | * | ||
766 | * 00: indoor (incandescant lighting) | ||
767 | * 01: outdoor (sunlight) | ||
768 | * 02: fluorescent lighting | ||
769 | * 03: manual | ||
770 | * 04: auto | ||
771 | */ | ||
772 | static inline int pwc_set_awb(struct pwc_device *pdev, int mode) | ||
773 | { | ||
774 | char buf; | ||
775 | int ret; | ||
776 | |||
777 | if (mode < 0) | ||
778 | mode = 0; | ||
779 | |||
780 | if (mode > 4) | ||
781 | mode = 4; | ||
782 | |||
783 | buf = mode & 0x07; /* just the lowest three bits */ | ||
784 | |||
785 | ret = SendControlMsg(SET_CHROM_CTL, WB_MODE_FORMATTER, 1); | ||
786 | |||
787 | if (ret < 0) | ||
788 | return ret; | ||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | static inline int pwc_get_awb(struct pwc_device *pdev) | ||
793 | { | ||
794 | unsigned char buf; | ||
795 | int ret; | ||
796 | |||
797 | ret = RecvControlMsg(GET_CHROM_CTL, WB_MODE_FORMATTER, 1); | ||
798 | |||
799 | if (ret < 0) | ||
800 | return ret; | ||
801 | return buf; | ||
802 | } | ||
803 | |||
804 | static inline int pwc_set_red_gain(struct pwc_device *pdev, int value) | ||
805 | { | ||
806 | unsigned char buf; | ||
807 | |||
808 | if (value < 0) | ||
809 | value = 0; | ||
810 | if (value > 0xffff) | ||
811 | value = 0xffff; | ||
812 | /* only the msb is considered */ | ||
813 | buf = value >> 8; | ||
814 | return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); | ||
815 | } | ||
816 | |||
817 | static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value) | ||
818 | { | ||
819 | unsigned char buf; | ||
820 | int ret; | ||
821 | |||
822 | ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); | ||
823 | if (ret < 0) | ||
824 | return ret; | ||
825 | *value = buf << 8; | ||
826 | return 0; | ||
827 | } | ||
828 | |||
829 | |||
830 | static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value) | ||
831 | { | ||
832 | unsigned char buf; | ||
833 | |||
834 | if (value < 0) | ||
835 | value = 0; | ||
836 | if (value > 0xffff) | ||
837 | value = 0xffff; | ||
838 | /* only the msb is considered */ | ||
839 | buf = value >> 8; | ||
840 | return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); | ||
841 | } | ||
842 | |||
843 | static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value) | ||
844 | { | ||
845 | unsigned char buf; | ||
846 | int ret; | ||
847 | |||
848 | ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); | ||
849 | if (ret < 0) | ||
850 | return ret; | ||
851 | *value = buf << 8; | ||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | |||
856 | /* The following two functions are different, since they only read the | ||
857 | internal red/blue gains, which may be different from the manual | ||
858 | gains set or read above. | ||
859 | */ | ||
860 | static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value) | ||
861 | { | ||
862 | unsigned char buf; | ||
863 | int ret; | ||
864 | |||
865 | ret = RecvControlMsg(GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, 1); | ||
866 | if (ret < 0) | ||
867 | return ret; | ||
868 | *value = buf << 8; | ||
869 | return 0; | ||
870 | } | ||
871 | |||
872 | static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value) | ||
873 | { | ||
874 | unsigned char buf; | ||
875 | int ret; | ||
876 | |||
877 | ret = RecvControlMsg(GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, 1); | ||
878 | if (ret < 0) | ||
879 | return ret; | ||
880 | *value = buf << 8; | ||
881 | return 0; | ||
882 | } | ||
883 | |||
884 | |||
885 | static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed) | ||
886 | { | ||
887 | unsigned char buf; | ||
888 | |||
889 | /* useful range is 0x01..0x20 */ | ||
890 | buf = speed / 0x7f0; | ||
891 | return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); | ||
892 | } | ||
893 | |||
894 | static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value) | ||
895 | { | ||
896 | unsigned char buf; | ||
897 | int ret; | ||
898 | |||
899 | ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); | ||
900 | if (ret < 0) | ||
901 | return ret; | ||
902 | *value = buf * 0x7f0; | ||
903 | return 0; | ||
904 | } | ||
905 | |||
906 | |||
907 | static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay) | ||
908 | { | ||
909 | unsigned char buf; | ||
910 | |||
911 | /* useful range is 0x01..0x3F */ | ||
912 | buf = (delay >> 10); | ||
913 | return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); | ||
914 | } | ||
915 | |||
916 | static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value) | ||
917 | { | ||
918 | unsigned char buf; | ||
919 | int ret; | ||
920 | |||
921 | ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); | ||
922 | if (ret < 0) | ||
923 | return ret; | ||
924 | *value = buf << 10; | ||
925 | return 0; | ||
926 | } | ||
927 | |||
928 | |||
929 | int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) | ||
930 | { | ||
931 | unsigned char buf[2]; | ||
932 | |||
933 | if (pdev->type < 730) | ||
934 | return 0; | ||
935 | on_value /= 100; | ||
936 | off_value /= 100; | ||
937 | if (on_value < 0) | ||
938 | on_value = 0; | ||
939 | if (on_value > 0xff) | ||
940 | on_value = 0xff; | ||
941 | if (off_value < 0) | ||
942 | off_value = 0; | ||
943 | if (off_value > 0xff) | ||
944 | off_value = 0xff; | ||
945 | |||
946 | buf[0] = on_value; | ||
947 | buf[1] = off_value; | ||
948 | |||
949 | return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2); | ||
950 | } | ||
951 | |||
952 | int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) | ||
953 | { | ||
954 | unsigned char buf[2]; | ||
955 | int ret; | ||
956 | |||
957 | if (pdev->type < 730) { | ||
958 | *on_value = -1; | ||
959 | *off_value = -1; | ||
960 | return 0; | ||
961 | } | ||
962 | |||
963 | ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2); | ||
964 | if (ret < 0) | ||
965 | return ret; | ||
966 | *on_value = buf[0] * 100; | ||
967 | *off_value = buf[1] * 100; | ||
968 | return 0; | ||
969 | } | ||
970 | |||
971 | static inline int pwc_set_contour(struct pwc_device *pdev, int contour) | ||
972 | { | ||
973 | unsigned char buf; | ||
974 | int ret; | ||
975 | |||
976 | if (contour < 0) | ||
977 | buf = 0xff; /* auto contour on */ | ||
978 | else | ||
979 | buf = 0x0; /* auto contour off */ | ||
980 | ret = SendControlMsg(SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); | ||
981 | if (ret < 0) | ||
982 | return ret; | ||
983 | |||
984 | if (contour < 0) | ||
985 | return 0; | ||
986 | if (contour > 0xffff) | ||
987 | contour = 0xffff; | ||
988 | |||
989 | buf = (contour >> 10); /* contour preset is [0..3f] */ | ||
990 | ret = SendControlMsg(SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); | ||
991 | if (ret < 0) | ||
992 | return ret; | ||
993 | return 0; | ||
994 | } | ||
995 | |||
996 | static inline int pwc_get_contour(struct pwc_device *pdev, int *contour) | ||
997 | { | ||
998 | unsigned char buf; | ||
999 | int ret; | ||
1000 | |||
1001 | ret = RecvControlMsg(GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); | ||
1002 | if (ret < 0) | ||
1003 | return ret; | ||
1004 | |||
1005 | if (buf == 0) { | ||
1006 | /* auto mode off, query current preset value */ | ||
1007 | ret = RecvControlMsg(GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); | ||
1008 | if (ret < 0) | ||
1009 | return ret; | ||
1010 | *contour = buf << 10; | ||
1011 | } | ||
1012 | else | ||
1013 | *contour = -1; | ||
1014 | return 0; | ||
1015 | } | ||
1016 | |||
1017 | |||
1018 | static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight) | ||
1019 | { | ||
1020 | unsigned char buf; | ||
1021 | |||
1022 | if (backlight) | ||
1023 | buf = 0xff; | ||
1024 | else | ||
1025 | buf = 0x0; | ||
1026 | return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); | ||
1027 | } | ||
1028 | |||
1029 | static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight) | ||
1030 | { | ||
1031 | int ret; | ||
1032 | unsigned char buf; | ||
1033 | |||
1034 | ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); | ||
1035 | if (ret < 0) | ||
1036 | return ret; | ||
1037 | *backlight = buf; | ||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | |||
1042 | static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker) | ||
1043 | { | ||
1044 | unsigned char buf; | ||
1045 | |||
1046 | if (flicker) | ||
1047 | buf = 0xff; | ||
1048 | else | ||
1049 | buf = 0x0; | ||
1050 | return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); | ||
1051 | } | ||
1052 | |||
1053 | static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker) | ||
1054 | { | ||
1055 | int ret; | ||
1056 | unsigned char buf; | ||
1057 | |||
1058 | ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); | ||
1059 | if (ret < 0) | ||
1060 | return ret; | ||
1061 | *flicker = buf; | ||
1062 | return 0; | ||
1063 | } | ||
1064 | |||
1065 | |||
1066 | static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise) | ||
1067 | { | ||
1068 | unsigned char buf; | ||
1069 | |||
1070 | if (noise < 0) | ||
1071 | noise = 0; | ||
1072 | if (noise > 3) | ||
1073 | noise = 3; | ||
1074 | buf = noise; | ||
1075 | return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); | ||
1076 | } | ||
1077 | |||
1078 | static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise) | ||
1079 | { | ||
1080 | int ret; | ||
1081 | unsigned char buf; | ||
1082 | |||
1083 | ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); | ||
1084 | if (ret < 0) | ||
1085 | return ret; | ||
1086 | *noise = buf; | ||
1087 | return 0; | ||
1088 | } | ||
1089 | |||
1090 | static int pwc_mpt_reset(struct pwc_device *pdev, int flags) | ||
1091 | { | ||
1092 | unsigned char buf; | ||
1093 | |||
1094 | buf = flags & 0x03; // only lower two bits are currently used | ||
1095 | return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1); | ||
1096 | } | ||
1097 | |||
1098 | static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) | ||
1099 | { | ||
1100 | unsigned char buf[4]; | ||
1101 | |||
1102 | /* set new relative angle; angles are expressed in degrees * 100, | ||
1103 | but cam as .5 degree resolution, hence devide by 200. Also | ||
1104 | the angle must be multiplied by 64 before it's send to | ||
1105 | the cam (??) | ||
1106 | */ | ||
1107 | pan = 64 * pan / 100; | ||
1108 | tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */ | ||
1109 | buf[0] = pan & 0xFF; | ||
1110 | buf[1] = (pan >> 8) & 0xFF; | ||
1111 | buf[2] = tilt & 0xFF; | ||
1112 | buf[3] = (tilt >> 8) & 0xFF; | ||
1113 | return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4); | ||
1114 | } | ||
1115 | |||
1116 | static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status) | ||
1117 | { | ||
1118 | int ret; | ||
1119 | unsigned char buf[5]; | ||
1120 | |||
1121 | ret = RecvControlMsg(GET_MPT_CTL, PT_STATUS_FORMATTER, 5); | ||
1122 | if (ret < 0) | ||
1123 | return ret; | ||
1124 | status->status = buf[0] & 0x7; // 3 bits are used for reporting | ||
1125 | status->time_pan = (buf[1] << 8) + buf[2]; | ||
1126 | status->time_tilt = (buf[3] << 8) + buf[4]; | ||
1127 | return 0; | ||
1128 | } | ||
1129 | |||
1130 | |||
1131 | int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) | ||
1132 | { | ||
1133 | unsigned char buf; | ||
1134 | int ret = -1, request; | ||
1135 | |||
1136 | if (pdev->type < 675) | ||
1137 | request = SENSOR_TYPE_FORMATTER1; | ||
1138 | else if (pdev->type < 730) | ||
1139 | return -1; /* The Vesta series doesn't have this call */ | ||
1140 | else | ||
1141 | request = SENSOR_TYPE_FORMATTER2; | ||
1142 | |||
1143 | ret = RecvControlMsg(GET_STATUS_CTL, request, 1); | ||
1144 | if (ret < 0) | ||
1145 | return ret; | ||
1146 | if (pdev->type < 675) | ||
1147 | *sensor = buf | 0x100; | ||
1148 | else | ||
1149 | *sensor = buf; | ||
1150 | return 0; | ||
1151 | } | ||
1152 | |||
1153 | |||
1154 | /* End of Add-Ons */ | ||
1155 | /* ************************************************* */ | ||
1156 | |||
1157 | /* Linux 2.5.something and 2.6 pass direct pointers to arguments of | ||
1158 | ioctl() calls. With 2.4, you have to do tedious copy_from_user() | ||
1159 | and copy_to_user() calls. With these macros we circumvent this, | ||
1160 | and let me maintain only one source file. The functionality is | ||
1161 | exactly the same otherwise. | ||
1162 | */ | ||
1163 | |||
1164 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) | ||
1165 | |||
1166 | /* define local variable for arg */ | ||
1167 | #define ARG_DEF(ARG_type, ARG_name)\ | ||
1168 | ARG_type *ARG_name = arg; | ||
1169 | /* copy arg to local variable */ | ||
1170 | #define ARG_IN(ARG_name) /* nothing */ | ||
1171 | /* argument itself (referenced) */ | ||
1172 | #define ARGR(ARG_name) (*ARG_name) | ||
1173 | /* argument address */ | ||
1174 | #define ARGA(ARG_name) ARG_name | ||
1175 | /* copy local variable to arg */ | ||
1176 | #define ARG_OUT(ARG_name) /* nothing */ | ||
1177 | |||
1178 | #else | ||
1179 | |||
1180 | #define ARG_DEF(ARG_type, ARG_name)\ | ||
1181 | ARG_type ARG_name; | ||
1182 | #define ARG_IN(ARG_name)\ | ||
1183 | if (copy_from_user(&ARG_name, arg, sizeof(ARG_name))) {\ | ||
1184 | ret = -EFAULT;\ | ||
1185 | break;\ | ||
1186 | } | ||
1187 | #define ARGR(ARG_name) ARG_name | ||
1188 | #define ARGA(ARG_name) &ARG_name | ||
1189 | #define ARG_OUT(ARG_name)\ | ||
1190 | if (copy_to_user(arg, &ARG_name, sizeof(ARG_name))) {\ | ||
1191 | ret = -EFAULT;\ | ||
1192 | break;\ | ||
1193 | } | ||
1194 | |||
1195 | #endif | ||
1196 | |||
1197 | int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | ||
1198 | { | ||
1199 | int ret = 0; | ||
1200 | |||
1201 | switch(cmd) { | ||
1202 | case VIDIOCPWCRUSER: | ||
1203 | { | ||
1204 | if (pwc_restore_user(pdev)) | ||
1205 | ret = -EINVAL; | ||
1206 | break; | ||
1207 | } | ||
1208 | |||
1209 | case VIDIOCPWCSUSER: | ||
1210 | { | ||
1211 | if (pwc_save_user(pdev)) | ||
1212 | ret = -EINVAL; | ||
1213 | break; | ||
1214 | } | ||
1215 | |||
1216 | case VIDIOCPWCFACTORY: | ||
1217 | { | ||
1218 | if (pwc_restore_factory(pdev)) | ||
1219 | ret = -EINVAL; | ||
1220 | break; | ||
1221 | } | ||
1222 | |||
1223 | case VIDIOCPWCSCQUAL: | ||
1224 | { | ||
1225 | ARG_DEF(int, qual) | ||
1226 | |||
1227 | ARG_IN(qual) | ||
1228 | if (ARGR(qual) < 0 || ARGR(qual) > 3) | ||
1229 | ret = -EINVAL; | ||
1230 | else | ||
1231 | ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot); | ||
1232 | if (ret >= 0) | ||
1233 | pdev->vcompression = ARGR(qual); | ||
1234 | break; | ||
1235 | } | ||
1236 | |||
1237 | case VIDIOCPWCGCQUAL: | ||
1238 | { | ||
1239 | ARG_DEF(int, qual) | ||
1240 | |||
1241 | ARGR(qual) = pdev->vcompression; | ||
1242 | ARG_OUT(qual) | ||
1243 | break; | ||
1244 | } | ||
1245 | |||
1246 | case VIDIOCPWCPROBE: | ||
1247 | { | ||
1248 | ARG_DEF(struct pwc_probe, probe) | ||
1249 | |||
1250 | strcpy(ARGR(probe).name, pdev->vdev->name); | ||
1251 | ARGR(probe).type = pdev->type; | ||
1252 | ARG_OUT(probe) | ||
1253 | break; | ||
1254 | } | ||
1255 | |||
1256 | case VIDIOCPWCGSERIAL: | ||
1257 | { | ||
1258 | ARG_DEF(struct pwc_serial, serial) | ||
1259 | |||
1260 | strcpy(ARGR(serial).serial, pdev->serial); | ||
1261 | ARG_OUT(serial) | ||
1262 | break; | ||
1263 | } | ||
1264 | |||
1265 | case VIDIOCPWCSAGC: | ||
1266 | { | ||
1267 | ARG_DEF(int, agc) | ||
1268 | |||
1269 | ARG_IN(agc) | ||
1270 | if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc))) | ||
1271 | ret = -EINVAL; | ||
1272 | break; | ||
1273 | } | ||
1274 | |||
1275 | case VIDIOCPWCGAGC: | ||
1276 | { | ||
1277 | ARG_DEF(int, agc) | ||
1278 | |||
1279 | if (pwc_get_agc(pdev, ARGA(agc))) | ||
1280 | ret = -EINVAL; | ||
1281 | ARG_OUT(agc) | ||
1282 | break; | ||
1283 | } | ||
1284 | |||
1285 | case VIDIOCPWCSSHUTTER: | ||
1286 | { | ||
1287 | ARG_DEF(int, shutter_speed) | ||
1288 | |||
1289 | ARG_IN(shutter_speed) | ||
1290 | ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed)); | ||
1291 | break; | ||
1292 | } | ||
1293 | |||
1294 | case VIDIOCPWCSAWB: | ||
1295 | { | ||
1296 | ARG_DEF(struct pwc_whitebalance, wb) | ||
1297 | |||
1298 | ARG_IN(wb) | ||
1299 | ret = pwc_set_awb(pdev, ARGR(wb).mode); | ||
1300 | if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) { | ||
1301 | pwc_set_red_gain(pdev, ARGR(wb).manual_red); | ||
1302 | pwc_set_blue_gain(pdev, ARGR(wb).manual_blue); | ||
1303 | } | ||
1304 | break; | ||
1305 | } | ||
1306 | |||
1307 | case VIDIOCPWCGAWB: | ||
1308 | { | ||
1309 | ARG_DEF(struct pwc_whitebalance, wb) | ||
1310 | |||
1311 | memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance)); | ||
1312 | ARGR(wb).mode = pwc_get_awb(pdev); | ||
1313 | if (ARGR(wb).mode < 0) | ||
1314 | ret = -EINVAL; | ||
1315 | else { | ||
1316 | if (ARGR(wb).mode == PWC_WB_MANUAL) { | ||
1317 | ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red); | ||
1318 | if (ret < 0) | ||
1319 | break; | ||
1320 | ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue); | ||
1321 | if (ret < 0) | ||
1322 | break; | ||
1323 | } | ||
1324 | if (ARGR(wb).mode == PWC_WB_AUTO) { | ||
1325 | ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); | ||
1326 | if (ret < 0) | ||
1327 | break; | ||
1328 | ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); | ||
1329 | if (ret < 0) | ||
1330 | break; | ||
1331 | } | ||
1332 | } | ||
1333 | ARG_OUT(wb) | ||
1334 | break; | ||
1335 | } | ||
1336 | |||
1337 | case VIDIOCPWCSAWBSPEED: | ||
1338 | { | ||
1339 | ARG_DEF(struct pwc_wb_speed, wbs) | ||
1340 | |||
1341 | if (ARGR(wbs).control_speed > 0) { | ||
1342 | ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed); | ||
1343 | } | ||
1344 | if (ARGR(wbs).control_delay > 0) { | ||
1345 | ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay); | ||
1346 | } | ||
1347 | break; | ||
1348 | } | ||
1349 | |||
1350 | case VIDIOCPWCGAWBSPEED: | ||
1351 | { | ||
1352 | ARG_DEF(struct pwc_wb_speed, wbs) | ||
1353 | |||
1354 | ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed); | ||
1355 | if (ret < 0) | ||
1356 | break; | ||
1357 | ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay); | ||
1358 | if (ret < 0) | ||
1359 | break; | ||
1360 | ARG_OUT(wbs) | ||
1361 | break; | ||
1362 | } | ||
1363 | |||
1364 | case VIDIOCPWCSLED: | ||
1365 | { | ||
1366 | ARG_DEF(struct pwc_leds, leds) | ||
1367 | |||
1368 | ARG_IN(leds) | ||
1369 | ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off); | ||
1370 | break; | ||
1371 | } | ||
1372 | |||
1373 | |||
1374 | case VIDIOCPWCGLED: | ||
1375 | { | ||
1376 | ARG_DEF(struct pwc_leds, leds) | ||
1377 | |||
1378 | ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off); | ||
1379 | ARG_OUT(leds) | ||
1380 | break; | ||
1381 | } | ||
1382 | |||
1383 | case VIDIOCPWCSCONTOUR: | ||
1384 | { | ||
1385 | ARG_DEF(int, contour) | ||
1386 | |||
1387 | ARG_IN(contour) | ||
1388 | ret = pwc_set_contour(pdev, ARGR(contour)); | ||
1389 | break; | ||
1390 | } | ||
1391 | |||
1392 | case VIDIOCPWCGCONTOUR: | ||
1393 | { | ||
1394 | ARG_DEF(int, contour) | ||
1395 | |||
1396 | ret = pwc_get_contour(pdev, ARGA(contour)); | ||
1397 | ARG_OUT(contour) | ||
1398 | break; | ||
1399 | } | ||
1400 | |||
1401 | case VIDIOCPWCSBACKLIGHT: | ||
1402 | { | ||
1403 | ARG_DEF(int, backlight) | ||
1404 | |||
1405 | ARG_IN(backlight) | ||
1406 | ret = pwc_set_backlight(pdev, ARGR(backlight)); | ||
1407 | break; | ||
1408 | } | ||
1409 | |||
1410 | case VIDIOCPWCGBACKLIGHT: | ||
1411 | { | ||
1412 | ARG_DEF(int, backlight) | ||
1413 | |||
1414 | ret = pwc_get_backlight(pdev, ARGA(backlight)); | ||
1415 | ARG_OUT(backlight) | ||
1416 | break; | ||
1417 | } | ||
1418 | |||
1419 | case VIDIOCPWCSFLICKER: | ||
1420 | { | ||
1421 | ARG_DEF(int, flicker) | ||
1422 | |||
1423 | ARG_IN(flicker) | ||
1424 | ret = pwc_set_flicker(pdev, ARGR(flicker)); | ||
1425 | break; | ||
1426 | } | ||
1427 | |||
1428 | case VIDIOCPWCGFLICKER: | ||
1429 | { | ||
1430 | ARG_DEF(int, flicker) | ||
1431 | |||
1432 | ret = pwc_get_flicker(pdev, ARGA(flicker)); | ||
1433 | ARG_OUT(flicker) | ||
1434 | break; | ||
1435 | } | ||
1436 | |||
1437 | case VIDIOCPWCSDYNNOISE: | ||
1438 | { | ||
1439 | ARG_DEF(int, dynnoise) | ||
1440 | |||
1441 | ARG_IN(dynnoise) | ||
1442 | ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise)); | ||
1443 | break; | ||
1444 | } | ||
1445 | |||
1446 | case VIDIOCPWCGDYNNOISE: | ||
1447 | { | ||
1448 | ARG_DEF(int, dynnoise) | ||
1449 | |||
1450 | ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise)); | ||
1451 | ARG_OUT(dynnoise); | ||
1452 | break; | ||
1453 | } | ||
1454 | |||
1455 | case VIDIOCPWCGREALSIZE: | ||
1456 | { | ||
1457 | ARG_DEF(struct pwc_imagesize, size) | ||
1458 | |||
1459 | ARGR(size).width = pdev->image.x; | ||
1460 | ARGR(size).height = pdev->image.y; | ||
1461 | ARG_OUT(size) | ||
1462 | break; | ||
1463 | } | ||
1464 | |||
1465 | case VIDIOCPWCMPTRESET: | ||
1466 | { | ||
1467 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
1468 | { | ||
1469 | ARG_DEF(int, flags) | ||
1470 | |||
1471 | ARG_IN(flags) | ||
1472 | ret = pwc_mpt_reset(pdev, ARGR(flags)); | ||
1473 | if (ret >= 0) | ||
1474 | { | ||
1475 | pdev->pan_angle = 0; | ||
1476 | pdev->tilt_angle = 0; | ||
1477 | } | ||
1478 | } | ||
1479 | else | ||
1480 | { | ||
1481 | ret = -ENXIO; | ||
1482 | } | ||
1483 | break; | ||
1484 | } | ||
1485 | |||
1486 | case VIDIOCPWCMPTGRANGE: | ||
1487 | { | ||
1488 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
1489 | { | ||
1490 | ARG_DEF(struct pwc_mpt_range, range) | ||
1491 | |||
1492 | ARGR(range) = pdev->angle_range; | ||
1493 | ARG_OUT(range) | ||
1494 | } | ||
1495 | else | ||
1496 | { | ||
1497 | ret = -ENXIO; | ||
1498 | } | ||
1499 | break; | ||
1500 | } | ||
1501 | |||
1502 | case VIDIOCPWCMPTSANGLE: | ||
1503 | { | ||
1504 | int new_pan, new_tilt; | ||
1505 | |||
1506 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
1507 | { | ||
1508 | ARG_DEF(struct pwc_mpt_angles, angles) | ||
1509 | |||
1510 | ARG_IN(angles) | ||
1511 | /* The camera can only set relative angles, so | ||
1512 | do some calculations when getting an absolute angle . | ||
1513 | */ | ||
1514 | if (ARGR(angles).absolute) | ||
1515 | { | ||
1516 | new_pan = ARGR(angles).pan; | ||
1517 | new_tilt = ARGR(angles).tilt; | ||
1518 | } | ||
1519 | else | ||
1520 | { | ||
1521 | new_pan = pdev->pan_angle + ARGR(angles).pan; | ||
1522 | new_tilt = pdev->tilt_angle + ARGR(angles).tilt; | ||
1523 | } | ||
1524 | /* check absolute ranges */ | ||
1525 | if (new_pan < pdev->angle_range.pan_min || | ||
1526 | new_pan > pdev->angle_range.pan_max || | ||
1527 | new_tilt < pdev->angle_range.tilt_min || | ||
1528 | new_tilt > pdev->angle_range.tilt_max) | ||
1529 | { | ||
1530 | ret = -ERANGE; | ||
1531 | } | ||
1532 | else | ||
1533 | { | ||
1534 | /* go to relative range, check again */ | ||
1535 | new_pan -= pdev->pan_angle; | ||
1536 | new_tilt -= pdev->tilt_angle; | ||
1537 | /* angles are specified in degrees * 100, thus the limit = 36000 */ | ||
1538 | if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000) | ||
1539 | ret = -ERANGE; | ||
1540 | } | ||
1541 | if (ret == 0) /* no errors so far */ | ||
1542 | { | ||
1543 | ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt); | ||
1544 | if (ret >= 0) | ||
1545 | { | ||
1546 | pdev->pan_angle += new_pan; | ||
1547 | pdev->tilt_angle += new_tilt; | ||
1548 | } | ||
1549 | if (ret == -EPIPE) /* stall -> out of range */ | ||
1550 | ret = -ERANGE; | ||
1551 | } | ||
1552 | } | ||
1553 | else | ||
1554 | { | ||
1555 | ret = -ENXIO; | ||
1556 | } | ||
1557 | break; | ||
1558 | } | ||
1559 | |||
1560 | case VIDIOCPWCMPTGANGLE: | ||
1561 | { | ||
1562 | |||
1563 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
1564 | { | ||
1565 | ARG_DEF(struct pwc_mpt_angles, angles) | ||
1566 | |||
1567 | ARGR(angles).absolute = 1; | ||
1568 | ARGR(angles).pan = pdev->pan_angle; | ||
1569 | ARGR(angles).tilt = pdev->tilt_angle; | ||
1570 | ARG_OUT(angles) | ||
1571 | } | ||
1572 | else | ||
1573 | { | ||
1574 | ret = -ENXIO; | ||
1575 | } | ||
1576 | break; | ||
1577 | } | ||
1578 | |||
1579 | case VIDIOCPWCMPTSTATUS: | ||
1580 | { | ||
1581 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
1582 | { | ||
1583 | ARG_DEF(struct pwc_mpt_status, status) | ||
1584 | |||
1585 | ret = pwc_mpt_get_status(pdev, ARGA(status)); | ||
1586 | ARG_OUT(status) | ||
1587 | } | ||
1588 | else | ||
1589 | { | ||
1590 | ret = -ENXIO; | ||
1591 | } | ||
1592 | break; | ||
1593 | } | ||
1594 | |||
1595 | case VIDIOCPWCGVIDCMD: | ||
1596 | { | ||
1597 | ARG_DEF(struct pwc_video_command, cmd); | ||
1598 | |||
1599 | ARGR(cmd).type = pdev->type; | ||
1600 | ARGR(cmd).release = pdev->release; | ||
1601 | ARGR(cmd).command_len = pdev->cmd_len; | ||
1602 | memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len); | ||
1603 | ARGR(cmd).bandlength = pdev->vbandlength; | ||
1604 | ARGR(cmd).frame_size = pdev->frame_size; | ||
1605 | ARG_OUT(cmd) | ||
1606 | break; | ||
1607 | } | ||
1608 | /* | ||
1609 | case VIDIOCPWCGVIDTABLE: | ||
1610 | { | ||
1611 | ARG_DEF(struct pwc_table_init_buffer, table); | ||
1612 | ARGR(table).len = pdev->cmd_len; | ||
1613 | memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size); | ||
1614 | ARG_OUT(table) | ||
1615 | break; | ||
1616 | } | ||
1617 | */ | ||
1618 | |||
1619 | default: | ||
1620 | ret = -ENOIOCTLCMD; | ||
1621 | break; | ||
1622 | } | ||
1623 | |||
1624 | if (ret > 0) | ||
1625 | return 0; | ||
1626 | return ret; | ||
1627 | } | ||
1628 | |||
1629 | |||
1630 | |||
diff --git a/drivers/usb/media/pwc/pwc-dec1.c b/drivers/usb/media/pwc/pwc-dec1.c new file mode 100644 index 000000000000..57d03d9178f6 --- /dev/null +++ b/drivers/usb/media/pwc/pwc-dec1.c | |||
@@ -0,0 +1,42 @@ | |||
1 | /* Linux driver for Philips webcam | ||
2 | Decompression for chipset version 1 | ||
3 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
4 | |||
5 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
6 | driver and thus may have bugs that are not present in the original version. | ||
7 | Please send bug reports and support requests to <luc@saillard.org>. | ||
8 | The decompression routines have been implemented by reverse-engineering the | ||
9 | Nemosoft binary pwcx module. Caveat emptor. | ||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | */ | ||
25 | |||
26 | |||
27 | |||
28 | #include "pwc-dec1.h" | ||
29 | |||
30 | |||
31 | void pwc_dec1_init(int type, int release, void *buffer, void *table) | ||
32 | { | ||
33 | |||
34 | } | ||
35 | |||
36 | void pwc_dec1_exit(void) | ||
37 | { | ||
38 | |||
39 | |||
40 | |||
41 | } | ||
42 | |||
diff --git a/drivers/usb/media/pwc/pwc-dec1.h b/drivers/usb/media/pwc/pwc-dec1.h new file mode 100644 index 000000000000..a7ffd9c45a2c --- /dev/null +++ b/drivers/usb/media/pwc/pwc-dec1.h | |||
@@ -0,0 +1,36 @@ | |||
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 | #ifndef PWC_DEC1_H | ||
28 | #define PWC_DEC1_H | ||
29 | |||
30 | void pwc_dec1_init(int type, int release, void *buffer, void *private_data); | ||
31 | void pwc_dec1_exit(void); | ||
32 | |||
33 | #endif | ||
34 | |||
35 | |||
36 | |||
diff --git a/drivers/usb/media/pwc/pwc-dec23.c b/drivers/usb/media/pwc/pwc-dec23.c new file mode 100644 index 000000000000..98fa3f7a9eff --- /dev/null +++ b/drivers/usb/media/pwc/pwc-dec23.c | |||
@@ -0,0 +1,623 @@ | |||
1 | /* Linux driver for Philips webcam | ||
2 | Decompression for chipset version 2 et 3 | ||
3 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
4 | |||
5 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
6 | driver and thus may have bugs that are not present in the original version. | ||
7 | Please send bug reports and support requests to <luc@saillard.org>. | ||
8 | The decompression routines have been implemented by reverse-engineering the | ||
9 | Nemosoft binary pwcx module. Caveat emptor. | ||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | */ | ||
25 | |||
26 | #include "pwc-timon.h" | ||
27 | #include "pwc-kiara.h" | ||
28 | #include "pwc-dec23.h" | ||
29 | #include "pwc-ioctl.h" | ||
30 | |||
31 | #include <linux/string.h> | ||
32 | |||
33 | /**** | ||
34 | * | ||
35 | * | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | |||
40 | static void fill_table_a000(unsigned int *p) | ||
41 | { | ||
42 | static unsigned int initial_values[12] = { | ||
43 | 0xFFAD9B00, 0xFFDDEE00, 0x00221200, 0x00526500, | ||
44 | 0xFFC21E00, 0x003DE200, 0xFF924B80, 0xFFD2A300, | ||
45 | 0x002D5D00, 0x006DB480, 0xFFED3E00, 0x0012C200 | ||
46 | }; | ||
47 | static unsigned int values_derivated[12] = { | ||
48 | 0x0000A4CA, 0x00004424, 0xFFFFBBDC, 0xFFFF5B36, | ||
49 | 0x00007BC4, 0xFFFF843C, 0x0000DB69, 0x00005ABA, | ||
50 | 0xFFFFA546, 0xFFFF2497, 0x00002584, 0xFFFFDA7C | ||
51 | }; | ||
52 | unsigned int temp_values[12]; | ||
53 | int i,j; | ||
54 | |||
55 | memcpy(temp_values,initial_values,sizeof(initial_values)); | ||
56 | for (i=0;i<256;i++) | ||
57 | { | ||
58 | for (j=0;j<12;j++) | ||
59 | { | ||
60 | *p++ = temp_values[j]; | ||
61 | temp_values[j] += values_derivated[j]; | ||
62 | } | ||
63 | } | ||
64 | } | ||
65 | |||
66 | static void fill_table_d000(unsigned char *p) | ||
67 | { | ||
68 | int bit,byte; | ||
69 | |||
70 | for (bit=0; bit<8; bit++) | ||
71 | { | ||
72 | unsigned char bitpower = 1<<bit; | ||
73 | unsigned char mask = bitpower-1; | ||
74 | for (byte=0; byte<256; byte++) | ||
75 | { | ||
76 | if (byte & bitpower) | ||
77 | *p++ = -(byte & mask); | ||
78 | else | ||
79 | *p++ = (byte & mask); | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * | ||
86 | * Kiara: 0 <= ver <= 7 | ||
87 | * Timon: 0 <= ver <= 15 | ||
88 | * | ||
89 | */ | ||
90 | static void fill_table_color(unsigned int version, const unsigned int *romtable, | ||
91 | unsigned char *p0004, | ||
92 | unsigned char *p8004) | ||
93 | { | ||
94 | const unsigned int *table; | ||
95 | unsigned char *p0, *p8; | ||
96 | int i,j,k; | ||
97 | int dl,bit,pw; | ||
98 | |||
99 | romtable += version*256; | ||
100 | |||
101 | for (i=0; i<2; i++) | ||
102 | { | ||
103 | table = romtable + i*128; | ||
104 | |||
105 | for (dl=0; dl<16; dl++) | ||
106 | { | ||
107 | p0 = p0004 + (i<<14) + (dl<<10); | ||
108 | p8 = p8004 + (i<<12) + (dl<<8); | ||
109 | |||
110 | for (j=0; j<8; j++ , table++, p0+=128) | ||
111 | { | ||
112 | for (k=0; k<16; k++) | ||
113 | { | ||
114 | if (k==0) | ||
115 | bit=1; | ||
116 | else if (k>=1 && k<3) | ||
117 | bit=(table[0]>>15)&7; | ||
118 | else if (k>=3 && k<6) | ||
119 | bit=(table[0]>>12)&7; | ||
120 | else if (k>=6 && k<10) | ||
121 | bit=(table[0]>>9)&7; | ||
122 | else if (k>=10 && k<13) | ||
123 | bit=(table[0]>>6)&7; | ||
124 | else if (k>=13 && k<15) | ||
125 | bit=(table[0]>>3)&7; | ||
126 | else | ||
127 | bit=(table[0])&7; | ||
128 | if (k == 0) | ||
129 | *(unsigned char *)p8++ = 8; | ||
130 | else | ||
131 | *(unsigned char *)p8++ = j - bit; | ||
132 | *(unsigned char *)p8++ = bit; | ||
133 | |||
134 | pw = 1<<bit; | ||
135 | p0[k+0x00] = (1*pw) + 0x80; | ||
136 | p0[k+0x10] = (2*pw) + 0x80; | ||
137 | p0[k+0x20] = (3*pw) + 0x80; | ||
138 | p0[k+0x30] = (4*pw) + 0x80; | ||
139 | p0[k+0x40] = (-pw) + 0x80; | ||
140 | p0[k+0x50] = (2*-pw) + 0x80; | ||
141 | p0[k+0x60] = (3*-pw) + 0x80; | ||
142 | p0[k+0x70] = (4*-pw) + 0x80; | ||
143 | } /* end of for (k=0; k<16; k++, p8++) */ | ||
144 | } /* end of for (j=0; j<8; j++ , table++) */ | ||
145 | } /* end of for (dl=0; dl<16; dl++) */ | ||
146 | } /* end of for (i=0; i<2; i++) */ | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * precision = (pdev->xx + pdev->yy) | ||
151 | * | ||
152 | */ | ||
153 | static void fill_table_dc00_d800(unsigned int precision, unsigned int *pdc00, unsigned int *pd800) | ||
154 | { | ||
155 | int i; | ||
156 | unsigned int offset1, offset2; | ||
157 | |||
158 | for(i=0,offset1=0x4000, offset2=0; i<256 ; i++,offset1+=0x7BC4, offset2+=0x7BC4) | ||
159 | { | ||
160 | unsigned int msb = offset1 >> 15; | ||
161 | |||
162 | if ( msb > 255) | ||
163 | { | ||
164 | if (msb) | ||
165 | msb=0; | ||
166 | else | ||
167 | msb=255; | ||
168 | } | ||
169 | |||
170 | *pdc00++ = msb << precision; | ||
171 | *pd800++ = offset2; | ||
172 | } | ||
173 | |||
174 | } | ||
175 | |||
176 | /* | ||
177 | * struct { | ||
178 | * unsigned char op; // operation to execute | ||
179 | * unsigned char bits; // bits use to perform operation | ||
180 | * unsigned char offset1; // offset to add to access in the table_0004 % 16 | ||
181 | * unsigned char offset2; // offset to add to access in the table_0004 | ||
182 | * } | ||
183 | * | ||
184 | */ | ||
185 | static unsigned int table_ops[] = { | ||
186 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x01,0x30, | ||
187 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x20, 0x01,0x00,0x00,0x00, | ||
188 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x00, | ||
189 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x00, 0x01,0x00,0x00,0x00, | ||
190 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x02,0x10, | ||
191 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x60, 0x01,0x00,0x00,0x00, | ||
192 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x40, | ||
193 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x40, 0x01,0x00,0x00,0x00, | ||
194 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x01,0x70, | ||
195 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x20, 0x01,0x00,0x00,0x00, | ||
196 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x00, | ||
197 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x00, 0x01,0x00,0x00,0x00, | ||
198 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x02,0x50, | ||
199 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x60, 0x01,0x00,0x00,0x00, | ||
200 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x40, | ||
201 | 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x40, 0x01,0x00,0x00,0x00 | ||
202 | }; | ||
203 | |||
204 | /* | ||
205 | * TODO: multiply by 4 all values | ||
206 | * | ||
207 | */ | ||
208 | static unsigned int MulIdx[256] = { | ||
209 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
210 | 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, | ||
211 | 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, | ||
212 | 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, | ||
213 | 6, 7, 8, 9, 7,10,11, 8, 8,11,10, 7, 9, 8, 7, 6, | ||
214 | 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, | ||
215 | 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, | ||
216 | 0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3, | ||
217 | 0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3, | ||
218 | 1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2, | ||
219 | 7,10,11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8,11,10, 7, | ||
220 | 4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4, | ||
221 | 7, 9, 6, 8,10, 8, 7,11,11, 7, 8,10, 8, 6, 9, 7, | ||
222 | 1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2, | ||
223 | 1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2, | ||
224 | 10, 8, 7,11, 8, 6, 9, 7, 7, 9, 6, 8,11, 7, 8,10 | ||
225 | }; | ||
226 | |||
227 | |||
228 | |||
229 | void pwc_dec23_init(int type, int release, unsigned char *mode, void *data) | ||
230 | { | ||
231 | int flags; | ||
232 | struct pwc_dec23_private *pdev = data; | ||
233 | release = release; | ||
234 | |||
235 | switch (type) | ||
236 | { | ||
237 | case 720: | ||
238 | case 730: | ||
239 | case 740: | ||
240 | case 750: | ||
241 | flags = mode[2]&0x18; /* our: flags = 8, mode[2]==e8 */ | ||
242 | if (flags==8) | ||
243 | pdev->zz = 7; | ||
244 | else if (flags==0x10) | ||
245 | pdev->zz = 8; | ||
246 | else | ||
247 | pdev->zz = 6; | ||
248 | flags = mode[2]>>5; /* our: 7 */ | ||
249 | |||
250 | fill_table_color(flags, (unsigned int *)KiaraRomTable, pdev->table_0004, pdev->table_8004); | ||
251 | break; | ||
252 | |||
253 | |||
254 | case 675: | ||
255 | case 680: | ||
256 | case 690: | ||
257 | flags = mode[2]&6; | ||
258 | if (flags==2) | ||
259 | pdev->zz = 7; | ||
260 | else if (flags==4) | ||
261 | pdev->zz = 8; | ||
262 | else | ||
263 | pdev->zz = 6; | ||
264 | flags = mode[2]>>3; | ||
265 | |||
266 | fill_table_color(flags, (unsigned int *)TimonRomTable, pdev->table_0004, pdev->table_8004); | ||
267 | break; | ||
268 | |||
269 | default: | ||
270 | /* Not supported */ | ||
271 | return; | ||
272 | } | ||
273 | |||
274 | /* * * * ** */ | ||
275 | pdev->xx = 8 - pdev->zz; | ||
276 | pdev->yy = 15 - pdev->xx; | ||
277 | pdev->zzmask = 0xFF>>pdev->xx; | ||
278 | //pdev->zzmask = (1U<<pdev->zz)-1; | ||
279 | |||
280 | |||
281 | fill_table_dc00_d800(pdev->xx + pdev->yy, pdev->table_dc00, pdev->table_d800); | ||
282 | fill_table_a000(pdev->table_a004); | ||
283 | fill_table_d000(pdev->table_d004); | ||
284 | } | ||
285 | |||
286 | |||
287 | /* | ||
288 | * To manage the stream, we keep in a 32 bits variables, | ||
289 | * the next bits in the stream. fill_reservoir() add to | ||
290 | * the reservoir at least wanted nbits. | ||
291 | * | ||
292 | * | ||
293 | */ | ||
294 | #define fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \ | ||
295 | while (nbits_in_reservoir<nbits_wanted) \ | ||
296 | { \ | ||
297 | reservoir |= (*(stream)++) << nbits_in_reservoir; \ | ||
298 | nbits_in_reservoir+=8; \ | ||
299 | } \ | ||
300 | } while(0); | ||
301 | |||
302 | #define get_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) do { \ | ||
303 | fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted); \ | ||
304 | result = (reservoir) & ((1U<<nbits_wanted)-1); \ | ||
305 | reservoir >>= nbits_wanted; \ | ||
306 | nbits_in_reservoir -= nbits_wanted; \ | ||
307 | } while(0); | ||
308 | |||
309 | |||
310 | |||
311 | static void DecompressBand23(const struct pwc_dec23_private *pdev, | ||
312 | const unsigned char *rawyuv, | ||
313 | unsigned char *planar_y, | ||
314 | unsigned char *planar_u, | ||
315 | unsigned char *planar_v, | ||
316 | unsigned int image_x, /* aka number of pixels wanted ??? */ | ||
317 | unsigned int pixels_per_line, /* aka number of pixels per line */ | ||
318 | int flags) | ||
319 | { | ||
320 | |||
321 | |||
322 | unsigned int reservoir, nbits_in_reservoir; | ||
323 | int first_4_bits; | ||
324 | unsigned int bytes_per_channel; | ||
325 | int line_size; /* size of the line (4Y+U+V) */ | ||
326 | int passes; | ||
327 | const unsigned char *ptable0004, *ptable8004; | ||
328 | |||
329 | int even_line; | ||
330 | unsigned int temp_colors[16]; | ||
331 | int nblocks; | ||
332 | |||
333 | const unsigned char *stream; | ||
334 | unsigned char *dest_y, *dest_u=NULL, *dest_v=NULL; | ||
335 | unsigned int offset_to_plane_u, offset_to_plane_v; | ||
336 | |||
337 | int i; | ||
338 | |||
339 | |||
340 | reservoir = 0; | ||
341 | nbits_in_reservoir = 0; | ||
342 | stream = rawyuv+1; /* The first byte of the stream is skipped */ | ||
343 | even_line = 1; | ||
344 | |||
345 | get_nbits(reservoir,nbits_in_reservoir,stream,4,first_4_bits); | ||
346 | |||
347 | line_size = pixels_per_line*3; | ||
348 | |||
349 | for (passes=0;passes<2;passes++) | ||
350 | { | ||
351 | if (passes==0) | ||
352 | { | ||
353 | bytes_per_channel = pixels_per_line; | ||
354 | dest_y = planar_y; | ||
355 | nblocks = image_x/4; | ||
356 | } | ||
357 | else | ||
358 | { | ||
359 | /* Format planar: All Y, then all U, then all V */ | ||
360 | bytes_per_channel = pixels_per_line/2; | ||
361 | dest_u = planar_u; | ||
362 | dest_v = planar_v; | ||
363 | dest_y = dest_u; | ||
364 | nblocks = image_x/8; | ||
365 | } | ||
366 | |||
367 | offset_to_plane_u = bytes_per_channel*2; | ||
368 | offset_to_plane_v = bytes_per_channel*3; | ||
369 | /* | ||
370 | printf("bytes_per_channel = %d\n",bytes_per_channel); | ||
371 | printf("offset_to_plane_u = %d\n",offset_to_plane_u); | ||
372 | printf("offset_to_plane_v = %d\n",offset_to_plane_v); | ||
373 | */ | ||
374 | |||
375 | while (nblocks-->0) | ||
376 | { | ||
377 | unsigned int gray_index; | ||
378 | |||
379 | fill_nbits(reservoir,nbits_in_reservoir,stream,16); | ||
380 | gray_index = reservoir & pdev->zzmask; | ||
381 | reservoir >>= pdev->zz; | ||
382 | nbits_in_reservoir -= pdev->zz; | ||
383 | |||
384 | fill_nbits(reservoir,nbits_in_reservoir,stream,2); | ||
385 | |||
386 | if ( (reservoir & 3) == 0) | ||
387 | { | ||
388 | reservoir>>=2; | ||
389 | nbits_in_reservoir-=2; | ||
390 | for (i=0;i<16;i++) | ||
391 | temp_colors[i] = pdev->table_dc00[gray_index]; | ||
392 | |||
393 | } | ||
394 | else | ||
395 | { | ||
396 | unsigned int channel_v, offset1; | ||
397 | |||
398 | /* swap bit 0 and 2 of offset_OR */ | ||
399 | channel_v = ((reservoir & 1) << 2) | (reservoir & 2) | ((reservoir & 4)>>2); | ||
400 | reservoir>>=3; | ||
401 | nbits_in_reservoir-=3; | ||
402 | |||
403 | for (i=0;i<16;i++) | ||
404 | temp_colors[i] = pdev->table_d800[gray_index]; | ||
405 | |||
406 | ptable0004 = pdev->table_0004 + (passes*16384) + (first_4_bits*1024) + (channel_v*128); | ||
407 | ptable8004 = pdev->table_8004 + (passes*4096) + (first_4_bits*256) + (channel_v*32); | ||
408 | |||
409 | offset1 = 0; | ||
410 | while(1) | ||
411 | { | ||
412 | unsigned int index_in_table_ops, op, rows=0; | ||
413 | fill_nbits(reservoir,nbits_in_reservoir,stream,16); | ||
414 | |||
415 | /* mode is 0,1 or 2 */ | ||
416 | index_in_table_ops = (reservoir&0x3F); | ||
417 | op = table_ops[ index_in_table_ops*4 ]; | ||
418 | if (op == 2) | ||
419 | { | ||
420 | reservoir >>= 2; | ||
421 | nbits_in_reservoir -= 2; | ||
422 | break; /* exit the while(1) */ | ||
423 | } | ||
424 | if (op == 0) | ||
425 | { | ||
426 | unsigned int shift; | ||
427 | |||
428 | offset1 = (offset1 + table_ops[index_in_table_ops*4+2]) & 0x0F; | ||
429 | shift = table_ops[ index_in_table_ops*4+1 ]; | ||
430 | reservoir >>= shift; | ||
431 | nbits_in_reservoir -= shift; | ||
432 | rows = ptable0004[ offset1 + table_ops[index_in_table_ops*4+3] ]; | ||
433 | } | ||
434 | if (op == 1) | ||
435 | { | ||
436 | /* 10bits [ xxxx xxxx yyyy 000 ] | ||
437 | * yyy => offset in the table8004 | ||
438 | * xxx => offset in the tabled004 | ||
439 | */ | ||
440 | unsigned int mask, shift; | ||
441 | unsigned int col1, row1, total_bits; | ||
442 | |||
443 | offset1 = (offset1 + ((reservoir>>3)&0x0F)+1) & 0x0F; | ||
444 | |||
445 | col1 = (reservoir>>7) & 0xFF; | ||
446 | row1 = ptable8004 [ offset1*2 ]; | ||
447 | |||
448 | /* Bit mask table */ | ||
449 | mask = pdev->table_d004[ (row1<<8) + col1 ]; | ||
450 | shift = ptable8004 [ offset1*2 + 1]; | ||
451 | rows = ((mask << shift) + 0x80) & 0xFF; | ||
452 | |||
453 | total_bits = row1 + 8; | ||
454 | reservoir >>= total_bits; | ||
455 | nbits_in_reservoir -= total_bits; | ||
456 | } | ||
457 | { | ||
458 | const unsigned int *table_a004 = pdev->table_a004 + rows*12; | ||
459 | unsigned int *poffset = MulIdx + offset1*16; /* 64/4 (int) */ | ||
460 | for (i=0;i<16;i++) | ||
461 | { | ||
462 | temp_colors[i] += table_a004[ *poffset ]; | ||
463 | poffset++; | ||
464 | } | ||
465 | } | ||
466 | } | ||
467 | } | ||
468 | #define USE_SIGNED_INT_FOR_COLOR | ||
469 | #ifdef USE_SIGNED_INT_FOR_COLOR | ||
470 | # define CLAMP(x) ((x)>255?255:((x)<0?0:x)) | ||
471 | #else | ||
472 | # define CLAMP(x) ((x)>255?255:x) | ||
473 | #endif | ||
474 | |||
475 | if (passes == 0) | ||
476 | { | ||
477 | #ifdef USE_SIGNED_INT_FOR_COLOR | ||
478 | const int *c = temp_colors; | ||
479 | #else | ||
480 | const unsigned int *c = temp_colors; | ||
481 | #endif | ||
482 | unsigned char *d; | ||
483 | |||
484 | d = dest_y; | ||
485 | for (i=0;i<4;i++,c++) | ||
486 | *d++ = CLAMP((*c) >> pdev->yy); | ||
487 | |||
488 | d = dest_y + bytes_per_channel; | ||
489 | for (i=0;i<4;i++,c++) | ||
490 | *d++ = CLAMP((*c) >> pdev->yy); | ||
491 | |||
492 | d = dest_y + offset_to_plane_u; | ||
493 | for (i=0;i<4;i++,c++) | ||
494 | *d++ = CLAMP((*c) >> pdev->yy); | ||
495 | |||
496 | d = dest_y + offset_to_plane_v; | ||
497 | for (i=0;i<4;i++,c++) | ||
498 | *d++ = CLAMP((*c) >> pdev->yy); | ||
499 | |||
500 | dest_y += 4; | ||
501 | } | ||
502 | else if (passes == 1) | ||
503 | { | ||
504 | #ifdef USE_SIGNED_INT_FOR_COLOR | ||
505 | int *c1 = temp_colors; | ||
506 | int *c2 = temp_colors+4; | ||
507 | #else | ||
508 | unsigned int *c1 = temp_colors; | ||
509 | unsigned int *c2 = temp_colors+4; | ||
510 | #endif | ||
511 | unsigned char *d; | ||
512 | |||
513 | d = dest_y; | ||
514 | for (i=0;i<4;i++,c1++,c2++) | ||
515 | { | ||
516 | *d++ = CLAMP((*c1) >> pdev->yy); | ||
517 | *d++ = CLAMP((*c2) >> pdev->yy); | ||
518 | } | ||
519 | c1 = temp_colors+12; | ||
520 | //c2 = temp_colors+8; | ||
521 | d = dest_y + bytes_per_channel; | ||
522 | for (i=0;i<4;i++,c1++,c2++) | ||
523 | { | ||
524 | *d++ = CLAMP((*c1) >> pdev->yy); | ||
525 | *d++ = CLAMP((*c2) >> pdev->yy); | ||
526 | } | ||
527 | |||
528 | if (even_line) /* Each line, swap u/v */ | ||
529 | { | ||
530 | even_line=0; | ||
531 | dest_y = dest_v; | ||
532 | dest_u += 8; | ||
533 | } | ||
534 | else | ||
535 | { | ||
536 | even_line=1; | ||
537 | dest_y = dest_u; | ||
538 | dest_v += 8; | ||
539 | } | ||
540 | } | ||
541 | |||
542 | } /* end of while (nblocks-->0) */ | ||
543 | |||
544 | } /* end of for (passes=0;passes<2;passes++) */ | ||
545 | |||
546 | } | ||
547 | |||
548 | |||
549 | /** | ||
550 | * | ||
551 | * image: size of the image wanted | ||
552 | * view : size of the image returned by the camera | ||
553 | * offset: (x,y) to displayer image in the view | ||
554 | * | ||
555 | * src: raw data | ||
556 | * dst: image output | ||
557 | * flags: PWCX_FLAG_PLANAR | ||
558 | * pdev: private buffer | ||
559 | * bandlength: | ||
560 | * | ||
561 | */ | ||
562 | void pwc_dec23_decompress(const struct pwc_coord *image, | ||
563 | const struct pwc_coord *view, | ||
564 | const struct pwc_coord *offset, | ||
565 | const void *src, | ||
566 | void *dst, | ||
567 | int flags, | ||
568 | const void *data, | ||
569 | int bandlength) | ||
570 | { | ||
571 | const struct pwc_dec23_private *pdev = data; | ||
572 | unsigned char *pout, *pout_planar_y=NULL, *pout_planar_u=NULL, *pout_planar_v=NULL; | ||
573 | int i,n,stride,pixel_size; | ||
574 | |||
575 | |||
576 | if (flags & PWCX_FLAG_BAYER) | ||
577 | { | ||
578 | pout = dst + (view->x * offset->y) + offset->x; | ||
579 | pixel_size = view->x * 4; | ||
580 | } | ||
581 | else | ||
582 | { | ||
583 | n = view->x * view->y; | ||
584 | |||
585 | /* offset in Y plane */ | ||
586 | stride = view->x * offset->y; | ||
587 | pout_planar_y = dst + stride + offset->x; | ||
588 | |||
589 | /* offsets in U/V planes */ | ||
590 | stride = (view->x * offset->y)/4 + offset->x/2; | ||
591 | pout_planar_u = dst + n + + stride; | ||
592 | pout_planar_v = dst + n + n/4 + stride; | ||
593 | |||
594 | pixel_size = view->x * 4; | ||
595 | } | ||
596 | |||
597 | |||
598 | for (i=0;i<image->y;i+=4) | ||
599 | { | ||
600 | if (flags & PWCX_FLAG_BAYER) | ||
601 | { | ||
602 | //TODO: | ||
603 | //DecompressBandBayer(pdev,src,pout,image.x,view->x,flags); | ||
604 | src += bandlength; | ||
605 | pout += pixel_size; | ||
606 | } | ||
607 | else | ||
608 | { | ||
609 | DecompressBand23(pdev,src,pout_planar_y,pout_planar_u,pout_planar_v,image->x,view->x,flags); | ||
610 | src += bandlength; | ||
611 | pout_planar_y += pixel_size; | ||
612 | pout_planar_u += view->x; | ||
613 | pout_planar_v += view->x; | ||
614 | } | ||
615 | } | ||
616 | } | ||
617 | |||
618 | void pwc_dec23_exit(void) | ||
619 | { | ||
620 | /* Do nothing */ | ||
621 | |||
622 | } | ||
623 | |||
diff --git a/drivers/usb/media/pwc/pwc-dec23.h b/drivers/usb/media/pwc/pwc-dec23.h new file mode 100644 index 000000000000..5b2aacdefa6c --- /dev/null +++ b/drivers/usb/media/pwc/pwc-dec23.h | |||
@@ -0,0 +1,58 @@ | |||
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 | #ifndef PWC_DEC23_H | ||
26 | #define PWC_DEC23_H | ||
27 | |||
28 | struct pwc_dec23_private | ||
29 | { | ||
30 | unsigned char xx,yy,zz,zzmask; | ||
31 | |||
32 | unsigned char table_0004[2*0x4000]; | ||
33 | unsigned char table_8004[2*0x1000]; | ||
34 | unsigned int table_a004[256*12]; | ||
35 | |||
36 | unsigned char table_d004[8*256]; | ||
37 | unsigned int table_d800[256]; | ||
38 | unsigned int table_dc00[256]; | ||
39 | }; | ||
40 | |||
41 | |||
42 | void pwc_dec23_init(int type, int release, unsigned char *buffer, void *private_data); | ||
43 | void pwc_dec23_exit(void); | ||
44 | void pwc_dec23_decompress(const struct pwc_coord *image, | ||
45 | const struct pwc_coord *view, | ||
46 | const struct pwc_coord *offset, | ||
47 | const void *src, | ||
48 | void *dst, | ||
49 | int flags, | ||
50 | const void *data, | ||
51 | int bandlength); | ||
52 | |||
53 | |||
54 | |||
55 | #endif | ||
56 | |||
57 | |||
58 | |||
diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c new file mode 100644 index 000000000000..100a5a4f03a3 --- /dev/null +++ b/drivers/usb/media/pwc/pwc-if.c | |||
@@ -0,0 +1,2212 @@ | |||
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-dec23.h" | ||
72 | #include "pwc-dec1.h" | ||
73 | #include "pwc-uncompress.h" | ||
74 | |||
75 | /* Function prototypes and driver templates */ | ||
76 | |||
77 | /* hotplug device table support */ | ||
78 | static struct usb_device_id pwc_device_table [] = { | ||
79 | { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */ | ||
80 | { USB_DEVICE(0x0471, 0x0303) }, | ||
81 | { USB_DEVICE(0x0471, 0x0304) }, | ||
82 | { USB_DEVICE(0x0471, 0x0307) }, | ||
83 | { USB_DEVICE(0x0471, 0x0308) }, | ||
84 | { USB_DEVICE(0x0471, 0x030C) }, | ||
85 | { USB_DEVICE(0x0471, 0x0310) }, | ||
86 | { USB_DEVICE(0x0471, 0x0311) }, | ||
87 | { USB_DEVICE(0x0471, 0x0312) }, | ||
88 | { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */ | ||
89 | { USB_DEVICE(0x069A, 0x0001) }, /* Askey */ | ||
90 | { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */ | ||
91 | { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */ | ||
92 | { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */ | ||
93 | { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */ | ||
94 | { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */ | ||
95 | { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */ | ||
96 | { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */ | ||
97 | { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */ | ||
98 | { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ | ||
99 | { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */ | ||
100 | { USB_DEVICE(0x055D, 0x9001) }, | ||
101 | { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */ | ||
102 | { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */ | ||
103 | { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ | ||
104 | { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */ | ||
105 | { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */ | ||
106 | { USB_DEVICE(0x0d81, 0x1900) }, | ||
107 | { } | ||
108 | }; | ||
109 | MODULE_DEVICE_TABLE(usb, pwc_device_table); | ||
110 | |||
111 | static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id); | ||
112 | static void usb_pwc_disconnect(struct usb_interface *intf); | ||
113 | |||
114 | static struct usb_driver pwc_driver = { | ||
115 | .owner = THIS_MODULE, | ||
116 | .name = "Philips webcam", /* name */ | ||
117 | .id_table = pwc_device_table, | ||
118 | .probe = usb_pwc_probe, /* probe() */ | ||
119 | .disconnect = usb_pwc_disconnect, /* disconnect() */ | ||
120 | }; | ||
121 | |||
122 | #define MAX_DEV_HINTS 20 | ||
123 | #define MAX_ISOC_ERRORS 20 | ||
124 | |||
125 | static int default_size = PSZ_QCIF; | ||
126 | static int default_fps = 10; | ||
127 | static int default_fbufs = 3; /* Default number of frame buffers */ | ||
128 | static int default_mbufs = 2; /* Default number of mmap() buffers */ | ||
129 | int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; | ||
130 | static int power_save = 0; | ||
131 | static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ | ||
132 | int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ | ||
133 | static struct { | ||
134 | int type; | ||
135 | char serial_number[30]; | ||
136 | int device_node; | ||
137 | struct pwc_device *pdev; | ||
138 | } device_hint[MAX_DEV_HINTS]; | ||
139 | |||
140 | /***/ | ||
141 | |||
142 | static int pwc_video_open(struct inode *inode, struct file *file); | ||
143 | static int pwc_video_close(struct inode *inode, struct file *file); | ||
144 | static ssize_t pwc_video_read(struct file *file, char __user * buf, | ||
145 | size_t count, loff_t *ppos); | ||
146 | static unsigned int pwc_video_poll(struct file *file, poll_table *wait); | ||
147 | static int pwc_video_ioctl(struct inode *inode, struct file *file, | ||
148 | unsigned int ioctlnr, unsigned long arg); | ||
149 | static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); | ||
150 | |||
151 | static struct file_operations pwc_fops = { | ||
152 | .owner = THIS_MODULE, | ||
153 | .open = pwc_video_open, | ||
154 | .release = pwc_video_close, | ||
155 | .read = pwc_video_read, | ||
156 | .poll = pwc_video_poll, | ||
157 | .mmap = pwc_video_mmap, | ||
158 | .ioctl = pwc_video_ioctl, | ||
159 | .llseek = no_llseek, | ||
160 | }; | ||
161 | static struct video_device pwc_template = { | ||
162 | .owner = THIS_MODULE, | ||
163 | .name = "Philips Webcam", /* Filled in later */ | ||
164 | .type = VID_TYPE_CAPTURE, | ||
165 | .hardware = VID_HARDWARE_PWC, | ||
166 | .release = video_device_release, | ||
167 | .fops = &pwc_fops, | ||
168 | .minor = -1, | ||
169 | }; | ||
170 | |||
171 | /***************************************************************************/ | ||
172 | |||
173 | /* Okay, this is some magic that I worked out and the reasoning behind it... | ||
174 | |||
175 | The biggest problem with any USB device is of course: "what to do | ||
176 | when the user unplugs the device while it is in use by an application?" | ||
177 | We have several options: | ||
178 | 1) Curse them with the 7 plagues when they do (requires divine intervention) | ||
179 | 2) Tell them not to (won't work: they'll do it anyway) | ||
180 | 3) Oops the kernel (this will have a negative effect on a user's uptime) | ||
181 | 4) Do something sensible. | ||
182 | |||
183 | Of course, we go for option 4. | ||
184 | |||
185 | It happens that this device will be linked to two times, once from | ||
186 | usb_device and once from the video_device in their respective 'private' | ||
187 | pointers. This is done when the device is probed() and all initialization | ||
188 | succeeded. The pwc_device struct links back to both structures. | ||
189 | |||
190 | When a device is unplugged while in use it will be removed from the | ||
191 | list of known USB devices; I also de-register it as a V4L device, but | ||
192 | unfortunately I can't free the memory since the struct is still in use | ||
193 | by the file descriptor. This free-ing is then deferend until the first | ||
194 | opportunity. Crude, but it works. | ||
195 | |||
196 | A small 'advantage' is that if a user unplugs the cam and plugs it back | ||
197 | in, it should get assigned the same video device minor, but unfortunately | ||
198 | it's non-trivial to re-link the cam back to the video device... (that | ||
199 | would surely be magic! :)) | ||
200 | */ | ||
201 | |||
202 | /***************************************************************************/ | ||
203 | /* Private functions */ | ||
204 | |||
205 | /* Here we want the physical address of the memory. | ||
206 | * This is used when initializing the contents of the area. | ||
207 | */ | ||
208 | static inline unsigned long kvirt_to_pa(unsigned long adr) | ||
209 | { | ||
210 | unsigned long kva, ret; | ||
211 | |||
212 | kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); | ||
213 | kva |= adr & (PAGE_SIZE-1); /* restore the offset */ | ||
214 | ret = __pa(kva); | ||
215 | return ret; | ||
216 | } | ||
217 | |||
218 | static void * rvmalloc(unsigned long size) | ||
219 | { | ||
220 | void * mem; | ||
221 | unsigned long adr; | ||
222 | |||
223 | size=PAGE_ALIGN(size); | ||
224 | mem=vmalloc_32(size); | ||
225 | if (mem) | ||
226 | { | ||
227 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
228 | adr=(unsigned long) mem; | ||
229 | while (size > 0) | ||
230 | { | ||
231 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
232 | adr+=PAGE_SIZE; | ||
233 | size-=PAGE_SIZE; | ||
234 | } | ||
235 | } | ||
236 | return mem; | ||
237 | } | ||
238 | |||
239 | static void rvfree(void * mem, unsigned long size) | ||
240 | { | ||
241 | unsigned long adr; | ||
242 | |||
243 | if (mem) | ||
244 | { | ||
245 | adr=(unsigned long) mem; | ||
246 | while ((long) size > 0) | ||
247 | { | ||
248 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
249 | adr+=PAGE_SIZE; | ||
250 | size-=PAGE_SIZE; | ||
251 | } | ||
252 | vfree(mem); | ||
253 | } | ||
254 | } | ||
255 | |||
256 | |||
257 | |||
258 | |||
259 | static int pwc_allocate_buffers(struct pwc_device *pdev) | ||
260 | { | ||
261 | int i; | ||
262 | void *kbuf; | ||
263 | |||
264 | Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev); | ||
265 | |||
266 | if (pdev == NULL) | ||
267 | return -ENXIO; | ||
268 | |||
269 | #ifdef PWC_MAGIC | ||
270 | if (pdev->magic != PWC_MAGIC) { | ||
271 | Err("allocate_buffers(): magic failed.\n"); | ||
272 | return -ENXIO; | ||
273 | } | ||
274 | #endif | ||
275 | /* Allocate Isochronuous pipe buffers */ | ||
276 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
277 | if (pdev->sbuf[i].data == NULL) { | ||
278 | kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL); | ||
279 | if (kbuf == NULL) { | ||
280 | Err("Failed to allocate iso buffer %d.\n", i); | ||
281 | return -ENOMEM; | ||
282 | } | ||
283 | Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf); | ||
284 | pdev->sbuf[i].data = kbuf; | ||
285 | memset(kbuf, 0, ISO_BUFFER_SIZE); | ||
286 | } | ||
287 | } | ||
288 | |||
289 | /* Allocate frame buffer structure */ | ||
290 | if (pdev->fbuf == NULL) { | ||
291 | kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL); | ||
292 | if (kbuf == NULL) { | ||
293 | Err("Failed to allocate frame buffer structure.\n"); | ||
294 | return -ENOMEM; | ||
295 | } | ||
296 | Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf); | ||
297 | pdev->fbuf = kbuf; | ||
298 | memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf)); | ||
299 | } | ||
300 | /* create frame buffers, and make circular ring */ | ||
301 | for (i = 0; i < default_fbufs; i++) { | ||
302 | if (pdev->fbuf[i].data == NULL) { | ||
303 | kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */ | ||
304 | if (kbuf == NULL) { | ||
305 | Err("Failed to allocate frame buffer %d.\n", i); | ||
306 | return -ENOMEM; | ||
307 | } | ||
308 | Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf); | ||
309 | pdev->fbuf[i].data = kbuf; | ||
310 | memset(kbuf, 128, PWC_FRAME_SIZE); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | /* Allocate decompressor table space */ | ||
315 | kbuf = NULL; | ||
316 | switch (pdev->type) | ||
317 | { | ||
318 | case 675: | ||
319 | case 680: | ||
320 | case 690: | ||
321 | case 720: | ||
322 | case 730: | ||
323 | case 740: | ||
324 | case 750: | ||
325 | Trace(TRACE_MEMORY,"private_data(%Zd)\n",sizeof(struct pwc_dec23_private)); | ||
326 | kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); /* Timon & Kiara */ | ||
327 | break; | ||
328 | case 645: | ||
329 | case 646: | ||
330 | /* TODO & FIXME */ | ||
331 | kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); | ||
332 | break; | ||
333 | } | ||
334 | if (kbuf == NULL) { | ||
335 | Err("Failed to allocate decompress table.\n"); | ||
336 | return -ENOMEM; | ||
337 | } | ||
338 | pdev->decompress_data = kbuf; | ||
339 | |||
340 | /* Allocate image buffer; double buffer for mmap() */ | ||
341 | kbuf = rvmalloc(default_mbufs * pdev->len_per_image); | ||
342 | if (kbuf == NULL) { | ||
343 | Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image); | ||
344 | return -ENOMEM; | ||
345 | } | ||
346 | Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf); | ||
347 | pdev->image_data = kbuf; | ||
348 | for (i = 0; i < default_mbufs; i++) | ||
349 | pdev->image_ptr[i] = kbuf + i * pdev->len_per_image; | ||
350 | for (; i < MAX_IMAGES; i++) | ||
351 | pdev->image_ptr[i] = NULL; | ||
352 | |||
353 | kbuf = NULL; | ||
354 | |||
355 | Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n"); | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static void pwc_free_buffers(struct pwc_device *pdev) | ||
360 | { | ||
361 | int i; | ||
362 | |||
363 | Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev); | ||
364 | |||
365 | if (pdev == NULL) | ||
366 | return; | ||
367 | #ifdef PWC_MAGIC | ||
368 | if (pdev->magic != PWC_MAGIC) { | ||
369 | Err("free_buffers(): magic failed.\n"); | ||
370 | return; | ||
371 | } | ||
372 | #endif | ||
373 | |||
374 | /* Release Iso-pipe buffers */ | ||
375 | for (i = 0; i < MAX_ISO_BUFS; i++) | ||
376 | if (pdev->sbuf[i].data != NULL) { | ||
377 | Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data); | ||
378 | kfree(pdev->sbuf[i].data); | ||
379 | pdev->sbuf[i].data = NULL; | ||
380 | } | ||
381 | |||
382 | /* The same for frame buffers */ | ||
383 | if (pdev->fbuf != NULL) { | ||
384 | for (i = 0; i < default_fbufs; i++) { | ||
385 | if (pdev->fbuf[i].data != NULL) { | ||
386 | Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data); | ||
387 | vfree(pdev->fbuf[i].data); | ||
388 | pdev->fbuf[i].data = NULL; | ||
389 | } | ||
390 | } | ||
391 | kfree(pdev->fbuf); | ||
392 | pdev->fbuf = NULL; | ||
393 | } | ||
394 | |||
395 | /* Intermediate decompression buffer & tables */ | ||
396 | if (pdev->decompress_data != NULL) { | ||
397 | Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data); | ||
398 | kfree(pdev->decompress_data); | ||
399 | pdev->decompress_data = NULL; | ||
400 | } | ||
401 | pdev->decompressor = NULL; | ||
402 | |||
403 | /* Release image buffers */ | ||
404 | if (pdev->image_data != NULL) { | ||
405 | Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data); | ||
406 | rvfree(pdev->image_data, default_mbufs * pdev->len_per_image); | ||
407 | } | ||
408 | pdev->image_data = NULL; | ||
409 | |||
410 | Trace(TRACE_MEMORY, "Leaving free_buffers().\n"); | ||
411 | } | ||
412 | |||
413 | /* The frame & image buffer mess. | ||
414 | |||
415 | Yes, this is a mess. Well, it used to be simple, but alas... In this | ||
416 | module, 3 buffers schemes are used to get the data from the USB bus to | ||
417 | the user program. The first scheme involves the ISO buffers (called thus | ||
418 | since they transport ISO data from the USB controller), and not really | ||
419 | interesting. Suffices to say the data from this buffer is quickly | ||
420 | gathered in an interrupt handler (pwc_isoc_handler) and placed into the | ||
421 | frame buffer. | ||
422 | |||
423 | The frame buffer is the second scheme, and is the central element here. | ||
424 | It collects the data from a single frame from the camera (hence, the | ||
425 | name). Frames are delimited by the USB camera with a short USB packet, | ||
426 | so that's easy to detect. The frame buffers form a list that is filled | ||
427 | by the camera+USB controller and drained by the user process through | ||
428 | either read() or mmap(). | ||
429 | |||
430 | The image buffer is the third scheme, in which frames are decompressed | ||
431 | and converted into planar format. For mmap() there is more than | ||
432 | one image buffer available. | ||
433 | |||
434 | The frame buffers provide the image buffering. In case the user process | ||
435 | is a bit slow, this introduces lag and some undesired side-effects. | ||
436 | The problem arises when the frame buffer is full. I used to drop the last | ||
437 | frame, which makes the data in the queue stale very quickly. But dropping | ||
438 | the frame at the head of the queue proved to be a litte bit more difficult. | ||
439 | I tried a circular linked scheme, but this introduced more problems than | ||
440 | it solved. | ||
441 | |||
442 | Because filling and draining are completely asynchronous processes, this | ||
443 | requires some fiddling with pointers and mutexes. | ||
444 | |||
445 | Eventually, I came up with a system with 2 lists: an 'empty' frame list | ||
446 | and a 'full' frame list: | ||
447 | * Initially, all frame buffers but one are on the 'empty' list; the one | ||
448 | remaining buffer is our initial fill frame. | ||
449 | * If a frame is needed for filling, we try to take it from the 'empty' | ||
450 | list, unless that list is empty, in which case we take the buffer at | ||
451 | the head of the 'full' list. | ||
452 | * When our fill buffer has been filled, it is appended to the 'full' | ||
453 | list. | ||
454 | * If a frame is needed by read() or mmap(), it is taken from the head of | ||
455 | the 'full' list, handled, and then appended to the 'empty' list. If no | ||
456 | buffer is present on the 'full' list, we wait. | ||
457 | The advantage is that the buffer that is currently being decompressed/ | ||
458 | converted, is on neither list, and thus not in our way (any other scheme | ||
459 | I tried had the problem of old data lingering in the queue). | ||
460 | |||
461 | Whatever strategy you choose, it always remains a tradeoff: with more | ||
462 | frame buffers the chances of a missed frame are reduced. On the other | ||
463 | hand, on slower machines it introduces lag because the queue will | ||
464 | always be full. | ||
465 | */ | ||
466 | |||
467 | /** | ||
468 | \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first. | ||
469 | */ | ||
470 | static inline int pwc_next_fill_frame(struct pwc_device *pdev) | ||
471 | { | ||
472 | int ret; | ||
473 | unsigned long flags; | ||
474 | |||
475 | ret = 0; | ||
476 | spin_lock_irqsave(&pdev->ptrlock, flags); | ||
477 | if (pdev->fill_frame != NULL) { | ||
478 | /* append to 'full' list */ | ||
479 | if (pdev->full_frames == NULL) { | ||
480 | pdev->full_frames = pdev->fill_frame; | ||
481 | pdev->full_frames_tail = pdev->full_frames; | ||
482 | } | ||
483 | else { | ||
484 | pdev->full_frames_tail->next = pdev->fill_frame; | ||
485 | pdev->full_frames_tail = pdev->fill_frame; | ||
486 | } | ||
487 | } | ||
488 | if (pdev->empty_frames != NULL) { | ||
489 | /* We have empty frames available. That's easy */ | ||
490 | pdev->fill_frame = pdev->empty_frames; | ||
491 | pdev->empty_frames = pdev->empty_frames->next; | ||
492 | } | ||
493 | else { | ||
494 | /* Hmm. Take it from the full list */ | ||
495 | #if PWC_DEBUG | ||
496 | /* sanity check */ | ||
497 | if (pdev->full_frames == NULL) { | ||
498 | Err("Neither empty or full frames available!\n"); | ||
499 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
500 | return -EINVAL; | ||
501 | } | ||
502 | #endif | ||
503 | pdev->fill_frame = pdev->full_frames; | ||
504 | pdev->full_frames = pdev->full_frames->next; | ||
505 | ret = 1; | ||
506 | } | ||
507 | pdev->fill_frame->next = NULL; | ||
508 | #if PWC_DEBUG | ||
509 | Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence); | ||
510 | pdev->fill_frame->sequence = pdev->sequence++; | ||
511 | #endif | ||
512 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
513 | return ret; | ||
514 | } | ||
515 | |||
516 | |||
517 | /** | ||
518 | \brief Reset all buffers, pointers and lists, except for the image_used[] buffer. | ||
519 | |||
520 | If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble. | ||
521 | */ | ||
522 | static void pwc_reset_buffers(struct pwc_device *pdev) | ||
523 | { | ||
524 | int i; | ||
525 | unsigned long flags; | ||
526 | |||
527 | spin_lock_irqsave(&pdev->ptrlock, flags); | ||
528 | pdev->full_frames = NULL; | ||
529 | pdev->full_frames_tail = NULL; | ||
530 | for (i = 0; i < default_fbufs; i++) { | ||
531 | pdev->fbuf[i].filled = 0; | ||
532 | if (i > 0) | ||
533 | pdev->fbuf[i].next = &pdev->fbuf[i - 1]; | ||
534 | else | ||
535 | pdev->fbuf->next = NULL; | ||
536 | } | ||
537 | pdev->empty_frames = &pdev->fbuf[default_fbufs - 1]; | ||
538 | pdev->empty_frames_tail = pdev->fbuf; | ||
539 | pdev->read_frame = NULL; | ||
540 | pdev->fill_frame = pdev->empty_frames; | ||
541 | pdev->empty_frames = pdev->empty_frames->next; | ||
542 | |||
543 | pdev->image_read_pos = 0; | ||
544 | pdev->fill_image = 0; | ||
545 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
546 | } | ||
547 | |||
548 | |||
549 | /** | ||
550 | \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers. | ||
551 | */ | ||
552 | static int pwc_handle_frame(struct pwc_device *pdev) | ||
553 | { | ||
554 | int ret = 0; | ||
555 | unsigned long flags; | ||
556 | |||
557 | spin_lock_irqsave(&pdev->ptrlock, flags); | ||
558 | /* First grab our read_frame; this is removed from all lists, so | ||
559 | we can release the lock after this without problems */ | ||
560 | if (pdev->read_frame != NULL) { | ||
561 | /* This can't theoretically happen */ | ||
562 | Err("Huh? Read frame still in use?\n"); | ||
563 | } | ||
564 | else { | ||
565 | if (pdev->full_frames == NULL) { | ||
566 | Err("Woops. No frames ready.\n"); | ||
567 | } | ||
568 | else { | ||
569 | pdev->read_frame = pdev->full_frames; | ||
570 | pdev->full_frames = pdev->full_frames->next; | ||
571 | pdev->read_frame->next = NULL; | ||
572 | } | ||
573 | |||
574 | if (pdev->read_frame != NULL) { | ||
575 | #if PWC_DEBUG | ||
576 | Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence); | ||
577 | #endif | ||
578 | /* Decompression is a lenghty process, so it's outside of the lock. | ||
579 | This gives the isoc_handler the opportunity to fill more frames | ||
580 | in the mean time. | ||
581 | */ | ||
582 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
583 | ret = pwc_decompress(pdev); | ||
584 | spin_lock_irqsave(&pdev->ptrlock, flags); | ||
585 | |||
586 | /* We're done with read_buffer, tack it to the end of the empty buffer list */ | ||
587 | if (pdev->empty_frames == NULL) { | ||
588 | pdev->empty_frames = pdev->read_frame; | ||
589 | pdev->empty_frames_tail = pdev->empty_frames; | ||
590 | } | ||
591 | else { | ||
592 | pdev->empty_frames_tail->next = pdev->read_frame; | ||
593 | pdev->empty_frames_tail = pdev->read_frame; | ||
594 | } | ||
595 | pdev->read_frame = NULL; | ||
596 | } | ||
597 | } | ||
598 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
599 | return ret; | ||
600 | } | ||
601 | |||
602 | /** | ||
603 | \brief Advance pointers of image buffer (after each user request) | ||
604 | */ | ||
605 | static inline void pwc_next_image(struct pwc_device *pdev) | ||
606 | { | ||
607 | pdev->image_used[pdev->fill_image] = 0; | ||
608 | pdev->fill_image = (pdev->fill_image + 1) % default_mbufs; | ||
609 | } | ||
610 | |||
611 | |||
612 | /* This gets called for the Isochronous pipe (video). This is done in | ||
613 | * interrupt time, so it has to be fast, not crash, and not stall. Neat. | ||
614 | */ | ||
615 | static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs) | ||
616 | { | ||
617 | struct pwc_device *pdev; | ||
618 | int i, fst, flen; | ||
619 | int awake; | ||
620 | struct pwc_frame_buf *fbuf; | ||
621 | unsigned char *fillptr = NULL, *iso_buf = NULL; | ||
622 | |||
623 | awake = 0; | ||
624 | pdev = (struct pwc_device *)urb->context; | ||
625 | if (pdev == NULL) { | ||
626 | Err("isoc_handler() called with NULL device?!\n"); | ||
627 | return; | ||
628 | } | ||
629 | #ifdef PWC_MAGIC | ||
630 | if (pdev->magic != PWC_MAGIC) { | ||
631 | Err("isoc_handler() called with bad magic!\n"); | ||
632 | return; | ||
633 | } | ||
634 | #endif | ||
635 | if (urb->status == -ENOENT || urb->status == -ECONNRESET) { | ||
636 | Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); | ||
637 | return; | ||
638 | } | ||
639 | if (urb->status != -EINPROGRESS && urb->status != 0) { | ||
640 | const char *errmsg; | ||
641 | |||
642 | errmsg = "Unknown"; | ||
643 | switch(urb->status) { | ||
644 | case -ENOSR: errmsg = "Buffer error (overrun)"; break; | ||
645 | case -EPIPE: errmsg = "Stalled (device not responding)"; break; | ||
646 | case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break; | ||
647 | case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break; | ||
648 | case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break; | ||
649 | case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break; | ||
650 | } | ||
651 | Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg); | ||
652 | /* Give up after a number of contiguous errors on the USB bus. | ||
653 | Appearantly something is wrong so we simulate an unplug event. | ||
654 | */ | ||
655 | if (++pdev->visoc_errors > MAX_ISOC_ERRORS) | ||
656 | { | ||
657 | Info("Too many ISOC errors, bailing out.\n"); | ||
658 | pdev->error_status = EIO; | ||
659 | awake = 1; | ||
660 | wake_up_interruptible(&pdev->frameq); | ||
661 | } | ||
662 | goto handler_end; // ugly, but practical | ||
663 | } | ||
664 | |||
665 | fbuf = pdev->fill_frame; | ||
666 | if (fbuf == NULL) { | ||
667 | Err("pwc_isoc_handler without valid fill frame.\n"); | ||
668 | awake = 1; | ||
669 | goto handler_end; | ||
670 | } | ||
671 | else { | ||
672 | fillptr = fbuf->data + fbuf->filled; | ||
673 | } | ||
674 | |||
675 | /* Reset ISOC error counter. We did get here, after all. */ | ||
676 | pdev->visoc_errors = 0; | ||
677 | |||
678 | /* vsync: 0 = don't copy data | ||
679 | 1 = sync-hunt | ||
680 | 2 = synched | ||
681 | */ | ||
682 | /* Compact data */ | ||
683 | for (i = 0; i < urb->number_of_packets; i++) { | ||
684 | fst = urb->iso_frame_desc[i].status; | ||
685 | flen = urb->iso_frame_desc[i].actual_length; | ||
686 | iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; | ||
687 | if (fst == 0) { | ||
688 | if (flen > 0) { /* if valid data... */ | ||
689 | if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */ | ||
690 | pdev->vsync = 2; | ||
691 | |||
692 | /* ...copy data to frame buffer, if possible */ | ||
693 | if (flen + fbuf->filled > pdev->frame_total_size) { | ||
694 | Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size); | ||
695 | pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */ | ||
696 | pdev->vframes_error++; | ||
697 | } | ||
698 | else { | ||
699 | memmove(fillptr, iso_buf, flen); | ||
700 | fillptr += flen; | ||
701 | } | ||
702 | } | ||
703 | fbuf->filled += flen; | ||
704 | } /* ..flen > 0 */ | ||
705 | |||
706 | if (flen < pdev->vlast_packet_size) { | ||
707 | /* Shorter packet... We probably have the end of an image-frame; | ||
708 | wake up read() process and let select()/poll() do something. | ||
709 | Decompression is done in user time over there. | ||
710 | */ | ||
711 | if (pdev->vsync == 2) { | ||
712 | /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus | ||
713 | frames on the USB wire after an exposure change. This conditition is | ||
714 | however detected in the cam and a bit is set in the header. | ||
715 | */ | ||
716 | if (pdev->type == 730) { | ||
717 | unsigned char *ptr = (unsigned char *)fbuf->data; | ||
718 | |||
719 | if (ptr[1] == 1 && ptr[0] & 0x10) { | ||
720 | #if PWC_DEBUG | ||
721 | Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence); | ||
722 | #endif | ||
723 | pdev->drop_frames += 2; | ||
724 | pdev->vframes_error++; | ||
725 | } | ||
726 | if ((ptr[0] ^ pdev->vmirror) & 0x01) { | ||
727 | if (ptr[0] & 0x01) | ||
728 | Info("Snapshot button pressed.\n"); | ||
729 | else | ||
730 | Info("Snapshot button released.\n"); | ||
731 | } | ||
732 | if ((ptr[0] ^ pdev->vmirror) & 0x02) { | ||
733 | if (ptr[0] & 0x02) | ||
734 | Info("Image is mirrored.\n"); | ||
735 | else | ||
736 | Info("Image is normal.\n"); | ||
737 | } | ||
738 | pdev->vmirror = ptr[0] & 0x03; | ||
739 | /* Sometimes the trailer of the 730 is still sent as a 4 byte packet | ||
740 | after a short frame; this condition is filtered out specifically. A 4 byte | ||
741 | frame doesn't make sense anyway. | ||
742 | So we get either this sequence: | ||
743 | drop_bit set -> 4 byte frame -> short frame -> good frame | ||
744 | Or this one: | ||
745 | drop_bit set -> short frame -> good frame | ||
746 | So we drop either 3 or 2 frames in all! | ||
747 | */ | ||
748 | if (fbuf->filled == 4) | ||
749 | pdev->drop_frames++; | ||
750 | } | ||
751 | |||
752 | /* In case we were instructed to drop the frame, do so silently. | ||
753 | The buffer pointers are not updated either (but the counters are reset below). | ||
754 | */ | ||
755 | if (pdev->drop_frames > 0) | ||
756 | pdev->drop_frames--; | ||
757 | else { | ||
758 | /* Check for underflow first */ | ||
759 | if (fbuf->filled < pdev->frame_total_size) { | ||
760 | Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled); | ||
761 | pdev->vframes_error++; | ||
762 | } | ||
763 | else { | ||
764 | /* Send only once per EOF */ | ||
765 | awake = 1; /* delay wake_ups */ | ||
766 | |||
767 | /* Find our next frame to fill. This will always succeed, since we | ||
768 | * nick a frame from either empty or full list, but if we had to | ||
769 | * take it from the full list, it means a frame got dropped. | ||
770 | */ | ||
771 | if (pwc_next_fill_frame(pdev)) { | ||
772 | pdev->vframes_dumped++; | ||
773 | if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) { | ||
774 | if (pdev->vframes_dumped < 20) | ||
775 | Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count); | ||
776 | if (pdev->vframes_dumped == 20) | ||
777 | Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count); | ||
778 | } | ||
779 | } | ||
780 | fbuf = pdev->fill_frame; | ||
781 | } | ||
782 | } /* !drop_frames */ | ||
783 | pdev->vframe_count++; | ||
784 | } | ||
785 | fbuf->filled = 0; | ||
786 | fillptr = fbuf->data; | ||
787 | pdev->vsync = 1; | ||
788 | } /* .. flen < last_packet_size */ | ||
789 | pdev->vlast_packet_size = flen; | ||
790 | } /* ..status == 0 */ | ||
791 | #if PWC_DEBUG | ||
792 | /* This is normally not interesting to the user, unless you are really debugging something */ | ||
793 | else { | ||
794 | static int iso_error = 0; | ||
795 | iso_error++; | ||
796 | if (iso_error < 20) | ||
797 | Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst); | ||
798 | } | ||
799 | #endif | ||
800 | } | ||
801 | |||
802 | handler_end: | ||
803 | if (awake) | ||
804 | wake_up_interruptible(&pdev->frameq); | ||
805 | |||
806 | urb->dev = pdev->udev; | ||
807 | i = usb_submit_urb(urb, GFP_ATOMIC); | ||
808 | if (i != 0) | ||
809 | Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); | ||
810 | } | ||
811 | |||
812 | |||
813 | static int pwc_isoc_init(struct pwc_device *pdev) | ||
814 | { | ||
815 | struct usb_device *udev; | ||
816 | struct urb *urb; | ||
817 | int i, j, ret; | ||
818 | |||
819 | struct usb_interface *intf; | ||
820 | struct usb_host_interface *idesc = NULL; | ||
821 | |||
822 | if (pdev == NULL) | ||
823 | return -EFAULT; | ||
824 | if (pdev->iso_init) | ||
825 | return 0; | ||
826 | pdev->vsync = 0; | ||
827 | udev = pdev->udev; | ||
828 | |||
829 | /* Get the current alternate interface, adjust packet size */ | ||
830 | if (!udev->actconfig) | ||
831 | return -EFAULT; | ||
832 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5) | ||
833 | idesc = &udev->actconfig->interface[0]->altsetting[pdev->valternate]; | ||
834 | #else | ||
835 | intf = usb_ifnum_to_if(udev, 0); | ||
836 | if (intf) | ||
837 | idesc = usb_altnum_to_altsetting(intf, pdev->valternate); | ||
838 | #endif | ||
839 | |||
840 | if (!idesc) | ||
841 | return -EFAULT; | ||
842 | |||
843 | /* Search video endpoint */ | ||
844 | pdev->vmax_packet_size = -1; | ||
845 | for (i = 0; i < idesc->desc.bNumEndpoints; i++) | ||
846 | if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) { | ||
847 | pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize); | ||
848 | break; | ||
849 | } | ||
850 | |||
851 | if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) { | ||
852 | Err("Failed to find packet size for video endpoint in current alternate setting.\n"); | ||
853 | return -ENFILE; /* Odd error, that should be noticable */ | ||
854 | } | ||
855 | |||
856 | /* Set alternate interface */ | ||
857 | ret = 0; | ||
858 | Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate); | ||
859 | ret = usb_set_interface(pdev->udev, 0, pdev->valternate); | ||
860 | if (ret < 0) | ||
861 | return ret; | ||
862 | |||
863 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
864 | urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); | ||
865 | if (urb == NULL) { | ||
866 | Err("Failed to allocate urb %d\n", i); | ||
867 | ret = -ENOMEM; | ||
868 | break; | ||
869 | } | ||
870 | pdev->sbuf[i].urb = urb; | ||
871 | Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb); | ||
872 | } | ||
873 | if (ret) { | ||
874 | /* De-allocate in reverse order */ | ||
875 | while (i >= 0) { | ||
876 | if (pdev->sbuf[i].urb != NULL) | ||
877 | usb_free_urb(pdev->sbuf[i].urb); | ||
878 | pdev->sbuf[i].urb = NULL; | ||
879 | i--; | ||
880 | } | ||
881 | return ret; | ||
882 | } | ||
883 | |||
884 | /* init URB structure */ | ||
885 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
886 | urb = pdev->sbuf[i].urb; | ||
887 | |||
888 | urb->interval = 1; // devik | ||
889 | urb->dev = udev; | ||
890 | urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); | ||
891 | urb->transfer_flags = URB_ISO_ASAP; | ||
892 | urb->transfer_buffer = pdev->sbuf[i].data; | ||
893 | urb->transfer_buffer_length = ISO_BUFFER_SIZE; | ||
894 | urb->complete = pwc_isoc_handler; | ||
895 | urb->context = pdev; | ||
896 | urb->start_frame = 0; | ||
897 | urb->number_of_packets = ISO_FRAMES_PER_DESC; | ||
898 | for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { | ||
899 | urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; | ||
900 | urb->iso_frame_desc[j].length = pdev->vmax_packet_size; | ||
901 | } | ||
902 | } | ||
903 | |||
904 | /* link */ | ||
905 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
906 | ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL); | ||
907 | if (ret) | ||
908 | Err("isoc_init() submit_urb %d failed with error %d\n", i, ret); | ||
909 | else | ||
910 | Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb); | ||
911 | } | ||
912 | |||
913 | /* All is done... */ | ||
914 | pdev->iso_init = 1; | ||
915 | Trace(TRACE_OPEN, "<< pwc_isoc_init()\n"); | ||
916 | return 0; | ||
917 | } | ||
918 | |||
919 | static void pwc_isoc_cleanup(struct pwc_device *pdev) | ||
920 | { | ||
921 | int i; | ||
922 | |||
923 | Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n"); | ||
924 | if (pdev == NULL) | ||
925 | return; | ||
926 | |||
927 | /* Unlinking ISOC buffers one by one */ | ||
928 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
929 | struct urb *urb; | ||
930 | |||
931 | urb = pdev->sbuf[i].urb; | ||
932 | if (urb != 0) { | ||
933 | if (pdev->iso_init) { | ||
934 | Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb); | ||
935 | usb_kill_urb(urb); | ||
936 | } | ||
937 | Trace(TRACE_MEMORY, "Freeing URB\n"); | ||
938 | usb_free_urb(urb); | ||
939 | pdev->sbuf[i].urb = NULL; | ||
940 | } | ||
941 | } | ||
942 | |||
943 | /* Stop camera, but only if we are sure the camera is still there (unplug | ||
944 | is signalled by EPIPE) | ||
945 | */ | ||
946 | if (pdev->error_status && pdev->error_status != EPIPE) { | ||
947 | Trace(TRACE_OPEN, "Setting alternate interface 0.\n"); | ||
948 | usb_set_interface(pdev->udev, 0, 0); | ||
949 | } | ||
950 | |||
951 | pdev->iso_init = 0; | ||
952 | Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n"); | ||
953 | } | ||
954 | |||
955 | int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot) | ||
956 | { | ||
957 | int ret, start; | ||
958 | |||
959 | /* Stop isoc stuff */ | ||
960 | pwc_isoc_cleanup(pdev); | ||
961 | /* Reset parameters */ | ||
962 | pwc_reset_buffers(pdev); | ||
963 | /* Try to set video mode... */ | ||
964 | start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot); | ||
965 | if (ret) { | ||
966 | Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n"); | ||
967 | /* That failed... restore old mode (we know that worked) */ | ||
968 | start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); | ||
969 | if (start) { | ||
970 | Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n"); | ||
971 | } | ||
972 | } | ||
973 | if (start == 0) | ||
974 | { | ||
975 | if (pwc_isoc_init(pdev) < 0) | ||
976 | { | ||
977 | Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n"); | ||
978 | ret = -EAGAIN; /* let's try again, who knows if it works a second time */ | ||
979 | } | ||
980 | } | ||
981 | pdev->drop_frames++; /* try to avoid garbage during switch */ | ||
982 | return ret; /* Return original error code */ | ||
983 | } | ||
984 | |||
985 | |||
986 | /***************************************************************************/ | ||
987 | /* Video4Linux functions */ | ||
988 | |||
989 | static int pwc_video_open(struct inode *inode, struct file *file) | ||
990 | { | ||
991 | int i; | ||
992 | struct video_device *vdev = video_devdata(file); | ||
993 | struct pwc_device *pdev; | ||
994 | |||
995 | Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev); | ||
996 | |||
997 | pdev = (struct pwc_device *)vdev->priv; | ||
998 | if (pdev == NULL) | ||
999 | BUG(); | ||
1000 | if (pdev->vopen) | ||
1001 | return -EBUSY; | ||
1002 | |||
1003 | down(&pdev->modlock); | ||
1004 | if (!pdev->usb_init) { | ||
1005 | Trace(TRACE_OPEN, "Doing first time initialization.\n"); | ||
1006 | pdev->usb_init = 1; | ||
1007 | |||
1008 | if (pwc_trace & TRACE_OPEN) | ||
1009 | { | ||
1010 | /* Query sensor type */ | ||
1011 | const char *sensor_type = NULL; | ||
1012 | int ret; | ||
1013 | |||
1014 | ret = pwc_get_cmos_sensor(pdev, &i); | ||
1015 | if (ret >= 0) | ||
1016 | { | ||
1017 | switch(i) { | ||
1018 | case 0x00: sensor_type = "Hyundai CMOS sensor"; break; | ||
1019 | case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break; | ||
1020 | case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break; | ||
1021 | case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break; | ||
1022 | case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break; | ||
1023 | case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break; | ||
1024 | case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break; | ||
1025 | case 0x40: sensor_type = "UPA 1021 sensor"; break; | ||
1026 | case 0x100: sensor_type = "VGA sensor"; break; | ||
1027 | case 0x101: sensor_type = "PAL MR sensor"; break; | ||
1028 | default: sensor_type = "unknown type of sensor"; break; | ||
1029 | } | ||
1030 | } | ||
1031 | if (sensor_type != NULL) | ||
1032 | Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i); | ||
1033 | } | ||
1034 | } | ||
1035 | |||
1036 | /* Turn on camera */ | ||
1037 | if (power_save) { | ||
1038 | i = pwc_camera_power(pdev, 1); | ||
1039 | if (i < 0) | ||
1040 | Info("Failed to restore power to the camera! (%d)\n", i); | ||
1041 | } | ||
1042 | /* Set LED on/off time */ | ||
1043 | if (pwc_set_leds(pdev, led_on, led_off) < 0) | ||
1044 | Info("Failed to set LED on/off time.\n"); | ||
1045 | |||
1046 | pwc_construct(pdev); /* set min/max sizes correct */ | ||
1047 | |||
1048 | /* So far, so good. Allocate memory. */ | ||
1049 | i = pwc_allocate_buffers(pdev); | ||
1050 | if (i < 0) { | ||
1051 | Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n"); | ||
1052 | up(&pdev->modlock); | ||
1053 | return i; | ||
1054 | } | ||
1055 | |||
1056 | /* Reset buffers & parameters */ | ||
1057 | pwc_reset_buffers(pdev); | ||
1058 | for (i = 0; i < default_mbufs; i++) | ||
1059 | pdev->image_used[i] = 0; | ||
1060 | pdev->vframe_count = 0; | ||
1061 | pdev->vframes_dumped = 0; | ||
1062 | pdev->vframes_error = 0; | ||
1063 | pdev->visoc_errors = 0; | ||
1064 | pdev->error_status = 0; | ||
1065 | #if PWC_DEBUG | ||
1066 | pdev->sequence = 0; | ||
1067 | #endif | ||
1068 | pwc_construct(pdev); /* set min/max sizes correct */ | ||
1069 | |||
1070 | /* Set some defaults */ | ||
1071 | pdev->vsnapshot = 0; | ||
1072 | |||
1073 | /* Start iso pipe for video; first try the last used video size | ||
1074 | (or the default one); if that fails try QCIF/10 or QSIF/10; | ||
1075 | it that fails too, give up. | ||
1076 | */ | ||
1077 | i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0); | ||
1078 | if (i) { | ||
1079 | Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n"); | ||
1080 | if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750) | ||
1081 | i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0); | ||
1082 | else | ||
1083 | i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0); | ||
1084 | } | ||
1085 | if (i) { | ||
1086 | Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n"); | ||
1087 | up(&pdev->modlock); | ||
1088 | return i; | ||
1089 | } | ||
1090 | |||
1091 | i = pwc_isoc_init(pdev); | ||
1092 | if (i) { | ||
1093 | Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i); | ||
1094 | up(&pdev->modlock); | ||
1095 | return i; | ||
1096 | } | ||
1097 | |||
1098 | pdev->vopen++; | ||
1099 | file->private_data = vdev; | ||
1100 | up(&pdev->modlock); | ||
1101 | Trace(TRACE_OPEN, "<< video_open() returns 0.\n"); | ||
1102 | return 0; | ||
1103 | } | ||
1104 | |||
1105 | /* Note that all cleanup is done in the reverse order as in _open */ | ||
1106 | static int pwc_video_close(struct inode *inode, struct file *file) | ||
1107 | { | ||
1108 | struct video_device *vdev = file->private_data; | ||
1109 | struct pwc_device *pdev; | ||
1110 | int i; | ||
1111 | |||
1112 | Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev); | ||
1113 | |||
1114 | pdev = (struct pwc_device *)vdev->priv; | ||
1115 | if (pdev->vopen == 0) | ||
1116 | Info("video_close() called on closed device?\n"); | ||
1117 | |||
1118 | /* Dump statistics, but only if a reasonable amount of frames were | ||
1119 | processed (to prevent endless log-entries in case of snap-shot | ||
1120 | programs) | ||
1121 | */ | ||
1122 | if (pdev->vframe_count > 20) | ||
1123 | Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); | ||
1124 | |||
1125 | switch (pdev->type) | ||
1126 | { | ||
1127 | case 675: | ||
1128 | case 680: | ||
1129 | case 690: | ||
1130 | case 720: | ||
1131 | case 730: | ||
1132 | case 740: | ||
1133 | case 750: | ||
1134 | pwc_dec23_exit(); /* Timon & Kiara */ | ||
1135 | break; | ||
1136 | case 645: | ||
1137 | case 646: | ||
1138 | pwc_dec1_exit(); | ||
1139 | break; | ||
1140 | } | ||
1141 | |||
1142 | pwc_isoc_cleanup(pdev); | ||
1143 | pwc_free_buffers(pdev); | ||
1144 | |||
1145 | /* Turn off LEDS and power down camera, but only when not unplugged */ | ||
1146 | if (pdev->error_status != EPIPE) { | ||
1147 | /* Turn LEDs off */ | ||
1148 | if (pwc_set_leds(pdev, 0, 0) < 0) | ||
1149 | Info("Failed to set LED on/off time.\n"); | ||
1150 | if (power_save) { | ||
1151 | i = pwc_camera_power(pdev, 0); | ||
1152 | if (i < 0) | ||
1153 | Err("Failed to power down camera (%d)\n", i); | ||
1154 | } | ||
1155 | } | ||
1156 | pdev->vopen = 0; | ||
1157 | Trace(TRACE_OPEN, "<< video_close()\n"); | ||
1158 | return 0; | ||
1159 | } | ||
1160 | |||
1161 | /* | ||
1162 | * FIXME: what about two parallel reads ???? | ||
1163 | * ANSWER: Not supported. You can't open the device more than once, | ||
1164 | despite what the V4L1 interface says. First, I don't see | ||
1165 | the need, second there's no mechanism of alerting the | ||
1166 | 2nd/3rd/... process of events like changing image size. | ||
1167 | And I don't see the point of blocking that for the | ||
1168 | 2nd/3rd/... process. | ||
1169 | In multi-threaded environments reading parallel from any | ||
1170 | device is tricky anyhow. | ||
1171 | */ | ||
1172 | |||
1173 | static ssize_t pwc_video_read(struct file *file, char __user * buf, | ||
1174 | size_t count, loff_t *ppos) | ||
1175 | { | ||
1176 | struct video_device *vdev = file->private_data; | ||
1177 | struct pwc_device *pdev; | ||
1178 | int noblock = file->f_flags & O_NONBLOCK; | ||
1179 | DECLARE_WAITQUEUE(wait, current); | ||
1180 | int bytes_to_read; | ||
1181 | |||
1182 | Trace(TRACE_READ, "video_read(0x%p, %p, %Zd) called.\n", vdev, buf, count); | ||
1183 | if (vdev == NULL) | ||
1184 | return -EFAULT; | ||
1185 | pdev = vdev->priv; | ||
1186 | if (pdev == NULL) | ||
1187 | return -EFAULT; | ||
1188 | if (pdev->error_status) | ||
1189 | return -pdev->error_status; /* Something happened, report what. */ | ||
1190 | |||
1191 | /* In case we're doing partial reads, we don't have to wait for a frame */ | ||
1192 | if (pdev->image_read_pos == 0) { | ||
1193 | /* Do wait queueing according to the (doc)book */ | ||
1194 | add_wait_queue(&pdev->frameq, &wait); | ||
1195 | while (pdev->full_frames == NULL) { | ||
1196 | /* Check for unplugged/etc. here */ | ||
1197 | if (pdev->error_status) { | ||
1198 | remove_wait_queue(&pdev->frameq, &wait); | ||
1199 | set_current_state(TASK_RUNNING); | ||
1200 | return -pdev->error_status ; | ||
1201 | } | ||
1202 | if (noblock) { | ||
1203 | remove_wait_queue(&pdev->frameq, &wait); | ||
1204 | set_current_state(TASK_RUNNING); | ||
1205 | return -EWOULDBLOCK; | ||
1206 | } | ||
1207 | if (signal_pending(current)) { | ||
1208 | remove_wait_queue(&pdev->frameq, &wait); | ||
1209 | set_current_state(TASK_RUNNING); | ||
1210 | return -ERESTARTSYS; | ||
1211 | } | ||
1212 | schedule(); | ||
1213 | set_current_state(TASK_INTERRUPTIBLE); | ||
1214 | } | ||
1215 | remove_wait_queue(&pdev->frameq, &wait); | ||
1216 | set_current_state(TASK_RUNNING); | ||
1217 | |||
1218 | /* Decompress and release frame */ | ||
1219 | if (pwc_handle_frame(pdev)) | ||
1220 | return -EFAULT; | ||
1221 | } | ||
1222 | |||
1223 | Trace(TRACE_READ, "Copying data to user space.\n"); | ||
1224 | if (pdev->vpalette == VIDEO_PALETTE_RAW) | ||
1225 | bytes_to_read = pdev->frame_size; | ||
1226 | else | ||
1227 | bytes_to_read = pdev->view.size; | ||
1228 | |||
1229 | /* copy bytes to user space; we allow for partial reads */ | ||
1230 | if (count + pdev->image_read_pos > bytes_to_read) | ||
1231 | count = bytes_to_read - pdev->image_read_pos; | ||
1232 | if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count)) | ||
1233 | return -EFAULT; | ||
1234 | pdev->image_read_pos += count; | ||
1235 | if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */ | ||
1236 | pdev->image_read_pos = 0; | ||
1237 | pwc_next_image(pdev); | ||
1238 | } | ||
1239 | return count; | ||
1240 | } | ||
1241 | |||
1242 | static unsigned int pwc_video_poll(struct file *file, poll_table *wait) | ||
1243 | { | ||
1244 | struct video_device *vdev = file->private_data; | ||
1245 | struct pwc_device *pdev; | ||
1246 | |||
1247 | if (vdev == NULL) | ||
1248 | return -EFAULT; | ||
1249 | pdev = vdev->priv; | ||
1250 | if (pdev == NULL) | ||
1251 | return -EFAULT; | ||
1252 | |||
1253 | poll_wait(file, &pdev->frameq, wait); | ||
1254 | if (pdev->error_status) | ||
1255 | return POLLERR; | ||
1256 | if (pdev->full_frames != NULL) /* we have frames waiting */ | ||
1257 | return (POLLIN | POLLRDNORM); | ||
1258 | |||
1259 | return 0; | ||
1260 | } | ||
1261 | |||
1262 | static int pwc_video_do_ioctl(struct inode *inode, struct file *file, | ||
1263 | unsigned int cmd, void *arg) | ||
1264 | { | ||
1265 | struct video_device *vdev = file->private_data; | ||
1266 | struct pwc_device *pdev; | ||
1267 | DECLARE_WAITQUEUE(wait, current); | ||
1268 | |||
1269 | if (vdev == NULL) | ||
1270 | return -EFAULT; | ||
1271 | pdev = vdev->priv; | ||
1272 | if (pdev == NULL) | ||
1273 | return -EFAULT; | ||
1274 | |||
1275 | switch (cmd) { | ||
1276 | /* Query cabapilities */ | ||
1277 | case VIDIOCGCAP: | ||
1278 | { | ||
1279 | struct video_capability *caps = arg; | ||
1280 | |||
1281 | strcpy(caps->name, vdev->name); | ||
1282 | caps->type = VID_TYPE_CAPTURE; | ||
1283 | caps->channels = 1; | ||
1284 | caps->audios = 1; | ||
1285 | caps->minwidth = pdev->view_min.x; | ||
1286 | caps->minheight = pdev->view_min.y; | ||
1287 | caps->maxwidth = pdev->view_max.x; | ||
1288 | caps->maxheight = pdev->view_max.y; | ||
1289 | break; | ||
1290 | } | ||
1291 | |||
1292 | /* Channel functions (simulate 1 channel) */ | ||
1293 | case VIDIOCGCHAN: | ||
1294 | { | ||
1295 | struct video_channel *v = arg; | ||
1296 | |||
1297 | if (v->channel != 0) | ||
1298 | return -EINVAL; | ||
1299 | v->flags = 0; | ||
1300 | v->tuners = 0; | ||
1301 | v->type = VIDEO_TYPE_CAMERA; | ||
1302 | strcpy(v->name, "Webcam"); | ||
1303 | return 0; | ||
1304 | } | ||
1305 | |||
1306 | case VIDIOCSCHAN: | ||
1307 | { | ||
1308 | /* The spec says the argument is an integer, but | ||
1309 | the bttv driver uses a video_channel arg, which | ||
1310 | makes sense becasue it also has the norm flag. | ||
1311 | */ | ||
1312 | struct video_channel *v = arg; | ||
1313 | if (v->channel != 0) | ||
1314 | return -EINVAL; | ||
1315 | return 0; | ||
1316 | } | ||
1317 | |||
1318 | |||
1319 | /* Picture functions; contrast etc. */ | ||
1320 | case VIDIOCGPICT: | ||
1321 | { | ||
1322 | struct video_picture *p = arg; | ||
1323 | int val; | ||
1324 | |||
1325 | val = pwc_get_brightness(pdev); | ||
1326 | if (val >= 0) | ||
1327 | p->brightness = val; | ||
1328 | else | ||
1329 | p->brightness = 0xffff; | ||
1330 | val = pwc_get_contrast(pdev); | ||
1331 | if (val >= 0) | ||
1332 | p->contrast = val; | ||
1333 | else | ||
1334 | p->contrast = 0xffff; | ||
1335 | /* Gamma, Whiteness, what's the difference? :) */ | ||
1336 | val = pwc_get_gamma(pdev); | ||
1337 | if (val >= 0) | ||
1338 | p->whiteness = val; | ||
1339 | else | ||
1340 | p->whiteness = 0xffff; | ||
1341 | val = pwc_get_saturation(pdev); | ||
1342 | if (val >= 0) | ||
1343 | p->colour = val; | ||
1344 | else | ||
1345 | p->colour = 0xffff; | ||
1346 | p->depth = 24; | ||
1347 | p->palette = pdev->vpalette; | ||
1348 | p->hue = 0xFFFF; /* N/A */ | ||
1349 | break; | ||
1350 | } | ||
1351 | |||
1352 | case VIDIOCSPICT: | ||
1353 | { | ||
1354 | struct video_picture *p = arg; | ||
1355 | /* | ||
1356 | * FIXME: Suppose we are mid read | ||
1357 | ANSWER: No problem: the firmware of the camera | ||
1358 | can handle brightness/contrast/etc | ||
1359 | changes at _any_ time, and the palette | ||
1360 | is used exactly once in the uncompress | ||
1361 | routine. | ||
1362 | */ | ||
1363 | pwc_set_brightness(pdev, p->brightness); | ||
1364 | pwc_set_contrast(pdev, p->contrast); | ||
1365 | pwc_set_gamma(pdev, p->whiteness); | ||
1366 | pwc_set_saturation(pdev, p->colour); | ||
1367 | if (p->palette && p->palette != pdev->vpalette) { | ||
1368 | switch (p->palette) { | ||
1369 | case VIDEO_PALETTE_YUV420P: | ||
1370 | case VIDEO_PALETTE_RAW: | ||
1371 | pdev->vpalette = p->palette; | ||
1372 | return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); | ||
1373 | break; | ||
1374 | default: | ||
1375 | return -EINVAL; | ||
1376 | break; | ||
1377 | } | ||
1378 | } | ||
1379 | break; | ||
1380 | } | ||
1381 | |||
1382 | /* Window/size parameters */ | ||
1383 | case VIDIOCGWIN: | ||
1384 | { | ||
1385 | struct video_window *vw = arg; | ||
1386 | |||
1387 | vw->x = 0; | ||
1388 | vw->y = 0; | ||
1389 | vw->width = pdev->view.x; | ||
1390 | vw->height = pdev->view.y; | ||
1391 | vw->chromakey = 0; | ||
1392 | vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | | ||
1393 | (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0); | ||
1394 | break; | ||
1395 | } | ||
1396 | |||
1397 | case VIDIOCSWIN: | ||
1398 | { | ||
1399 | struct video_window *vw = arg; | ||
1400 | int fps, snapshot, ret; | ||
1401 | |||
1402 | fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; | ||
1403 | snapshot = vw->flags & PWC_FPS_SNAPSHOT; | ||
1404 | if (fps == 0) | ||
1405 | fps = pdev->vframes; | ||
1406 | if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot) | ||
1407 | return 0; | ||
1408 | ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot); | ||
1409 | if (ret) | ||
1410 | return ret; | ||
1411 | break; | ||
1412 | } | ||
1413 | |||
1414 | /* We don't have overlay support (yet) */ | ||
1415 | case VIDIOCGFBUF: | ||
1416 | { | ||
1417 | struct video_buffer *vb = arg; | ||
1418 | |||
1419 | memset(vb,0,sizeof(*vb)); | ||
1420 | break; | ||
1421 | } | ||
1422 | |||
1423 | /* mmap() functions */ | ||
1424 | case VIDIOCGMBUF: | ||
1425 | { | ||
1426 | /* Tell the user program how much memory is needed for a mmap() */ | ||
1427 | struct video_mbuf *vm = arg; | ||
1428 | int i; | ||
1429 | |||
1430 | memset(vm, 0, sizeof(*vm)); | ||
1431 | vm->size = default_mbufs * pdev->len_per_image; | ||
1432 | vm->frames = default_mbufs; /* double buffering should be enough for most applications */ | ||
1433 | for (i = 0; i < default_mbufs; i++) | ||
1434 | vm->offsets[i] = i * pdev->len_per_image; | ||
1435 | break; | ||
1436 | } | ||
1437 | |||
1438 | case VIDIOCMCAPTURE: | ||
1439 | { | ||
1440 | /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */ | ||
1441 | struct video_mmap *vm = arg; | ||
1442 | |||
1443 | Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format); | ||
1444 | if (vm->frame < 0 || vm->frame >= default_mbufs) | ||
1445 | return -EINVAL; | ||
1446 | |||
1447 | /* xawtv is nasty. It probes the available palettes | ||
1448 | by setting a very small image size and trying | ||
1449 | various palettes... The driver doesn't support | ||
1450 | such small images, so I'm working around it. | ||
1451 | */ | ||
1452 | if (vm->format) | ||
1453 | { | ||
1454 | switch (vm->format) | ||
1455 | { | ||
1456 | case VIDEO_PALETTE_YUV420P: | ||
1457 | case VIDEO_PALETTE_RAW: | ||
1458 | break; | ||
1459 | default: | ||
1460 | return -EINVAL; | ||
1461 | break; | ||
1462 | } | ||
1463 | } | ||
1464 | |||
1465 | if ((vm->width != pdev->view.x || vm->height != pdev->view.y) && | ||
1466 | (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) { | ||
1467 | int ret; | ||
1468 | |||
1469 | Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n"); | ||
1470 | ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot); | ||
1471 | if (ret) | ||
1472 | return ret; | ||
1473 | } /* ... size mismatch */ | ||
1474 | |||
1475 | /* FIXME: should we lock here? */ | ||
1476 | if (pdev->image_used[vm->frame]) | ||
1477 | return -EBUSY; /* buffer wasn't available. Bummer */ | ||
1478 | pdev->image_used[vm->frame] = 1; | ||
1479 | |||
1480 | /* Okay, we're done here. In the SYNC call we wait until a | ||
1481 | frame comes available, then expand image into the given | ||
1482 | buffer. | ||
1483 | In contrast to the CPiA cam the Philips cams deliver a | ||
1484 | constant stream, almost like a grabber card. Also, | ||
1485 | we have separate buffers for the rawdata and the image, | ||
1486 | meaning we can nearly always expand into the requested buffer. | ||
1487 | */ | ||
1488 | Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n"); | ||
1489 | break; | ||
1490 | } | ||
1491 | |||
1492 | case VIDIOCSYNC: | ||
1493 | { | ||
1494 | /* The doc says: "Whenever a buffer is used it should | ||
1495 | call VIDIOCSYNC to free this frame up and continue." | ||
1496 | |||
1497 | The only odd thing about this whole procedure is | ||
1498 | that MCAPTURE flags the buffer as "in use", and | ||
1499 | SYNC immediately unmarks it, while it isn't | ||
1500 | after SYNC that you know that the buffer actually | ||
1501 | got filled! So you better not start a CAPTURE in | ||
1502 | the same frame immediately (use double buffering). | ||
1503 | This is not a problem for this cam, since it has | ||
1504 | extra intermediate buffers, but a hardware | ||
1505 | grabber card will then overwrite the buffer | ||
1506 | you're working on. | ||
1507 | */ | ||
1508 | int *mbuf = arg; | ||
1509 | int ret; | ||
1510 | |||
1511 | Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf); | ||
1512 | |||
1513 | /* bounds check */ | ||
1514 | if (*mbuf < 0 || *mbuf >= default_mbufs) | ||
1515 | return -EINVAL; | ||
1516 | /* check if this buffer was requested anyway */ | ||
1517 | if (pdev->image_used[*mbuf] == 0) | ||
1518 | return -EINVAL; | ||
1519 | |||
1520 | /* Add ourselves to the frame wait-queue. | ||
1521 | |||
1522 | FIXME: needs auditing for safety. | ||
1523 | QUESTION: In what respect? I think that using the | ||
1524 | frameq is safe now. | ||
1525 | */ | ||
1526 | add_wait_queue(&pdev->frameq, &wait); | ||
1527 | while (pdev->full_frames == NULL) { | ||
1528 | if (pdev->error_status) { | ||
1529 | remove_wait_queue(&pdev->frameq, &wait); | ||
1530 | set_current_state(TASK_RUNNING); | ||
1531 | return -pdev->error_status; | ||
1532 | } | ||
1533 | |||
1534 | if (signal_pending(current)) { | ||
1535 | remove_wait_queue(&pdev->frameq, &wait); | ||
1536 | set_current_state(TASK_RUNNING); | ||
1537 | return -ERESTARTSYS; | ||
1538 | } | ||
1539 | schedule(); | ||
1540 | set_current_state(TASK_INTERRUPTIBLE); | ||
1541 | } | ||
1542 | remove_wait_queue(&pdev->frameq, &wait); | ||
1543 | set_current_state(TASK_RUNNING); | ||
1544 | |||
1545 | /* The frame is ready. Expand in the image buffer | ||
1546 | requested by the user. I don't care if you | ||
1547 | mmap() 5 buffers and request data in this order: | ||
1548 | buffer 4 2 3 0 1 2 3 0 4 3 1 . . . | ||
1549 | Grabber hardware may not be so forgiving. | ||
1550 | */ | ||
1551 | Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n"); | ||
1552 | pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */ | ||
1553 | /* Decompress, etc */ | ||
1554 | ret = pwc_handle_frame(pdev); | ||
1555 | pdev->image_used[*mbuf] = 0; | ||
1556 | if (ret) | ||
1557 | return -EFAULT; | ||
1558 | break; | ||
1559 | } | ||
1560 | |||
1561 | case VIDIOCGAUDIO: | ||
1562 | { | ||
1563 | struct video_audio *v = arg; | ||
1564 | |||
1565 | strcpy(v->name, "Microphone"); | ||
1566 | v->audio = -1; /* unknown audio minor */ | ||
1567 | v->flags = 0; | ||
1568 | v->mode = VIDEO_SOUND_MONO; | ||
1569 | v->volume = 0; | ||
1570 | v->bass = 0; | ||
1571 | v->treble = 0; | ||
1572 | v->balance = 0x8000; | ||
1573 | v->step = 1; | ||
1574 | break; | ||
1575 | } | ||
1576 | |||
1577 | case VIDIOCSAUDIO: | ||
1578 | { | ||
1579 | /* Dummy: nothing can be set */ | ||
1580 | break; | ||
1581 | } | ||
1582 | |||
1583 | case VIDIOCGUNIT: | ||
1584 | { | ||
1585 | struct video_unit *vu = arg; | ||
1586 | |||
1587 | vu->video = pdev->vdev->minor & 0x3F; | ||
1588 | vu->audio = -1; /* not known yet */ | ||
1589 | vu->vbi = -1; | ||
1590 | vu->radio = -1; | ||
1591 | vu->teletext = -1; | ||
1592 | break; | ||
1593 | } | ||
1594 | default: | ||
1595 | return pwc_ioctl(pdev, cmd, arg); | ||
1596 | } /* ..switch */ | ||
1597 | return 0; | ||
1598 | } | ||
1599 | |||
1600 | static int pwc_video_ioctl(struct inode *inode, struct file *file, | ||
1601 | unsigned int cmd, unsigned long arg) | ||
1602 | { | ||
1603 | return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); | ||
1604 | } | ||
1605 | |||
1606 | |||
1607 | static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) | ||
1608 | { | ||
1609 | struct video_device *vdev = file->private_data; | ||
1610 | struct pwc_device *pdev; | ||
1611 | unsigned long start = vma->vm_start; | ||
1612 | unsigned long size = vma->vm_end-vma->vm_start; | ||
1613 | unsigned long page, pos; | ||
1614 | |||
1615 | Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size); | ||
1616 | pdev = vdev->priv; | ||
1617 | |||
1618 | vma->vm_flags |= VM_IO; | ||
1619 | |||
1620 | pos = (unsigned long)pdev->image_data; | ||
1621 | while (size > 0) { | ||
1622 | page = vmalloc_to_pfn((void *)pos); | ||
1623 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) | ||
1624 | return -EAGAIN; | ||
1625 | |||
1626 | start += PAGE_SIZE; | ||
1627 | pos += PAGE_SIZE; | ||
1628 | if (size > PAGE_SIZE) | ||
1629 | size -= PAGE_SIZE; | ||
1630 | else | ||
1631 | size = 0; | ||
1632 | } | ||
1633 | |||
1634 | return 0; | ||
1635 | } | ||
1636 | |||
1637 | /***************************************************************************/ | ||
1638 | /* USB functions */ | ||
1639 | |||
1640 | /* This function gets called when a new device is plugged in or the usb core | ||
1641 | * is loaded. | ||
1642 | */ | ||
1643 | |||
1644 | static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
1645 | { | ||
1646 | struct usb_device *udev = interface_to_usbdev(intf); | ||
1647 | struct pwc_device *pdev = NULL; | ||
1648 | int vendor_id, product_id, type_id; | ||
1649 | int i, hint; | ||
1650 | int features = 0; | ||
1651 | int video_nr = -1; /* default: use next available device */ | ||
1652 | char serial_number[30], *name; | ||
1653 | |||
1654 | /* Check if we can handle this device */ | ||
1655 | Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", | ||
1656 | le16_to_cpu(udev->descriptor.idVendor), | ||
1657 | le16_to_cpu(udev->descriptor.idProduct), | ||
1658 | intf->altsetting->desc.bInterfaceNumber); | ||
1659 | |||
1660 | /* the interfaces are probed one by one. We are only interested in the | ||
1661 | video interface (0) now. | ||
1662 | Interface 1 is the Audio Control, and interface 2 Audio itself. | ||
1663 | */ | ||
1664 | if (intf->altsetting->desc.bInterfaceNumber > 0) | ||
1665 | return -ENODEV; | ||
1666 | |||
1667 | vendor_id = le16_to_cpu(udev->descriptor.idVendor); | ||
1668 | product_id = le16_to_cpu(udev->descriptor.idProduct); | ||
1669 | |||
1670 | if (vendor_id == 0x0471) { | ||
1671 | switch (product_id) { | ||
1672 | case 0x0302: | ||
1673 | Info("Philips PCA645VC USB webcam detected.\n"); | ||
1674 | name = "Philips 645 webcam"; | ||
1675 | type_id = 645; | ||
1676 | break; | ||
1677 | case 0x0303: | ||
1678 | Info("Philips PCA646VC USB webcam detected.\n"); | ||
1679 | name = "Philips 646 webcam"; | ||
1680 | type_id = 646; | ||
1681 | break; | ||
1682 | case 0x0304: | ||
1683 | Info("Askey VC010 type 2 USB webcam detected.\n"); | ||
1684 | name = "Askey VC010 webcam"; | ||
1685 | type_id = 646; | ||
1686 | break; | ||
1687 | case 0x0307: | ||
1688 | Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); | ||
1689 | name = "Philips 675 webcam"; | ||
1690 | type_id = 675; | ||
1691 | break; | ||
1692 | case 0x0308: | ||
1693 | Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); | ||
1694 | name = "Philips 680 webcam"; | ||
1695 | type_id = 680; | ||
1696 | break; | ||
1697 | case 0x030C: | ||
1698 | Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); | ||
1699 | name = "Philips 690 webcam"; | ||
1700 | type_id = 690; | ||
1701 | break; | ||
1702 | case 0x0310: | ||
1703 | Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n"); | ||
1704 | name = "Philips 730 webcam"; | ||
1705 | type_id = 730; | ||
1706 | break; | ||
1707 | case 0x0311: | ||
1708 | Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n"); | ||
1709 | name = "Philips 740 webcam"; | ||
1710 | type_id = 740; | ||
1711 | break; | ||
1712 | case 0x0312: | ||
1713 | Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); | ||
1714 | name = "Philips 750 webcam"; | ||
1715 | type_id = 750; | ||
1716 | break; | ||
1717 | case 0x0313: | ||
1718 | Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n"); | ||
1719 | name = "Philips 720K/40 webcam"; | ||
1720 | type_id = 720; | ||
1721 | break; | ||
1722 | default: | ||
1723 | return -ENODEV; | ||
1724 | break; | ||
1725 | } | ||
1726 | } | ||
1727 | else if (vendor_id == 0x069A) { | ||
1728 | switch(product_id) { | ||
1729 | case 0x0001: | ||
1730 | Info("Askey VC010 type 1 USB webcam detected.\n"); | ||
1731 | name = "Askey VC010 webcam"; | ||
1732 | type_id = 645; | ||
1733 | break; | ||
1734 | default: | ||
1735 | return -ENODEV; | ||
1736 | break; | ||
1737 | } | ||
1738 | } | ||
1739 | else if (vendor_id == 0x046d) { | ||
1740 | switch(product_id) { | ||
1741 | case 0x08b0: | ||
1742 | Info("Logitech QuickCam Pro 3000 USB webcam detected.\n"); | ||
1743 | name = "Logitech QuickCam Pro 3000"; | ||
1744 | type_id = 740; /* CCD sensor */ | ||
1745 | break; | ||
1746 | case 0x08b1: | ||
1747 | Info("Logitech QuickCam Notebook Pro USB webcam detected.\n"); | ||
1748 | name = "Logitech QuickCam Notebook Pro"; | ||
1749 | type_id = 740; /* CCD sensor */ | ||
1750 | break; | ||
1751 | case 0x08b2: | ||
1752 | Info("Logitech QuickCam 4000 Pro USB webcam detected.\n"); | ||
1753 | name = "Logitech QuickCam Pro 4000"; | ||
1754 | type_id = 740; /* CCD sensor */ | ||
1755 | break; | ||
1756 | case 0x08b3: | ||
1757 | Info("Logitech QuickCam Zoom USB webcam detected.\n"); | ||
1758 | name = "Logitech QuickCam Zoom"; | ||
1759 | type_id = 740; /* CCD sensor */ | ||
1760 | break; | ||
1761 | case 0x08B4: | ||
1762 | Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); | ||
1763 | name = "Logitech QuickCam Zoom"; | ||
1764 | type_id = 740; /* CCD sensor */ | ||
1765 | break; | ||
1766 | case 0x08b5: | ||
1767 | Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); | ||
1768 | name = "Logitech QuickCam Orbit"; | ||
1769 | type_id = 740; /* CCD sensor */ | ||
1770 | features |= FEATURE_MOTOR_PANTILT; | ||
1771 | break; | ||
1772 | case 0x08b6: | ||
1773 | case 0x08b7: | ||
1774 | case 0x08b8: | ||
1775 | Info("Logitech QuickCam detected (reserved ID).\n"); | ||
1776 | name = "Logitech QuickCam (res.)"; | ||
1777 | type_id = 730; /* Assuming CMOS */ | ||
1778 | break; | ||
1779 | default: | ||
1780 | return -ENODEV; | ||
1781 | break; | ||
1782 | } | ||
1783 | } | ||
1784 | else if (vendor_id == 0x055d) { | ||
1785 | /* I don't know the difference between the C10 and the C30; | ||
1786 | I suppose the difference is the sensor, but both cameras | ||
1787 | work equally well with a type_id of 675 | ||
1788 | */ | ||
1789 | switch(product_id) { | ||
1790 | case 0x9000: | ||
1791 | Info("Samsung MPC-C10 USB webcam detected.\n"); | ||
1792 | name = "Samsung MPC-C10"; | ||
1793 | type_id = 675; | ||
1794 | break; | ||
1795 | case 0x9001: | ||
1796 | Info("Samsung MPC-C30 USB webcam detected.\n"); | ||
1797 | name = "Samsung MPC-C30"; | ||
1798 | type_id = 675; | ||
1799 | break; | ||
1800 | default: | ||
1801 | return -ENODEV; | ||
1802 | break; | ||
1803 | } | ||
1804 | } | ||
1805 | else if (vendor_id == 0x041e) { | ||
1806 | switch(product_id) { | ||
1807 | case 0x400c: | ||
1808 | Info("Creative Labs Webcam 5 detected.\n"); | ||
1809 | name = "Creative Labs Webcam 5"; | ||
1810 | type_id = 730; | ||
1811 | break; | ||
1812 | case 0x4011: | ||
1813 | Info("Creative Labs Webcam Pro Ex detected.\n"); | ||
1814 | name = "Creative Labs Webcam Pro Ex"; | ||
1815 | type_id = 740; | ||
1816 | break; | ||
1817 | default: | ||
1818 | return -ENODEV; | ||
1819 | break; | ||
1820 | } | ||
1821 | } | ||
1822 | else if (vendor_id == 0x04cc) { | ||
1823 | switch(product_id) { | ||
1824 | case 0x8116: | ||
1825 | Info("Sotec Afina Eye USB webcam detected.\n"); | ||
1826 | name = "Sotec Afina Eye"; | ||
1827 | type_id = 730; | ||
1828 | break; | ||
1829 | default: | ||
1830 | return -ENODEV; | ||
1831 | break; | ||
1832 | } | ||
1833 | } | ||
1834 | else if (vendor_id == 0x06be) { | ||
1835 | switch(product_id) { | ||
1836 | case 0x8116: | ||
1837 | /* This is essentially the same cam as the Sotec Afina Eye */ | ||
1838 | Info("AME Co. Afina Eye USB webcam detected.\n"); | ||
1839 | name = "AME Co. Afina Eye"; | ||
1840 | type_id = 750; | ||
1841 | break; | ||
1842 | default: | ||
1843 | return -ENODEV; | ||
1844 | break; | ||
1845 | } | ||
1846 | |||
1847 | } | ||
1848 | else if (vendor_id == 0x0d81) { | ||
1849 | switch(product_id) { | ||
1850 | case 0x1900: | ||
1851 | Info("Visionite VCS-UC300 USB webcam detected.\n"); | ||
1852 | name = "Visionite VCS-UC300"; | ||
1853 | type_id = 740; /* CCD sensor */ | ||
1854 | break; | ||
1855 | case 0x1910: | ||
1856 | Info("Visionite VCS-UM100 USB webcam detected.\n"); | ||
1857 | name = "Visionite VCS-UM100"; | ||
1858 | type_id = 730; /* CMOS sensor */ | ||
1859 | break; | ||
1860 | default: | ||
1861 | return -ENODEV; | ||
1862 | break; | ||
1863 | } | ||
1864 | } | ||
1865 | else | ||
1866 | return -ENODEV; /* Not any of the know types; but the list keeps growing. */ | ||
1867 | |||
1868 | memset(serial_number, 0, 30); | ||
1869 | usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); | ||
1870 | Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number); | ||
1871 | |||
1872 | if (udev->descriptor.bNumConfigurations > 1) | ||
1873 | Info("Warning: more than 1 configuration available.\n"); | ||
1874 | |||
1875 | /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */ | ||
1876 | pdev = kmalloc(sizeof(struct pwc_device), GFP_KERNEL); | ||
1877 | if (pdev == NULL) { | ||
1878 | Err("Oops, could not allocate memory for pwc_device.\n"); | ||
1879 | return -ENOMEM; | ||
1880 | } | ||
1881 | memset(pdev, 0, sizeof(struct pwc_device)); | ||
1882 | pdev->type = type_id; | ||
1883 | pdev->vsize = default_size; | ||
1884 | pdev->vframes = default_fps; | ||
1885 | strcpy(pdev->serial, serial_number); | ||
1886 | pdev->features = features; | ||
1887 | if (vendor_id == 0x046D && product_id == 0x08B5) | ||
1888 | { | ||
1889 | /* Logitech QuickCam Orbit | ||
1890 | The ranges have been determined experimentally; they may differ from cam to cam. | ||
1891 | Also, the exact ranges left-right and up-down are different for my cam | ||
1892 | */ | ||
1893 | pdev->angle_range.pan_min = -7000; | ||
1894 | pdev->angle_range.pan_max = 7000; | ||
1895 | pdev->angle_range.tilt_min = -3000; | ||
1896 | pdev->angle_range.tilt_max = 2500; | ||
1897 | } | ||
1898 | |||
1899 | init_MUTEX(&pdev->modlock); | ||
1900 | spin_lock_init(&pdev->ptrlock); | ||
1901 | |||
1902 | pdev->udev = udev; | ||
1903 | init_waitqueue_head(&pdev->frameq); | ||
1904 | pdev->vcompression = pwc_preferred_compression; | ||
1905 | |||
1906 | /* Allocate video_device structure */ | ||
1907 | pdev->vdev = video_device_alloc(); | ||
1908 | if (pdev->vdev == 0) | ||
1909 | { | ||
1910 | Err("Err, cannot allocate video_device struture. Failing probe."); | ||
1911 | kfree(pdev); | ||
1912 | return -ENOMEM; | ||
1913 | } | ||
1914 | memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); | ||
1915 | strcpy(pdev->vdev->name, name); | ||
1916 | pdev->vdev->owner = THIS_MODULE; | ||
1917 | video_set_drvdata(pdev->vdev, pdev); | ||
1918 | |||
1919 | pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); | ||
1920 | Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); | ||
1921 | |||
1922 | /* Now search device_hint[] table for a match, so we can hint a node number. */ | ||
1923 | for (hint = 0; hint < MAX_DEV_HINTS; hint++) { | ||
1924 | if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && | ||
1925 | (device_hint[hint].pdev == NULL)) { | ||
1926 | /* so far, so good... try serial number */ | ||
1927 | if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) { | ||
1928 | /* match! */ | ||
1929 | video_nr = device_hint[hint].device_node; | ||
1930 | Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr); | ||
1931 | break; | ||
1932 | } | ||
1933 | } | ||
1934 | } | ||
1935 | |||
1936 | pdev->vdev->release = video_device_release; | ||
1937 | i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); | ||
1938 | if (i < 0) { | ||
1939 | Err("Failed to register as video device (%d).\n", i); | ||
1940 | video_device_release(pdev->vdev); /* Drip... drip... drip... */ | ||
1941 | kfree(pdev); /* Oops, no memory leaks please */ | ||
1942 | return -EIO; | ||
1943 | } | ||
1944 | else { | ||
1945 | Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F); | ||
1946 | } | ||
1947 | |||
1948 | /* occupy slot */ | ||
1949 | if (hint < MAX_DEV_HINTS) | ||
1950 | device_hint[hint].pdev = pdev; | ||
1951 | |||
1952 | Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev); | ||
1953 | usb_set_intfdata (intf, pdev); | ||
1954 | return 0; | ||
1955 | } | ||
1956 | |||
1957 | /* The user janked out the cable... */ | ||
1958 | static void usb_pwc_disconnect(struct usb_interface *intf) | ||
1959 | { | ||
1960 | struct pwc_device *pdev; | ||
1961 | int hint; | ||
1962 | |||
1963 | lock_kernel(); | ||
1964 | pdev = usb_get_intfdata (intf); | ||
1965 | usb_set_intfdata (intf, NULL); | ||
1966 | if (pdev == NULL) { | ||
1967 | Err("pwc_disconnect() Called without private pointer.\n"); | ||
1968 | goto disconnect_out; | ||
1969 | } | ||
1970 | if (pdev->udev == NULL) { | ||
1971 | Err("pwc_disconnect() already called for %p\n", pdev); | ||
1972 | goto disconnect_out; | ||
1973 | } | ||
1974 | if (pdev->udev != interface_to_usbdev(intf)) { | ||
1975 | Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); | ||
1976 | goto disconnect_out; | ||
1977 | } | ||
1978 | #ifdef PWC_MAGIC | ||
1979 | if (pdev->magic != PWC_MAGIC) { | ||
1980 | Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n"); | ||
1981 | goto disconnect_out; | ||
1982 | } | ||
1983 | #endif | ||
1984 | |||
1985 | /* We got unplugged; this is signalled by an EPIPE error code */ | ||
1986 | if (pdev->vopen) { | ||
1987 | Info("Disconnected while webcam is in use!\n"); | ||
1988 | pdev->error_status = EPIPE; | ||
1989 | } | ||
1990 | |||
1991 | /* Alert waiting processes */ | ||
1992 | wake_up_interruptible(&pdev->frameq); | ||
1993 | /* Wait until device is closed */ | ||
1994 | while (pdev->vopen) | ||
1995 | schedule(); | ||
1996 | /* Device is now closed, so we can safely unregister it */ | ||
1997 | Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n"); | ||
1998 | video_unregister_device(pdev->vdev); | ||
1999 | |||
2000 | /* Free memory (don't set pdev to 0 just yet) */ | ||
2001 | kfree(pdev); | ||
2002 | |||
2003 | disconnect_out: | ||
2004 | /* search device_hint[] table if we occupy a slot, by any chance */ | ||
2005 | for (hint = 0; hint < MAX_DEV_HINTS; hint++) | ||
2006 | if (device_hint[hint].pdev == pdev) | ||
2007 | device_hint[hint].pdev = NULL; | ||
2008 | |||
2009 | unlock_kernel(); | ||
2010 | } | ||
2011 | |||
2012 | |||
2013 | /* *grunt* We have to do atoi ourselves :-( */ | ||
2014 | static int pwc_atoi(const char *s) | ||
2015 | { | ||
2016 | int k = 0; | ||
2017 | |||
2018 | k = 0; | ||
2019 | while (*s != '\0' && *s >= '0' && *s <= '9') { | ||
2020 | k = 10 * k + (*s - '0'); | ||
2021 | s++; | ||
2022 | } | ||
2023 | return k; | ||
2024 | } | ||
2025 | |||
2026 | |||
2027 | /* | ||
2028 | * Initialization code & module stuff | ||
2029 | */ | ||
2030 | |||
2031 | static char size[10]; | ||
2032 | static int fps = 0; | ||
2033 | static int fbufs = 0; | ||
2034 | static int mbufs = 0; | ||
2035 | static int trace = -1; | ||
2036 | static int compression = -1; | ||
2037 | static int leds[2] = { -1, -1 }; | ||
2038 | static char *dev_hint[MAX_DEV_HINTS] = { }; | ||
2039 | |||
2040 | module_param_string(size, size, sizeof(size), 0); | ||
2041 | MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga"); | ||
2042 | module_param(fps, int, 0000); | ||
2043 | MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); | ||
2044 | module_param(fbufs, int, 0000); | ||
2045 | MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve"); | ||
2046 | module_param(mbufs, int, 0000); | ||
2047 | MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers"); | ||
2048 | module_param(trace, int, 0000); | ||
2049 | MODULE_PARM_DESC(trace, "For debugging purposes"); | ||
2050 | module_param(power_save, bool, 0000); | ||
2051 | MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off"); | ||
2052 | module_param(compression, int, 0000); | ||
2053 | MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); | ||
2054 | module_param_array(leds, int, NULL, 0000); | ||
2055 | MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); | ||
2056 | module_param_array(dev_hint, charp, NULL, 0000); | ||
2057 | MODULE_PARM_DESC(dev_hint, "Device node hints"); | ||
2058 | |||
2059 | MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); | ||
2060 | MODULE_AUTHOR("Luc Saillard <luc@saillard.org>"); | ||
2061 | MODULE_LICENSE("GPL"); | ||
2062 | |||
2063 | static int __init usb_pwc_init(void) | ||
2064 | { | ||
2065 | int i, sz; | ||
2066 | char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; | ||
2067 | |||
2068 | Info("Philips webcam module version " PWC_VERSION " loaded.\n"); | ||
2069 | Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); | ||
2070 | Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); | ||
2071 | Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); | ||
2072 | |||
2073 | if (fps) { | ||
2074 | if (fps < 4 || fps > 30) { | ||
2075 | Err("Framerate out of bounds (4-30).\n"); | ||
2076 | return -EINVAL; | ||
2077 | } | ||
2078 | default_fps = fps; | ||
2079 | Info("Default framerate set to %d.\n", default_fps); | ||
2080 | } | ||
2081 | |||
2082 | if (size[0]) { | ||
2083 | /* string; try matching with array */ | ||
2084 | for (sz = 0; sz < PSZ_MAX; sz++) { | ||
2085 | if (!strcmp(sizenames[sz], size)) { /* Found! */ | ||
2086 | default_size = sz; | ||
2087 | break; | ||
2088 | } | ||
2089 | } | ||
2090 | if (sz == PSZ_MAX) { | ||
2091 | Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n"); | ||
2092 | return -EINVAL; | ||
2093 | } | ||
2094 | 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); | ||
2095 | } | ||
2096 | if (mbufs) { | ||
2097 | if (mbufs < 1 || mbufs > MAX_IMAGES) { | ||
2098 | Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES); | ||
2099 | return -EINVAL; | ||
2100 | } | ||
2101 | default_mbufs = mbufs; | ||
2102 | Info("Number of image buffers set to %d.\n", default_mbufs); | ||
2103 | } | ||
2104 | if (fbufs) { | ||
2105 | if (fbufs < 2 || fbufs > MAX_FRAMES) { | ||
2106 | Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES); | ||
2107 | return -EINVAL; | ||
2108 | } | ||
2109 | default_fbufs = fbufs; | ||
2110 | Info("Number of frame buffers set to %d.\n", default_fbufs); | ||
2111 | } | ||
2112 | if (trace >= 0) { | ||
2113 | Info("Trace options: 0x%04x\n", trace); | ||
2114 | pwc_trace = trace; | ||
2115 | } | ||
2116 | if (compression >= 0) { | ||
2117 | if (compression > 3) { | ||
2118 | Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); | ||
2119 | return -EINVAL; | ||
2120 | } | ||
2121 | pwc_preferred_compression = compression; | ||
2122 | Info("Preferred compression set to %d.\n", pwc_preferred_compression); | ||
2123 | } | ||
2124 | if (power_save) | ||
2125 | Info("Enabling power save on open/close.\n"); | ||
2126 | if (leds[0] >= 0) | ||
2127 | led_on = leds[0]; | ||
2128 | if (leds[1] >= 0) | ||
2129 | led_off = leds[1]; | ||
2130 | |||
2131 | /* Big device node whoopla. Basicly, it allows you to assign a | ||
2132 | device node (/dev/videoX) to a camera, based on its type | ||
2133 | & serial number. The format is [type[.serialnumber]:]node. | ||
2134 | |||
2135 | Any camera that isn't matched by these rules gets the next | ||
2136 | available free device node. | ||
2137 | */ | ||
2138 | for (i = 0; i < MAX_DEV_HINTS; i++) { | ||
2139 | char *s, *colon, *dot; | ||
2140 | |||
2141 | /* This loop also initializes the array */ | ||
2142 | device_hint[i].pdev = NULL; | ||
2143 | s = dev_hint[i]; | ||
2144 | if (s != NULL && *s != '\0') { | ||
2145 | device_hint[i].type = -1; /* wildcard */ | ||
2146 | strcpy(device_hint[i].serial_number, "*"); | ||
2147 | |||
2148 | /* parse string: chop at ':' & '/' */ | ||
2149 | colon = dot = s; | ||
2150 | while (*colon != '\0' && *colon != ':') | ||
2151 | colon++; | ||
2152 | while (*dot != '\0' && *dot != '.') | ||
2153 | dot++; | ||
2154 | /* Few sanity checks */ | ||
2155 | if (*dot != '\0' && dot > colon) { | ||
2156 | Err("Malformed camera hint: the colon must be after the dot.\n"); | ||
2157 | return -EINVAL; | ||
2158 | } | ||
2159 | |||
2160 | if (*colon == '\0') { | ||
2161 | /* No colon */ | ||
2162 | if (*dot != '\0') { | ||
2163 | Err("Malformed camera hint: no colon + device node given.\n"); | ||
2164 | return -EINVAL; | ||
2165 | } | ||
2166 | else { | ||
2167 | /* No type or serial number specified, just a number. */ | ||
2168 | device_hint[i].device_node = pwc_atoi(s); | ||
2169 | } | ||
2170 | } | ||
2171 | else { | ||
2172 | /* There's a colon, so we have at least a type and a device node */ | ||
2173 | device_hint[i].type = pwc_atoi(s); | ||
2174 | device_hint[i].device_node = pwc_atoi(colon + 1); | ||
2175 | if (*dot != '\0') { | ||
2176 | /* There's a serial number as well */ | ||
2177 | int k; | ||
2178 | |||
2179 | dot++; | ||
2180 | k = 0; | ||
2181 | while (*dot != ':' && k < 29) { | ||
2182 | device_hint[i].serial_number[k++] = *dot; | ||
2183 | dot++; | ||
2184 | } | ||
2185 | device_hint[i].serial_number[k] = '\0'; | ||
2186 | } | ||
2187 | } | ||
2188 | #if PWC_DEBUG | ||
2189 | Debug("device_hint[%d]:\n", i); | ||
2190 | Debug(" type : %d\n", device_hint[i].type); | ||
2191 | Debug(" serial# : %s\n", device_hint[i].serial_number); | ||
2192 | Debug(" node : %d\n", device_hint[i].device_node); | ||
2193 | #endif | ||
2194 | } | ||
2195 | else | ||
2196 | device_hint[i].type = 0; /* not filled */ | ||
2197 | } /* ..for MAX_DEV_HINTS */ | ||
2198 | |||
2199 | Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver); | ||
2200 | return usb_register(&pwc_driver); | ||
2201 | } | ||
2202 | |||
2203 | static void __exit usb_pwc_exit(void) | ||
2204 | { | ||
2205 | Trace(TRACE_MODULE, "Deregistering driver.\n"); | ||
2206 | usb_deregister(&pwc_driver); | ||
2207 | Info("Philips webcam module removed.\n"); | ||
2208 | } | ||
2209 | |||
2210 | module_init(usb_pwc_init); | ||
2211 | module_exit(usb_pwc_exit); | ||
2212 | |||
diff --git a/drivers/usb/media/pwc/pwc-ioctl.h b/drivers/usb/media/pwc/pwc-ioctl.h new file mode 100644 index 000000000000..65805eaa9a1c --- /dev/null +++ b/drivers/usb/media/pwc/pwc-ioctl.h | |||
@@ -0,0 +1,292 @@ | |||
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 transfering 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 new file mode 100644 index 000000000000..5485800efd83 --- /dev/null +++ b/drivers/usb/media/pwc/pwc-kiara.c | |||
@@ -0,0 +1,891 @@ | |||
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 | |||
319 | |||
320 | /* | ||
321 | * Rom table for kiara chips | ||
322 | * | ||
323 | * 32 roms tables (one for each resolution ?) | ||
324 | * 2 tables per roms (one for each passes) (Y, and U&V) | ||
325 | * 128 bytes per passes | ||
326 | */ | ||
327 | |||
328 | const unsigned int KiaraRomTable [8][2][16][8] = | ||
329 | { | ||
330 | { /* version 0 */ | ||
331 | { /* version 0, passes 0 */ | ||
332 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
333 | 0x00000000,0x00000000,0x00000001,0x00000001}, | ||
334 | {0x00000000,0x00000000,0x00000009,0x00000009, | ||
335 | 0x00000009,0x00000009,0x00000009,0x00000009}, | ||
336 | {0x00000000,0x00000000,0x00000009,0x00000049, | ||
337 | 0x00000049,0x00000049,0x00000049,0x00000049}, | ||
338 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
339 | 0x00000049,0x00000249,0x0000024a,0x00000049}, | ||
340 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
341 | 0x00000249,0x00000249,0x0000024a,0x0000024a}, | ||
342 | {0x00000000,0x00000000,0x00000049,0x00000249, | ||
343 | 0x00000249,0x0000124a,0x0000024a,0x0000024a}, | ||
344 | {0x00000000,0x00000000,0x00000049,0x00000249, | ||
345 | 0x0000124a,0x00009252,0x00001252,0x00001252}, | ||
346 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
347 | 0x00009252,0x00009292,0x00009292,0x00009292}, | ||
348 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
349 | 0x00009292,0x00009292,0x00009493,0x000124db}, | ||
350 | {0x00000000,0x00000000,0x00000249,0x0000924a, | ||
351 | 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, | ||
352 | {0x00000000,0x00000000,0x00001249,0x00009252, | ||
353 | 0x0000a493,0x000124db,0x000124db,0x000126dc}, | ||
354 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
355 | 0x000124db,0x000126dc,0x000136e4,0x000126dc}, | ||
356 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
357 | 0x000124db,0x000136e4,0x000136e4,0x000136e4}, | ||
358 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
359 | 0x000126dc,0x0001b724,0x0001b92d,0x0001b925}, | ||
360 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
361 | 0x000136e4,0x0001b925,0x0001c96e,0x0001c92d}, | ||
362 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
363 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
364 | }, | ||
365 | { /* version 0, passes 1 */ | ||
366 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
367 | 0x00000000,0x00000000,0x00000000,0x00000000}, | ||
368 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
369 | 0x00000000,0x00000000,0x00000000,0x00000000}, | ||
370 | {0x00000000,0x00000000,0x00000001,0x00000009, | ||
371 | 0x00000009,0x00000009,0x00000009,0x00000001}, | ||
372 | {0x00000000,0x00000000,0x00000009,0x00000009, | ||
373 | 0x00000049,0x00000049,0x00000049,0x00000049}, | ||
374 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
375 | 0x00000049,0x00000049,0x0000024a,0x0000024a}, | ||
376 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
377 | 0x00000249,0x00000249,0x0000024a,0x0000024a}, | ||
378 | {0x00000000,0x00000000,0x00000049,0x00000249, | ||
379 | 0x00000249,0x00000249,0x0000024a,0x00001252}, | ||
380 | {0x00000000,0x00000000,0x00000049,0x00001249, | ||
381 | 0x0000124a,0x0000124a,0x00001252,0x00009292}, | ||
382 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
383 | 0x00009252,0x00009252,0x00009292,0x00009493}, | ||
384 | {0x00000000,0x00000000,0x00000249,0x0000924a, | ||
385 | 0x00009292,0x00009292,0x00009292,0x00009493}, | ||
386 | {0x00000000,0x00000000,0x00000249,0x00009292, | ||
387 | 0x00009492,0x00009493,0x0000a49b,0x00009493}, | ||
388 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
389 | 0x0000a493,0x000124db,0x000126dc,0x000126dc}, | ||
390 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
391 | 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, | ||
392 | {0x00000000,0x00000000,0x00009252,0x00009493, | ||
393 | 0x000126dc,0x000126dc,0x000136e4,0x000136e4}, | ||
394 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
395 | 0x000136e4,0x000136e4,0x0001b725,0x0001b724}, | ||
396 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
397 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
398 | } | ||
399 | }, | ||
400 | { /* version 1 */ | ||
401 | { /* version 1, passes 0 */ | ||
402 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
403 | 0x00000000,0x00000000,0x00000000,0x00000001}, | ||
404 | {0x00000000,0x00000000,0x00000009,0x00000009, | ||
405 | 0x00000009,0x00000009,0x00000009,0x00000009}, | ||
406 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
407 | 0x00000049,0x00000049,0x00000049,0x00000049}, | ||
408 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
409 | 0x00000049,0x00000249,0x0000024a,0x0000024a}, | ||
410 | {0x00000000,0x00000000,0x00000049,0x00000249, | ||
411 | 0x00000249,0x00000249,0x0000024a,0x00001252}, | ||
412 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
413 | 0x00000249,0x0000124a,0x00001252,0x00001252}, | ||
414 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
415 | 0x0000124a,0x0000124a,0x00009292,0x00009292}, | ||
416 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
417 | 0x0000124a,0x00009252,0x00009292,0x00009292}, | ||
418 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
419 | 0x00009252,0x00009292,0x00009292,0x00009292}, | ||
420 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
421 | 0x00009252,0x00009292,0x00009493,0x00009493}, | ||
422 | {0x00000000,0x00000000,0x00000249,0x0000924a, | ||
423 | 0x00009252,0x00009493,0x00009493,0x00009493}, | ||
424 | {0x00000000,0x00000000,0x00000249,0x0000924a, | ||
425 | 0x00009292,0x00009493,0x00009493,0x00009493}, | ||
426 | {0x00000000,0x00000000,0x00000249,0x00009252, | ||
427 | 0x00009492,0x00009493,0x0000a49b,0x0000a49b}, | ||
428 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
429 | 0x00009492,0x000124db,0x000124db,0x000124db}, | ||
430 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
431 | 0x0000a493,0x000126dc,0x000126dc,0x000126dc}, | ||
432 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
433 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
434 | }, | ||
435 | { /* version 1, passes 1 */ | ||
436 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
437 | 0x00000000,0x00000000,0x00000000,0x00000000}, | ||
438 | {0x00000000,0x00000000,0x00000049,0x00000009, | ||
439 | 0x00000049,0x00000009,0x00000001,0x00000000}, | ||
440 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
441 | 0x00000049,0x00000049,0x00000049,0x00000000}, | ||
442 | {0x00000000,0x00000000,0x00000249,0x00000049, | ||
443 | 0x00000249,0x00000049,0x0000024a,0x00000001}, | ||
444 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
445 | 0x00000249,0x00000249,0x0000024a,0x00000001}, | ||
446 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
447 | 0x00000249,0x00000249,0x0000024a,0x00000001}, | ||
448 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
449 | 0x00000249,0x00000249,0x0000024a,0x00000009}, | ||
450 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
451 | 0x0000124a,0x0000124a,0x0000024a,0x00000009}, | ||
452 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
453 | 0x0000124a,0x0000124a,0x0000024a,0x00000009}, | ||
454 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
455 | 0x0000124a,0x00009252,0x00001252,0x00000049}, | ||
456 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
457 | 0x0000124a,0x00009292,0x00001252,0x00000049}, | ||
458 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
459 | 0x0000124a,0x00009292,0x00001252,0x00000049}, | ||
460 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
461 | 0x00009252,0x00009292,0x00001252,0x0000024a}, | ||
462 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
463 | 0x00009292,0x00009292,0x00001252,0x0000024a}, | ||
464 | {0x00000000,0x00000000,0x0000924a,0x0000924a, | ||
465 | 0x00009492,0x00009493,0x00009292,0x00001252}, | ||
466 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
467 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
468 | } | ||
469 | }, | ||
470 | { /* version 2 */ | ||
471 | { /* version 2, passes 0 */ | ||
472 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
473 | 0x00000049,0x00000049,0x0000024a,0x0000024a}, | ||
474 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
475 | 0x00000249,0x0000124a,0x00001252,0x00009292}, | ||
476 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
477 | 0x0000124a,0x00009252,0x00009292,0x00009292}, | ||
478 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
479 | 0x0000124a,0x00009292,0x00009493,0x00009493}, | ||
480 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
481 | 0x00009252,0x00009493,0x00009493,0x0000a49b}, | ||
482 | {0x00000000,0x00000000,0x00000249,0x0000924a, | ||
483 | 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, | ||
484 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
485 | 0x00009292,0x00009493,0x0000a49b,0x000124db}, | ||
486 | {0x00000000,0x00000000,0x00001249,0x00009252, | ||
487 | 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, | ||
488 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
489 | 0x00009492,0x000124db,0x000124db,0x000126dc}, | ||
490 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
491 | 0x0000a493,0x000124db,0x000126dc,0x000126dc}, | ||
492 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
493 | 0x0000a493,0x000124db,0x000126dc,0x000136e4}, | ||
494 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
495 | 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, | ||
496 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
497 | 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, | ||
498 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
499 | 0x000124db,0x000136e4,0x000136e4,0x0001b724}, | ||
500 | {0x00000000,0x00000000,0x00009252,0x000124db, | ||
501 | 0x000126dc,0x0001b724,0x0001b725,0x0001b925}, | ||
502 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
503 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
504 | }, | ||
505 | { /* version 2, passes 1 */ | ||
506 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
507 | 0x00000049,0x00000049,0x00000049,0x00000049}, | ||
508 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
509 | 0x00000249,0x00000249,0x0000024a,0x00000049}, | ||
510 | {0x00000000,0x00000000,0x00001249,0x00000249, | ||
511 | 0x0000124a,0x0000124a,0x00001252,0x00000049}, | ||
512 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
513 | 0x0000124a,0x0000124a,0x00009292,0x0000024a}, | ||
514 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
515 | 0x00009252,0x00009292,0x00009292,0x0000024a}, | ||
516 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
517 | 0x00009252,0x00009292,0x0000a49b,0x0000024a}, | ||
518 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
519 | 0x00009292,0x00009493,0x0000a49b,0x00001252}, | ||
520 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
521 | 0x00009292,0x00009493,0x0000a49b,0x00001252}, | ||
522 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
523 | 0x00009492,0x0000a49b,0x0000a49b,0x00001252}, | ||
524 | {0x00000000,0x00000000,0x00001249,0x00009252, | ||
525 | 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, | ||
526 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
527 | 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, | ||
528 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
529 | 0x0000a493,0x0000a49b,0x0000a49b,0x00009292}, | ||
530 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
531 | 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, | ||
532 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
533 | 0x0000a493,0x000124db,0x0000a49b,0x00009493}, | ||
534 | {0x00000000,0x00000000,0x00009252,0x0000a49b, | ||
535 | 0x0001249b,0x000126dc,0x000124db,0x0000a49b}, | ||
536 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
537 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
538 | } | ||
539 | }, | ||
540 | { /* version 3 */ | ||
541 | { /* version 3, passes 0 */ | ||
542 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
543 | 0x0000124a,0x0000124a,0x00009292,0x00009292}, | ||
544 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
545 | 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, | ||
546 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
547 | 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, | ||
548 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
549 | 0x00009492,0x000124db,0x000126dc,0x000126dc}, | ||
550 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
551 | 0x0000a493,0x000124db,0x000126dc,0x000126dc}, | ||
552 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
553 | 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, | ||
554 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
555 | 0x0000a493,0x000126dc,0x000136e4,0x0001b724}, | ||
556 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
557 | 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, | ||
558 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
559 | 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, | ||
560 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
561 | 0x0001249b,0x000136e4,0x0001b725,0x0001b724}, | ||
562 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
563 | 0x000124db,0x000136e4,0x0001b725,0x0001b925}, | ||
564 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
565 | 0x000126dc,0x000136e4,0x0001b92d,0x0001b925}, | ||
566 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
567 | 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, | ||
568 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
569 | 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, | ||
570 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
571 | 0x000136e4,0x0001b925,0x00025bb6,0x00024b77}, | ||
572 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
573 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
574 | }, | ||
575 | { /* version 3, passes 1 */ | ||
576 | {0x00000000,0x00000000,0x00001249,0x00000249, | ||
577 | 0x0000124a,0x0000124a,0x00001252,0x00001252}, | ||
578 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
579 | 0x00009252,0x00009292,0x00009292,0x00001252}, | ||
580 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
581 | 0x00009492,0x00009493,0x0000a49b,0x00001252}, | ||
582 | {0x00000000,0x00000000,0x00001249,0x00009252, | ||
583 | 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, | ||
584 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
585 | 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, | ||
586 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
587 | 0x0000a493,0x0000a49b,0x000126dc,0x00009292}, | ||
588 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
589 | 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, | ||
590 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
591 | 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, | ||
592 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
593 | 0x0000a493,0x000124db,0x000126dc,0x00009493}, | ||
594 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
595 | 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, | ||
596 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
597 | 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, | ||
598 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
599 | 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, | ||
600 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
601 | 0x000124db,0x000136e4,0x000126dc,0x000124db}, | ||
602 | {0x00000000,0x00000000,0x00009492,0x0000a49b, | ||
603 | 0x000136e4,0x000136e4,0x000126dc,0x000124db}, | ||
604 | {0x00000000,0x00000000,0x0000a492,0x000124db, | ||
605 | 0x0001b724,0x0001b724,0x000136e4,0x000126dc}, | ||
606 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
607 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
608 | } | ||
609 | }, | ||
610 | { /* version 4 */ | ||
611 | { /* version 4, passes 0 */ | ||
612 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
613 | 0x00000049,0x00000049,0x00000049,0x00000049}, | ||
614 | {0x00000000,0x00000000,0x00000249,0x00000049, | ||
615 | 0x00000249,0x00000249,0x0000024a,0x00000049}, | ||
616 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
617 | 0x0000124a,0x00009252,0x00001252,0x0000024a}, | ||
618 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
619 | 0x00009252,0x00009292,0x00009493,0x00001252}, | ||
620 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
621 | 0x00009292,0x00009493,0x00009493,0x00001252}, | ||
622 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
623 | 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, | ||
624 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
625 | 0x0000a493,0x000124db,0x000124db,0x00009493}, | ||
626 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
627 | 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, | ||
628 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
629 | 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, | ||
630 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
631 | 0x0001249b,0x000126dc,0x000126dc,0x000124db}, | ||
632 | {0x00000000,0x00000000,0x00009252,0x00009493, | ||
633 | 0x000124db,0x000136e4,0x000136e4,0x000126dc}, | ||
634 | {0x00000000,0x00000000,0x00009252,0x0000a49b, | ||
635 | 0x000124db,0x000136e4,0x000136e4,0x000126dc}, | ||
636 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
637 | 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, | ||
638 | {0x00000000,0x00000000,0x00009492,0x0000a49b, | ||
639 | 0x000126dc,0x0001b724,0x0001b725,0x0001b724}, | ||
640 | {0x00000000,0x00000000,0x0000a492,0x000124db, | ||
641 | 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, | ||
642 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
643 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
644 | }, | ||
645 | { /* version 4, passes 1 */ | ||
646 | {0x00000000,0x00000000,0x00000249,0x00000049, | ||
647 | 0x00000009,0x00000009,0x00000009,0x00000009}, | ||
648 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
649 | 0x00000049,0x00000049,0x00000009,0x00000009}, | ||
650 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
651 | 0x0000124a,0x00000249,0x00000049,0x00000049}, | ||
652 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
653 | 0x0000124a,0x0000124a,0x00000049,0x00000049}, | ||
654 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
655 | 0x00009252,0x0000124a,0x0000024a,0x0000024a}, | ||
656 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
657 | 0x00009252,0x0000124a,0x0000024a,0x0000024a}, | ||
658 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
659 | 0x00009492,0x00009252,0x00001252,0x00001252}, | ||
660 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
661 | 0x0000a493,0x00009292,0x00009292,0x00001252}, | ||
662 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
663 | 0x0000a493,0x00009292,0x00009292,0x00009292}, | ||
664 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
665 | 0x0000a493,0x00009493,0x00009493,0x00009292}, | ||
666 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
667 | 0x0000a493,0x0000a49b,0x00009493,0x00009493}, | ||
668 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
669 | 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, | ||
670 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
671 | 0x0001249b,0x000124db,0x0000a49b,0x0000a49b}, | ||
672 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
673 | 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, | ||
674 | {0x00000000,0x00000000,0x00009252,0x000124db, | ||
675 | 0x0001b724,0x000136e4,0x000126dc,0x000124db}, | ||
676 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
677 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
678 | } | ||
679 | }, | ||
680 | { /* version 5 */ | ||
681 | { /* version 5, passes 0 */ | ||
682 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
683 | 0x00000249,0x00000249,0x00001252,0x00001252}, | ||
684 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
685 | 0x00009252,0x00009292,0x00009292,0x00001252}, | ||
686 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
687 | 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, | ||
688 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
689 | 0x0000a493,0x0000a49b,0x000124db,0x00009493}, | ||
690 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
691 | 0x0000a493,0x000124db,0x000126dc,0x00009493}, | ||
692 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
693 | 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, | ||
694 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
695 | 0x0001249b,0x000126dc,0x000136e4,0x000124db}, | ||
696 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
697 | 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, | ||
698 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
699 | 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, | ||
700 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
701 | 0x000126dc,0x0001b724,0x0001b725,0x000136e4}, | ||
702 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
703 | 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, | ||
704 | {0x00000000,0x00000000,0x00009492,0x0000a49b, | ||
705 | 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, | ||
706 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
707 | 0x000136e4,0x0001b925,0x0001c96e,0x0001b925}, | ||
708 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
709 | 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, | ||
710 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
711 | 0x0001c924,0x0002496d,0x00025bb6,0x00024b77}, | ||
712 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
713 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
714 | }, | ||
715 | { /* version 5, passes 1 */ | ||
716 | {0x00000000,0x00000000,0x00001249,0x00000249, | ||
717 | 0x00000249,0x00000249,0x0000024a,0x0000024a}, | ||
718 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
719 | 0x0000124a,0x0000124a,0x0000024a,0x0000024a}, | ||
720 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
721 | 0x00009252,0x00009252,0x0000024a,0x0000024a}, | ||
722 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
723 | 0x00009492,0x0000a49b,0x00001252,0x00001252}, | ||
724 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
725 | 0x0000a493,0x0000a49b,0x00001252,0x00001252}, | ||
726 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
727 | 0x0000a493,0x0000a49b,0x00009292,0x00001252}, | ||
728 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
729 | 0x0000a493,0x0000a49b,0x00009292,0x00009292}, | ||
730 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
731 | 0x0000a493,0x0000a49b,0x00009493,0x00009292}, | ||
732 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
733 | 0x0001249b,0x000124db,0x00009493,0x00009292}, | ||
734 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
735 | 0x0001249b,0x000124db,0x00009493,0x00009493}, | ||
736 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
737 | 0x000124db,0x000124db,0x0000a49b,0x00009493}, | ||
738 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
739 | 0x000126dc,0x000126dc,0x0000a49b,0x00009493}, | ||
740 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
741 | 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, | ||
742 | {0x00000000,0x00000000,0x00009292,0x000124db, | ||
743 | 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, | ||
744 | {0x00000000,0x00000000,0x00009492,0x000126db, | ||
745 | 0x0001b724,0x000136e4,0x000126dc,0x000124db}, | ||
746 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
747 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
748 | } | ||
749 | }, | ||
750 | { /* version 6 */ | ||
751 | { /* version 6, passes 0 */ | ||
752 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
753 | 0x00009252,0x00009292,0x00009493,0x00009493}, | ||
754 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
755 | 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, | ||
756 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
757 | 0x0000a493,0x000124db,0x000124db,0x0000a49b}, | ||
758 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
759 | 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, | ||
760 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
761 | 0x0001249b,0x000126dc,0x000136e4,0x000124db}, | ||
762 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
763 | 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, | ||
764 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
765 | 0x000126dc,0x0001b724,0x0001b725,0x000126dc}, | ||
766 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
767 | 0x000136e4,0x0001b724,0x0001b92d,0x000136e4}, | ||
768 | {0x00000000,0x00000000,0x00009492,0x0000a49b, | ||
769 | 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, | ||
770 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
771 | 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, | ||
772 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
773 | 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, | ||
774 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
775 | 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, | ||
776 | {0x00000000,0x00000000,0x0000a492,0x000124db, | ||
777 | 0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d}, | ||
778 | {0x00000000,0x00000000,0x0000a492,0x000124db, | ||
779 | 0x0001b724,0x0001c92d,0x00024b76,0x0002496e}, | ||
780 | {0x00000000,0x00000000,0x00012492,0x000126db, | ||
781 | 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf}, | ||
782 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
783 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
784 | }, | ||
785 | { /* version 6, passes 1 */ | ||
786 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
787 | 0x0000124a,0x0000124a,0x00001252,0x00001252}, | ||
788 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
789 | 0x00009492,0x00009252,0x00001252,0x00001252}, | ||
790 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
791 | 0x0000a493,0x00009292,0x00001252,0x00001252}, | ||
792 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
793 | 0x0000a493,0x0000a49b,0x00009292,0x00009292}, | ||
794 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
795 | 0x0000a493,0x0000a49b,0x00009292,0x00009292}, | ||
796 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
797 | 0x0001249b,0x0000a49b,0x00009493,0x00009292}, | ||
798 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
799 | 0x000124db,0x000124db,0x00009493,0x00009493}, | ||
800 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
801 | 0x000124db,0x000124db,0x0000a49b,0x00009493}, | ||
802 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
803 | 0x000126dc,0x000124db,0x0000a49b,0x00009493}, | ||
804 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
805 | 0x000126dc,0x000126dc,0x0000a49b,0x0000a49b}, | ||
806 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
807 | 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, | ||
808 | {0x00000000,0x00000000,0x00009492,0x000126db, | ||
809 | 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, | ||
810 | {0x00000000,0x00000000,0x00009492,0x000126db, | ||
811 | 0x0001b724,0x000136e4,0x000126dc,0x000124db}, | ||
812 | {0x00000000,0x00000000,0x00009492,0x000126db, | ||
813 | 0x0001b724,0x000136e4,0x000126dc,0x000124db}, | ||
814 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
815 | 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, | ||
816 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
817 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
818 | } | ||
819 | }, | ||
820 | { /* version 7 */ | ||
821 | { /* version 7, passes 0 */ | ||
822 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
823 | 0x00009252,0x00009292,0x00009493,0x00009493}, | ||
824 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
825 | 0x0000a493,0x000124db,0x000126dc,0x00009493}, | ||
826 | {0x00000000,0x00000000,0x00001249,0x0000a49b, | ||
827 | 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, | ||
828 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
829 | 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, | ||
830 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
831 | 0x000126dc,0x000136e4,0x0001b725,0x000124db}, | ||
832 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
833 | 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, | ||
834 | {0x00000000,0x00000000,0x00009292,0x000124db, | ||
835 | 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, | ||
836 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
837 | 0x000136e4,0x0001b724,0x0001c96e,0x000136e4}, | ||
838 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
839 | 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, | ||
840 | {0x00000000,0x00000000,0x0000a492,0x000124db, | ||
841 | 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, | ||
842 | {0x00000000,0x00000000,0x0000a492,0x000124db, | ||
843 | 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925}, | ||
844 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
845 | 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, | ||
846 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
847 | 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, | ||
848 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
849 | 0x0001b924,0x0001c92d,0x00024b76,0x0002496e}, | ||
850 | {0x00000000,0x00000000,0x00012492,0x000136db, | ||
851 | 0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf}, | ||
852 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
853 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
854 | }, | ||
855 | { /* version 7, passes 1 */ | ||
856 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
857 | 0x0000124a,0x0000124a,0x00001252,0x00001252}, | ||
858 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
859 | 0x00009492,0x00009292,0x00001252,0x00001252}, | ||
860 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
861 | 0x0000a493,0x0000a49b,0x00001252,0x00001252}, | ||
862 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
863 | 0x0000a493,0x0000a49b,0x00009292,0x00009292}, | ||
864 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
865 | 0x0000a493,0x0000a49b,0x00009292,0x00009292}, | ||
866 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
867 | 0x000126dc,0x0000a49b,0x00009493,0x00009292}, | ||
868 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
869 | 0x000126dc,0x000124db,0x00009493,0x00009493}, | ||
870 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
871 | 0x000136e4,0x000124db,0x0000a49b,0x00009493}, | ||
872 | {0x00000000,0x00000000,0x0000924a,0x000136db, | ||
873 | 0x0001b724,0x000124db,0x0000a49b,0x00009493}, | ||
874 | {0x00000000,0x00000000,0x0000924a,0x000136db, | ||
875 | 0x0001b724,0x000126dc,0x0000a49b,0x0000a49b}, | ||
876 | {0x00000000,0x00000000,0x00009292,0x000136db, | ||
877 | 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, | ||
878 | {0x00000000,0x00000000,0x00009492,0x000136db, | ||
879 | 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, | ||
880 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
881 | 0x0001b724,0x000136e4,0x000126dc,0x000124db}, | ||
882 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
883 | 0x0001b724,0x000136e4,0x000126dc,0x000124db}, | ||
884 | {0x00000000,0x00000000,0x00012492,0x0001b6db, | ||
885 | 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, | ||
886 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
887 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
888 | } | ||
889 | } | ||
890 | }; | ||
891 | |||
diff --git a/drivers/usb/media/pwc/pwc-kiara.h b/drivers/usb/media/pwc/pwc-kiara.h new file mode 100644 index 000000000000..12929abbb1f0 --- /dev/null +++ b/drivers/usb/media/pwc/pwc-kiara.h | |||
@@ -0,0 +1,45 @@ | |||
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 new file mode 100644 index 000000000000..b7a4bd3524c7 --- /dev/null +++ b/drivers/usb/media/pwc/pwc-misc.c | |||
@@ -0,0 +1,140 @@ | |||
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 new file mode 100644 index 000000000000..e6c5cb69d03b --- /dev/null +++ b/drivers/usb/media/pwc/pwc-nala.h | |||
@@ -0,0 +1,66 @@ | |||
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 new file mode 100644 index 000000000000..f950a4e5ed96 --- /dev/null +++ b/drivers/usb/media/pwc/pwc-timon.c | |||
@@ -0,0 +1,1446 @@ | |||
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 | |||
317 | /* | ||
318 | * 16 versions: | ||
319 | * 2 tables (one for Y, and one for U&V) | ||
320 | * 16 levels of details per tables | ||
321 | * 8 blocs | ||
322 | */ | ||
323 | |||
324 | const unsigned int TimonRomTable [16][2][16][8] = | ||
325 | { | ||
326 | { /* version 0 */ | ||
327 | { /* version 0, passes 0 */ | ||
328 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
329 | 0x00000000,0x00000000,0x00000000,0x00000001}, | ||
330 | {0x00000000,0x00000000,0x00000001,0x00000001, | ||
331 | 0x00000001,0x00000001,0x00000001,0x00000001}, | ||
332 | {0x00000000,0x00000000,0x00000001,0x00000001, | ||
333 | 0x00000001,0x00000009,0x00000009,0x00000009}, | ||
334 | {0x00000000,0x00000000,0x00000009,0x00000001, | ||
335 | 0x00000009,0x00000009,0x00000009,0x00000009}, | ||
336 | {0x00000000,0x00000000,0x00000009,0x00000009, | ||
337 | 0x00000009,0x00000009,0x00000049,0x00000009}, | ||
338 | {0x00000000,0x00000000,0x00000009,0x00000009, | ||
339 | 0x00000009,0x00000049,0x00000049,0x00000049}, | ||
340 | {0x00000000,0x00000000,0x00000009,0x00000009, | ||
341 | 0x00000049,0x00000049,0x00000049,0x00000049}, | ||
342 | {0x00000000,0x00000000,0x00000009,0x00000049, | ||
343 | 0x00000049,0x00000049,0x00000049,0x00000049}, | ||
344 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
345 | 0x00000049,0x00000049,0x0000024a,0x0000024a}, | ||
346 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
347 | 0x00000049,0x00000249,0x0000024a,0x0000024a}, | ||
348 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
349 | 0x00000249,0x00000249,0x0000024a,0x0000024a}, | ||
350 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
351 | 0x00000249,0x00000249,0x00001252,0x0000024a}, | ||
352 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
353 | 0x00000249,0x0000124a,0x00001252,0x0000024a}, | ||
354 | {0x00000000,0x00000000,0x00000049,0x00000249, | ||
355 | 0x00000249,0x0000124a,0x00001252,0x0000024a}, | ||
356 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
357 | 0x0000124a,0x00009252,0x00009292,0x00001252}, | ||
358 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
359 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
360 | }, | ||
361 | { /* version 0, passes 1 */ | ||
362 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
363 | 0x00000000,0x00000000,0x00000000,0x00000000}, | ||
364 | {0x00000000,0x00000000,0x00000001,0x00000001, | ||
365 | 0x00000001,0x00000001,0x00000000,0x00000000}, | ||
366 | {0x00000000,0x00000000,0x00000009,0x00000001, | ||
367 | 0x00000001,0x00000009,0x00000000,0x00000000}, | ||
368 | {0x00000000,0x00000000,0x00000009,0x00000009, | ||
369 | 0x00000009,0x00000009,0x00000000,0x00000000}, | ||
370 | {0x00000000,0x00000000,0x00000009,0x00000009, | ||
371 | 0x00000009,0x00000009,0x00000001,0x00000000}, | ||
372 | {0x00000000,0x00000000,0x00000049,0x00000009, | ||
373 | 0x00000009,0x00000049,0x00000001,0x00000001}, | ||
374 | {0x00000000,0x00000000,0x00000049,0x00000009, | ||
375 | 0x00000009,0x00000049,0x00000001,0x00000001}, | ||
376 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
377 | 0x00000049,0x00000049,0x00000009,0x00000001}, | ||
378 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
379 | 0x00000049,0x00000049,0x00000009,0x00000001}, | ||
380 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
381 | 0x00000049,0x00000049,0x00000009,0x00000001}, | ||
382 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
383 | 0x00000049,0x00000049,0x00000009,0x00000009}, | ||
384 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
385 | 0x00000049,0x00000249,0x00000049,0x00000009}, | ||
386 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
387 | 0x00000049,0x00000249,0x00000049,0x00000009}, | ||
388 | {0x00000000,0x00000000,0x00000249,0x00000049, | ||
389 | 0x00000249,0x00000249,0x00000049,0x00000009}, | ||
390 | {0x00000000,0x00000000,0x00001249,0x00000249, | ||
391 | 0x0000124a,0x0000124a,0x0000024a,0x00000049}, | ||
392 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
393 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
394 | } | ||
395 | }, | ||
396 | { /* version 1 */ | ||
397 | { /* version 1, passes 0 */ | ||
398 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
399 | 0x00000000,0x00000000,0x00000000,0x00000001}, | ||
400 | {0x00000000,0x00000000,0x00000001,0x00000001, | ||
401 | 0x00000001,0x00000009,0x00000009,0x00000009}, | ||
402 | {0x00000000,0x00000000,0x00000009,0x00000009, | ||
403 | 0x00000009,0x00000009,0x00000009,0x00000009}, | ||
404 | {0x00000000,0x00000000,0x00000009,0x00000009, | ||
405 | 0x00000009,0x00000049,0x00000049,0x00000049}, | ||
406 | {0x00000000,0x00000000,0x00000009,0x00000049, | ||
407 | 0x00000049,0x00000049,0x00000049,0x00000049}, | ||
408 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
409 | 0x00000049,0x00000249,0x0000024a,0x0000024a}, | ||
410 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
411 | 0x00000249,0x00000249,0x0000024a,0x0000024a}, | ||
412 | {0x00000000,0x00000000,0x00000049,0x00000249, | ||
413 | 0x00000249,0x00000249,0x0000024a,0x00001252}, | ||
414 | {0x00000000,0x00000000,0x00000049,0x00000249, | ||
415 | 0x00000249,0x0000124a,0x00001252,0x00001252}, | ||
416 | {0x00000000,0x00000000,0x00000049,0x00000249, | ||
417 | 0x0000124a,0x0000124a,0x00001252,0x00001252}, | ||
418 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
419 | 0x0000124a,0x0000124a,0x00009292,0x00009292}, | ||
420 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
421 | 0x0000124a,0x00009252,0x00009292,0x00009292}, | ||
422 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
423 | 0x00009252,0x00009252,0x00009292,0x00009292}, | ||
424 | {0x00000000,0x00000000,0x00000249,0x0000924a, | ||
425 | 0x00009292,0x00009493,0x00009493,0x00009493}, | ||
426 | {0x00000000,0x00000000,0x00001249,0x00009252, | ||
427 | 0x00009492,0x0000a49b,0x0000a49b,0x0000a49b}, | ||
428 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
429 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
430 | }, | ||
431 | { /* version 1, passes 1 */ | ||
432 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
433 | 0x00000000,0x00000000,0x00000000,0x00000000}, | ||
434 | {0x00000000,0x00000000,0x00000009,0x00000009, | ||
435 | 0x00000009,0x00000001,0x00000001,0x00000000}, | ||
436 | {0x00000000,0x00000000,0x00000009,0x00000009, | ||
437 | 0x00000009,0x00000009,0x00000001,0x00000000}, | ||
438 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
439 | 0x00000049,0x00000009,0x00000001,0x00000000}, | ||
440 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
441 | 0x00000049,0x00000049,0x00000001,0x00000001}, | ||
442 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
443 | 0x00000049,0x00000049,0x00000009,0x00000001}, | ||
444 | {0x00000000,0x00000000,0x00000249,0x00000049, | ||
445 | 0x00000049,0x00000249,0x00000009,0x00000001}, | ||
446 | {0x00000000,0x00000000,0x00000249,0x00000049, | ||
447 | 0x00000249,0x00000249,0x00000009,0x00000009}, | ||
448 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
449 | 0x00000249,0x00000249,0x00000049,0x00000009}, | ||
450 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
451 | 0x00000249,0x0000124a,0x00000049,0x00000009}, | ||
452 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
453 | 0x00000249,0x0000124a,0x00000049,0x00000009}, | ||
454 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
455 | 0x00000249,0x0000124a,0x0000024a,0x00000049}, | ||
456 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
457 | 0x0000124a,0x0000124a,0x0000024a,0x00000049}, | ||
458 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
459 | 0x0000124a,0x0000124a,0x0000024a,0x00000049}, | ||
460 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
461 | 0x00009252,0x00009252,0x00001252,0x0000024a}, | ||
462 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
463 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
464 | } | ||
465 | }, | ||
466 | { /* version 2 */ | ||
467 | { /* version 2, passes 0 */ | ||
468 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
469 | 0x00000000,0x00000000,0x00000000,0x00000001}, | ||
470 | {0x00000000,0x00000000,0x00000009,0x00000009, | ||
471 | 0x00000009,0x00000009,0x00000009,0x00000009}, | ||
472 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
473 | 0x00000049,0x00000049,0x00000049,0x00000049}, | ||
474 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
475 | 0x00000049,0x00000249,0x0000024a,0x0000024a}, | ||
476 | {0x00000000,0x00000000,0x00000049,0x00000249, | ||
477 | 0x00000249,0x00000249,0x0000024a,0x00001252}, | ||
478 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
479 | 0x00000249,0x0000124a,0x00001252,0x00001252}, | ||
480 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
481 | 0x0000124a,0x0000124a,0x00009292,0x00009292}, | ||
482 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
483 | 0x0000124a,0x00009252,0x00009292,0x00009292}, | ||
484 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
485 | 0x00009252,0x00009292,0x00009292,0x00009292}, | ||
486 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
487 | 0x00009252,0x00009292,0x00009493,0x00009493}, | ||
488 | {0x00000000,0x00000000,0x00000249,0x0000924a, | ||
489 | 0x00009252,0x00009493,0x00009493,0x00009493}, | ||
490 | {0x00000000,0x00000000,0x00000249,0x0000924a, | ||
491 | 0x00009292,0x00009493,0x00009493,0x00009493}, | ||
492 | {0x00000000,0x00000000,0x00000249,0x00009252, | ||
493 | 0x00009492,0x00009493,0x0000a49b,0x0000a49b}, | ||
494 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
495 | 0x00009492,0x000124db,0x000124db,0x000124db}, | ||
496 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
497 | 0x0000a493,0x000126dc,0x000126dc,0x000126dc}, | ||
498 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
499 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
500 | }, | ||
501 | { /* version 2, passes 1 */ | ||
502 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
503 | 0x00000000,0x00000000,0x00000000,0x00000000}, | ||
504 | {0x00000000,0x00000000,0x00000049,0x00000009, | ||
505 | 0x00000049,0x00000009,0x00000001,0x00000000}, | ||
506 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
507 | 0x00000049,0x00000049,0x00000049,0x00000000}, | ||
508 | {0x00000000,0x00000000,0x00000249,0x00000049, | ||
509 | 0x00000249,0x00000049,0x0000024a,0x00000001}, | ||
510 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
511 | 0x00000249,0x00000249,0x0000024a,0x00000001}, | ||
512 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
513 | 0x00000249,0x00000249,0x0000024a,0x00000001}, | ||
514 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
515 | 0x00000249,0x00000249,0x0000024a,0x00000009}, | ||
516 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
517 | 0x0000124a,0x0000124a,0x0000024a,0x00000009}, | ||
518 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
519 | 0x0000124a,0x0000124a,0x0000024a,0x00000009}, | ||
520 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
521 | 0x0000124a,0x00009252,0x00001252,0x00000049}, | ||
522 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
523 | 0x0000124a,0x00009292,0x00001252,0x00000049}, | ||
524 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
525 | 0x0000124a,0x00009292,0x00001252,0x00000049}, | ||
526 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
527 | 0x00009252,0x00009292,0x00001252,0x0000024a}, | ||
528 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
529 | 0x00009292,0x00009292,0x00001252,0x0000024a}, | ||
530 | {0x00000000,0x00000000,0x0000924a,0x0000924a, | ||
531 | 0x00009492,0x00009493,0x00009292,0x00001252}, | ||
532 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
533 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
534 | } | ||
535 | }, | ||
536 | { /* version 3 */ | ||
537 | { /* version 3, passes 0 */ | ||
538 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
539 | 0x00000000,0x00000000,0x00000000,0x00000001}, | ||
540 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
541 | 0x00000049,0x00000049,0x00000049,0x00000049}, | ||
542 | {0x00000000,0x00000000,0x00000049,0x00000249, | ||
543 | 0x00000249,0x00000249,0x00001252,0x0000024a}, | ||
544 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
545 | 0x00000249,0x0000124a,0x00001252,0x00001252}, | ||
546 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
547 | 0x0000124a,0x00009252,0x00009292,0x00009292}, | ||
548 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
549 | 0x0000124a,0x00009292,0x00009292,0x00009493}, | ||
550 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
551 | 0x00009252,0x00009292,0x00009493,0x00009493}, | ||
552 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
553 | 0x00009292,0x00009493,0x00009493,0x00009493}, | ||
554 | {0x00000000,0x00000000,0x00000249,0x00009252, | ||
555 | 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, | ||
556 | {0x00000000,0x00000000,0x00001249,0x00009252, | ||
557 | 0x00009292,0x0000a49b,0x0000a49b,0x0000a49b}, | ||
558 | {0x00000000,0x00000000,0x00001249,0x00009252, | ||
559 | 0x00009492,0x0000a49b,0x0000a49b,0x0000a49b}, | ||
560 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
561 | 0x00009492,0x0000a49b,0x000124db,0x000124db}, | ||
562 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
563 | 0x0000a493,0x0000a49b,0x000124db,0x000124db}, | ||
564 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
565 | 0x0001249b,0x000126dc,0x000136e4,0x000126dc}, | ||
566 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
567 | 0x000124db,0x000136e4,0x0001b725,0x000136e4}, | ||
568 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
569 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
570 | }, | ||
571 | { /* version 3, passes 1 */ | ||
572 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
573 | 0x00000000,0x00000000,0x00000000,0x00000000}, | ||
574 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
575 | 0x00000049,0x00000049,0x00000001,0x00000000}, | ||
576 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
577 | 0x00000249,0x00000249,0x00000049,0x00000001}, | ||
578 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
579 | 0x00000249,0x0000124a,0x00001252,0x00000001}, | ||
580 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
581 | 0x0000124a,0x0000124a,0x00001252,0x00000009}, | ||
582 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
583 | 0x0000124a,0x00009252,0x00009292,0x00000009}, | ||
584 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
585 | 0x0000124a,0x00009252,0x00009292,0x00000049}, | ||
586 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
587 | 0x00009252,0x00009252,0x00009292,0x00000049}, | ||
588 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
589 | 0x00009252,0x00009493,0x00009292,0x0000024a}, | ||
590 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
591 | 0x00009252,0x00009493,0x00009292,0x0000024a}, | ||
592 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
593 | 0x00009252,0x00009493,0x00009493,0x00001252}, | ||
594 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
595 | 0x00009292,0x00009493,0x00009493,0x00001252}, | ||
596 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
597 | 0x00009492,0x00009493,0x00009493,0x00009292}, | ||
598 | {0x00000000,0x00000000,0x00001249,0x00009252, | ||
599 | 0x00009492,0x0000a49b,0x00009493,0x00009292}, | ||
600 | {0x00000000,0x00000000,0x0000924a,0x00009292, | ||
601 | 0x0000a493,0x000124db,0x0000a49b,0x00009493}, | ||
602 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
603 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
604 | } | ||
605 | }, | ||
606 | { /* version 4 */ | ||
607 | { /* version 4, passes 0 */ | ||
608 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
609 | 0x00000049,0x00000049,0x0000024a,0x0000024a}, | ||
610 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
611 | 0x00000249,0x0000124a,0x00001252,0x00009292}, | ||
612 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
613 | 0x0000124a,0x00009252,0x00009292,0x00009292}, | ||
614 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
615 | 0x0000124a,0x00009292,0x00009493,0x00009493}, | ||
616 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
617 | 0x00009252,0x00009493,0x00009493,0x0000a49b}, | ||
618 | {0x00000000,0x00000000,0x00000249,0x0000924a, | ||
619 | 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, | ||
620 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
621 | 0x00009292,0x00009493,0x0000a49b,0x000124db}, | ||
622 | {0x00000000,0x00000000,0x00001249,0x00009252, | ||
623 | 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, | ||
624 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
625 | 0x00009492,0x000124db,0x000124db,0x000126dc}, | ||
626 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
627 | 0x0000a493,0x000124db,0x000126dc,0x000126dc}, | ||
628 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
629 | 0x0000a493,0x000124db,0x000126dc,0x000136e4}, | ||
630 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
631 | 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, | ||
632 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
633 | 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, | ||
634 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
635 | 0x000124db,0x000136e4,0x000136e4,0x0001b724}, | ||
636 | {0x00000000,0x00000000,0x00009252,0x000124db, | ||
637 | 0x000126dc,0x0001b724,0x0001b725,0x0001b925}, | ||
638 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
639 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
640 | }, | ||
641 | { /* version 4, passes 1 */ | ||
642 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
643 | 0x00000049,0x00000049,0x00000049,0x00000049}, | ||
644 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
645 | 0x00000249,0x00000249,0x0000024a,0x00000049}, | ||
646 | {0x00000000,0x00000000,0x00001249,0x00000249, | ||
647 | 0x0000124a,0x0000124a,0x00001252,0x00000049}, | ||
648 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
649 | 0x0000124a,0x0000124a,0x00009292,0x0000024a}, | ||
650 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
651 | 0x00009252,0x00009292,0x00009292,0x0000024a}, | ||
652 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
653 | 0x00009252,0x00009292,0x0000a49b,0x0000024a}, | ||
654 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
655 | 0x00009292,0x00009493,0x0000a49b,0x00001252}, | ||
656 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
657 | 0x00009292,0x00009493,0x0000a49b,0x00001252}, | ||
658 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
659 | 0x00009492,0x0000a49b,0x0000a49b,0x00001252}, | ||
660 | {0x00000000,0x00000000,0x00001249,0x00009252, | ||
661 | 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, | ||
662 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
663 | 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, | ||
664 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
665 | 0x0000a493,0x0000a49b,0x0000a49b,0x00009292}, | ||
666 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
667 | 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, | ||
668 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
669 | 0x0000a493,0x000124db,0x0000a49b,0x00009493}, | ||
670 | {0x00000000,0x00000000,0x00009252,0x0000a49b, | ||
671 | 0x0001249b,0x000126dc,0x000124db,0x0000a49b}, | ||
672 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
673 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
674 | } | ||
675 | }, | ||
676 | { /* version 5 */ | ||
677 | { /* version 5, passes 0 */ | ||
678 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
679 | 0x00000249,0x0000124a,0x00001252,0x00009292}, | ||
680 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
681 | 0x0000124a,0x00009292,0x00009292,0x00009493}, | ||
682 | {0x00000000,0x00000000,0x00000249,0x0000924a, | ||
683 | 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, | ||
684 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
685 | 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, | ||
686 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
687 | 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, | ||
688 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
689 | 0x00009492,0x0000a49b,0x000124db,0x000124db}, | ||
690 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
691 | 0x0000a493,0x000124db,0x000124db,0x000126dc}, | ||
692 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
693 | 0x0000a493,0x000124db,0x000126dc,0x000126dc}, | ||
694 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
695 | 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, | ||
696 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
697 | 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, | ||
698 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
699 | 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, | ||
700 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
701 | 0x0001249b,0x000126dc,0x0001b725,0x0001b724}, | ||
702 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
703 | 0x000124db,0x000126dc,0x0001b725,0x0001b724}, | ||
704 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
705 | 0x000126dc,0x000136e4,0x0001b92d,0x0001b925}, | ||
706 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
707 | 0x000136e4,0x0001b724,0x0001c96e,0x0001c92d}, | ||
708 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
709 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
710 | }, | ||
711 | { /* version 5, passes 1 */ | ||
712 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
713 | 0x0000124a,0x00000249,0x0000024a,0x0000024a}, | ||
714 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
715 | 0x0000124a,0x0000124a,0x00001252,0x0000024a}, | ||
716 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
717 | 0x00009292,0x00009493,0x00009493,0x0000024a}, | ||
718 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
719 | 0x00009292,0x00009493,0x00009493,0x00001252}, | ||
720 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
721 | 0x00009292,0x00009493,0x0000a49b,0x00001252}, | ||
722 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
723 | 0x00009492,0x00009493,0x000124db,0x00001252}, | ||
724 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
725 | 0x00009492,0x00009493,0x000124db,0x00009292}, | ||
726 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
727 | 0x00009492,0x0000a49b,0x000124db,0x00009292}, | ||
728 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
729 | 0x0000a493,0x0000a49b,0x000124db,0x00009292}, | ||
730 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
731 | 0x0000a493,0x000124db,0x000124db,0x00009493}, | ||
732 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
733 | 0x0000a493,0x000124db,0x000124db,0x00009493}, | ||
734 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
735 | 0x0000a493,0x000124db,0x000124db,0x00009493}, | ||
736 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
737 | 0x0000a493,0x000124db,0x000124db,0x0000a49b}, | ||
738 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
739 | 0x000124db,0x000126dc,0x000124db,0x0000a49b}, | ||
740 | {0x00000000,0x00000000,0x00009252,0x000124db, | ||
741 | 0x000126dc,0x000136e4,0x000126dc,0x000124db}, | ||
742 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
743 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
744 | } | ||
745 | }, | ||
746 | { /* version 6 */ | ||
747 | { /* version 6, passes 0 */ | ||
748 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
749 | 0x0000124a,0x0000124a,0x00009292,0x00009292}, | ||
750 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
751 | 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, | ||
752 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
753 | 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, | ||
754 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
755 | 0x00009492,0x000124db,0x000126dc,0x000126dc}, | ||
756 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
757 | 0x0000a493,0x000124db,0x000126dc,0x000126dc}, | ||
758 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
759 | 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, | ||
760 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
761 | 0x0000a493,0x000126dc,0x000136e4,0x0001b724}, | ||
762 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
763 | 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, | ||
764 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
765 | 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, | ||
766 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
767 | 0x0001249b,0x000136e4,0x0001b725,0x0001b724}, | ||
768 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
769 | 0x000124db,0x000136e4,0x0001b725,0x0001b925}, | ||
770 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
771 | 0x000126dc,0x000136e4,0x0001b92d,0x0001b925}, | ||
772 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
773 | 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, | ||
774 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
775 | 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, | ||
776 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
777 | 0x000136e4,0x0001b925,0x00025bb6,0x00024b77}, | ||
778 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
779 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
780 | }, | ||
781 | { /* version 6, passes 1 */ | ||
782 | {0x00000000,0x00000000,0x00001249,0x00000249, | ||
783 | 0x0000124a,0x0000124a,0x00001252,0x00001252}, | ||
784 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
785 | 0x00009252,0x00009292,0x00009292,0x00001252}, | ||
786 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
787 | 0x00009492,0x00009493,0x0000a49b,0x00001252}, | ||
788 | {0x00000000,0x00000000,0x00001249,0x00009252, | ||
789 | 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, | ||
790 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
791 | 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, | ||
792 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
793 | 0x0000a493,0x0000a49b,0x000126dc,0x00009292}, | ||
794 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
795 | 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, | ||
796 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
797 | 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, | ||
798 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
799 | 0x0000a493,0x000124db,0x000126dc,0x00009493}, | ||
800 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
801 | 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, | ||
802 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
803 | 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, | ||
804 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
805 | 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, | ||
806 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
807 | 0x000124db,0x000136e4,0x000126dc,0x000124db}, | ||
808 | {0x00000000,0x00000000,0x00009492,0x0000a49b, | ||
809 | 0x000136e4,0x000136e4,0x000126dc,0x000124db}, | ||
810 | {0x00000000,0x00000000,0x0000a492,0x000124db, | ||
811 | 0x0001b724,0x0001b724,0x000136e4,0x000126dc}, | ||
812 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
813 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
814 | } | ||
815 | }, | ||
816 | { /* version 7 */ | ||
817 | { /* version 7, passes 0 */ | ||
818 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
819 | 0x00009292,0x00009493,0x0000a49b,0x000124db}, | ||
820 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
821 | 0x0000a493,0x0000a49b,0x000124db,0x000126dc}, | ||
822 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
823 | 0x0000a493,0x000124db,0x000126dc,0x000136e4}, | ||
824 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
825 | 0x0000a493,0x000124db,0x000136e4,0x000136e4}, | ||
826 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
827 | 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, | ||
828 | {0x00000000,0x00000000,0x00001249,0x0000a49b, | ||
829 | 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, | ||
830 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
831 | 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, | ||
832 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
833 | 0x000124db,0x000136e4,0x0001b725,0x0001b724}, | ||
834 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
835 | 0x000126dc,0x000136e4,0x0001b725,0x0001b925}, | ||
836 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
837 | 0x000126dc,0x0001b724,0x0001b92d,0x0001b925}, | ||
838 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
839 | 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, | ||
840 | {0x00000000,0x00000000,0x00009292,0x000124db, | ||
841 | 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, | ||
842 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
843 | 0x000136e4,0x0001b724,0x0001c96e,0x0002496e}, | ||
844 | {0x00000000,0x00000000,0x00009492,0x000126db, | ||
845 | 0x000136e4,0x0001b925,0x0001c96e,0x0002496e}, | ||
846 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
847 | 0x0001b724,0x0002496d,0x00025bb6,0x00025bbf}, | ||
848 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
849 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
850 | }, | ||
851 | { /* version 7, passes 1 */ | ||
852 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
853 | 0x00009252,0x00009292,0x00009292,0x00009292}, | ||
854 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
855 | 0x00009492,0x00009493,0x00009493,0x00009292}, | ||
856 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
857 | 0x0000a493,0x0000a49b,0x0000a49b,0x00009292}, | ||
858 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
859 | 0x0000a493,0x0000a49b,0x000124db,0x00009493}, | ||
860 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
861 | 0x0000a493,0x000124db,0x000124db,0x00009493}, | ||
862 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
863 | 0x0000a493,0x000124db,0x000136e4,0x00009493}, | ||
864 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
865 | 0x0000a493,0x000124db,0x000136e4,0x0000a49b}, | ||
866 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
867 | 0x0001249b,0x000124db,0x000136e4,0x0000a49b}, | ||
868 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
869 | 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, | ||
870 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
871 | 0x0001249b,0x000126dc,0x000136e4,0x000124db}, | ||
872 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
873 | 0x000126dc,0x000136e4,0x000136e4,0x000124db}, | ||
874 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
875 | 0x000126dc,0x000136e4,0x000136e4,0x000124db}, | ||
876 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
877 | 0x000136e4,0x000136e4,0x000136e4,0x000126dc}, | ||
878 | {0x00000000,0x00000000,0x0000a492,0x000124db, | ||
879 | 0x000136e4,0x0001b724,0x000136e4,0x000126dc}, | ||
880 | {0x00000000,0x00000000,0x00012492,0x000126db, | ||
881 | 0x0001b724,0x0001b925,0x0001b725,0x000136e4}, | ||
882 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
883 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
884 | } | ||
885 | }, | ||
886 | { /* version 8 */ | ||
887 | { /* version 8, passes 0 */ | ||
888 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
889 | 0x00009292,0x00009493,0x0000a49b,0x000124db}, | ||
890 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
891 | 0x0000a493,0x000124db,0x000126dc,0x000126dc}, | ||
892 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
893 | 0x0000a493,0x000124db,0x000126dc,0x000136e4}, | ||
894 | {0x00000000,0x00000000,0x00001249,0x0000a49b, | ||
895 | 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, | ||
896 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
897 | 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, | ||
898 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
899 | 0x000124db,0x000136e4,0x0001b725,0x0001b724}, | ||
900 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
901 | 0x000126dc,0x000136e4,0x0001b725,0x0001b925}, | ||
902 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
903 | 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, | ||
904 | {0x00000000,0x00000000,0x00009252,0x000124db, | ||
905 | 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, | ||
906 | {0x00000000,0x00000000,0x00009292,0x000124db, | ||
907 | 0x000126dc,0x0001b925,0x0001c96e,0x0001c92d}, | ||
908 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
909 | 0x000136e4,0x0001b925,0x0001c96e,0x0001c92d}, | ||
910 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
911 | 0x000136e4,0x0001b925,0x00024b76,0x00024b77}, | ||
912 | {0x00000000,0x00000000,0x00009492,0x000126db, | ||
913 | 0x000136e4,0x0001b925,0x00024b76,0x00025bbf}, | ||
914 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
915 | 0x000136e4,0x0001c92d,0x00024b76,0x00025bbf}, | ||
916 | {0x00000000,0x00000000,0x00012492,0x000136db, | ||
917 | 0x0001b724,0x00024b6d,0x0002ddb6,0x0002efff}, | ||
918 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
919 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
920 | }, | ||
921 | { /* version 8, passes 1 */ | ||
922 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
923 | 0x00009252,0x00009493,0x00009493,0x00009493}, | ||
924 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
925 | 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, | ||
926 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
927 | 0x0000a493,0x0000a49b,0x000124db,0x00009493}, | ||
928 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
929 | 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, | ||
930 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
931 | 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, | ||
932 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
933 | 0x0000a493,0x000124db,0x000136e4,0x000124db}, | ||
934 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
935 | 0x0001249b,0x000126dc,0x000136e4,0x000124db}, | ||
936 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
937 | 0x000126dc,0x000126dc,0x000136e4,0x000126dc}, | ||
938 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
939 | 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, | ||
940 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
941 | 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, | ||
942 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
943 | 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, | ||
944 | {0x00000000,0x00000000,0x00009292,0x000124db, | ||
945 | 0x000136e4,0x0001b724,0x0001b725,0x000136e4}, | ||
946 | {0x00000000,0x00000000,0x00009492,0x000126db, | ||
947 | 0x000136e4,0x0001b925,0x0001b725,0x0001b724}, | ||
948 | {0x00000000,0x00000000,0x00009492,0x000126db, | ||
949 | 0x000136e4,0x0001b925,0x0001b725,0x0001b724}, | ||
950 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
951 | 0x0001b724,0x0002496d,0x0001b92d,0x0001b925}, | ||
952 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
953 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
954 | } | ||
955 | }, | ||
956 | { /* version 9 */ | ||
957 | { /* version 9, passes 0 */ | ||
958 | {0x00000000,0x00000000,0x00000049,0x00000049, | ||
959 | 0x00000049,0x00000049,0x00000049,0x00000049}, | ||
960 | {0x00000000,0x00000000,0x00000249,0x00000049, | ||
961 | 0x00000249,0x00000249,0x0000024a,0x00000049}, | ||
962 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
963 | 0x0000124a,0x00009252,0x00001252,0x0000024a}, | ||
964 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
965 | 0x00009252,0x00009292,0x00009493,0x00001252}, | ||
966 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
967 | 0x00009292,0x00009493,0x00009493,0x00001252}, | ||
968 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
969 | 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, | ||
970 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
971 | 0x0000a493,0x000124db,0x000124db,0x00009493}, | ||
972 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
973 | 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, | ||
974 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
975 | 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, | ||
976 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
977 | 0x0001249b,0x000126dc,0x000126dc,0x000124db}, | ||
978 | {0x00000000,0x00000000,0x00009252,0x00009493, | ||
979 | 0x000124db,0x000136e4,0x000136e4,0x000126dc}, | ||
980 | {0x00000000,0x00000000,0x00009252,0x0000a49b, | ||
981 | 0x000124db,0x000136e4,0x000136e4,0x000126dc}, | ||
982 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
983 | 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, | ||
984 | {0x00000000,0x00000000,0x00009492,0x0000a49b, | ||
985 | 0x000126dc,0x0001b724,0x0001b725,0x0001b724}, | ||
986 | {0x00000000,0x00000000,0x0000a492,0x000124db, | ||
987 | 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, | ||
988 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
989 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
990 | }, | ||
991 | { /* version 9, passes 1 */ | ||
992 | {0x00000000,0x00000000,0x00000249,0x00000049, | ||
993 | 0x00000009,0x00000009,0x00000009,0x00000009}, | ||
994 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
995 | 0x00000049,0x00000049,0x00000009,0x00000009}, | ||
996 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
997 | 0x0000124a,0x00000249,0x00000049,0x00000049}, | ||
998 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
999 | 0x0000124a,0x0000124a,0x00000049,0x00000049}, | ||
1000 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
1001 | 0x00009252,0x0000124a,0x0000024a,0x0000024a}, | ||
1002 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
1003 | 0x00009252,0x0000124a,0x0000024a,0x0000024a}, | ||
1004 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
1005 | 0x00009492,0x00009252,0x00001252,0x00001252}, | ||
1006 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
1007 | 0x0000a493,0x00009292,0x00009292,0x00001252}, | ||
1008 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
1009 | 0x0000a493,0x00009292,0x00009292,0x00009292}, | ||
1010 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
1011 | 0x0000a493,0x00009493,0x00009493,0x00009292}, | ||
1012 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1013 | 0x0000a493,0x0000a49b,0x00009493,0x00009493}, | ||
1014 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1015 | 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, | ||
1016 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1017 | 0x0001249b,0x000124db,0x0000a49b,0x0000a49b}, | ||
1018 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1019 | 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, | ||
1020 | {0x00000000,0x00000000,0x00009252,0x000124db, | ||
1021 | 0x0001b724,0x000136e4,0x000126dc,0x000124db}, | ||
1022 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
1023 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
1024 | } | ||
1025 | }, | ||
1026 | { /* version 10 */ | ||
1027 | { /* version 10, passes 0 */ | ||
1028 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
1029 | 0x00000249,0x00000249,0x0000024a,0x0000024a}, | ||
1030 | {0x00000000,0x00000000,0x00000249,0x00001249, | ||
1031 | 0x00009252,0x00009292,0x00009292,0x0000024a}, | ||
1032 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
1033 | 0x00009252,0x00009292,0x00009292,0x00001252}, | ||
1034 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
1035 | 0x00009492,0x00009493,0x0000a49b,0x00009292}, | ||
1036 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
1037 | 0x00009492,0x000124db,0x000124db,0x00009292}, | ||
1038 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
1039 | 0x0000a493,0x000124db,0x000124db,0x00009493}, | ||
1040 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
1041 | 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, | ||
1042 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
1043 | 0x0000a493,0x000124db,0x000126dc,0x000124db}, | ||
1044 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
1045 | 0x0001249b,0x000126dc,0x000126dc,0x000124db}, | ||
1046 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1047 | 0x000124db,0x000126dc,0x000136e4,0x000126dc}, | ||
1048 | {0x00000000,0x00000000,0x00009252,0x0000a49b, | ||
1049 | 0x000124db,0x000136e4,0x000136e4,0x000136e4}, | ||
1050 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
1051 | 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, | ||
1052 | {0x00000000,0x00000000,0x00009492,0x0000a49b, | ||
1053 | 0x000126dc,0x0001b724,0x0001b92d,0x0001b724}, | ||
1054 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
1055 | 0x000126dc,0x0001b925,0x0001b92d,0x0001b925}, | ||
1056 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
1057 | 0x000136e4,0x0002496d,0x0001c96e,0x0001c92d}, | ||
1058 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
1059 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
1060 | }, | ||
1061 | { /* version 10, passes 1 */ | ||
1062 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
1063 | 0x00000049,0x00000049,0x00000049,0x00000049}, | ||
1064 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
1065 | 0x0000124a,0x00000249,0x00000049,0x00000049}, | ||
1066 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
1067 | 0x0000124a,0x00009252,0x0000024a,0x00000049}, | ||
1068 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
1069 | 0x00009252,0x00009493,0x0000024a,0x0000024a}, | ||
1070 | {0x00000000,0x00000000,0x00001249,0x00009252, | ||
1071 | 0x00009492,0x00009493,0x00001252,0x0000024a}, | ||
1072 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
1073 | 0x00009492,0x00009493,0x00001252,0x00001252}, | ||
1074 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
1075 | 0x00009492,0x00009493,0x00009292,0x00001252}, | ||
1076 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
1077 | 0x0000a493,0x00009493,0x00009292,0x00009292}, | ||
1078 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
1079 | 0x0000a493,0x0000a49b,0x00009493,0x00009292}, | ||
1080 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
1081 | 0x0000a493,0x0000a49b,0x00009493,0x00009292}, | ||
1082 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1083 | 0x0000a493,0x000124db,0x0000a49b,0x00009493}, | ||
1084 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1085 | 0x0000a493,0x000124db,0x0000a49b,0x00009493}, | ||
1086 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
1087 | 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, | ||
1088 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
1089 | 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, | ||
1090 | {0x00000000,0x00000000,0x00009252,0x000126db, | ||
1091 | 0x0001b724,0x000136e4,0x000126dc,0x000124db}, | ||
1092 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
1093 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
1094 | } | ||
1095 | }, | ||
1096 | { /* version 11 */ | ||
1097 | { /* version 11, passes 0 */ | ||
1098 | {0x00000000,0x00000000,0x00000249,0x00000249, | ||
1099 | 0x00000249,0x00000249,0x00001252,0x00001252}, | ||
1100 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
1101 | 0x00009252,0x00009292,0x00009292,0x00001252}, | ||
1102 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
1103 | 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, | ||
1104 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
1105 | 0x0000a493,0x0000a49b,0x000124db,0x00009493}, | ||
1106 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
1107 | 0x0000a493,0x000124db,0x000126dc,0x00009493}, | ||
1108 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
1109 | 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, | ||
1110 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1111 | 0x0001249b,0x000126dc,0x000136e4,0x000124db}, | ||
1112 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1113 | 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, | ||
1114 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
1115 | 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, | ||
1116 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
1117 | 0x000126dc,0x0001b724,0x0001b725,0x000136e4}, | ||
1118 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
1119 | 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, | ||
1120 | {0x00000000,0x00000000,0x00009492,0x0000a49b, | ||
1121 | 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, | ||
1122 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
1123 | 0x000136e4,0x0001b925,0x0001c96e,0x0001b925}, | ||
1124 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
1125 | 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, | ||
1126 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
1127 | 0x0001c924,0x0002496d,0x00025bb6,0x00024b77}, | ||
1128 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
1129 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
1130 | }, | ||
1131 | { /* version 11, passes 1 */ | ||
1132 | {0x00000000,0x00000000,0x00001249,0x00000249, | ||
1133 | 0x00000249,0x00000249,0x0000024a,0x0000024a}, | ||
1134 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
1135 | 0x0000124a,0x0000124a,0x0000024a,0x0000024a}, | ||
1136 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
1137 | 0x00009252,0x00009252,0x0000024a,0x0000024a}, | ||
1138 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
1139 | 0x00009492,0x0000a49b,0x00001252,0x00001252}, | ||
1140 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
1141 | 0x0000a493,0x0000a49b,0x00001252,0x00001252}, | ||
1142 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
1143 | 0x0000a493,0x0000a49b,0x00009292,0x00001252}, | ||
1144 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1145 | 0x0000a493,0x0000a49b,0x00009292,0x00009292}, | ||
1146 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1147 | 0x0000a493,0x0000a49b,0x00009493,0x00009292}, | ||
1148 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1149 | 0x0001249b,0x000124db,0x00009493,0x00009292}, | ||
1150 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1151 | 0x0001249b,0x000124db,0x00009493,0x00009493}, | ||
1152 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1153 | 0x000124db,0x000124db,0x0000a49b,0x00009493}, | ||
1154 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
1155 | 0x000126dc,0x000126dc,0x0000a49b,0x00009493}, | ||
1156 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
1157 | 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, | ||
1158 | {0x00000000,0x00000000,0x00009292,0x000124db, | ||
1159 | 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, | ||
1160 | {0x00000000,0x00000000,0x00009492,0x000126db, | ||
1161 | 0x0001b724,0x000136e4,0x000126dc,0x000124db}, | ||
1162 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
1163 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
1164 | } | ||
1165 | }, | ||
1166 | { /* version 12 */ | ||
1167 | { /* version 12, passes 0 */ | ||
1168 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
1169 | 0x00009252,0x00009292,0x00009493,0x00009493}, | ||
1170 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
1171 | 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, | ||
1172 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
1173 | 0x0000a493,0x000124db,0x000124db,0x0000a49b}, | ||
1174 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
1175 | 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, | ||
1176 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1177 | 0x0001249b,0x000126dc,0x000136e4,0x000124db}, | ||
1178 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1179 | 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, | ||
1180 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
1181 | 0x000126dc,0x0001b724,0x0001b725,0x000126dc}, | ||
1182 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
1183 | 0x000136e4,0x0001b724,0x0001b92d,0x000136e4}, | ||
1184 | {0x00000000,0x00000000,0x00009492,0x0000a49b, | ||
1185 | 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, | ||
1186 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
1187 | 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, | ||
1188 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
1189 | 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, | ||
1190 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
1191 | 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, | ||
1192 | {0x00000000,0x00000000,0x0000a492,0x000124db, | ||
1193 | 0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d}, | ||
1194 | {0x00000000,0x00000000,0x0000a492,0x000124db, | ||
1195 | 0x0001b724,0x0001c92d,0x00024b76,0x0002496e}, | ||
1196 | {0x00000000,0x00000000,0x00012492,0x000126db, | ||
1197 | 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf}, | ||
1198 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
1199 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
1200 | }, | ||
1201 | { /* version 12, passes 1 */ | ||
1202 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
1203 | 0x0000124a,0x0000124a,0x00001252,0x00001252}, | ||
1204 | {0x00000000,0x00000000,0x00001249,0x00009292, | ||
1205 | 0x00009492,0x00009252,0x00001252,0x00001252}, | ||
1206 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
1207 | 0x0000a493,0x00009292,0x00001252,0x00001252}, | ||
1208 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1209 | 0x0000a493,0x0000a49b,0x00009292,0x00009292}, | ||
1210 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1211 | 0x0000a493,0x0000a49b,0x00009292,0x00009292}, | ||
1212 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1213 | 0x0001249b,0x0000a49b,0x00009493,0x00009292}, | ||
1214 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1215 | 0x000124db,0x000124db,0x00009493,0x00009493}, | ||
1216 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1217 | 0x000124db,0x000124db,0x0000a49b,0x00009493}, | ||
1218 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
1219 | 0x000126dc,0x000124db,0x0000a49b,0x00009493}, | ||
1220 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
1221 | 0x000126dc,0x000126dc,0x0000a49b,0x0000a49b}, | ||
1222 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
1223 | 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, | ||
1224 | {0x00000000,0x00000000,0x00009492,0x000126db, | ||
1225 | 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, | ||
1226 | {0x00000000,0x00000000,0x00009492,0x000126db, | ||
1227 | 0x0001b724,0x000136e4,0x000126dc,0x000124db}, | ||
1228 | {0x00000000,0x00000000,0x00009492,0x000126db, | ||
1229 | 0x0001b724,0x000136e4,0x000126dc,0x000124db}, | ||
1230 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1231 | 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, | ||
1232 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
1233 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
1234 | } | ||
1235 | }, | ||
1236 | { /* version 13 */ | ||
1237 | { /* version 13, passes 0 */ | ||
1238 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
1239 | 0x00009252,0x00009292,0x00009493,0x00009493}, | ||
1240 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
1241 | 0x0000a493,0x000124db,0x000126dc,0x00009493}, | ||
1242 | {0x00000000,0x00000000,0x00001249,0x0000a49b, | ||
1243 | 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, | ||
1244 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1245 | 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, | ||
1246 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1247 | 0x000126dc,0x000136e4,0x0001b725,0x000124db}, | ||
1248 | {0x00000000,0x00000000,0x00009292,0x0000a49b, | ||
1249 | 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, | ||
1250 | {0x00000000,0x00000000,0x00009292,0x000124db, | ||
1251 | 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, | ||
1252 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
1253 | 0x000136e4,0x0001b724,0x0001c96e,0x000136e4}, | ||
1254 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
1255 | 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, | ||
1256 | {0x00000000,0x00000000,0x0000a492,0x000124db, | ||
1257 | 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, | ||
1258 | {0x00000000,0x00000000,0x0000a492,0x000124db, | ||
1259 | 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925}, | ||
1260 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
1261 | 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, | ||
1262 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
1263 | 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, | ||
1264 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
1265 | 0x0001b924,0x0001c92d,0x00024b76,0x0002496e}, | ||
1266 | {0x00000000,0x00000000,0x00012492,0x000136db, | ||
1267 | 0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf}, | ||
1268 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
1269 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
1270 | }, | ||
1271 | { /* version 13, passes 1 */ | ||
1272 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
1273 | 0x0000124a,0x0000124a,0x00001252,0x00001252}, | ||
1274 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
1275 | 0x00009492,0x00009292,0x00001252,0x00001252}, | ||
1276 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1277 | 0x0000a493,0x0000a49b,0x00001252,0x00001252}, | ||
1278 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1279 | 0x0000a493,0x0000a49b,0x00009292,0x00009292}, | ||
1280 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1281 | 0x0000a493,0x0000a49b,0x00009292,0x00009292}, | ||
1282 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1283 | 0x000126dc,0x0000a49b,0x00009493,0x00009292}, | ||
1284 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
1285 | 0x000126dc,0x000124db,0x00009493,0x00009493}, | ||
1286 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
1287 | 0x000136e4,0x000124db,0x0000a49b,0x00009493}, | ||
1288 | {0x00000000,0x00000000,0x0000924a,0x000136db, | ||
1289 | 0x0001b724,0x000124db,0x0000a49b,0x00009493}, | ||
1290 | {0x00000000,0x00000000,0x0000924a,0x000136db, | ||
1291 | 0x0001b724,0x000126dc,0x0000a49b,0x0000a49b}, | ||
1292 | {0x00000000,0x00000000,0x00009292,0x000136db, | ||
1293 | 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, | ||
1294 | {0x00000000,0x00000000,0x00009492,0x000136db, | ||
1295 | 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, | ||
1296 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1297 | 0x0001b724,0x000136e4,0x000126dc,0x000124db}, | ||
1298 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1299 | 0x0001b724,0x000136e4,0x000126dc,0x000124db}, | ||
1300 | {0x00000000,0x00000000,0x00012492,0x0001b6db, | ||
1301 | 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, | ||
1302 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
1303 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
1304 | } | ||
1305 | }, | ||
1306 | { /* version 14 */ | ||
1307 | { /* version 14, passes 0 */ | ||
1308 | {0x00000000,0x00000000,0x00001249,0x0000924a, | ||
1309 | 0x00009292,0x00009493,0x00009493,0x00009493}, | ||
1310 | {0x00000000,0x00000000,0x00001249,0x0000a49b, | ||
1311 | 0x0000a493,0x000124db,0x000126dc,0x00009493}, | ||
1312 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1313 | 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, | ||
1314 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
1315 | 0x000126dc,0x000136e4,0x0001b725,0x000124db}, | ||
1316 | {0x00000000,0x00000000,0x00009292,0x000124db, | ||
1317 | 0x000126dc,0x0001b724,0x0001b92d,0x000126dc}, | ||
1318 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
1319 | 0x000136e4,0x0001b724,0x0001b92d,0x000126dc}, | ||
1320 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
1321 | 0x000136e4,0x0001c92d,0x0001c96e,0x000136e4}, | ||
1322 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
1323 | 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724}, | ||
1324 | {0x00000000,0x00000000,0x0000a492,0x000124db, | ||
1325 | 0x0001b724,0x0001c92d,0x00024b76,0x0001b925}, | ||
1326 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
1327 | 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, | ||
1328 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
1329 | 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, | ||
1330 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1331 | 0x0001b724,0x0001c92d,0x00024b76,0x0002496e}, | ||
1332 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1333 | 0x0001b924,0x0002496d,0x00024b76,0x00024b77}, | ||
1334 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1335 | 0x0001b924,0x00024b6d,0x0002ddb6,0x00025bbf}, | ||
1336 | {0x00000000,0x00000000,0x00012492,0x0001b6db, | ||
1337 | 0x00024924,0x0002db6d,0x00036db6,0x0002efff}, | ||
1338 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
1339 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
1340 | }, | ||
1341 | { /* version 14, passes 1 */ | ||
1342 | {0x00000000,0x00000000,0x00001249,0x00001249, | ||
1343 | 0x0000124a,0x0000124a,0x00001252,0x00001252}, | ||
1344 | {0x00000000,0x00000000,0x0000924a,0x00009493, | ||
1345 | 0x0000a493,0x00009292,0x00001252,0x00001252}, | ||
1346 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1347 | 0x0000a493,0x0000a49b,0x00001252,0x00001252}, | ||
1348 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1349 | 0x0001249b,0x000136e4,0x00009292,0x00009292}, | ||
1350 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1351 | 0x0001249b,0x000136e4,0x00009292,0x00009292}, | ||
1352 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
1353 | 0x000136e4,0x000136e4,0x00009493,0x00009292}, | ||
1354 | {0x00000000,0x00000000,0x00009492,0x000136db, | ||
1355 | 0x0001b724,0x000136e4,0x00009493,0x00009493}, | ||
1356 | {0x00000000,0x00000000,0x00009492,0x000136db, | ||
1357 | 0x0001b724,0x000136e4,0x0000a49b,0x00009493}, | ||
1358 | {0x00000000,0x00000000,0x00009492,0x000136db, | ||
1359 | 0x0001b724,0x000136e4,0x0000a49b,0x00009493}, | ||
1360 | {0x00000000,0x00000000,0x00009492,0x000136db, | ||
1361 | 0x0001b724,0x000136e4,0x0000a49b,0x0000a49b}, | ||
1362 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1363 | 0x0001b724,0x000136e4,0x000124db,0x0000a49b}, | ||
1364 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1365 | 0x0001b724,0x000136e4,0x000124db,0x0000a49b}, | ||
1366 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1367 | 0x0001b724,0x000136e4,0x000126dc,0x000124db}, | ||
1368 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1369 | 0x0001b724,0x000136e4,0x000126dc,0x000124db}, | ||
1370 | {0x00000000,0x00000000,0x00012492,0x0001b6db, | ||
1371 | 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, | ||
1372 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
1373 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
1374 | } | ||
1375 | }, | ||
1376 | { /* version 15 */ | ||
1377 | { /* version 15, passes 0 */ | ||
1378 | {0x00000000,0x00000000,0x00001249,0x00009493, | ||
1379 | 0x0000a493,0x0000a49b,0x000124db,0x000124db}, | ||
1380 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1381 | 0x0001249b,0x000126dc,0x000136e4,0x000124db}, | ||
1382 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1383 | 0x000126dc,0x0001b724,0x0001b725,0x000126dc}, | ||
1384 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
1385 | 0x000136e4,0x0001b724,0x0001b92d,0x000126dc}, | ||
1386 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
1387 | 0x000136e4,0x0001b925,0x0001c96e,0x000136e4}, | ||
1388 | {0x00000000,0x00000000,0x00009492,0x000124db, | ||
1389 | 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724}, | ||
1390 | {0x00000000,0x00000000,0x0000a492,0x000124db, | ||
1391 | 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724}, | ||
1392 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
1393 | 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925}, | ||
1394 | {0x00000000,0x00000000,0x0000a492,0x000126db, | ||
1395 | 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, | ||
1396 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1397 | 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, | ||
1398 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1399 | 0x0001b924,0x0002496d,0x00024b76,0x0002496e}, | ||
1400 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1401 | 0x0001c924,0x0002496d,0x00025bb6,0x00024b77}, | ||
1402 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1403 | 0x0001c924,0x00024b6d,0x00025bb6,0x00024b77}, | ||
1404 | {0x00000000,0x00000000,0x00012492,0x000136db, | ||
1405 | 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf}, | ||
1406 | {0x00000000,0x00000000,0x00012492,0x0001b6db, | ||
1407 | 0x00024924,0x0002db6d,0x00036db6,0x0002efff}, | ||
1408 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
1409 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
1410 | }, | ||
1411 | { /* version 15, passes 1 */ | ||
1412 | {0x00000000,0x00000000,0x0000924a,0x0000924a, | ||
1413 | 0x00009292,0x00009292,0x00009292,0x00009292}, | ||
1414 | {0x00000000,0x00000000,0x0000924a,0x0000a49b, | ||
1415 | 0x0000a493,0x000124db,0x00009292,0x00009292}, | ||
1416 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
1417 | 0x000124db,0x0001b724,0x00009493,0x00009493}, | ||
1418 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
1419 | 0x000126dc,0x0001b724,0x00009493,0x00009493}, | ||
1420 | {0x00000000,0x00000000,0x0000924a,0x000124db, | ||
1421 | 0x000136e4,0x0001b724,0x0000a49b,0x0000a49b}, | ||
1422 | {0x00000000,0x00000000,0x00009292,0x000136db, | ||
1423 | 0x0001b724,0x0001b724,0x0000a49b,0x0000a49b}, | ||
1424 | {0x00000000,0x00000000,0x00009492,0x000136db, | ||
1425 | 0x0001c924,0x0001b724,0x000124db,0x000124db}, | ||
1426 | {0x00000000,0x00000000,0x00009492,0x000136db, | ||
1427 | 0x0001c924,0x0001b724,0x000124db,0x000124db}, | ||
1428 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1429 | 0x0001c924,0x0001b724,0x000126dc,0x000126dc}, | ||
1430 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1431 | 0x0001c924,0x0001b925,0x000126dc,0x000126dc}, | ||
1432 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1433 | 0x0001c924,0x0001b925,0x000136e4,0x000136e4}, | ||
1434 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1435 | 0x0001c924,0x0001b925,0x000136e4,0x000136e4}, | ||
1436 | {0x00000000,0x00000000,0x0000a492,0x000136db, | ||
1437 | 0x0001c924,0x0001b925,0x0001b725,0x0001b724}, | ||
1438 | {0x00000000,0x00000000,0x00012492,0x000136db, | ||
1439 | 0x0001c924,0x0001b925,0x0001b725,0x0001b724}, | ||
1440 | {0x00000000,0x00000000,0x00012492,0x0001b6db, | ||
1441 | 0x00024924,0x0002496d,0x0001b92d,0x0001b925}, | ||
1442 | {0x00000000,0x00000000,0x00000000,0x00000000, | ||
1443 | 0x00000000,0x00000000,0x00000000,0x00000000} | ||
1444 | } | ||
1445 | } | ||
1446 | }; | ||
diff --git a/drivers/usb/media/pwc/pwc-timon.h b/drivers/usb/media/pwc/pwc-timon.h new file mode 100644 index 000000000000..a86b3782a081 --- /dev/null +++ b/drivers/usb/media/pwc/pwc-timon.h | |||
@@ -0,0 +1,61 @@ | |||
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 new file mode 100644 index 000000000000..c062e43b3ac5 --- /dev/null +++ b/drivers/usb/media/pwc/pwc-uncompress.c | |||
@@ -0,0 +1,147 @@ | |||
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 | #include "pwc-dec1.h" | ||
33 | #include "pwc-dec23.h" | ||
34 | |||
35 | int pwc_decompress(struct pwc_device *pdev) | ||
36 | { | ||
37 | struct pwc_frame_buf *fbuf; | ||
38 | int n, line, col, stride; | ||
39 | void *yuv, *image; | ||
40 | u16 *src; | ||
41 | u16 *dsty, *dstu, *dstv; | ||
42 | |||
43 | if (pdev == NULL) | ||
44 | return -EFAULT; | ||
45 | #if defined(__KERNEL__) && defined(PWC_MAGIC) | ||
46 | if (pdev->magic != PWC_MAGIC) { | ||
47 | Err("pwc_decompress(): magic failed.\n"); | ||
48 | return -EFAULT; | ||
49 | } | ||
50 | #endif | ||
51 | |||
52 | fbuf = pdev->read_frame; | ||
53 | if (fbuf == NULL) | ||
54 | return -EFAULT; | ||
55 | image = pdev->image_ptr[pdev->fill_image]; | ||
56 | if (!image) | ||
57 | return -EFAULT; | ||
58 | |||
59 | yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ | ||
60 | |||
61 | /* Raw format; that's easy... */ | ||
62 | if (pdev->vpalette == VIDEO_PALETTE_RAW) | ||
63 | { | ||
64 | memcpy(image, yuv, pdev->frame_size); | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | if (pdev->vbandlength == 0) { | ||
69 | /* Uncompressed mode. We copy the data into the output buffer, | ||
70 | using the viewport size (which may be larger than the image | ||
71 | size). Unfortunately we have to do a bit of byte stuffing | ||
72 | to get the desired output format/size. | ||
73 | */ | ||
74 | /* | ||
75 | * We do some byte shuffling here to go from the | ||
76 | * native format to YUV420P. | ||
77 | */ | ||
78 | src = (u16 *)yuv; | ||
79 | n = pdev->view.x * pdev->view.y; | ||
80 | |||
81 | /* offset in Y plane */ | ||
82 | stride = pdev->view.x * pdev->offset.y + pdev->offset.x; | ||
83 | dsty = (u16 *)(image + stride); | ||
84 | |||
85 | /* offsets in U/V planes */ | ||
86 | stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2; | ||
87 | dstu = (u16 *)(image + n + stride); | ||
88 | dstv = (u16 *)(image + n + n / 4 + stride); | ||
89 | |||
90 | /* increment after each line */ | ||
91 | stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */ | ||
92 | |||
93 | for (line = 0; line < pdev->image.y; line++) { | ||
94 | for (col = 0; col < pdev->image.x; col += 4) { | ||
95 | *dsty++ = *src++; | ||
96 | *dsty++ = *src++; | ||
97 | if (line & 1) | ||
98 | *dstv++ = *src++; | ||
99 | else | ||
100 | *dstu++ = *src++; | ||
101 | } | ||
102 | dsty += stride; | ||
103 | if (line & 1) | ||
104 | dstv += (stride >> 1); | ||
105 | else | ||
106 | dstu += (stride >> 1); | ||
107 | } | ||
108 | } | ||
109 | else { | ||
110 | /* Compressed; the decompressor routines will write the data | ||
111 | in planar format immediately. | ||
112 | */ | ||
113 | int flags; | ||
114 | |||
115 | flags = PWCX_FLAG_PLANAR; | ||
116 | if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) | ||
117 | { | ||
118 | printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n"); | ||
119 | flags |= PWCX_FLAG_BAYER; | ||
120 | return -ENXIO; /* No such device or address: missing decompressor */ | ||
121 | } | ||
122 | |||
123 | switch (pdev->type) | ||
124 | { | ||
125 | case 675: | ||
126 | case 680: | ||
127 | case 690: | ||
128 | case 720: | ||
129 | case 730: | ||
130 | case 740: | ||
131 | case 750: | ||
132 | pwc_dec23_decompress(&pdev->image, &pdev->view, &pdev->offset, | ||
133 | yuv, image, | ||
134 | flags, | ||
135 | pdev->decompress_data, pdev->vbandlength); | ||
136 | break; | ||
137 | case 645: | ||
138 | case 646: | ||
139 | /* TODO & FIXME */ | ||
140 | return -ENXIO; /* No such device or address: missing decompressor */ | ||
141 | break; | ||
142 | } | ||
143 | } | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | |||
diff --git a/drivers/usb/media/pwc/pwc-uncompress.h b/drivers/usb/media/pwc/pwc-uncompress.h new file mode 100644 index 000000000000..d3b9250e4ed3 --- /dev/null +++ b/drivers/usb/media/pwc/pwc-uncompress.h | |||
@@ -0,0 +1,41 @@ | |||
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 new file mode 100644 index 000000000000..53b516d29cf5 --- /dev/null +++ b/drivers/usb/media/pwc/pwc.h | |||
@@ -0,0 +1,278 @@ | |||
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/version.h> | ||
29 | |||
30 | #include <linux/config.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/usb.h> | ||
33 | #include <linux/spinlock.h> | ||
34 | #include <linux/videodev.h> | ||
35 | #include <linux/wait.h> | ||
36 | #include <linux/smp_lock.h> | ||
37 | #include <asm/semaphore.h> | ||
38 | #include <asm/errno.h> | ||
39 | |||
40 | #include "pwc-uncompress.h" | ||
41 | #include "pwc-ioctl.h" | ||
42 | |||
43 | /* Defines and structures for the Philips webcam */ | ||
44 | /* Used for checking memory corruption/pointer validation */ | ||
45 | #define PWC_MAGIC 0x89DC10ABUL | ||
46 | #undef PWC_MAGIC | ||
47 | |||
48 | /* Turn some debugging options on/off */ | ||
49 | #define PWC_DEBUG 0 | ||
50 | |||
51 | /* Trace certain actions in the driver */ | ||
52 | #define TRACE_MODULE 0x0001 | ||
53 | #define TRACE_PROBE 0x0002 | ||
54 | #define TRACE_OPEN 0x0004 | ||
55 | #define TRACE_READ 0x0008 | ||
56 | #define TRACE_MEMORY 0x0010 | ||
57 | #define TRACE_FLOW 0x0020 | ||
58 | #define TRACE_SIZE 0x0040 | ||
59 | #define TRACE_PWCX 0x0080 | ||
60 | #define TRACE_SEQUENCE 0x1000 | ||
61 | |||
62 | #define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A) | ||
63 | #define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A) | ||
64 | #define Info(A...) printk(KERN_INFO PWC_NAME " " A) | ||
65 | #define Err(A...) printk(KERN_ERR PWC_NAME " " A) | ||
66 | |||
67 | |||
68 | /* Defines for ToUCam cameras */ | ||
69 | #define TOUCAM_HEADER_SIZE 8 | ||
70 | #define TOUCAM_TRAILER_SIZE 4 | ||
71 | |||
72 | #define FEATURE_MOTOR_PANTILT 0x0001 | ||
73 | |||
74 | /* Version block */ | ||
75 | #define PWC_MAJOR 9 | ||
76 | #define PWC_MINOR 0 | ||
77 | #define PWC_VERSION "9.0.2-unofficial" | ||
78 | #define PWC_NAME "pwc" | ||
79 | |||
80 | /* Turn certain features on/off */ | ||
81 | #define PWC_INT_PIPE 0 | ||
82 | |||
83 | /* Ignore errors in the first N frames, to allow for startup delays */ | ||
84 | #define FRAME_LOWMARK 5 | ||
85 | |||
86 | /* Size and number of buffers for the ISO pipe. */ | ||
87 | #define MAX_ISO_BUFS 2 | ||
88 | #define ISO_FRAMES_PER_DESC 10 | ||
89 | #define ISO_MAX_FRAME_SIZE 960 | ||
90 | #define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) | ||
91 | |||
92 | /* Frame buffers: contains compressed or uncompressed video data. */ | ||
93 | #define MAX_FRAMES 5 | ||
94 | /* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */ | ||
95 | #define PWC_FRAME_SIZE (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE) | ||
96 | |||
97 | /* Absolute maximum number of buffers available for mmap() */ | ||
98 | #define MAX_IMAGES 10 | ||
99 | |||
100 | /* The following structures were based on cpia.h. Why reinvent the wheel? :-) */ | ||
101 | struct pwc_iso_buf | ||
102 | { | ||
103 | void *data; | ||
104 | int length; | ||
105 | int read; | ||
106 | struct urb *urb; | ||
107 | }; | ||
108 | |||
109 | /* intermediate buffers with raw data from the USB cam */ | ||
110 | struct pwc_frame_buf | ||
111 | { | ||
112 | void *data; | ||
113 | volatile int filled; /* number of bytes filled */ | ||
114 | struct pwc_frame_buf *next; /* list */ | ||
115 | #if PWC_DEBUG | ||
116 | int sequence; /* Sequence number */ | ||
117 | #endif | ||
118 | }; | ||
119 | |||
120 | struct pwc_device | ||
121 | { | ||
122 | struct video_device *vdev; | ||
123 | #ifdef PWC_MAGIC | ||
124 | int magic; | ||
125 | #endif | ||
126 | /* Pointer to our usb_device */ | ||
127 | struct usb_device *udev; | ||
128 | |||
129 | int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ | ||
130 | int release; /* release number */ | ||
131 | int features; /* feature bits */ | ||
132 | char serial[30]; /* serial number (string) */ | ||
133 | int error_status; /* set when something goes wrong with the cam (unplugged, USB errors) */ | ||
134 | int usb_init; /* set when the cam has been initialized over USB */ | ||
135 | |||
136 | /*** Video data ***/ | ||
137 | int vopen; /* flag */ | ||
138 | int vendpoint; /* video isoc endpoint */ | ||
139 | int vcinterface; /* video control interface */ | ||
140 | int valternate; /* alternate interface needed */ | ||
141 | int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ | ||
142 | int vpalette; /* palette: 420P, RAW or RGBBAYER */ | ||
143 | int vframe_count; /* received frames */ | ||
144 | int vframes_dumped; /* counter for dumped frames */ | ||
145 | int vframes_error; /* frames received in error */ | ||
146 | int vmax_packet_size; /* USB maxpacket size */ | ||
147 | int vlast_packet_size; /* for frame synchronisation */ | ||
148 | int visoc_errors; /* number of contiguous ISOC errors */ | ||
149 | int vcompression; /* desired compression factor */ | ||
150 | int vbandlength; /* compressed band length; 0 is uncompressed */ | ||
151 | char vsnapshot; /* snapshot mode */ | ||
152 | char vsync; /* used by isoc handler */ | ||
153 | char vmirror; /* for ToUCaM series */ | ||
154 | |||
155 | int cmd_len; | ||
156 | unsigned char cmd_buf[13]; | ||
157 | |||
158 | /* The image acquisition requires 3 to 4 steps: | ||
159 | 1. data is gathered in short packets from the USB controller | ||
160 | 2. data is synchronized and packed into a frame buffer | ||
161 | 3a. in case data is compressed, decompress it directly into image buffer | ||
162 | 3b. in case data is uncompressed, copy into image buffer with viewport | ||
163 | 4. data is transferred to the user process | ||
164 | |||
165 | Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES.... | ||
166 | We have in effect a back-to-back-double-buffer system. | ||
167 | */ | ||
168 | /* 1: isoc */ | ||
169 | struct pwc_iso_buf sbuf[MAX_ISO_BUFS]; | ||
170 | char iso_init; | ||
171 | |||
172 | /* 2: frame */ | ||
173 | struct pwc_frame_buf *fbuf; /* all frames */ | ||
174 | struct pwc_frame_buf *empty_frames, *empty_frames_tail; /* all empty frames */ | ||
175 | struct pwc_frame_buf *full_frames, *full_frames_tail; /* all filled frames */ | ||
176 | struct pwc_frame_buf *fill_frame; /* frame currently being filled */ | ||
177 | struct pwc_frame_buf *read_frame; /* frame currently read by user process */ | ||
178 | int frame_header_size, frame_trailer_size; | ||
179 | int frame_size; | ||
180 | int frame_total_size; /* including header & trailer */ | ||
181 | int drop_frames; | ||
182 | #if PWC_DEBUG | ||
183 | int sequence; /* Debugging aid */ | ||
184 | #endif | ||
185 | |||
186 | /* 3: decompression */ | ||
187 | struct pwc_decompressor *decompressor; /* function block with decompression routines */ | ||
188 | void *decompress_data; /* private data for decompression engine */ | ||
189 | |||
190 | /* 4: image */ | ||
191 | /* We have an 'image' and a 'view', where 'image' is the fixed-size image | ||
192 | as delivered by the camera, and 'view' is the size requested by the | ||
193 | program. The camera image is centered in this viewport, laced with | ||
194 | a gray or black border. view_min <= image <= view <= view_max; | ||
195 | */ | ||
196 | int image_mask; /* bitmask of supported sizes */ | ||
197 | struct pwc_coord view_min, view_max; /* minimum and maximum viewable sizes */ | ||
198 | struct pwc_coord abs_max; /* maximum supported size with compression */ | ||
199 | struct pwc_coord image, view; /* image and viewport size */ | ||
200 | struct pwc_coord offset; /* offset within the viewport */ | ||
201 | |||
202 | void *image_data; /* total buffer, which is subdivided into ... */ | ||
203 | void *image_ptr[MAX_IMAGES]; /* ...several images... */ | ||
204 | int fill_image; /* ...which are rotated. */ | ||
205 | int len_per_image; /* length per image */ | ||
206 | int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */ | ||
207 | int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */ | ||
208 | |||
209 | struct semaphore modlock; /* to prevent races in video_open(), etc */ | ||
210 | spinlock_t ptrlock; /* for manipulating the buffer pointers */ | ||
211 | |||
212 | /*** motorized pan/tilt feature */ | ||
213 | struct pwc_mpt_range angle_range; | ||
214 | int pan_angle; /* in degrees * 100 */ | ||
215 | int tilt_angle; /* absolute angle; 0,0 is home position */ | ||
216 | |||
217 | /*** Misc. data ***/ | ||
218 | wait_queue_head_t frameq; /* When waiting for a frame to finish... */ | ||
219 | #if PWC_INT_PIPE | ||
220 | void *usb_int_handler; /* for the interrupt endpoint */ | ||
221 | #endif | ||
222 | }; | ||
223 | |||
224 | |||
225 | #ifdef __cplusplus | ||
226 | extern "C" { | ||
227 | #endif | ||
228 | |||
229 | /* Global variables */ | ||
230 | extern int pwc_trace; | ||
231 | extern int pwc_preferred_compression; | ||
232 | |||
233 | /** functions in pwc-if.c */ | ||
234 | int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot); | ||
235 | |||
236 | /** Functions in pwc-misc.c */ | ||
237 | /* sizes in pixels */ | ||
238 | extern struct pwc_coord pwc_image_sizes[PSZ_MAX]; | ||
239 | |||
240 | int pwc_decode_size(struct pwc_device *pdev, int width, int height); | ||
241 | void pwc_construct(struct pwc_device *pdev); | ||
242 | |||
243 | /** Functions in pwc-ctrl.c */ | ||
244 | /* Request a certain video mode. Returns < 0 if not possible */ | ||
245 | extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); | ||
246 | /* Calculate the number of bytes per image (not frame) */ | ||
247 | extern void pwc_set_image_buffer_size(struct pwc_device *pdev); | ||
248 | |||
249 | /* Various controls; should be obvious. Value 0..65535, or < 0 on error */ | ||
250 | extern int pwc_get_brightness(struct pwc_device *pdev); | ||
251 | extern int pwc_set_brightness(struct pwc_device *pdev, int value); | ||
252 | extern int pwc_get_contrast(struct pwc_device *pdev); | ||
253 | extern int pwc_set_contrast(struct pwc_device *pdev, int value); | ||
254 | extern int pwc_get_gamma(struct pwc_device *pdev); | ||
255 | extern int pwc_set_gamma(struct pwc_device *pdev, int value); | ||
256 | extern int pwc_get_saturation(struct pwc_device *pdev); | ||
257 | extern int pwc_set_saturation(struct pwc_device *pdev, int value); | ||
258 | extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); | ||
259 | extern int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value); | ||
260 | extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); | ||
261 | |||
262 | /* Power down or up the camera; not supported by all models */ | ||
263 | extern int pwc_camera_power(struct pwc_device *pdev, int power); | ||
264 | |||
265 | /* Private ioctl()s; see pwc-ioctl.h */ | ||
266 | extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); | ||
267 | |||
268 | |||
269 | /** pwc-uncompress.c */ | ||
270 | /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ | ||
271 | extern int pwc_decompress(struct pwc_device *pdev); | ||
272 | |||
273 | #ifdef __cplusplus | ||
274 | } | ||
275 | #endif | ||
276 | |||
277 | |||
278 | #endif | ||
diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c new file mode 100644 index 000000000000..685bdae5cb62 --- /dev/null +++ b/drivers/usb/media/se401.c | |||
@@ -0,0 +1,1436 @@ | |||
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++) if (se401->urb[i]) { | ||
872 | usb_kill_urb(se401->urb[i]); | ||
873 | usb_free_urb(se401->urb[i]); | ||
874 | se401->urb[i] = NULL; | ||
875 | kfree(se401->sbuf[i].data); | ||
876 | } | ||
877 | for (i=0; i<SE401_NUMSCRATCH; i++) if (se401->scratch[i].data) { | ||
878 | kfree(se401->scratch[i].data); | ||
879 | } | ||
880 | if (se401->inturb) { | ||
881 | usb_kill_urb(se401->inturb); | ||
882 | usb_free_urb(se401->inturb); | ||
883 | } | ||
884 | info("%s disconnected", se401->camera_name); | ||
885 | |||
886 | /* Free the memory */ | ||
887 | kfree(se401->width); | ||
888 | kfree(se401->height); | ||
889 | kfree(se401); | ||
890 | } | ||
891 | |||
892 | |||
893 | |||
894 | /**************************************************************************** | ||
895 | * | ||
896 | * Video4Linux | ||
897 | * | ||
898 | ***************************************************************************/ | ||
899 | |||
900 | |||
901 | static int se401_open(struct inode *inode, struct file *file) | ||
902 | { | ||
903 | struct video_device *dev = video_devdata(file); | ||
904 | struct usb_se401 *se401 = (struct usb_se401 *)dev; | ||
905 | int err = 0; | ||
906 | |||
907 | if (se401->user) | ||
908 | return -EBUSY; | ||
909 | se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES); | ||
910 | if (se401->fbuf) | ||
911 | file->private_data = dev; | ||
912 | else | ||
913 | err = -ENOMEM; | ||
914 | se401->user = !err; | ||
915 | |||
916 | return err; | ||
917 | } | ||
918 | |||
919 | static int se401_close(struct inode *inode, struct file *file) | ||
920 | { | ||
921 | struct video_device *dev = file->private_data; | ||
922 | struct usb_se401 *se401 = (struct usb_se401 *)dev; | ||
923 | int i; | ||
924 | |||
925 | rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES); | ||
926 | if (se401->removed) { | ||
927 | usb_se401_remove_disconnected(se401); | ||
928 | info("device unregistered"); | ||
929 | } else { | ||
930 | for (i=0; i<SE401_NUMFRAMES; i++) | ||
931 | se401->frame[i].grabstate=FRAME_UNUSED; | ||
932 | if (se401->streaming) | ||
933 | se401_stop_stream(se401); | ||
934 | se401->user=0; | ||
935 | } | ||
936 | file->private_data = NULL; | ||
937 | return 0; | ||
938 | } | ||
939 | |||
940 | static int se401_do_ioctl(struct inode *inode, struct file *file, | ||
941 | unsigned int cmd, void *arg) | ||
942 | { | ||
943 | struct video_device *vdev = file->private_data; | ||
944 | struct usb_se401 *se401 = (struct usb_se401 *)vdev; | ||
945 | |||
946 | if (!se401->dev) | ||
947 | return -EIO; | ||
948 | |||
949 | switch (cmd) { | ||
950 | case VIDIOCGCAP: | ||
951 | { | ||
952 | struct video_capability *b = arg; | ||
953 | strcpy(b->name, se401->camera_name); | ||
954 | b->type = VID_TYPE_CAPTURE; | ||
955 | b->channels = 1; | ||
956 | b->audios = 0; | ||
957 | b->maxwidth = se401->width[se401->sizes-1]; | ||
958 | b->maxheight = se401->height[se401->sizes-1]; | ||
959 | b->minwidth = se401->width[0]; | ||
960 | b->minheight = se401->height[0]; | ||
961 | return 0; | ||
962 | } | ||
963 | case VIDIOCGCHAN: | ||
964 | { | ||
965 | struct video_channel *v = arg; | ||
966 | |||
967 | if (v->channel != 0) | ||
968 | return -EINVAL; | ||
969 | v->flags = 0; | ||
970 | v->tuners = 0; | ||
971 | v->type = VIDEO_TYPE_CAMERA; | ||
972 | strcpy(v->name, "Camera"); | ||
973 | return 0; | ||
974 | } | ||
975 | case VIDIOCSCHAN: | ||
976 | { | ||
977 | struct video_channel *v = arg; | ||
978 | |||
979 | if (v->channel != 0) | ||
980 | return -EINVAL; | ||
981 | return 0; | ||
982 | } | ||
983 | case VIDIOCGPICT: | ||
984 | { | ||
985 | struct video_picture *p = arg; | ||
986 | |||
987 | se401_get_pict(se401, p); | ||
988 | return 0; | ||
989 | } | ||
990 | case VIDIOCSPICT: | ||
991 | { | ||
992 | struct video_picture *p = arg; | ||
993 | |||
994 | if (se401_set_pict(se401, p)) | ||
995 | return -EINVAL; | ||
996 | return 0; | ||
997 | } | ||
998 | case VIDIOCSWIN: | ||
999 | { | ||
1000 | struct video_window *vw = arg; | ||
1001 | |||
1002 | if (vw->flags) | ||
1003 | return -EINVAL; | ||
1004 | if (vw->clipcount) | ||
1005 | return -EINVAL; | ||
1006 | if (se401_set_size(se401, vw->width, vw->height)) | ||
1007 | return -EINVAL; | ||
1008 | return 0; | ||
1009 | } | ||
1010 | case VIDIOCGWIN: | ||
1011 | { | ||
1012 | struct video_window *vw = arg; | ||
1013 | |||
1014 | vw->x = 0; /* FIXME */ | ||
1015 | vw->y = 0; | ||
1016 | vw->chromakey = 0; | ||
1017 | vw->flags = 0; | ||
1018 | vw->clipcount = 0; | ||
1019 | vw->width = se401->cwidth; | ||
1020 | vw->height = se401->cheight; | ||
1021 | return 0; | ||
1022 | } | ||
1023 | case VIDIOCGMBUF: | ||
1024 | { | ||
1025 | struct video_mbuf *vm = arg; | ||
1026 | int i; | ||
1027 | |||
1028 | memset(vm, 0, sizeof(*vm)); | ||
1029 | vm->size = SE401_NUMFRAMES * se401->maxframesize; | ||
1030 | vm->frames = SE401_NUMFRAMES; | ||
1031 | for (i=0; i<SE401_NUMFRAMES; i++) | ||
1032 | vm->offsets[i] = se401->maxframesize * i; | ||
1033 | return 0; | ||
1034 | } | ||
1035 | case VIDIOCMCAPTURE: | ||
1036 | { | ||
1037 | struct video_mmap *vm = arg; | ||
1038 | |||
1039 | if (vm->format != VIDEO_PALETTE_RGB24) | ||
1040 | return -EINVAL; | ||
1041 | if (vm->frame >= SE401_NUMFRAMES) | ||
1042 | return -EINVAL; | ||
1043 | if (se401->frame[vm->frame].grabstate != FRAME_UNUSED) | ||
1044 | return -EBUSY; | ||
1045 | |||
1046 | /* Is this according to the v4l spec??? */ | ||
1047 | if (se401_set_size(se401, vm->width, vm->height)) | ||
1048 | return -EINVAL; | ||
1049 | se401->frame[vm->frame].grabstate=FRAME_READY; | ||
1050 | |||
1051 | if (!se401->streaming) | ||
1052 | se401_start_stream(se401); | ||
1053 | |||
1054 | /* Set the picture properties */ | ||
1055 | if (se401->framecount==0) | ||
1056 | se401_send_pict(se401); | ||
1057 | /* Calibrate the reset level after a few frames. */ | ||
1058 | if (se401->framecount%20==1) | ||
1059 | se401_auto_resetlevel(se401); | ||
1060 | |||
1061 | return 0; | ||
1062 | } | ||
1063 | case VIDIOCSYNC: | ||
1064 | { | ||
1065 | int *frame = arg; | ||
1066 | int ret=0; | ||
1067 | |||
1068 | if(*frame <0 || *frame >= SE401_NUMFRAMES) | ||
1069 | return -EINVAL; | ||
1070 | |||
1071 | ret=se401_newframe(se401, *frame); | ||
1072 | se401->frame[*frame].grabstate=FRAME_UNUSED; | ||
1073 | return ret; | ||
1074 | } | ||
1075 | case VIDIOCGFBUF: | ||
1076 | { | ||
1077 | struct video_buffer *vb = arg; | ||
1078 | |||
1079 | memset(vb, 0, sizeof(*vb)); | ||
1080 | return 0; | ||
1081 | } | ||
1082 | case VIDIOCKEY: | ||
1083 | return 0; | ||
1084 | case VIDIOCCAPTURE: | ||
1085 | return -EINVAL; | ||
1086 | case VIDIOCSFBUF: | ||
1087 | return -EINVAL; | ||
1088 | case VIDIOCGTUNER: | ||
1089 | case VIDIOCSTUNER: | ||
1090 | return -EINVAL; | ||
1091 | case VIDIOCGFREQ: | ||
1092 | case VIDIOCSFREQ: | ||
1093 | return -EINVAL; | ||
1094 | case VIDIOCGAUDIO: | ||
1095 | case VIDIOCSAUDIO: | ||
1096 | return -EINVAL; | ||
1097 | default: | ||
1098 | return -ENOIOCTLCMD; | ||
1099 | } /* end switch */ | ||
1100 | |||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | static int se401_ioctl(struct inode *inode, struct file *file, | ||
1105 | unsigned int cmd, unsigned long arg) | ||
1106 | { | ||
1107 | return video_usercopy(inode, file, cmd, arg, se401_do_ioctl); | ||
1108 | } | ||
1109 | |||
1110 | static ssize_t se401_read(struct file *file, char __user *buf, | ||
1111 | size_t count, loff_t *ppos) | ||
1112 | { | ||
1113 | int realcount=count, ret=0; | ||
1114 | struct video_device *dev = file->private_data; | ||
1115 | struct usb_se401 *se401 = (struct usb_se401 *)dev; | ||
1116 | |||
1117 | |||
1118 | if (se401->dev == NULL) | ||
1119 | return -EIO; | ||
1120 | if (realcount > se401->cwidth*se401->cheight*3) | ||
1121 | realcount=se401->cwidth*se401->cheight*3; | ||
1122 | |||
1123 | /* Shouldn't happen: */ | ||
1124 | if (se401->frame[0].grabstate==FRAME_GRABBING) | ||
1125 | return -EBUSY; | ||
1126 | se401->frame[0].grabstate=FRAME_READY; | ||
1127 | se401->frame[1].grabstate=FRAME_UNUSED; | ||
1128 | se401->curframe=0; | ||
1129 | |||
1130 | if (!se401->streaming) | ||
1131 | se401_start_stream(se401); | ||
1132 | |||
1133 | /* Set the picture properties */ | ||
1134 | if (se401->framecount==0) | ||
1135 | se401_send_pict(se401); | ||
1136 | /* Calibrate the reset level after a few frames. */ | ||
1137 | if (se401->framecount%20==1) | ||
1138 | se401_auto_resetlevel(se401); | ||
1139 | |||
1140 | ret=se401_newframe(se401, 0); | ||
1141 | |||
1142 | se401->frame[0].grabstate=FRAME_UNUSED; | ||
1143 | if (ret) | ||
1144 | return ret; | ||
1145 | if (copy_to_user(buf, se401->frame[0].data, realcount)) | ||
1146 | return -EFAULT; | ||
1147 | |||
1148 | return realcount; | ||
1149 | } | ||
1150 | |||
1151 | static int se401_mmap(struct file *file, struct vm_area_struct *vma) | ||
1152 | { | ||
1153 | struct video_device *dev = file->private_data; | ||
1154 | struct usb_se401 *se401 = (struct usb_se401 *)dev; | ||
1155 | unsigned long start = vma->vm_start; | ||
1156 | unsigned long size = vma->vm_end-vma->vm_start; | ||
1157 | unsigned long page, pos; | ||
1158 | |||
1159 | down(&se401->lock); | ||
1160 | |||
1161 | if (se401->dev == NULL) { | ||
1162 | up(&se401->lock); | ||
1163 | return -EIO; | ||
1164 | } | ||
1165 | if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { | ||
1166 | up(&se401->lock); | ||
1167 | return -EINVAL; | ||
1168 | } | ||
1169 | pos = (unsigned long)se401->fbuf; | ||
1170 | while (size > 0) { | ||
1171 | page = vmalloc_to_pfn((void *)pos); | ||
1172 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { | ||
1173 | up(&se401->lock); | ||
1174 | return -EAGAIN; | ||
1175 | } | ||
1176 | start += PAGE_SIZE; | ||
1177 | pos += PAGE_SIZE; | ||
1178 | if (size > PAGE_SIZE) | ||
1179 | size -= PAGE_SIZE; | ||
1180 | else | ||
1181 | size = 0; | ||
1182 | } | ||
1183 | up(&se401->lock); | ||
1184 | |||
1185 | return 0; | ||
1186 | } | ||
1187 | |||
1188 | static struct file_operations se401_fops = { | ||
1189 | .owner = THIS_MODULE, | ||
1190 | .open = se401_open, | ||
1191 | .release = se401_close, | ||
1192 | .read = se401_read, | ||
1193 | .mmap = se401_mmap, | ||
1194 | .ioctl = se401_ioctl, | ||
1195 | .llseek = no_llseek, | ||
1196 | }; | ||
1197 | static struct video_device se401_template = { | ||
1198 | .owner = THIS_MODULE, | ||
1199 | .name = "se401 USB camera", | ||
1200 | .type = VID_TYPE_CAPTURE, | ||
1201 | .hardware = VID_HARDWARE_SE401, | ||
1202 | .fops = &se401_fops, | ||
1203 | }; | ||
1204 | |||
1205 | |||
1206 | |||
1207 | /***************************/ | ||
1208 | static int se401_init(struct usb_se401 *se401, int button) | ||
1209 | { | ||
1210 | int i=0, rc; | ||
1211 | unsigned char cp[0x40]; | ||
1212 | char temp[200]; | ||
1213 | |||
1214 | /* led on */ | ||
1215 | se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); | ||
1216 | |||
1217 | /* get camera descriptor */ | ||
1218 | rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp)); | ||
1219 | if (cp[1]!=0x41) { | ||
1220 | err("Wrong descriptor type"); | ||
1221 | return 1; | ||
1222 | } | ||
1223 | sprintf (temp, "ExtraFeatures: %d", cp[3]); | ||
1224 | |||
1225 | se401->sizes=cp[4]+cp[5]*256; | ||
1226 | se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); | ||
1227 | if (!se401->width) | ||
1228 | return 1; | ||
1229 | se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); | ||
1230 | if (!se401->height) { | ||
1231 | kfree(se401->width); | ||
1232 | return 1; | ||
1233 | } | ||
1234 | for (i=0; i<se401->sizes; i++) { | ||
1235 | se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256; | ||
1236 | se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256; | ||
1237 | } | ||
1238 | sprintf (temp, "%s Sizes:", temp); | ||
1239 | for (i=0; i<se401->sizes; i++) { | ||
1240 | sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]); | ||
1241 | } | ||
1242 | info("%s", temp); | ||
1243 | se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3; | ||
1244 | |||
1245 | rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp)); | ||
1246 | se401->cwidth=cp[0]+cp[1]*256; | ||
1247 | rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp)); | ||
1248 | se401->cheight=cp[0]+cp[1]*256; | ||
1249 | |||
1250 | if (!cp[2] && SE401_FORMAT_BAYER) { | ||
1251 | err("Bayer format not supported!"); | ||
1252 | return 1; | ||
1253 | } | ||
1254 | /* set output mode (BAYER) */ | ||
1255 | se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0); | ||
1256 | |||
1257 | rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp)); | ||
1258 | se401->brightness=cp[0]+cp[1]*256; | ||
1259 | /* some default values */ | ||
1260 | se401->resetlevel=0x2d; | ||
1261 | se401->rgain=0x20; | ||
1262 | se401->ggain=0x20; | ||
1263 | se401->bgain=0x20; | ||
1264 | se401_set_exposure(se401, 20000); | ||
1265 | se401->palette=VIDEO_PALETTE_RGB24; | ||
1266 | se401->enhance=1; | ||
1267 | se401->dropped=0; | ||
1268 | se401->error=0; | ||
1269 | se401->framecount=0; | ||
1270 | se401->readcount=0; | ||
1271 | |||
1272 | /* Start interrupt transfers for snapshot button */ | ||
1273 | if (button) { | ||
1274 | se401->inturb=usb_alloc_urb(0, GFP_KERNEL); | ||
1275 | if (!se401->inturb) { | ||
1276 | info("Allocation of inturb failed"); | ||
1277 | return 1; | ||
1278 | } | ||
1279 | usb_fill_int_urb(se401->inturb, se401->dev, | ||
1280 | usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT), | ||
1281 | &se401->button, sizeof(se401->button), | ||
1282 | se401_button_irq, | ||
1283 | se401, | ||
1284 | 8 | ||
1285 | ); | ||
1286 | if (usb_submit_urb(se401->inturb, GFP_KERNEL)) { | ||
1287 | info("int urb burned down"); | ||
1288 | return 1; | ||
1289 | } | ||
1290 | } else | ||
1291 | se401->inturb=NULL; | ||
1292 | |||
1293 | /* Flash the led */ | ||
1294 | se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0); | ||
1295 | se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); | ||
1296 | se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0); | ||
1297 | se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0); | ||
1298 | |||
1299 | return 0; | ||
1300 | } | ||
1301 | |||
1302 | static int se401_probe(struct usb_interface *intf, | ||
1303 | const struct usb_device_id *id) | ||
1304 | { | ||
1305 | struct usb_device *dev = interface_to_usbdev(intf); | ||
1306 | struct usb_interface_descriptor *interface; | ||
1307 | struct usb_se401 *se401; | ||
1308 | char *camera_name=NULL; | ||
1309 | int button=1; | ||
1310 | |||
1311 | /* We don't handle multi-config cameras */ | ||
1312 | if (dev->descriptor.bNumConfigurations != 1) | ||
1313 | return -ENODEV; | ||
1314 | |||
1315 | interface = &intf->cur_altsetting->desc; | ||
1316 | |||
1317 | /* Is it an se401? */ | ||
1318 | if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 && | ||
1319 | le16_to_cpu(dev->descriptor.idProduct) == 0x0004) { | ||
1320 | camera_name="Endpoints/Aox SE401"; | ||
1321 | } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 && | ||
1322 | le16_to_cpu(dev->descriptor.idProduct) == 0x030b) { | ||
1323 | camera_name="Philips PCVC665K"; | ||
1324 | } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && | ||
1325 | le16_to_cpu(dev->descriptor.idProduct) == 0x5001) { | ||
1326 | camera_name="Kensington VideoCAM 67014"; | ||
1327 | } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && | ||
1328 | le16_to_cpu(dev->descriptor.idProduct) == 0x5002) { | ||
1329 | camera_name="Kensington VideoCAM 6701(5/7)"; | ||
1330 | } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && | ||
1331 | le16_to_cpu(dev->descriptor.idProduct) == 0x5003) { | ||
1332 | camera_name="Kensington VideoCAM 67016"; | ||
1333 | button=0; | ||
1334 | } else | ||
1335 | return -ENODEV; | ||
1336 | |||
1337 | /* Checking vendor/product should be enough, but what the hell */ | ||
1338 | if (interface->bInterfaceClass != 0x00) | ||
1339 | return -ENODEV; | ||
1340 | if (interface->bInterfaceSubClass != 0x00) | ||
1341 | return -ENODEV; | ||
1342 | |||
1343 | /* We found one */ | ||
1344 | info("SE401 camera found: %s", camera_name); | ||
1345 | |||
1346 | if ((se401 = kmalloc(sizeof(*se401), GFP_KERNEL)) == NULL) { | ||
1347 | err("couldn't kmalloc se401 struct"); | ||
1348 | return -ENOMEM; | ||
1349 | } | ||
1350 | |||
1351 | memset(se401, 0, sizeof(*se401)); | ||
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 | init_MUTEX(&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 | .owner = THIS_MODULE, | ||
1404 | .name = "se401", | ||
1405 | .id_table = device_table, | ||
1406 | .probe = se401_probe, | ||
1407 | .disconnect = se401_disconnect, | ||
1408 | }; | ||
1409 | |||
1410 | |||
1411 | |||
1412 | /**************************************************************************** | ||
1413 | * | ||
1414 | * Module routines | ||
1415 | * | ||
1416 | ***************************************************************************/ | ||
1417 | |||
1418 | static int __init usb_se401_init(void) | ||
1419 | { | ||
1420 | info("SE401 usb camera driver version %s registering", version); | ||
1421 | if (flickerless) | ||
1422 | if (flickerless!=50 && flickerless!=60) { | ||
1423 | info("Invallid flickerless value, use 0, 50 or 60."); | ||
1424 | return -1; | ||
1425 | } | ||
1426 | return usb_register(&se401_driver); | ||
1427 | } | ||
1428 | |||
1429 | static void __exit usb_se401_exit(void) | ||
1430 | { | ||
1431 | usb_deregister(&se401_driver); | ||
1432 | info("SE401 driver deregistered"); | ||
1433 | } | ||
1434 | |||
1435 | module_init(usb_se401_init); | ||
1436 | module_exit(usb_se401_exit); | ||
diff --git a/drivers/usb/media/se401.h b/drivers/usb/media/se401.h new file mode 100644 index 000000000000..2e5846f1eb20 --- /dev/null +++ b/drivers/usb/media/se401.h | |||
@@ -0,0 +1,233 @@ | |||
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 | |||
9 | #define se401_DEBUG /* Turn on debug messages */ | ||
10 | |||
11 | #ifdef se401_DEBUG | ||
12 | # define PDEBUG(level, fmt, args...) \ | ||
13 | if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args) | ||
14 | #else | ||
15 | # define PDEBUG(level, fmt, args...) do {} while(0) | ||
16 | #endif | ||
17 | |||
18 | /* An almost drop-in replacement for sleep_on_interruptible */ | ||
19 | #define wait_interruptible(test, queue, wait) \ | ||
20 | { \ | ||
21 | add_wait_queue(queue, wait); \ | ||
22 | set_current_state(TASK_INTERRUPTIBLE); \ | ||
23 | if (test) \ | ||
24 | schedule(); \ | ||
25 | remove_wait_queue(queue, wait); \ | ||
26 | set_current_state(TASK_RUNNING); \ | ||
27 | if (signal_pending(current)) \ | ||
28 | break; \ | ||
29 | } | ||
30 | |||
31 | #define SE401_REQ_GET_CAMERA_DESCRIPTOR 0x06 | ||
32 | #define SE401_REQ_START_CONTINUOUS_CAPTURE 0x41 | ||
33 | #define SE401_REQ_STOP_CONTINUOUS_CAPTURE 0x42 | ||
34 | #define SE401_REQ_CAPTURE_FRAME 0x43 | ||
35 | #define SE401_REQ_GET_BRT 0x44 | ||
36 | #define SE401_REQ_SET_BRT 0x45 | ||
37 | #define SE401_REQ_GET_WIDTH 0x4c | ||
38 | #define SE401_REQ_SET_WIDTH 0x4d | ||
39 | #define SE401_REQ_GET_HEIGHT 0x4e | ||
40 | #define SE401_REQ_SET_HEIGHT 0x4f | ||
41 | #define SE401_REQ_GET_OUTPUT_MODE 0x50 | ||
42 | #define SE401_REQ_SET_OUTPUT_MODE 0x51 | ||
43 | #define SE401_REQ_GET_EXT_FEATURE 0x52 | ||
44 | #define SE401_REQ_SET_EXT_FEATURE 0x53 | ||
45 | #define SE401_REQ_CAMERA_POWER 0x56 | ||
46 | #define SE401_REQ_LED_CONTROL 0x57 | ||
47 | #define SE401_REQ_BIOS 0xff | ||
48 | |||
49 | #define SE401_BIOS_READ 0x07 | ||
50 | |||
51 | #define SE401_FORMAT_BAYER 0x40 | ||
52 | |||
53 | /* Hyundai hv7131b registers | ||
54 | 7121 and 7141 should be the same (haven't really checked...) */ | ||
55 | /* Mode registers: */ | ||
56 | #define HV7131_REG_MODE_A 0x00 | ||
57 | #define HV7131_REG_MODE_B 0x01 | ||
58 | #define HV7131_REG_MODE_C 0x02 | ||
59 | /* Frame registers: */ | ||
60 | #define HV7131_REG_FRSU 0x10 | ||
61 | #define HV7131_REG_FRSL 0x11 | ||
62 | #define HV7131_REG_FCSU 0x12 | ||
63 | #define HV7131_REG_FCSL 0x13 | ||
64 | #define HV7131_REG_FWHU 0x14 | ||
65 | #define HV7131_REG_FWHL 0x15 | ||
66 | #define HV7131_REG_FWWU 0x16 | ||
67 | #define HV7131_REG_FWWL 0x17 | ||
68 | /* Timing registers: */ | ||
69 | #define HV7131_REG_THBU 0x20 | ||
70 | #define HV7131_REG_THBL 0x21 | ||
71 | #define HV7131_REG_TVBU 0x22 | ||
72 | #define HV7131_REG_TVBL 0x23 | ||
73 | #define HV7131_REG_TITU 0x25 | ||
74 | #define HV7131_REG_TITM 0x26 | ||
75 | #define HV7131_REG_TITL 0x27 | ||
76 | #define HV7131_REG_TMCD 0x28 | ||
77 | /* Adjust Registers: */ | ||
78 | #define HV7131_REG_ARLV 0x30 | ||
79 | #define HV7131_REG_ARCG 0x31 | ||
80 | #define HV7131_REG_AGCG 0x32 | ||
81 | #define HV7131_REG_ABCG 0x33 | ||
82 | #define HV7131_REG_APBV 0x34 | ||
83 | #define HV7131_REG_ASLP 0x54 | ||
84 | /* Offset Registers: */ | ||
85 | #define HV7131_REG_OFSR 0x50 | ||
86 | #define HV7131_REG_OFSG 0x51 | ||
87 | #define HV7131_REG_OFSB 0x52 | ||
88 | /* REset level statistics registers: */ | ||
89 | #define HV7131_REG_LOREFNOH 0x57 | ||
90 | #define HV7131_REG_LOREFNOL 0x58 | ||
91 | #define HV7131_REG_HIREFNOH 0x59 | ||
92 | #define HV7131_REG_HIREFNOL 0x5a | ||
93 | |||
94 | /* se401 registers */ | ||
95 | #define SE401_OPERATINGMODE 0x2000 | ||
96 | |||
97 | |||
98 | /* size of usb transfers */ | ||
99 | #define SE401_PACKETSIZE 4096 | ||
100 | /* number of queued bulk transfers to use, should be about 8 */ | ||
101 | #define SE401_NUMSBUF 1 | ||
102 | /* read the usb specs for this one :) */ | ||
103 | #define SE401_VIDEO_ENDPOINT 1 | ||
104 | #define SE401_BUTTON_ENDPOINT 2 | ||
105 | /* number of frames supported by the v4l part */ | ||
106 | #define SE401_NUMFRAMES 2 | ||
107 | /* scratch buffers for passing data to the decoders */ | ||
108 | #define SE401_NUMSCRATCH 32 | ||
109 | /* maximum amount of data in a JangGu packet */ | ||
110 | #define SE401_VLCDATALEN 1024 | ||
111 | /* number of nul sized packets to receive before kicking the camera */ | ||
112 | #define SE401_MAX_NULLPACKETS 4000 | ||
113 | /* number of decoding errors before kicking the camera */ | ||
114 | #define SE401_MAX_ERRORS 200 | ||
115 | |||
116 | struct usb_device; | ||
117 | |||
118 | struct se401_sbuf { | ||
119 | unsigned char *data; | ||
120 | }; | ||
121 | |||
122 | enum { | ||
123 | FRAME_UNUSED, /* Unused (no MCAPTURE) */ | ||
124 | FRAME_READY, /* Ready to start grabbing */ | ||
125 | FRAME_GRABBING, /* In the process of being grabbed into */ | ||
126 | FRAME_DONE, /* Finished grabbing, but not been synced yet */ | ||
127 | FRAME_ERROR, /* Something bad happened while processing */ | ||
128 | }; | ||
129 | |||
130 | enum { | ||
131 | FMT_BAYER, | ||
132 | FMT_JANGGU, | ||
133 | }; | ||
134 | |||
135 | enum { | ||
136 | BUFFER_UNUSED, | ||
137 | BUFFER_READY, | ||
138 | BUFFER_BUSY, | ||
139 | BUFFER_DONE, | ||
140 | }; | ||
141 | |||
142 | struct se401_scratch { | ||
143 | unsigned char *data; | ||
144 | volatile int state; | ||
145 | int offset; | ||
146 | int length; | ||
147 | }; | ||
148 | |||
149 | struct se401_frame { | ||
150 | unsigned char *data; /* Frame buffer */ | ||
151 | |||
152 | volatile int grabstate; /* State of grabbing */ | ||
153 | |||
154 | unsigned char *curline; | ||
155 | int curlinepix; | ||
156 | int curpix; | ||
157 | }; | ||
158 | |||
159 | struct usb_se401 { | ||
160 | struct video_device vdev; | ||
161 | |||
162 | /* Device structure */ | ||
163 | struct usb_device *dev; | ||
164 | |||
165 | unsigned char iface; | ||
166 | |||
167 | char *camera_name; | ||
168 | |||
169 | int change; | ||
170 | int brightness; | ||
171 | int hue; | ||
172 | int rgain; | ||
173 | int ggain; | ||
174 | int bgain; | ||
175 | int expose_h; | ||
176 | int expose_m; | ||
177 | int expose_l; | ||
178 | int resetlevel; | ||
179 | |||
180 | int enhance; | ||
181 | |||
182 | int format; | ||
183 | int sizes; | ||
184 | int *width; | ||
185 | int *height; | ||
186 | int cwidth; /* current width */ | ||
187 | int cheight; /* current height */ | ||
188 | int palette; | ||
189 | int maxframesize; | ||
190 | int cframesize; /* current framesize */ | ||
191 | |||
192 | struct semaphore lock; | ||
193 | int user; /* user count for exclusive use */ | ||
194 | int removed; /* device disconnected */ | ||
195 | |||
196 | int streaming; /* Are we streaming video? */ | ||
197 | |||
198 | char *fbuf; /* Videodev buffer area */ | ||
199 | |||
200 | struct urb *urb[SE401_NUMSBUF]; | ||
201 | struct urb *inturb; | ||
202 | |||
203 | int button; | ||
204 | int buttonpressed; | ||
205 | |||
206 | int curframe; /* Current receiving frame */ | ||
207 | struct se401_frame frame[SE401_NUMFRAMES]; | ||
208 | int readcount; | ||
209 | int framecount; | ||
210 | int error; | ||
211 | int dropped; | ||
212 | |||
213 | int scratch_next; | ||
214 | int scratch_use; | ||
215 | int scratch_overflow; | ||
216 | struct se401_scratch scratch[SE401_NUMSCRATCH]; | ||
217 | |||
218 | /* Decoder specific data: */ | ||
219 | unsigned char vlcdata[SE401_VLCDATALEN]; | ||
220 | int vlcdatapos; | ||
221 | int bayeroffset; | ||
222 | |||
223 | struct se401_sbuf sbuf[SE401_NUMSBUF]; | ||
224 | |||
225 | wait_queue_head_t wq; /* Processes waiting */ | ||
226 | |||
227 | int nullpackets; | ||
228 | }; | ||
229 | |||
230 | |||
231 | |||
232 | #endif | ||
233 | |||
diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h new file mode 100644 index 000000000000..8b8a4c8743f8 --- /dev/null +++ b/drivers/usb/media/sn9c102.h | |||
@@ -0,0 +1,206 @@ | |||
1 | /*************************************************************************** | ||
2 | * V4L2 driver for SN9C10x PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2004-2005 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/videodev.h> | ||
27 | #include <linux/device.h> | ||
28 | #include <linux/list.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/time.h> | ||
31 | #include <linux/wait.h> | ||
32 | #include <linux/types.h> | ||
33 | #include <linux/param.h> | ||
34 | #include <linux/rwsem.h> | ||
35 | #include <asm/semaphore.h> | ||
36 | |||
37 | #include "sn9c102_sensor.h" | ||
38 | |||
39 | /*****************************************************************************/ | ||
40 | |||
41 | #define SN9C102_DEBUG | ||
42 | #define SN9C102_DEBUG_LEVEL 2 | ||
43 | #define SN9C102_MAX_DEVICES 64 | ||
44 | #define SN9C102_PRESERVE_IMGSCALE 0 | ||
45 | #define SN9C102_FORCE_MUNMAP 0 | ||
46 | #define SN9C102_MAX_FRAMES 32 | ||
47 | #define SN9C102_URBS 2 | ||
48 | #define SN9C102_ISO_PACKETS 7 | ||
49 | #define SN9C102_ALTERNATE_SETTING 8 | ||
50 | #define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS) | ||
51 | #define SN9C102_CTRL_TIMEOUT 300 | ||
52 | |||
53 | /*****************************************************************************/ | ||
54 | |||
55 | #define SN9C102_MODULE_NAME "V4L2 driver for SN9C10x PC Camera Controllers" | ||
56 | #define SN9C102_MODULE_AUTHOR "(C) 2004-2005 Luca Risolia" | ||
57 | #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" | ||
58 | #define SN9C102_MODULE_LICENSE "GPL" | ||
59 | #define SN9C102_MODULE_VERSION "1:1.24" | ||
60 | #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 24) | ||
61 | |||
62 | enum sn9c102_bridge { | ||
63 | BRIDGE_SN9C101 = 0x01, | ||
64 | BRIDGE_SN9C102 = 0x02, | ||
65 | BRIDGE_SN9C103 = 0x04, | ||
66 | }; | ||
67 | |||
68 | SN9C102_ID_TABLE | ||
69 | SN9C102_SENSOR_TABLE | ||
70 | |||
71 | enum sn9c102_frame_state { | ||
72 | F_UNUSED, | ||
73 | F_QUEUED, | ||
74 | F_GRABBING, | ||
75 | F_DONE, | ||
76 | F_ERROR, | ||
77 | }; | ||
78 | |||
79 | struct sn9c102_frame_t { | ||
80 | void* bufmem; | ||
81 | struct v4l2_buffer buf; | ||
82 | enum sn9c102_frame_state state; | ||
83 | struct list_head frame; | ||
84 | unsigned long vma_use_count; | ||
85 | }; | ||
86 | |||
87 | enum sn9c102_dev_state { | ||
88 | DEV_INITIALIZED = 0x01, | ||
89 | DEV_DISCONNECTED = 0x02, | ||
90 | DEV_MISCONFIGURED = 0x04, | ||
91 | }; | ||
92 | |||
93 | enum sn9c102_io_method { | ||
94 | IO_NONE, | ||
95 | IO_READ, | ||
96 | IO_MMAP, | ||
97 | }; | ||
98 | |||
99 | enum sn9c102_stream_state { | ||
100 | STREAM_OFF, | ||
101 | STREAM_INTERRUPT, | ||
102 | STREAM_ON, | ||
103 | }; | ||
104 | |||
105 | typedef char sn9c102_sof_header_t[12]; | ||
106 | typedef char sn9c102_eof_header_t[4]; | ||
107 | |||
108 | struct sn9c102_sysfs_attr { | ||
109 | u8 reg, i2c_reg; | ||
110 | sn9c102_sof_header_t frame_header; | ||
111 | }; | ||
112 | |||
113 | struct sn9c102_module_param { | ||
114 | u8 force_munmap; | ||
115 | }; | ||
116 | |||
117 | static DECLARE_MUTEX(sn9c102_sysfs_lock); | ||
118 | static DECLARE_RWSEM(sn9c102_disconnect); | ||
119 | |||
120 | struct sn9c102_device { | ||
121 | struct device dev; | ||
122 | |||
123 | struct video_device* v4ldev; | ||
124 | |||
125 | enum sn9c102_bridge bridge; | ||
126 | struct sn9c102_sensor* sensor; | ||
127 | |||
128 | struct usb_device* usbdev; | ||
129 | struct urb* urb[SN9C102_URBS]; | ||
130 | void* transfer_buffer[SN9C102_URBS]; | ||
131 | u8* control_buffer; | ||
132 | |||
133 | struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES]; | ||
134 | struct list_head inqueue, outqueue; | ||
135 | u32 frame_count, nbuffers, nreadbuffers; | ||
136 | |||
137 | enum sn9c102_io_method io; | ||
138 | enum sn9c102_stream_state stream; | ||
139 | |||
140 | struct v4l2_jpegcompression compression; | ||
141 | |||
142 | struct sn9c102_sysfs_attr sysfs; | ||
143 | sn9c102_sof_header_t sof_header; | ||
144 | u16 reg[32]; | ||
145 | |||
146 | struct sn9c102_module_param module_param; | ||
147 | |||
148 | enum sn9c102_dev_state state; | ||
149 | u8 users; | ||
150 | |||
151 | struct semaphore dev_sem, fileop_sem; | ||
152 | spinlock_t queue_lock; | ||
153 | wait_queue_head_t open, wait_frame, wait_stream; | ||
154 | }; | ||
155 | |||
156 | /*****************************************************************************/ | ||
157 | |||
158 | void | ||
159 | sn9c102_attach_sensor(struct sn9c102_device* cam, | ||
160 | struct sn9c102_sensor* sensor) | ||
161 | { | ||
162 | cam->sensor = sensor; | ||
163 | cam->sensor->dev = &cam->dev; | ||
164 | cam->sensor->usbdev = cam->usbdev; | ||
165 | } | ||
166 | |||
167 | /*****************************************************************************/ | ||
168 | |||
169 | #undef DBG | ||
170 | #undef KDBG | ||
171 | #ifdef SN9C102_DEBUG | ||
172 | # define DBG(level, fmt, args...) \ | ||
173 | { \ | ||
174 | if (debug >= (level)) { \ | ||
175 | if ((level) == 1) \ | ||
176 | dev_err(&cam->dev, fmt "\n", ## args); \ | ||
177 | else if ((level) == 2) \ | ||
178 | dev_info(&cam->dev, fmt "\n", ## args); \ | ||
179 | else if ((level) >= 3) \ | ||
180 | dev_info(&cam->dev, "[%s:%d] " fmt "\n", \ | ||
181 | __FUNCTION__, __LINE__ , ## args); \ | ||
182 | } \ | ||
183 | } | ||
184 | # define KDBG(level, fmt, args...) \ | ||
185 | { \ | ||
186 | if (debug >= (level)) { \ | ||
187 | if ((level) == 1 || (level) == 2) \ | ||
188 | pr_info("sn9c102: " fmt "\n", ## args); \ | ||
189 | else if ((level) == 3) \ | ||
190 | pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__, \ | ||
191 | __LINE__ , ## args); \ | ||
192 | } \ | ||
193 | } | ||
194 | #else | ||
195 | # define KDBG(level, fmt, args...) do {;} while(0); | ||
196 | # define DBG(level, fmt, args...) do {;} while(0); | ||
197 | #endif | ||
198 | |||
199 | #undef PDBG | ||
200 | #define PDBG(fmt, args...) \ | ||
201 | dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args); | ||
202 | |||
203 | #undef PDBGG | ||
204 | #define PDBGG(fmt, args...) do {;} while(0); /* placeholder */ | ||
205 | |||
206 | #endif /* _SN9C102_H_ */ | ||
diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c new file mode 100644 index 000000000000..898401cf7dcc --- /dev/null +++ b/drivers/usb/media/sn9c102_core.c | |||
@@ -0,0 +1,2744 @@ | |||
1 | /*************************************************************************** | ||
2 | * V4L2 driver for SN9C10x PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2004-2005 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/string.h> | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/fs.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <linux/stddef.h> | ||
33 | #include <linux/compiler.h> | ||
34 | #include <linux/ioctl.h> | ||
35 | #include <linux/poll.h> | ||
36 | #include <linux/stat.h> | ||
37 | #include <linux/mm.h> | ||
38 | #include <linux/vmalloc.h> | ||
39 | #include <linux/page-flags.h> | ||
40 | #include <linux/byteorder/generic.h> | ||
41 | #include <asm/page.h> | ||
42 | #include <asm/uaccess.h> | ||
43 | |||
44 | #include "sn9c102.h" | ||
45 | |||
46 | /*****************************************************************************/ | ||
47 | |||
48 | MODULE_DEVICE_TABLE(usb, sn9c102_id_table); | ||
49 | |||
50 | MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL); | ||
51 | MODULE_DESCRIPTION(SN9C102_MODULE_NAME); | ||
52 | MODULE_VERSION(SN9C102_MODULE_VERSION); | ||
53 | MODULE_LICENSE(SN9C102_MODULE_LICENSE); | ||
54 | |||
55 | static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1}; | ||
56 | module_param_array(video_nr, short, NULL, 0444); | ||
57 | MODULE_PARM_DESC(video_nr, | ||
58 | "\n<-1|n[,...]> Specify V4L2 minor mode number." | ||
59 | "\n -1 = use next available (default)" | ||
60 | "\n n = use minor number n (integer >= 0)" | ||
61 | "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES) | ||
62 | " cameras this way." | ||
63 | "\nFor example:" | ||
64 | "\nvideo_nr=-1,2,-1 would assign minor number 2 to" | ||
65 | "\nthe second camera and use auto for the first" | ||
66 | "\none and for every other camera." | ||
67 | "\n"); | ||
68 | |||
69 | static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = | ||
70 | SN9C102_FORCE_MUNMAP}; | ||
71 | module_param_array(force_munmap, bool, NULL, 0444); | ||
72 | MODULE_PARM_DESC(force_munmap, | ||
73 | "\n<0|1[,...]> Force the application to unmap previously " | ||
74 | "\nmapped buffer memory before calling any VIDIOC_S_CROP or " | ||
75 | "\nVIDIOC_S_FMT ioctl's. Not all the applications support " | ||
76 | "\nthis feature. This parameter is specific for each " | ||
77 | "\ndetected camera." | ||
78 | "\n 0 = do not force memory unmapping" | ||
79 | "\n 1 = force memory unmapping (save memory)" | ||
80 | "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." | ||
81 | "\n"); | ||
82 | |||
83 | #ifdef SN9C102_DEBUG | ||
84 | static unsigned short debug = SN9C102_DEBUG_LEVEL; | ||
85 | module_param(debug, ushort, 0644); | ||
86 | MODULE_PARM_DESC(debug, | ||
87 | "\n<n> Debugging information level, from 0 to 3:" | ||
88 | "\n0 = none (use carefully)" | ||
89 | "\n1 = critical errors" | ||
90 | "\n2 = significant informations" | ||
91 | "\n3 = more verbose messages" | ||
92 | "\nLevel 3 is useful for testing only, when only " | ||
93 | "one device is used." | ||
94 | "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"." | ||
95 | "\n"); | ||
96 | #endif | ||
97 | |||
98 | /*****************************************************************************/ | ||
99 | |||
100 | static sn9c102_sof_header_t sn9c102_sof_header[] = { | ||
101 | {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00}, | ||
102 | {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01}, | ||
103 | }; | ||
104 | |||
105 | |||
106 | static sn9c102_eof_header_t sn9c102_eof_header[] = { | ||
107 | {0x00, 0x00, 0x00, 0x00}, | ||
108 | {0x40, 0x00, 0x00, 0x00}, | ||
109 | {0x80, 0x00, 0x00, 0x00}, | ||
110 | {0xc0, 0x00, 0x00, 0x00}, | ||
111 | }; | ||
112 | |||
113 | /*****************************************************************************/ | ||
114 | |||
115 | static void* rvmalloc(size_t size) | ||
116 | { | ||
117 | void* mem; | ||
118 | unsigned long adr; | ||
119 | |||
120 | size = PAGE_ALIGN(size); | ||
121 | |||
122 | mem = vmalloc_32((unsigned long)size); | ||
123 | if (!mem) | ||
124 | return NULL; | ||
125 | |||
126 | memset(mem, 0, size); | ||
127 | |||
128 | adr = (unsigned long)mem; | ||
129 | while (size > 0) { | ||
130 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
131 | adr += PAGE_SIZE; | ||
132 | size -= PAGE_SIZE; | ||
133 | } | ||
134 | |||
135 | return mem; | ||
136 | } | ||
137 | |||
138 | |||
139 | static void rvfree(void* mem, size_t size) | ||
140 | { | ||
141 | unsigned long adr; | ||
142 | |||
143 | if (!mem) | ||
144 | return; | ||
145 | |||
146 | size = PAGE_ALIGN(size); | ||
147 | |||
148 | adr = (unsigned long)mem; | ||
149 | while (size > 0) { | ||
150 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
151 | adr += PAGE_SIZE; | ||
152 | size -= PAGE_SIZE; | ||
153 | } | ||
154 | |||
155 | vfree(mem); | ||
156 | } | ||
157 | |||
158 | |||
159 | static u32 | ||
160 | sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, | ||
161 | enum sn9c102_io_method io) | ||
162 | { | ||
163 | struct v4l2_pix_format* p = &(cam->sensor->pix_format); | ||
164 | struct v4l2_rect* r = &(cam->sensor->cropcap.bounds); | ||
165 | const size_t imagesize = cam->module_param.force_munmap || | ||
166 | io == IO_READ ? | ||
167 | (p->width * p->height * p->priv) / 8 : | ||
168 | (r->width * r->height * p->priv) / 8; | ||
169 | void* buff = NULL; | ||
170 | u32 i; | ||
171 | |||
172 | if (count > SN9C102_MAX_FRAMES) | ||
173 | count = SN9C102_MAX_FRAMES; | ||
174 | |||
175 | cam->nbuffers = count; | ||
176 | while (cam->nbuffers > 0) { | ||
177 | if ((buff = rvmalloc(cam->nbuffers * PAGE_ALIGN(imagesize)))) | ||
178 | break; | ||
179 | cam->nbuffers--; | ||
180 | } | ||
181 | |||
182 | for (i = 0; i < cam->nbuffers; i++) { | ||
183 | cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); | ||
184 | cam->frame[i].buf.index = i; | ||
185 | cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); | ||
186 | cam->frame[i].buf.length = imagesize; | ||
187 | cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
188 | cam->frame[i].buf.sequence = 0; | ||
189 | cam->frame[i].buf.field = V4L2_FIELD_NONE; | ||
190 | cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; | ||
191 | cam->frame[i].buf.flags = 0; | ||
192 | } | ||
193 | |||
194 | return cam->nbuffers; | ||
195 | } | ||
196 | |||
197 | |||
198 | static void sn9c102_release_buffers(struct sn9c102_device* cam) | ||
199 | { | ||
200 | if (cam->nbuffers) { | ||
201 | rvfree(cam->frame[0].bufmem, | ||
202 | cam->nbuffers * cam->frame[0].buf.length); | ||
203 | cam->nbuffers = 0; | ||
204 | } | ||
205 | } | ||
206 | |||
207 | |||
208 | static void sn9c102_empty_framequeues(struct sn9c102_device* cam) | ||
209 | { | ||
210 | u32 i; | ||
211 | |||
212 | INIT_LIST_HEAD(&cam->inqueue); | ||
213 | INIT_LIST_HEAD(&cam->outqueue); | ||
214 | |||
215 | for (i = 0; i < SN9C102_MAX_FRAMES; i++) { | ||
216 | cam->frame[i].state = F_UNUSED; | ||
217 | cam->frame[i].buf.bytesused = 0; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | |||
222 | static void sn9c102_queue_unusedframes(struct sn9c102_device* cam) | ||
223 | { | ||
224 | unsigned long lock_flags; | ||
225 | u32 i; | ||
226 | |||
227 | for (i = 0; i < cam->nbuffers; i++) | ||
228 | if (cam->frame[i].state == F_UNUSED) { | ||
229 | cam->frame[i].state = F_QUEUED; | ||
230 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
231 | list_add_tail(&cam->frame[i].frame, &cam->inqueue); | ||
232 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
233 | } | ||
234 | } | ||
235 | |||
236 | /*****************************************************************************/ | ||
237 | |||
238 | int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index) | ||
239 | { | ||
240 | struct usb_device* udev = cam->usbdev; | ||
241 | u8* buff = cam->control_buffer; | ||
242 | int res; | ||
243 | |||
244 | *buff = value; | ||
245 | |||
246 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
247 | index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); | ||
248 | if (res < 0) { | ||
249 | DBG(3, "Failed to write a register (value 0x%02X, index " | ||
250 | "0x%02X, error %d)", value, index, res) | ||
251 | return -1; | ||
252 | } | ||
253 | |||
254 | cam->reg[index] = value; | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | |||
260 | /* NOTE: reading some registers always returns 0 */ | ||
261 | static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index) | ||
262 | { | ||
263 | struct usb_device* udev = cam->usbdev; | ||
264 | u8* buff = cam->control_buffer; | ||
265 | int res; | ||
266 | |||
267 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, | ||
268 | index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); | ||
269 | if (res < 0) | ||
270 | DBG(3, "Failed to read a register (index 0x%02X, error %d)", | ||
271 | index, res) | ||
272 | |||
273 | return (res >= 0) ? (int)(*buff) : -1; | ||
274 | } | ||
275 | |||
276 | |||
277 | int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index) | ||
278 | { | ||
279 | if (index > 0x1f) | ||
280 | return -EINVAL; | ||
281 | |||
282 | return cam->reg[index]; | ||
283 | } | ||
284 | |||
285 | |||
286 | static int | ||
287 | sn9c102_i2c_wait(struct sn9c102_device* cam, struct sn9c102_sensor* sensor) | ||
288 | { | ||
289 | int i, r; | ||
290 | |||
291 | for (i = 1; i <= 5; i++) { | ||
292 | r = sn9c102_read_reg(cam, 0x08); | ||
293 | if (r < 0) | ||
294 | return -EIO; | ||
295 | if (r & 0x04) | ||
296 | return 0; | ||
297 | if (sensor->frequency & SN9C102_I2C_400KHZ) | ||
298 | udelay(5*16); | ||
299 | else | ||
300 | udelay(16*16); | ||
301 | } | ||
302 | return -EBUSY; | ||
303 | } | ||
304 | |||
305 | |||
306 | static int | ||
307 | sn9c102_i2c_detect_read_error(struct sn9c102_device* cam, | ||
308 | struct sn9c102_sensor* sensor) | ||
309 | { | ||
310 | int r; | ||
311 | r = sn9c102_read_reg(cam, 0x08); | ||
312 | return (r < 0 || (r >= 0 && !(r & 0x08))) ? -EIO : 0; | ||
313 | } | ||
314 | |||
315 | |||
316 | static int | ||
317 | sn9c102_i2c_detect_write_error(struct sn9c102_device* cam, | ||
318 | struct sn9c102_sensor* sensor) | ||
319 | { | ||
320 | int r; | ||
321 | r = sn9c102_read_reg(cam, 0x08); | ||
322 | return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0; | ||
323 | } | ||
324 | |||
325 | |||
326 | int | ||
327 | sn9c102_i2c_try_raw_read(struct sn9c102_device* cam, | ||
328 | struct sn9c102_sensor* sensor, u8 data0, u8 data1, | ||
329 | u8 n, u8 buffer[]) | ||
330 | { | ||
331 | struct usb_device* udev = cam->usbdev; | ||
332 | u8* data = cam->control_buffer; | ||
333 | int err = 0, res; | ||
334 | |||
335 | /* Write cycle */ | ||
336 | data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | | ||
337 | ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10; | ||
338 | data[1] = data0; /* I2C slave id */ | ||
339 | data[2] = data1; /* address */ | ||
340 | data[7] = 0x10; | ||
341 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
342 | 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); | ||
343 | if (res < 0) | ||
344 | err += res; | ||
345 | |||
346 | err += sn9c102_i2c_wait(cam, sensor); | ||
347 | |||
348 | /* Read cycle - n bytes */ | ||
349 | data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | | ||
350 | ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | | ||
351 | (n << 4) | 0x02; | ||
352 | data[1] = data0; | ||
353 | data[7] = 0x10; | ||
354 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
355 | 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); | ||
356 | if (res < 0) | ||
357 | err += res; | ||
358 | |||
359 | err += sn9c102_i2c_wait(cam, sensor); | ||
360 | |||
361 | /* The first read byte will be placed in data[4] */ | ||
362 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, | ||
363 | 0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT); | ||
364 | if (res < 0) | ||
365 | err += res; | ||
366 | |||
367 | err += sn9c102_i2c_detect_read_error(cam, sensor); | ||
368 | |||
369 | PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1, | ||
370 | data[4]) | ||
371 | |||
372 | if (err) { | ||
373 | DBG(3, "I2C read failed for %s image sensor", sensor->name) | ||
374 | return -1; | ||
375 | } | ||
376 | |||
377 | if (buffer) | ||
378 | memcpy(buffer, data, sizeof(buffer)); | ||
379 | |||
380 | return (int)data[4]; | ||
381 | } | ||
382 | |||
383 | |||
384 | int | ||
385 | sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, | ||
386 | struct sn9c102_sensor* sensor, u8 n, u8 data0, | ||
387 | u8 data1, u8 data2, u8 data3, u8 data4, u8 data5) | ||
388 | { | ||
389 | struct usb_device* udev = cam->usbdev; | ||
390 | u8* data = cam->control_buffer; | ||
391 | int err = 0, res; | ||
392 | |||
393 | /* Write cycle. It usually is address + value */ | ||
394 | data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | | ||
395 | ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | ||
396 | | ((n - 1) << 4); | ||
397 | data[1] = data0; | ||
398 | data[2] = data1; | ||
399 | data[3] = data2; | ||
400 | data[4] = data3; | ||
401 | data[5] = data4; | ||
402 | data[6] = data5; | ||
403 | data[7] = 0x14; | ||
404 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
405 | 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); | ||
406 | if (res < 0) | ||
407 | err += res; | ||
408 | |||
409 | err += sn9c102_i2c_wait(cam, sensor); | ||
410 | err += sn9c102_i2c_detect_write_error(cam, sensor); | ||
411 | |||
412 | if (err) | ||
413 | DBG(3, "I2C write failed for %s image sensor", sensor->name) | ||
414 | |||
415 | PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, " | ||
416 | "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X", | ||
417 | n, data0, data1, data2, data3, data4, data5) | ||
418 | |||
419 | return err ? -1 : 0; | ||
420 | } | ||
421 | |||
422 | |||
423 | int | ||
424 | sn9c102_i2c_try_read(struct sn9c102_device* cam, | ||
425 | struct sn9c102_sensor* sensor, u8 address) | ||
426 | { | ||
427 | return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id, | ||
428 | address, 1, NULL); | ||
429 | } | ||
430 | |||
431 | |||
432 | int | ||
433 | sn9c102_i2c_try_write(struct sn9c102_device* cam, | ||
434 | struct sn9c102_sensor* sensor, u8 address, u8 value) | ||
435 | { | ||
436 | return sn9c102_i2c_try_raw_write(cam, sensor, 3, | ||
437 | sensor->i2c_slave_id, address, | ||
438 | value, 0, 0, 0); | ||
439 | } | ||
440 | |||
441 | |||
442 | int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address) | ||
443 | { | ||
444 | if (!cam->sensor) | ||
445 | return -1; | ||
446 | |||
447 | return sn9c102_i2c_try_read(cam, cam->sensor, address); | ||
448 | } | ||
449 | |||
450 | |||
451 | int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value) | ||
452 | { | ||
453 | if (!cam->sensor) | ||
454 | return -1; | ||
455 | |||
456 | return sn9c102_i2c_try_write(cam, cam->sensor, address, value); | ||
457 | } | ||
458 | |||
459 | /*****************************************************************************/ | ||
460 | |||
461 | static void* | ||
462 | sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) | ||
463 | { | ||
464 | size_t soflen = sizeof(sn9c102_sof_header_t), i; | ||
465 | u8 j, n = sizeof(sn9c102_sof_header) / soflen; | ||
466 | |||
467 | for (i = 0; (len >= soflen) && (i <= len - soflen); i++) | ||
468 | for (j = 0; j < n; j++) | ||
469 | /* It's enough to compare 7 bytes */ | ||
470 | if (!memcmp(mem + i, sn9c102_sof_header[j], 7)) { | ||
471 | memcpy(cam->sof_header, mem + i, soflen); | ||
472 | /* Skip the header */ | ||
473 | return mem + i + soflen; | ||
474 | } | ||
475 | |||
476 | return NULL; | ||
477 | } | ||
478 | |||
479 | |||
480 | static void* | ||
481 | sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) | ||
482 | { | ||
483 | size_t eoflen = sizeof(sn9c102_eof_header_t), i; | ||
484 | unsigned j, n = sizeof(sn9c102_eof_header) / eoflen; | ||
485 | |||
486 | if (cam->sensor->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
487 | return NULL; /* EOF header does not exist in compressed data */ | ||
488 | |||
489 | for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++) | ||
490 | for (j = 0; j < n; j++) | ||
491 | if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen)) | ||
492 | return mem + i; | ||
493 | |||
494 | return NULL; | ||
495 | } | ||
496 | |||
497 | |||
498 | static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs) | ||
499 | { | ||
500 | struct sn9c102_device* cam = urb->context; | ||
501 | struct sn9c102_frame_t** f; | ||
502 | size_t imagesize; | ||
503 | unsigned long lock_flags; | ||
504 | u8 i; | ||
505 | int err = 0; | ||
506 | |||
507 | if (urb->status == -ENOENT) | ||
508 | return; | ||
509 | |||
510 | f = &cam->frame_current; | ||
511 | |||
512 | if (cam->stream == STREAM_INTERRUPT) { | ||
513 | cam->stream = STREAM_OFF; | ||
514 | if ((*f)) | ||
515 | (*f)->state = F_QUEUED; | ||
516 | DBG(3, "Stream interrupted") | ||
517 | wake_up_interruptible(&cam->wait_stream); | ||
518 | } | ||
519 | |||
520 | if (cam->state & DEV_DISCONNECTED) | ||
521 | return; | ||
522 | |||
523 | if (cam->state & DEV_MISCONFIGURED) { | ||
524 | wake_up_interruptible(&cam->wait_frame); | ||
525 | return; | ||
526 | } | ||
527 | |||
528 | if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) | ||
529 | goto resubmit_urb; | ||
530 | |||
531 | if (!(*f)) | ||
532 | (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t, | ||
533 | frame); | ||
534 | |||
535 | imagesize = (cam->sensor->pix_format.width * | ||
536 | cam->sensor->pix_format.height * | ||
537 | cam->sensor->pix_format.priv) / 8; | ||
538 | |||
539 | for (i = 0; i < urb->number_of_packets; i++) { | ||
540 | unsigned int img, len, status; | ||
541 | void *pos, *sof, *eof; | ||
542 | |||
543 | len = urb->iso_frame_desc[i].actual_length; | ||
544 | status = urb->iso_frame_desc[i].status; | ||
545 | pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; | ||
546 | |||
547 | if (status) { | ||
548 | DBG(3, "Error in isochronous frame") | ||
549 | (*f)->state = F_ERROR; | ||
550 | continue; | ||
551 | } | ||
552 | |||
553 | PDBGG("Isochrnous frame: length %u, #%u i", len, i) | ||
554 | |||
555 | /* | ||
556 | NOTE: It is probably correct to assume that SOF and EOF | ||
557 | headers do not occur between two consecutive packets, | ||
558 | but who knows..Whatever is the truth, this assumption | ||
559 | doesn't introduce bugs. | ||
560 | */ | ||
561 | |||
562 | redo: | ||
563 | sof = sn9c102_find_sof_header(cam, pos, len); | ||
564 | if (!sof) { | ||
565 | eof = sn9c102_find_eof_header(cam, pos, len); | ||
566 | if ((*f)->state == F_GRABBING) { | ||
567 | end_of_frame: | ||
568 | img = len; | ||
569 | |||
570 | if (eof) | ||
571 | img = (eof > pos) ? eof - pos - 1 : 0; | ||
572 | |||
573 | if ((*f)->buf.bytesused+img > imagesize) { | ||
574 | u32 b = (*f)->buf.bytesused + img - | ||
575 | imagesize; | ||
576 | img = imagesize - (*f)->buf.bytesused; | ||
577 | DBG(3, "Expected EOF not found: " | ||
578 | "video frame cut") | ||
579 | if (eof) | ||
580 | DBG(3, "Exceeded limit: +%u " | ||
581 | "bytes", (unsigned)(b)) | ||
582 | } | ||
583 | |||
584 | memcpy((*f)->bufmem + (*f)->buf.bytesused, pos, | ||
585 | img); | ||
586 | |||
587 | if ((*f)->buf.bytesused == 0) | ||
588 | do_gettimeofday(&(*f)->buf.timestamp); | ||
589 | |||
590 | (*f)->buf.bytesused += img; | ||
591 | |||
592 | if ((*f)->buf.bytesused == imagesize || | ||
593 | (cam->sensor->pix_format.pixelformat == | ||
594 | V4L2_PIX_FMT_SN9C10X && eof)) { | ||
595 | u32 b = (*f)->buf.bytesused; | ||
596 | (*f)->state = F_DONE; | ||
597 | (*f)->buf.sequence= ++cam->frame_count; | ||
598 | spin_lock_irqsave(&cam->queue_lock, | ||
599 | lock_flags); | ||
600 | list_move_tail(&(*f)->frame, | ||
601 | &cam->outqueue); | ||
602 | if (!list_empty(&cam->inqueue)) | ||
603 | (*f) = list_entry( | ||
604 | cam->inqueue.next, | ||
605 | struct sn9c102_frame_t, | ||
606 | frame ); | ||
607 | else | ||
608 | (*f) = NULL; | ||
609 | spin_unlock_irqrestore(&cam->queue_lock | ||
610 | , lock_flags); | ||
611 | memcpy(cam->sysfs.frame_header, | ||
612 | cam->sof_header, | ||
613 | sizeof(sn9c102_sof_header_t)); | ||
614 | DBG(3, "Video frame captured: " | ||
615 | "%lu bytes", (unsigned long)(b)) | ||
616 | |||
617 | if (!(*f)) | ||
618 | goto resubmit_urb; | ||
619 | |||
620 | } else if (eof) { | ||
621 | (*f)->state = F_ERROR; | ||
622 | DBG(3, "Not expected EOF after %lu " | ||
623 | "bytes of image data", | ||
624 | (unsigned long)((*f)->buf.bytesused)) | ||
625 | } | ||
626 | |||
627 | if (sof) /* (1) */ | ||
628 | goto start_of_frame; | ||
629 | |||
630 | } else if (eof) { | ||
631 | DBG(3, "EOF without SOF") | ||
632 | continue; | ||
633 | |||
634 | } else { | ||
635 | PDBGG("Ignoring pointless isochronous frame") | ||
636 | continue; | ||
637 | } | ||
638 | |||
639 | } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) { | ||
640 | start_of_frame: | ||
641 | (*f)->state = F_GRABBING; | ||
642 | (*f)->buf.bytesused = 0; | ||
643 | len -= (sof - pos); | ||
644 | pos = sof; | ||
645 | DBG(3, "SOF detected: new video frame") | ||
646 | if (len) | ||
647 | goto redo; | ||
648 | |||
649 | } else if ((*f)->state == F_GRABBING) { | ||
650 | eof = sn9c102_find_eof_header(cam, pos, len); | ||
651 | if (eof && eof < sof) | ||
652 | goto end_of_frame; /* (1) */ | ||
653 | else { | ||
654 | if (cam->sensor->pix_format.pixelformat == | ||
655 | V4L2_PIX_FMT_SN9C10X) { | ||
656 | eof = sof-sizeof(sn9c102_sof_header_t); | ||
657 | goto end_of_frame; | ||
658 | } else { | ||
659 | DBG(3, "SOF before expected EOF after " | ||
660 | "%lu bytes of image data", | ||
661 | (unsigned long)((*f)->buf.bytesused)) | ||
662 | goto start_of_frame; | ||
663 | } | ||
664 | } | ||
665 | } | ||
666 | } | ||
667 | |||
668 | resubmit_urb: | ||
669 | urb->dev = cam->usbdev; | ||
670 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
671 | if (err < 0 && err != -EPERM) { | ||
672 | cam->state |= DEV_MISCONFIGURED; | ||
673 | DBG(1, "usb_submit_urb() failed") | ||
674 | } | ||
675 | |||
676 | wake_up_interruptible(&cam->wait_frame); | ||
677 | } | ||
678 | |||
679 | |||
680 | static int sn9c102_start_transfer(struct sn9c102_device* cam) | ||
681 | { | ||
682 | struct usb_device *udev = cam->usbdev; | ||
683 | struct urb* urb; | ||
684 | const unsigned int wMaxPacketSize[] = {0, 128, 256, 384, 512, | ||
685 | 680, 800, 900, 1023}; | ||
686 | const unsigned int psz = wMaxPacketSize[SN9C102_ALTERNATE_SETTING]; | ||
687 | s8 i, j; | ||
688 | int err = 0; | ||
689 | |||
690 | for (i = 0; i < SN9C102_URBS; i++) { | ||
691 | cam->transfer_buffer[i] = kmalloc(SN9C102_ISO_PACKETS * psz, | ||
692 | GFP_KERNEL); | ||
693 | if (!cam->transfer_buffer[i]) { | ||
694 | err = -ENOMEM; | ||
695 | DBG(1, "Not enough memory") | ||
696 | goto free_buffers; | ||
697 | } | ||
698 | } | ||
699 | |||
700 | for (i = 0; i < SN9C102_URBS; i++) { | ||
701 | urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL); | ||
702 | cam->urb[i] = urb; | ||
703 | if (!urb) { | ||
704 | err = -ENOMEM; | ||
705 | DBG(1, "usb_alloc_urb() failed") | ||
706 | goto free_urbs; | ||
707 | } | ||
708 | urb->dev = udev; | ||
709 | urb->context = cam; | ||
710 | urb->pipe = usb_rcvisocpipe(udev, 1); | ||
711 | urb->transfer_flags = URB_ISO_ASAP; | ||
712 | urb->number_of_packets = SN9C102_ISO_PACKETS; | ||
713 | urb->complete = sn9c102_urb_complete; | ||
714 | urb->transfer_buffer = cam->transfer_buffer[i]; | ||
715 | urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS; | ||
716 | urb->interval = 1; | ||
717 | for (j = 0; j < SN9C102_ISO_PACKETS; j++) { | ||
718 | urb->iso_frame_desc[j].offset = psz * j; | ||
719 | urb->iso_frame_desc[j].length = psz; | ||
720 | } | ||
721 | } | ||
722 | |||
723 | /* Enable video */ | ||
724 | if (!(cam->reg[0x01] & 0x04)) { | ||
725 | err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01); | ||
726 | if (err) { | ||
727 | err = -EIO; | ||
728 | DBG(1, "I/O hardware error") | ||
729 | goto free_urbs; | ||
730 | } | ||
731 | } | ||
732 | |||
733 | err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING); | ||
734 | if (err) { | ||
735 | DBG(1, "usb_set_interface() failed") | ||
736 | goto free_urbs; | ||
737 | } | ||
738 | |||
739 | cam->frame_current = NULL; | ||
740 | |||
741 | for (i = 0; i < SN9C102_URBS; i++) { | ||
742 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); | ||
743 | if (err) { | ||
744 | for (j = i-1; j >= 0; j--) | ||
745 | usb_kill_urb(cam->urb[j]); | ||
746 | DBG(1, "usb_submit_urb() failed, error %d", err) | ||
747 | goto free_urbs; | ||
748 | } | ||
749 | } | ||
750 | |||
751 | return 0; | ||
752 | |||
753 | free_urbs: | ||
754 | for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++) | ||
755 | usb_free_urb(cam->urb[i]); | ||
756 | |||
757 | free_buffers: | ||
758 | for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++) | ||
759 | kfree(cam->transfer_buffer[i]); | ||
760 | |||
761 | return err; | ||
762 | } | ||
763 | |||
764 | |||
765 | static int sn9c102_stop_transfer(struct sn9c102_device* cam) | ||
766 | { | ||
767 | struct usb_device *udev = cam->usbdev; | ||
768 | s8 i; | ||
769 | int err = 0; | ||
770 | |||
771 | if (cam->state & DEV_DISCONNECTED) | ||
772 | return 0; | ||
773 | |||
774 | for (i = SN9C102_URBS-1; i >= 0; i--) { | ||
775 | usb_kill_urb(cam->urb[i]); | ||
776 | usb_free_urb(cam->urb[i]); | ||
777 | kfree(cam->transfer_buffer[i]); | ||
778 | } | ||
779 | |||
780 | err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ | ||
781 | if (err) | ||
782 | DBG(3, "usb_set_interface() failed") | ||
783 | |||
784 | return err; | ||
785 | } | ||
786 | |||
787 | |||
788 | int sn9c102_stream_interrupt(struct sn9c102_device* cam) | ||
789 | { | ||
790 | int err = 0; | ||
791 | |||
792 | cam->stream = STREAM_INTERRUPT; | ||
793 | err = wait_event_timeout(cam->wait_stream, | ||
794 | (cam->stream == STREAM_OFF) || | ||
795 | (cam->state & DEV_DISCONNECTED), | ||
796 | SN9C102_URB_TIMEOUT); | ||
797 | if (cam->state & DEV_DISCONNECTED) | ||
798 | return -ENODEV; | ||
799 | else if (err) { | ||
800 | cam->state |= DEV_MISCONFIGURED; | ||
801 | DBG(1, "The camera is misconfigured. To use it, close and " | ||
802 | "open /dev/video%d again.", cam->v4ldev->minor) | ||
803 | return err; | ||
804 | } | ||
805 | |||
806 | return 0; | ||
807 | } | ||
808 | |||
809 | /*****************************************************************************/ | ||
810 | |||
811 | static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count) | ||
812 | { | ||
813 | char str[5]; | ||
814 | char* endp; | ||
815 | unsigned long val; | ||
816 | |||
817 | if (len < 4) { | ||
818 | strncpy(str, buff, len); | ||
819 | str[len+1] = '\0'; | ||
820 | } else { | ||
821 | strncpy(str, buff, 4); | ||
822 | str[4] = '\0'; | ||
823 | } | ||
824 | |||
825 | val = simple_strtoul(str, &endp, 0); | ||
826 | |||
827 | *count = 0; | ||
828 | if (val <= 0xff) | ||
829 | *count = (ssize_t)(endp - str); | ||
830 | if ((*count) && (len == *count+1) && (buff[*count] == '\n')) | ||
831 | *count += 1; | ||
832 | |||
833 | return (u8)val; | ||
834 | } | ||
835 | |||
836 | /* | ||
837 | NOTE 1: being inside one of the following methods implies that the v4l | ||
838 | device exists for sure (see kobjects and reference counters) | ||
839 | NOTE 2: buffers are PAGE_SIZE long | ||
840 | */ | ||
841 | |||
842 | static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) | ||
843 | { | ||
844 | struct sn9c102_device* cam; | ||
845 | ssize_t count; | ||
846 | |||
847 | if (down_interruptible(&sn9c102_sysfs_lock)) | ||
848 | return -ERESTARTSYS; | ||
849 | |||
850 | cam = video_get_drvdata(to_video_device(cd)); | ||
851 | if (!cam) { | ||
852 | up(&sn9c102_sysfs_lock); | ||
853 | return -ENODEV; | ||
854 | } | ||
855 | |||
856 | count = sprintf(buf, "%u\n", cam->sysfs.reg); | ||
857 | |||
858 | up(&sn9c102_sysfs_lock); | ||
859 | |||
860 | return count; | ||
861 | } | ||
862 | |||
863 | |||
864 | static ssize_t | ||
865 | sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) | ||
866 | { | ||
867 | struct sn9c102_device* cam; | ||
868 | u8 index; | ||
869 | ssize_t count; | ||
870 | |||
871 | if (down_interruptible(&sn9c102_sysfs_lock)) | ||
872 | return -ERESTARTSYS; | ||
873 | |||
874 | cam = video_get_drvdata(to_video_device(cd)); | ||
875 | if (!cam) { | ||
876 | up(&sn9c102_sysfs_lock); | ||
877 | return -ENODEV; | ||
878 | } | ||
879 | |||
880 | index = sn9c102_strtou8(buf, len, &count); | ||
881 | if (index > 0x1f || !count) { | ||
882 | up(&sn9c102_sysfs_lock); | ||
883 | return -EINVAL; | ||
884 | } | ||
885 | |||
886 | cam->sysfs.reg = index; | ||
887 | |||
888 | DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg) | ||
889 | DBG(3, "Written bytes: %zd", count) | ||
890 | |||
891 | up(&sn9c102_sysfs_lock); | ||
892 | |||
893 | return count; | ||
894 | } | ||
895 | |||
896 | |||
897 | static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) | ||
898 | { | ||
899 | struct sn9c102_device* cam; | ||
900 | ssize_t count; | ||
901 | int val; | ||
902 | |||
903 | if (down_interruptible(&sn9c102_sysfs_lock)) | ||
904 | return -ERESTARTSYS; | ||
905 | |||
906 | cam = video_get_drvdata(to_video_device(cd)); | ||
907 | if (!cam) { | ||
908 | up(&sn9c102_sysfs_lock); | ||
909 | return -ENODEV; | ||
910 | } | ||
911 | |||
912 | if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) { | ||
913 | up(&sn9c102_sysfs_lock); | ||
914 | return -EIO; | ||
915 | } | ||
916 | |||
917 | count = sprintf(buf, "%d\n", val); | ||
918 | |||
919 | DBG(3, "Read bytes: %zd", count) | ||
920 | |||
921 | up(&sn9c102_sysfs_lock); | ||
922 | |||
923 | return count; | ||
924 | } | ||
925 | |||
926 | |||
927 | static ssize_t | ||
928 | sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) | ||
929 | { | ||
930 | struct sn9c102_device* cam; | ||
931 | u8 value; | ||
932 | ssize_t count; | ||
933 | int err; | ||
934 | |||
935 | if (down_interruptible(&sn9c102_sysfs_lock)) | ||
936 | return -ERESTARTSYS; | ||
937 | |||
938 | cam = video_get_drvdata(to_video_device(cd)); | ||
939 | if (!cam) { | ||
940 | up(&sn9c102_sysfs_lock); | ||
941 | return -ENODEV; | ||
942 | } | ||
943 | |||
944 | value = sn9c102_strtou8(buf, len, &count); | ||
945 | if (!count) { | ||
946 | up(&sn9c102_sysfs_lock); | ||
947 | return -EINVAL; | ||
948 | } | ||
949 | |||
950 | err = sn9c102_write_reg(cam, value, cam->sysfs.reg); | ||
951 | if (err) { | ||
952 | up(&sn9c102_sysfs_lock); | ||
953 | return -EIO; | ||
954 | } | ||
955 | |||
956 | DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X", | ||
957 | cam->sysfs.reg, value) | ||
958 | DBG(3, "Written bytes: %zd", count) | ||
959 | |||
960 | up(&sn9c102_sysfs_lock); | ||
961 | |||
962 | return count; | ||
963 | } | ||
964 | |||
965 | |||
966 | static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) | ||
967 | { | ||
968 | struct sn9c102_device* cam; | ||
969 | ssize_t count; | ||
970 | |||
971 | if (down_interruptible(&sn9c102_sysfs_lock)) | ||
972 | return -ERESTARTSYS; | ||
973 | |||
974 | cam = video_get_drvdata(to_video_device(cd)); | ||
975 | if (!cam) { | ||
976 | up(&sn9c102_sysfs_lock); | ||
977 | return -ENODEV; | ||
978 | } | ||
979 | |||
980 | count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg); | ||
981 | |||
982 | DBG(3, "Read bytes: %zd", count) | ||
983 | |||
984 | up(&sn9c102_sysfs_lock); | ||
985 | |||
986 | return count; | ||
987 | } | ||
988 | |||
989 | |||
990 | static ssize_t | ||
991 | sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) | ||
992 | { | ||
993 | struct sn9c102_device* cam; | ||
994 | u8 index; | ||
995 | ssize_t count; | ||
996 | |||
997 | if (down_interruptible(&sn9c102_sysfs_lock)) | ||
998 | return -ERESTARTSYS; | ||
999 | |||
1000 | cam = video_get_drvdata(to_video_device(cd)); | ||
1001 | if (!cam) { | ||
1002 | up(&sn9c102_sysfs_lock); | ||
1003 | return -ENODEV; | ||
1004 | } | ||
1005 | |||
1006 | index = sn9c102_strtou8(buf, len, &count); | ||
1007 | if (!count) { | ||
1008 | up(&sn9c102_sysfs_lock); | ||
1009 | return -EINVAL; | ||
1010 | } | ||
1011 | |||
1012 | cam->sysfs.i2c_reg = index; | ||
1013 | |||
1014 | DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg) | ||
1015 | DBG(3, "Written bytes: %zd", count) | ||
1016 | |||
1017 | up(&sn9c102_sysfs_lock); | ||
1018 | |||
1019 | return count; | ||
1020 | } | ||
1021 | |||
1022 | |||
1023 | static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) | ||
1024 | { | ||
1025 | struct sn9c102_device* cam; | ||
1026 | ssize_t count; | ||
1027 | int val; | ||
1028 | |||
1029 | if (down_interruptible(&sn9c102_sysfs_lock)) | ||
1030 | return -ERESTARTSYS; | ||
1031 | |||
1032 | cam = video_get_drvdata(to_video_device(cd)); | ||
1033 | if (!cam) { | ||
1034 | up(&sn9c102_sysfs_lock); | ||
1035 | return -ENODEV; | ||
1036 | } | ||
1037 | |||
1038 | if (!(cam->sensor->sysfs_ops & SN9C102_I2C_READ)) { | ||
1039 | up(&sn9c102_sysfs_lock); | ||
1040 | return -ENOSYS; | ||
1041 | } | ||
1042 | |||
1043 | if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { | ||
1044 | up(&sn9c102_sysfs_lock); | ||
1045 | return -EIO; | ||
1046 | } | ||
1047 | |||
1048 | count = sprintf(buf, "%d\n", val); | ||
1049 | |||
1050 | DBG(3, "Read bytes: %zd", count) | ||
1051 | |||
1052 | up(&sn9c102_sysfs_lock); | ||
1053 | |||
1054 | return count; | ||
1055 | } | ||
1056 | |||
1057 | |||
1058 | static ssize_t | ||
1059 | sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) | ||
1060 | { | ||
1061 | struct sn9c102_device* cam; | ||
1062 | u8 value; | ||
1063 | ssize_t count; | ||
1064 | int err; | ||
1065 | |||
1066 | if (down_interruptible(&sn9c102_sysfs_lock)) | ||
1067 | return -ERESTARTSYS; | ||
1068 | |||
1069 | cam = video_get_drvdata(to_video_device(cd)); | ||
1070 | if (!cam) { | ||
1071 | up(&sn9c102_sysfs_lock); | ||
1072 | return -ENODEV; | ||
1073 | } | ||
1074 | |||
1075 | if (!(cam->sensor->sysfs_ops & SN9C102_I2C_WRITE)) { | ||
1076 | up(&sn9c102_sysfs_lock); | ||
1077 | return -ENOSYS; | ||
1078 | } | ||
1079 | |||
1080 | value = sn9c102_strtou8(buf, len, &count); | ||
1081 | if (!count) { | ||
1082 | up(&sn9c102_sysfs_lock); | ||
1083 | return -EINVAL; | ||
1084 | } | ||
1085 | |||
1086 | err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value); | ||
1087 | if (err) { | ||
1088 | up(&sn9c102_sysfs_lock); | ||
1089 | return -EIO; | ||
1090 | } | ||
1091 | |||
1092 | DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X", | ||
1093 | cam->sysfs.i2c_reg, value) | ||
1094 | DBG(3, "Written bytes: %zd", count) | ||
1095 | |||
1096 | up(&sn9c102_sysfs_lock); | ||
1097 | |||
1098 | return count; | ||
1099 | } | ||
1100 | |||
1101 | |||
1102 | static ssize_t | ||
1103 | sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) | ||
1104 | { | ||
1105 | struct sn9c102_device* cam; | ||
1106 | enum sn9c102_bridge bridge; | ||
1107 | ssize_t res = 0; | ||
1108 | u8 value; | ||
1109 | ssize_t count; | ||
1110 | |||
1111 | if (down_interruptible(&sn9c102_sysfs_lock)) | ||
1112 | return -ERESTARTSYS; | ||
1113 | |||
1114 | cam = video_get_drvdata(to_video_device(cd)); | ||
1115 | if (!cam) { | ||
1116 | up(&sn9c102_sysfs_lock); | ||
1117 | return -ENODEV; | ||
1118 | } | ||
1119 | |||
1120 | bridge = cam->bridge; | ||
1121 | |||
1122 | up(&sn9c102_sysfs_lock); | ||
1123 | |||
1124 | value = sn9c102_strtou8(buf, len, &count); | ||
1125 | if (!count) | ||
1126 | return -EINVAL; | ||
1127 | |||
1128 | switch (bridge) { | ||
1129 | case BRIDGE_SN9C101: | ||
1130 | case BRIDGE_SN9C102: | ||
1131 | if (value > 0x0f) | ||
1132 | return -EINVAL; | ||
1133 | if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0) | ||
1134 | res = sn9c102_store_val(cd, buf, len); | ||
1135 | break; | ||
1136 | case BRIDGE_SN9C103: | ||
1137 | if (value > 0x7f) | ||
1138 | return -EINVAL; | ||
1139 | if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0) | ||
1140 | res = sn9c102_store_val(cd, buf, len); | ||
1141 | break; | ||
1142 | } | ||
1143 | |||
1144 | return res; | ||
1145 | } | ||
1146 | |||
1147 | |||
1148 | static ssize_t | ||
1149 | sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len) | ||
1150 | { | ||
1151 | ssize_t res = 0; | ||
1152 | u8 value; | ||
1153 | ssize_t count; | ||
1154 | |||
1155 | value = sn9c102_strtou8(buf, len, &count); | ||
1156 | if (!count || value > 0x7f) | ||
1157 | return -EINVAL; | ||
1158 | |||
1159 | if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0) | ||
1160 | res = sn9c102_store_val(cd, buf, len); | ||
1161 | |||
1162 | return res; | ||
1163 | } | ||
1164 | |||
1165 | |||
1166 | static ssize_t | ||
1167 | sn9c102_store_red(struct class_device* cd, const char* buf, size_t len) | ||
1168 | { | ||
1169 | ssize_t res = 0; | ||
1170 | u8 value; | ||
1171 | ssize_t count; | ||
1172 | |||
1173 | value = sn9c102_strtou8(buf, len, &count); | ||
1174 | if (!count || value > 0x7f) | ||
1175 | return -EINVAL; | ||
1176 | |||
1177 | if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0) | ||
1178 | res = sn9c102_store_val(cd, buf, len); | ||
1179 | |||
1180 | return res; | ||
1181 | } | ||
1182 | |||
1183 | |||
1184 | static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf) | ||
1185 | { | ||
1186 | struct sn9c102_device* cam; | ||
1187 | ssize_t count; | ||
1188 | |||
1189 | cam = video_get_drvdata(to_video_device(cd)); | ||
1190 | if (!cam) | ||
1191 | return -ENODEV; | ||
1192 | |||
1193 | count = sizeof(cam->sysfs.frame_header); | ||
1194 | memcpy(buf, cam->sysfs.frame_header, count); | ||
1195 | |||
1196 | DBG(3, "Frame header, read bytes: %zd", count) | ||
1197 | |||
1198 | return count; | ||
1199 | } | ||
1200 | |||
1201 | |||
1202 | static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, | ||
1203 | sn9c102_show_reg, sn9c102_store_reg); | ||
1204 | static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, | ||
1205 | sn9c102_show_val, sn9c102_store_val); | ||
1206 | static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, | ||
1207 | sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); | ||
1208 | static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, | ||
1209 | sn9c102_show_i2c_val, sn9c102_store_i2c_val); | ||
1210 | static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); | ||
1211 | static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue); | ||
1212 | static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red); | ||
1213 | static CLASS_DEVICE_ATTR(frame_header, S_IRUGO, | ||
1214 | sn9c102_show_frame_header, NULL); | ||
1215 | |||
1216 | |||
1217 | static void sn9c102_create_sysfs(struct sn9c102_device* cam) | ||
1218 | { | ||
1219 | struct video_device *v4ldev = cam->v4ldev; | ||
1220 | |||
1221 | video_device_create_file(v4ldev, &class_device_attr_reg); | ||
1222 | video_device_create_file(v4ldev, &class_device_attr_val); | ||
1223 | video_device_create_file(v4ldev, &class_device_attr_frame_header); | ||
1224 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) | ||
1225 | video_device_create_file(v4ldev, &class_device_attr_green); | ||
1226 | else if (cam->bridge == BRIDGE_SN9C103) { | ||
1227 | video_device_create_file(v4ldev, &class_device_attr_blue); | ||
1228 | video_device_create_file(v4ldev, &class_device_attr_red); | ||
1229 | } | ||
1230 | if (cam->sensor->sysfs_ops) { | ||
1231 | video_device_create_file(v4ldev, &class_device_attr_i2c_reg); | ||
1232 | video_device_create_file(v4ldev, &class_device_attr_i2c_val); | ||
1233 | } | ||
1234 | } | ||
1235 | |||
1236 | /*****************************************************************************/ | ||
1237 | |||
1238 | static int | ||
1239 | sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix) | ||
1240 | { | ||
1241 | int err = 0; | ||
1242 | |||
1243 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
1244 | err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18); | ||
1245 | else | ||
1246 | err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18); | ||
1247 | |||
1248 | return err ? -EIO : 0; | ||
1249 | } | ||
1250 | |||
1251 | |||
1252 | static int | ||
1253 | sn9c102_set_compression(struct sn9c102_device* cam, | ||
1254 | struct v4l2_jpegcompression* compression) | ||
1255 | { | ||
1256 | int err = 0; | ||
1257 | |||
1258 | if (compression->quality == 0) | ||
1259 | err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17); | ||
1260 | else if (compression->quality == 1) | ||
1261 | err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17); | ||
1262 | |||
1263 | return err ? -EIO : 0; | ||
1264 | } | ||
1265 | |||
1266 | |||
1267 | static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale) | ||
1268 | { | ||
1269 | u8 r = 0; | ||
1270 | int err = 0; | ||
1271 | |||
1272 | if (scale == 1) | ||
1273 | r = cam->reg[0x18] & 0xcf; | ||
1274 | else if (scale == 2) { | ||
1275 | r = cam->reg[0x18] & 0xcf; | ||
1276 | r |= 0x10; | ||
1277 | } else if (scale == 4) | ||
1278 | r = cam->reg[0x18] | 0x20; | ||
1279 | |||
1280 | err += sn9c102_write_reg(cam, r, 0x18); | ||
1281 | if (err) | ||
1282 | return -EIO; | ||
1283 | |||
1284 | PDBGG("Scaling factor: %u", scale) | ||
1285 | |||
1286 | return 0; | ||
1287 | } | ||
1288 | |||
1289 | |||
1290 | static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect) | ||
1291 | { | ||
1292 | struct sn9c102_sensor* s = cam->sensor; | ||
1293 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left), | ||
1294 | v_start = (u8)(rect->top - s->cropcap.bounds.top), | ||
1295 | h_size = (u8)(rect->width / 16), | ||
1296 | v_size = (u8)(rect->height / 16); | ||
1297 | int err = 0; | ||
1298 | |||
1299 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
1300 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
1301 | err += sn9c102_write_reg(cam, h_size, 0x15); | ||
1302 | err += sn9c102_write_reg(cam, v_size, 0x16); | ||
1303 | if (err) | ||
1304 | return -EIO; | ||
1305 | |||
1306 | PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size " | ||
1307 | "%u %u %u %u", h_start, v_start, h_size, v_size) | ||
1308 | |||
1309 | return 0; | ||
1310 | } | ||
1311 | |||
1312 | |||
1313 | static int sn9c102_init(struct sn9c102_device* cam) | ||
1314 | { | ||
1315 | struct sn9c102_sensor* s = cam->sensor; | ||
1316 | struct v4l2_control ctrl; | ||
1317 | struct v4l2_queryctrl *qctrl; | ||
1318 | struct v4l2_rect* rect; | ||
1319 | u8 i = 0, n = 0; | ||
1320 | int err = 0; | ||
1321 | |||
1322 | if (!(cam->state & DEV_INITIALIZED)) { | ||
1323 | init_waitqueue_head(&cam->open); | ||
1324 | qctrl = s->qctrl; | ||
1325 | rect = &(s->cropcap.defrect); | ||
1326 | } else { /* use current values */ | ||
1327 | qctrl = s->_qctrl; | ||
1328 | rect = &(s->_rect); | ||
1329 | } | ||
1330 | |||
1331 | err += sn9c102_set_scale(cam, rect->width / s->pix_format.width); | ||
1332 | err += sn9c102_set_crop(cam, rect); | ||
1333 | if (err) | ||
1334 | return err; | ||
1335 | |||
1336 | if (s->init) { | ||
1337 | err = s->init(cam); | ||
1338 | if (err) { | ||
1339 | DBG(3, "Sensor initialization failed") | ||
1340 | return err; | ||
1341 | } | ||
1342 | } | ||
1343 | |||
1344 | if (!(cam->state & DEV_INITIALIZED)) | ||
1345 | cam->compression.quality = cam->reg[0x17] & 0x01 ? 0 : 1; | ||
1346 | else | ||
1347 | err += sn9c102_set_compression(cam, &cam->compression); | ||
1348 | err += sn9c102_set_pix_format(cam, &s->pix_format); | ||
1349 | if (s->set_pix_format) | ||
1350 | err += s->set_pix_format(cam, &s->pix_format); | ||
1351 | if (err) | ||
1352 | return err; | ||
1353 | |||
1354 | if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
1355 | DBG(3, "Compressed video format is active, quality %d", | ||
1356 | cam->compression.quality) | ||
1357 | else | ||
1358 | DBG(3, "Uncompressed video format is active") | ||
1359 | |||
1360 | if (s->set_crop) | ||
1361 | if ((err = s->set_crop(cam, rect))) { | ||
1362 | DBG(3, "set_crop() failed") | ||
1363 | return err; | ||
1364 | } | ||
1365 | |||
1366 | if (s->set_ctrl) { | ||
1367 | n = sizeof(s->qctrl) / sizeof(s->qctrl[0]); | ||
1368 | for (i = 0; i < n; i++) | ||
1369 | if (s->qctrl[i].id != 0 && | ||
1370 | !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { | ||
1371 | ctrl.id = s->qctrl[i].id; | ||
1372 | ctrl.value = qctrl[i].default_value; | ||
1373 | err = s->set_ctrl(cam, &ctrl); | ||
1374 | if (err) { | ||
1375 | DBG(3, "Set %s control failed", | ||
1376 | s->qctrl[i].name) | ||
1377 | return err; | ||
1378 | } | ||
1379 | DBG(3, "Image sensor supports '%s' control", | ||
1380 | s->qctrl[i].name) | ||
1381 | } | ||
1382 | } | ||
1383 | |||
1384 | if (!(cam->state & DEV_INITIALIZED)) { | ||
1385 | init_MUTEX(&cam->fileop_sem); | ||
1386 | spin_lock_init(&cam->queue_lock); | ||
1387 | init_waitqueue_head(&cam->wait_frame); | ||
1388 | init_waitqueue_head(&cam->wait_stream); | ||
1389 | cam->nreadbuffers = 2; | ||
1390 | memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); | ||
1391 | memcpy(&(s->_rect), &(s->cropcap.defrect), | ||
1392 | sizeof(struct v4l2_rect)); | ||
1393 | cam->state |= DEV_INITIALIZED; | ||
1394 | } | ||
1395 | |||
1396 | DBG(2, "Initialization succeeded") | ||
1397 | return 0; | ||
1398 | } | ||
1399 | |||
1400 | |||
1401 | static void sn9c102_release_resources(struct sn9c102_device* cam) | ||
1402 | { | ||
1403 | down(&sn9c102_sysfs_lock); | ||
1404 | |||
1405 | DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor) | ||
1406 | video_set_drvdata(cam->v4ldev, NULL); | ||
1407 | video_unregister_device(cam->v4ldev); | ||
1408 | |||
1409 | up(&sn9c102_sysfs_lock); | ||
1410 | |||
1411 | kfree(cam->control_buffer); | ||
1412 | } | ||
1413 | |||
1414 | /*****************************************************************************/ | ||
1415 | |||
1416 | static int sn9c102_open(struct inode* inode, struct file* filp) | ||
1417 | { | ||
1418 | struct sn9c102_device* cam; | ||
1419 | int err = 0; | ||
1420 | |||
1421 | /* | ||
1422 | This is the only safe way to prevent race conditions with | ||
1423 | disconnect | ||
1424 | */ | ||
1425 | if (!down_read_trylock(&sn9c102_disconnect)) | ||
1426 | return -ERESTARTSYS; | ||
1427 | |||
1428 | cam = video_get_drvdata(video_devdata(filp)); | ||
1429 | |||
1430 | if (down_interruptible(&cam->dev_sem)) { | ||
1431 | up_read(&sn9c102_disconnect); | ||
1432 | return -ERESTARTSYS; | ||
1433 | } | ||
1434 | |||
1435 | if (cam->users) { | ||
1436 | DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor) | ||
1437 | if ((filp->f_flags & O_NONBLOCK) || | ||
1438 | (filp->f_flags & O_NDELAY)) { | ||
1439 | err = -EWOULDBLOCK; | ||
1440 | goto out; | ||
1441 | } | ||
1442 | up(&cam->dev_sem); | ||
1443 | err = wait_event_interruptible_exclusive(cam->open, | ||
1444 | cam->state & DEV_DISCONNECTED | ||
1445 | || !cam->users); | ||
1446 | if (err) { | ||
1447 | up_read(&sn9c102_disconnect); | ||
1448 | return err; | ||
1449 | } | ||
1450 | if (cam->state & DEV_DISCONNECTED) { | ||
1451 | up_read(&sn9c102_disconnect); | ||
1452 | return -ENODEV; | ||
1453 | } | ||
1454 | down(&cam->dev_sem); | ||
1455 | } | ||
1456 | |||
1457 | |||
1458 | if (cam->state & DEV_MISCONFIGURED) { | ||
1459 | err = sn9c102_init(cam); | ||
1460 | if (err) { | ||
1461 | DBG(1, "Initialization failed again. " | ||
1462 | "I will retry on next open().") | ||
1463 | goto out; | ||
1464 | } | ||
1465 | cam->state &= ~DEV_MISCONFIGURED; | ||
1466 | } | ||
1467 | |||
1468 | if ((err = sn9c102_start_transfer(cam))) | ||
1469 | goto out; | ||
1470 | |||
1471 | filp->private_data = cam; | ||
1472 | cam->users++; | ||
1473 | cam->io = IO_NONE; | ||
1474 | cam->stream = STREAM_OFF; | ||
1475 | cam->nbuffers = 0; | ||
1476 | cam->frame_count = 0; | ||
1477 | sn9c102_empty_framequeues(cam); | ||
1478 | |||
1479 | DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor) | ||
1480 | |||
1481 | out: | ||
1482 | up(&cam->dev_sem); | ||
1483 | up_read(&sn9c102_disconnect); | ||
1484 | return err; | ||
1485 | } | ||
1486 | |||
1487 | |||
1488 | static int sn9c102_release(struct inode* inode, struct file* filp) | ||
1489 | { | ||
1490 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
1491 | |||
1492 | down(&cam->dev_sem); /* prevent disconnect() to be called */ | ||
1493 | |||
1494 | sn9c102_stop_transfer(cam); | ||
1495 | |||
1496 | sn9c102_release_buffers(cam); | ||
1497 | |||
1498 | if (cam->state & DEV_DISCONNECTED) { | ||
1499 | sn9c102_release_resources(cam); | ||
1500 | up(&cam->dev_sem); | ||
1501 | kfree(cam); | ||
1502 | return 0; | ||
1503 | } | ||
1504 | |||
1505 | cam->users--; | ||
1506 | wake_up_interruptible_nr(&cam->open, 1); | ||
1507 | |||
1508 | DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor) | ||
1509 | |||
1510 | up(&cam->dev_sem); | ||
1511 | |||
1512 | return 0; | ||
1513 | } | ||
1514 | |||
1515 | |||
1516 | static ssize_t | ||
1517 | sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | ||
1518 | { | ||
1519 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
1520 | struct sn9c102_frame_t* f, * i; | ||
1521 | unsigned long lock_flags; | ||
1522 | int err = 0; | ||
1523 | |||
1524 | if (down_interruptible(&cam->fileop_sem)) | ||
1525 | return -ERESTARTSYS; | ||
1526 | |||
1527 | if (cam->state & DEV_DISCONNECTED) { | ||
1528 | DBG(1, "Device not present") | ||
1529 | up(&cam->fileop_sem); | ||
1530 | return -ENODEV; | ||
1531 | } | ||
1532 | |||
1533 | if (cam->state & DEV_MISCONFIGURED) { | ||
1534 | DBG(1, "The camera is misconfigured. Close and open it again.") | ||
1535 | up(&cam->fileop_sem); | ||
1536 | return -EIO; | ||
1537 | } | ||
1538 | |||
1539 | if (cam->io == IO_MMAP) { | ||
1540 | DBG(3, "Close and open the device again to choose " | ||
1541 | "the read method") | ||
1542 | up(&cam->fileop_sem); | ||
1543 | return -EINVAL; | ||
1544 | } | ||
1545 | |||
1546 | if (cam->io == IO_NONE) { | ||
1547 | if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) { | ||
1548 | DBG(1, "read() failed, not enough memory") | ||
1549 | up(&cam->fileop_sem); | ||
1550 | return -ENOMEM; | ||
1551 | } | ||
1552 | cam->io = IO_READ; | ||
1553 | cam->stream = STREAM_ON; | ||
1554 | sn9c102_queue_unusedframes(cam); | ||
1555 | } | ||
1556 | |||
1557 | if (!count) { | ||
1558 | up(&cam->fileop_sem); | ||
1559 | return 0; | ||
1560 | } | ||
1561 | |||
1562 | if (list_empty(&cam->outqueue)) { | ||
1563 | if (filp->f_flags & O_NONBLOCK) { | ||
1564 | up(&cam->fileop_sem); | ||
1565 | return -EAGAIN; | ||
1566 | } | ||
1567 | err = wait_event_interruptible | ||
1568 | ( cam->wait_frame, | ||
1569 | (!list_empty(&cam->outqueue)) || | ||
1570 | (cam->state & DEV_DISCONNECTED) || | ||
1571 | (cam->state & DEV_MISCONFIGURED) ); | ||
1572 | if (err) { | ||
1573 | up(&cam->fileop_sem); | ||
1574 | return err; | ||
1575 | } | ||
1576 | if (cam->state & DEV_DISCONNECTED) { | ||
1577 | up(&cam->fileop_sem); | ||
1578 | return -ENODEV; | ||
1579 | } | ||
1580 | if (cam->state & DEV_MISCONFIGURED) { | ||
1581 | up(&cam->fileop_sem); | ||
1582 | return -EIO; | ||
1583 | } | ||
1584 | } | ||
1585 | |||
1586 | f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame); | ||
1587 | |||
1588 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
1589 | list_for_each_entry(i, &cam->outqueue, frame) | ||
1590 | i->state = F_UNUSED; | ||
1591 | INIT_LIST_HEAD(&cam->outqueue); | ||
1592 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
1593 | |||
1594 | sn9c102_queue_unusedframes(cam); | ||
1595 | |||
1596 | if (count > f->buf.bytesused) | ||
1597 | count = f->buf.bytesused; | ||
1598 | |||
1599 | if (copy_to_user(buf, f->bufmem, count)) { | ||
1600 | up(&cam->fileop_sem); | ||
1601 | return -EFAULT; | ||
1602 | } | ||
1603 | *f_pos += count; | ||
1604 | |||
1605 | PDBGG("Frame #%lu, bytes read: %zu", (unsigned long)f->buf.index,count) | ||
1606 | |||
1607 | up(&cam->fileop_sem); | ||
1608 | |||
1609 | return count; | ||
1610 | } | ||
1611 | |||
1612 | |||
1613 | static unsigned int sn9c102_poll(struct file *filp, poll_table *wait) | ||
1614 | { | ||
1615 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
1616 | unsigned int mask = 0; | ||
1617 | |||
1618 | if (down_interruptible(&cam->fileop_sem)) | ||
1619 | return POLLERR; | ||
1620 | |||
1621 | if (cam->state & DEV_DISCONNECTED) { | ||
1622 | DBG(1, "Device not present") | ||
1623 | goto error; | ||
1624 | } | ||
1625 | |||
1626 | if (cam->state & DEV_MISCONFIGURED) { | ||
1627 | DBG(1, "The camera is misconfigured. Close and open it again.") | ||
1628 | goto error; | ||
1629 | } | ||
1630 | |||
1631 | if (cam->io == IO_NONE) { | ||
1632 | if (!sn9c102_request_buffers(cam, cam->nreadbuffers, | ||
1633 | IO_READ)) { | ||
1634 | DBG(1, "poll() failed, not enough memory") | ||
1635 | goto error; | ||
1636 | } | ||
1637 | cam->io = IO_READ; | ||
1638 | cam->stream = STREAM_ON; | ||
1639 | } | ||
1640 | |||
1641 | if (cam->io == IO_READ) | ||
1642 | sn9c102_queue_unusedframes(cam); | ||
1643 | |||
1644 | poll_wait(filp, &cam->wait_frame, wait); | ||
1645 | |||
1646 | if (!list_empty(&cam->outqueue)) | ||
1647 | mask |= POLLIN | POLLRDNORM; | ||
1648 | |||
1649 | up(&cam->fileop_sem); | ||
1650 | |||
1651 | return mask; | ||
1652 | |||
1653 | error: | ||
1654 | up(&cam->fileop_sem); | ||
1655 | return POLLERR; | ||
1656 | } | ||
1657 | |||
1658 | |||
1659 | static void sn9c102_vm_open(struct vm_area_struct* vma) | ||
1660 | { | ||
1661 | struct sn9c102_frame_t* f = vma->vm_private_data; | ||
1662 | f->vma_use_count++; | ||
1663 | } | ||
1664 | |||
1665 | |||
1666 | static void sn9c102_vm_close(struct vm_area_struct* vma) | ||
1667 | { | ||
1668 | /* NOTE: buffers are not freed here */ | ||
1669 | struct sn9c102_frame_t* f = vma->vm_private_data; | ||
1670 | f->vma_use_count--; | ||
1671 | } | ||
1672 | |||
1673 | |||
1674 | static struct vm_operations_struct sn9c102_vm_ops = { | ||
1675 | .open = sn9c102_vm_open, | ||
1676 | .close = sn9c102_vm_close, | ||
1677 | }; | ||
1678 | |||
1679 | |||
1680 | static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) | ||
1681 | { | ||
1682 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
1683 | unsigned long size = vma->vm_end - vma->vm_start, | ||
1684 | start = vma->vm_start, | ||
1685 | pos, | ||
1686 | page; | ||
1687 | u32 i; | ||
1688 | |||
1689 | if (down_interruptible(&cam->fileop_sem)) | ||
1690 | return -ERESTARTSYS; | ||
1691 | |||
1692 | if (cam->state & DEV_DISCONNECTED) { | ||
1693 | DBG(1, "Device not present") | ||
1694 | up(&cam->fileop_sem); | ||
1695 | return -ENODEV; | ||
1696 | } | ||
1697 | |||
1698 | if (cam->state & DEV_MISCONFIGURED) { | ||
1699 | DBG(1, "The camera is misconfigured. Close and open it again.") | ||
1700 | up(&cam->fileop_sem); | ||
1701 | return -EIO; | ||
1702 | } | ||
1703 | |||
1704 | if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || | ||
1705 | size != PAGE_ALIGN(cam->frame[0].buf.length)) { | ||
1706 | up(&cam->fileop_sem); | ||
1707 | return -EINVAL; | ||
1708 | } | ||
1709 | |||
1710 | for (i = 0; i < cam->nbuffers; i++) { | ||
1711 | if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) | ||
1712 | break; | ||
1713 | } | ||
1714 | if (i == cam->nbuffers) { | ||
1715 | up(&cam->fileop_sem); | ||
1716 | return -EINVAL; | ||
1717 | } | ||
1718 | |||
1719 | /* VM_IO is eventually going to replace PageReserved altogether */ | ||
1720 | vma->vm_flags |= VM_IO; | ||
1721 | vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ | ||
1722 | |||
1723 | pos = (unsigned long)cam->frame[i].bufmem; | ||
1724 | while (size > 0) { /* size is page-aligned */ | ||
1725 | page = vmalloc_to_pfn((void *)pos); | ||
1726 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, | ||
1727 | vma->vm_page_prot)) { | ||
1728 | up(&cam->fileop_sem); | ||
1729 | return -EAGAIN; | ||
1730 | } | ||
1731 | start += PAGE_SIZE; | ||
1732 | pos += PAGE_SIZE; | ||
1733 | size -= PAGE_SIZE; | ||
1734 | } | ||
1735 | |||
1736 | vma->vm_ops = &sn9c102_vm_ops; | ||
1737 | vma->vm_private_data = &cam->frame[i]; | ||
1738 | |||
1739 | sn9c102_vm_open(vma); | ||
1740 | |||
1741 | up(&cam->fileop_sem); | ||
1742 | |||
1743 | return 0; | ||
1744 | } | ||
1745 | |||
1746 | |||
1747 | static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp, | ||
1748 | unsigned int cmd, void __user * arg) | ||
1749 | { | ||
1750 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
1751 | |||
1752 | switch (cmd) { | ||
1753 | |||
1754 | case VIDIOC_QUERYCAP: | ||
1755 | { | ||
1756 | struct v4l2_capability cap = { | ||
1757 | .driver = "sn9c102", | ||
1758 | .version = SN9C102_MODULE_VERSION_CODE, | ||
1759 | .capabilities = V4L2_CAP_VIDEO_CAPTURE | | ||
1760 | V4L2_CAP_READWRITE | | ||
1761 | V4L2_CAP_STREAMING, | ||
1762 | }; | ||
1763 | |||
1764 | strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); | ||
1765 | if (usb_make_path(cam->usbdev, cap.bus_info, | ||
1766 | sizeof(cap.bus_info)) < 0) | ||
1767 | strlcpy(cap.bus_info, cam->dev.bus_id, | ||
1768 | sizeof(cap.bus_info)); | ||
1769 | |||
1770 | if (copy_to_user(arg, &cap, sizeof(cap))) | ||
1771 | return -EFAULT; | ||
1772 | |||
1773 | return 0; | ||
1774 | } | ||
1775 | |||
1776 | case VIDIOC_ENUMINPUT: | ||
1777 | { | ||
1778 | struct v4l2_input i; | ||
1779 | |||
1780 | if (copy_from_user(&i, arg, sizeof(i))) | ||
1781 | return -EFAULT; | ||
1782 | |||
1783 | if (i.index) | ||
1784 | return -EINVAL; | ||
1785 | |||
1786 | memset(&i, 0, sizeof(i)); | ||
1787 | strcpy(i.name, "USB"); | ||
1788 | |||
1789 | if (copy_to_user(arg, &i, sizeof(i))) | ||
1790 | return -EFAULT; | ||
1791 | |||
1792 | return 0; | ||
1793 | } | ||
1794 | |||
1795 | case VIDIOC_G_INPUT: | ||
1796 | case VIDIOC_S_INPUT: | ||
1797 | { | ||
1798 | int index; | ||
1799 | |||
1800 | if (copy_from_user(&index, arg, sizeof(index))) | ||
1801 | return -EFAULT; | ||
1802 | |||
1803 | if (index != 0) | ||
1804 | return -EINVAL; | ||
1805 | |||
1806 | return 0; | ||
1807 | } | ||
1808 | |||
1809 | case VIDIOC_QUERYCTRL: | ||
1810 | { | ||
1811 | struct sn9c102_sensor* s = cam->sensor; | ||
1812 | struct v4l2_queryctrl qc; | ||
1813 | u8 i, n; | ||
1814 | |||
1815 | if (copy_from_user(&qc, arg, sizeof(qc))) | ||
1816 | return -EFAULT; | ||
1817 | |||
1818 | n = sizeof(s->qctrl) / sizeof(s->qctrl[0]); | ||
1819 | for (i = 0; i < n; i++) | ||
1820 | if (qc.id && qc.id == s->qctrl[i].id) { | ||
1821 | memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); | ||
1822 | if (copy_to_user(arg, &qc, sizeof(qc))) | ||
1823 | return -EFAULT; | ||
1824 | return 0; | ||
1825 | } | ||
1826 | |||
1827 | return -EINVAL; | ||
1828 | } | ||
1829 | |||
1830 | case VIDIOC_G_CTRL: | ||
1831 | { | ||
1832 | struct sn9c102_sensor* s = cam->sensor; | ||
1833 | struct v4l2_control ctrl; | ||
1834 | int err = 0; | ||
1835 | |||
1836 | if (!s->get_ctrl) | ||
1837 | return -EINVAL; | ||
1838 | |||
1839 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
1840 | return -EFAULT; | ||
1841 | |||
1842 | err = s->get_ctrl(cam, &ctrl); | ||
1843 | |||
1844 | if (copy_to_user(arg, &ctrl, sizeof(ctrl))) | ||
1845 | return -EFAULT; | ||
1846 | |||
1847 | return err; | ||
1848 | } | ||
1849 | |||
1850 | case VIDIOC_S_CTRL_OLD: | ||
1851 | case VIDIOC_S_CTRL: | ||
1852 | { | ||
1853 | struct sn9c102_sensor* s = cam->sensor; | ||
1854 | struct v4l2_control ctrl; | ||
1855 | u8 i, n; | ||
1856 | int err = 0; | ||
1857 | |||
1858 | if (!s->set_ctrl) | ||
1859 | return -EINVAL; | ||
1860 | |||
1861 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
1862 | return -EFAULT; | ||
1863 | |||
1864 | n = sizeof(s->qctrl) / sizeof(s->qctrl[0]); | ||
1865 | for (i = 0; i < n; i++) | ||
1866 | if (ctrl.id == s->qctrl[i].id) { | ||
1867 | if (ctrl.value < s->qctrl[i].minimum || | ||
1868 | ctrl.value > s->qctrl[i].maximum) | ||
1869 | return -ERANGE; | ||
1870 | ctrl.value -= ctrl.value % s->qctrl[i].step; | ||
1871 | break; | ||
1872 | } | ||
1873 | |||
1874 | if ((err = s->set_ctrl(cam, &ctrl))) | ||
1875 | return err; | ||
1876 | |||
1877 | s->_qctrl[i].default_value = ctrl.value; | ||
1878 | |||
1879 | PDBGG("VIDIOC_S_CTRL: id %lu, value %lu", | ||
1880 | (unsigned long)ctrl.id, (unsigned long)ctrl.value) | ||
1881 | |||
1882 | return 0; | ||
1883 | } | ||
1884 | |||
1885 | case VIDIOC_CROPCAP: | ||
1886 | { | ||
1887 | struct v4l2_cropcap* cc = &(cam->sensor->cropcap); | ||
1888 | |||
1889 | cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1890 | cc->pixelaspect.numerator = 1; | ||
1891 | cc->pixelaspect.denominator = 1; | ||
1892 | |||
1893 | if (copy_to_user(arg, cc, sizeof(*cc))) | ||
1894 | return -EFAULT; | ||
1895 | |||
1896 | return 0; | ||
1897 | } | ||
1898 | |||
1899 | case VIDIOC_G_CROP: | ||
1900 | { | ||
1901 | struct sn9c102_sensor* s = cam->sensor; | ||
1902 | struct v4l2_crop crop = { | ||
1903 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
1904 | }; | ||
1905 | |||
1906 | memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); | ||
1907 | |||
1908 | if (copy_to_user(arg, &crop, sizeof(crop))) | ||
1909 | return -EFAULT; | ||
1910 | |||
1911 | return 0; | ||
1912 | } | ||
1913 | |||
1914 | case VIDIOC_S_CROP: | ||
1915 | { | ||
1916 | struct sn9c102_sensor* s = cam->sensor; | ||
1917 | struct v4l2_crop crop; | ||
1918 | struct v4l2_rect* rect; | ||
1919 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
1920 | struct v4l2_pix_format* pix_format = &(s->pix_format); | ||
1921 | u8 scale; | ||
1922 | const enum sn9c102_stream_state stream = cam->stream; | ||
1923 | const u32 nbuffers = cam->nbuffers; | ||
1924 | u32 i; | ||
1925 | int err = 0; | ||
1926 | |||
1927 | if (copy_from_user(&crop, arg, sizeof(crop))) | ||
1928 | return -EFAULT; | ||
1929 | |||
1930 | rect = &(crop.c); | ||
1931 | |||
1932 | if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1933 | return -EINVAL; | ||
1934 | |||
1935 | if (cam->module_param.force_munmap) | ||
1936 | for (i = 0; i < cam->nbuffers; i++) | ||
1937 | if (cam->frame[i].vma_use_count) { | ||
1938 | DBG(3, "VIDIOC_S_CROP failed. " | ||
1939 | "Unmap the buffers first.") | ||
1940 | return -EINVAL; | ||
1941 | } | ||
1942 | |||
1943 | /* Preserve R,G or B origin */ | ||
1944 | rect->left = (s->_rect.left & 1L) ? | ||
1945 | rect->left | 1L : rect->left & ~1L; | ||
1946 | rect->top = (s->_rect.top & 1L) ? | ||
1947 | rect->top | 1L : rect->top & ~1L; | ||
1948 | |||
1949 | if (rect->width < 16) | ||
1950 | rect->width = 16; | ||
1951 | if (rect->height < 16) | ||
1952 | rect->height = 16; | ||
1953 | if (rect->width > bounds->width) | ||
1954 | rect->width = bounds->width; | ||
1955 | if (rect->height > bounds->height) | ||
1956 | rect->height = bounds->height; | ||
1957 | if (rect->left < bounds->left) | ||
1958 | rect->left = bounds->left; | ||
1959 | if (rect->top < bounds->top) | ||
1960 | rect->top = bounds->top; | ||
1961 | if (rect->left + rect->width > bounds->left + bounds->width) | ||
1962 | rect->left = bounds->left+bounds->width - rect->width; | ||
1963 | if (rect->top + rect->height > bounds->top + bounds->height) | ||
1964 | rect->top = bounds->top+bounds->height - rect->height; | ||
1965 | |||
1966 | rect->width &= ~15L; | ||
1967 | rect->height &= ~15L; | ||
1968 | |||
1969 | if (SN9C102_PRESERVE_IMGSCALE) { | ||
1970 | /* Calculate the actual scaling factor */ | ||
1971 | u32 a, b; | ||
1972 | a = rect->width * rect->height; | ||
1973 | b = pix_format->width * pix_format->height; | ||
1974 | scale = b ? (u8)((a / b) < 4 ? 1 : | ||
1975 | ((a / b) < 16 ? 2 : 4)) : 1; | ||
1976 | } else | ||
1977 | scale = 1; | ||
1978 | |||
1979 | if (cam->stream == STREAM_ON) | ||
1980 | if ((err = sn9c102_stream_interrupt(cam))) | ||
1981 | return err; | ||
1982 | |||
1983 | if (copy_to_user(arg, &crop, sizeof(crop))) { | ||
1984 | cam->stream = stream; | ||
1985 | return -EFAULT; | ||
1986 | } | ||
1987 | |||
1988 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
1989 | sn9c102_release_buffers(cam); | ||
1990 | |||
1991 | err = sn9c102_set_crop(cam, rect); | ||
1992 | if (s->set_crop) | ||
1993 | err += s->set_crop(cam, rect); | ||
1994 | err += sn9c102_set_scale(cam, scale); | ||
1995 | |||
1996 | if (err) { /* atomic, no rollback in ioctl() */ | ||
1997 | cam->state |= DEV_MISCONFIGURED; | ||
1998 | DBG(1, "VIDIOC_S_CROP failed because of hardware " | ||
1999 | "problems. To use the camera, close and open " | ||
2000 | "/dev/video%d again.", cam->v4ldev->minor) | ||
2001 | return -EIO; | ||
2002 | } | ||
2003 | |||
2004 | s->pix_format.width = rect->width/scale; | ||
2005 | s->pix_format.height = rect->height/scale; | ||
2006 | memcpy(&(s->_rect), rect, sizeof(*rect)); | ||
2007 | |||
2008 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
2009 | nbuffers != sn9c102_request_buffers(cam, nbuffers, | ||
2010 | cam->io)) { | ||
2011 | cam->state |= DEV_MISCONFIGURED; | ||
2012 | DBG(1, "VIDIOC_S_CROP failed because of not enough " | ||
2013 | "memory. To use the camera, close and open " | ||
2014 | "/dev/video%d again.", cam->v4ldev->minor) | ||
2015 | return -ENOMEM; | ||
2016 | } | ||
2017 | |||
2018 | cam->stream = stream; | ||
2019 | |||
2020 | return 0; | ||
2021 | } | ||
2022 | |||
2023 | case VIDIOC_ENUM_FMT: | ||
2024 | { | ||
2025 | struct v4l2_fmtdesc fmtd; | ||
2026 | |||
2027 | if (copy_from_user(&fmtd, arg, sizeof(fmtd))) | ||
2028 | return -EFAULT; | ||
2029 | |||
2030 | if (fmtd.index == 0) { | ||
2031 | strcpy(fmtd.description, "bayer rgb"); | ||
2032 | fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8; | ||
2033 | } else if (fmtd.index == 1) { | ||
2034 | strcpy(fmtd.description, "compressed"); | ||
2035 | fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; | ||
2036 | fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; | ||
2037 | } else | ||
2038 | return -EINVAL; | ||
2039 | |||
2040 | fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
2041 | memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); | ||
2042 | |||
2043 | if (copy_to_user(arg, &fmtd, sizeof(fmtd))) | ||
2044 | return -EFAULT; | ||
2045 | |||
2046 | return 0; | ||
2047 | } | ||
2048 | |||
2049 | case VIDIOC_G_FMT: | ||
2050 | { | ||
2051 | struct v4l2_format format; | ||
2052 | struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format); | ||
2053 | |||
2054 | if (copy_from_user(&format, arg, sizeof(format))) | ||
2055 | return -EFAULT; | ||
2056 | |||
2057 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2058 | return -EINVAL; | ||
2059 | |||
2060 | pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X) | ||
2061 | ? 0 : (pfmt->width * pfmt->priv) / 8; | ||
2062 | pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); | ||
2063 | pfmt->field = V4L2_FIELD_NONE; | ||
2064 | memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); | ||
2065 | |||
2066 | if (copy_to_user(arg, &format, sizeof(format))) | ||
2067 | return -EFAULT; | ||
2068 | |||
2069 | return 0; | ||
2070 | } | ||
2071 | |||
2072 | case VIDIOC_TRY_FMT: | ||
2073 | case VIDIOC_S_FMT: | ||
2074 | { | ||
2075 | struct sn9c102_sensor* s = cam->sensor; | ||
2076 | struct v4l2_format format; | ||
2077 | struct v4l2_pix_format* pix; | ||
2078 | struct v4l2_pix_format* pfmt = &(s->pix_format); | ||
2079 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
2080 | struct v4l2_rect rect; | ||
2081 | u8 scale; | ||
2082 | const enum sn9c102_stream_state stream = cam->stream; | ||
2083 | const u32 nbuffers = cam->nbuffers; | ||
2084 | u32 i; | ||
2085 | int err = 0; | ||
2086 | |||
2087 | if (copy_from_user(&format, arg, sizeof(format))) | ||
2088 | return -EFAULT; | ||
2089 | |||
2090 | pix = &(format.fmt.pix); | ||
2091 | |||
2092 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2093 | return -EINVAL; | ||
2094 | |||
2095 | memcpy(&rect, &(s->_rect), sizeof(rect)); | ||
2096 | |||
2097 | { /* calculate the actual scaling factor */ | ||
2098 | u32 a, b; | ||
2099 | a = rect.width * rect.height; | ||
2100 | b = pix->width * pix->height; | ||
2101 | scale = b ? (u8)((a / b) < 4 ? 1 : | ||
2102 | ((a / b) < 16 ? 2 : 4)) : 1; | ||
2103 | } | ||
2104 | |||
2105 | rect.width = scale * pix->width; | ||
2106 | rect.height = scale * pix->height; | ||
2107 | |||
2108 | if (rect.width < 16) | ||
2109 | rect.width = 16; | ||
2110 | if (rect.height < 16) | ||
2111 | rect.height = 16; | ||
2112 | if (rect.width > bounds->left + bounds->width - rect.left) | ||
2113 | rect.width = bounds->left + bounds->width - rect.left; | ||
2114 | if (rect.height > bounds->top + bounds->height - rect.top) | ||
2115 | rect.height = bounds->top + bounds->height - rect.top; | ||
2116 | |||
2117 | rect.width &= ~15L; | ||
2118 | rect.height &= ~15L; | ||
2119 | |||
2120 | { /* adjust the scaling factor */ | ||
2121 | u32 a, b; | ||
2122 | a = rect.width * rect.height; | ||
2123 | b = pix->width * pix->height; | ||
2124 | scale = b ? (u8)((a / b) < 4 ? 1 : | ||
2125 | ((a / b) < 16 ? 2 : 4)) : 1; | ||
2126 | } | ||
2127 | |||
2128 | pix->width = rect.width / scale; | ||
2129 | pix->height = rect.height / scale; | ||
2130 | |||
2131 | if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && | ||
2132 | pix->pixelformat != V4L2_PIX_FMT_SBGGR8) | ||
2133 | pix->pixelformat = pfmt->pixelformat; | ||
2134 | pix->priv = pfmt->priv; /* bpp */ | ||
2135 | pix->colorspace = pfmt->colorspace; | ||
2136 | pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
2137 | ? 0 : (pix->width * pix->priv) / 8; | ||
2138 | pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); | ||
2139 | pix->field = V4L2_FIELD_NONE; | ||
2140 | |||
2141 | if (cmd == VIDIOC_TRY_FMT) { | ||
2142 | if (copy_to_user(arg, &format, sizeof(format))) | ||
2143 | return -EFAULT; | ||
2144 | return 0; | ||
2145 | } | ||
2146 | |||
2147 | if (cam->module_param.force_munmap) | ||
2148 | for (i = 0; i < cam->nbuffers; i++) | ||
2149 | if (cam->frame[i].vma_use_count) { | ||
2150 | DBG(3, "VIDIOC_S_FMT failed. " | ||
2151 | "Unmap the buffers first.") | ||
2152 | return -EINVAL; | ||
2153 | } | ||
2154 | |||
2155 | if (cam->stream == STREAM_ON) | ||
2156 | if ((err = sn9c102_stream_interrupt(cam))) | ||
2157 | return err; | ||
2158 | |||
2159 | if (copy_to_user(arg, &format, sizeof(format))) { | ||
2160 | cam->stream = stream; | ||
2161 | return -EFAULT; | ||
2162 | } | ||
2163 | |||
2164 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
2165 | sn9c102_release_buffers(cam); | ||
2166 | |||
2167 | err += sn9c102_set_pix_format(cam, pix); | ||
2168 | err += sn9c102_set_crop(cam, &rect); | ||
2169 | if (s->set_pix_format) | ||
2170 | err += s->set_pix_format(cam, pix); | ||
2171 | if (s->set_crop) | ||
2172 | err += s->set_crop(cam, &rect); | ||
2173 | err += sn9c102_set_scale(cam, scale); | ||
2174 | |||
2175 | if (err) { /* atomic, no rollback in ioctl() */ | ||
2176 | cam->state |= DEV_MISCONFIGURED; | ||
2177 | DBG(1, "VIDIOC_S_FMT failed because of hardware " | ||
2178 | "problems. To use the camera, close and open " | ||
2179 | "/dev/video%d again.", cam->v4ldev->minor) | ||
2180 | return -EIO; | ||
2181 | } | ||
2182 | |||
2183 | memcpy(pfmt, pix, sizeof(*pix)); | ||
2184 | memcpy(&(s->_rect), &rect, sizeof(rect)); | ||
2185 | |||
2186 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
2187 | nbuffers != sn9c102_request_buffers(cam, nbuffers, | ||
2188 | cam->io)) { | ||
2189 | cam->state |= DEV_MISCONFIGURED; | ||
2190 | DBG(1, "VIDIOC_S_FMT failed because of not enough " | ||
2191 | "memory. To use the camera, close and open " | ||
2192 | "/dev/video%d again.", cam->v4ldev->minor) | ||
2193 | return -ENOMEM; | ||
2194 | } | ||
2195 | |||
2196 | cam->stream = stream; | ||
2197 | |||
2198 | return 0; | ||
2199 | } | ||
2200 | |||
2201 | case VIDIOC_G_JPEGCOMP: | ||
2202 | { | ||
2203 | if (copy_to_user(arg, &cam->compression, | ||
2204 | sizeof(cam->compression))) | ||
2205 | return -EFAULT; | ||
2206 | |||
2207 | return 0; | ||
2208 | } | ||
2209 | |||
2210 | case VIDIOC_S_JPEGCOMP: | ||
2211 | { | ||
2212 | struct v4l2_jpegcompression jc; | ||
2213 | const enum sn9c102_stream_state stream = cam->stream; | ||
2214 | int err = 0; | ||
2215 | |||
2216 | if (copy_from_user(&jc, arg, sizeof(jc))) | ||
2217 | return -EFAULT; | ||
2218 | |||
2219 | if (jc.quality != 0 && jc.quality != 1) | ||
2220 | return -EINVAL; | ||
2221 | |||
2222 | if (cam->stream == STREAM_ON) | ||
2223 | if ((err = sn9c102_stream_interrupt(cam))) | ||
2224 | return err; | ||
2225 | |||
2226 | err += sn9c102_set_compression(cam, &jc); | ||
2227 | if (err) { /* atomic, no rollback in ioctl() */ | ||
2228 | cam->state |= DEV_MISCONFIGURED; | ||
2229 | DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " | ||
2230 | "problems. To use the camera, close and open " | ||
2231 | "/dev/video%d again.", cam->v4ldev->minor) | ||
2232 | return -EIO; | ||
2233 | } | ||
2234 | |||
2235 | cam->compression.quality = jc.quality; | ||
2236 | |||
2237 | cam->stream = stream; | ||
2238 | |||
2239 | return 0; | ||
2240 | } | ||
2241 | |||
2242 | case VIDIOC_REQBUFS: | ||
2243 | { | ||
2244 | struct v4l2_requestbuffers rb; | ||
2245 | u32 i; | ||
2246 | int err; | ||
2247 | |||
2248 | if (copy_from_user(&rb, arg, sizeof(rb))) | ||
2249 | return -EFAULT; | ||
2250 | |||
2251 | if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
2252 | rb.memory != V4L2_MEMORY_MMAP) | ||
2253 | return -EINVAL; | ||
2254 | |||
2255 | if (cam->io == IO_READ) { | ||
2256 | DBG(3, "Close and open the device again to choose " | ||
2257 | "the mmap I/O method") | ||
2258 | return -EINVAL; | ||
2259 | } | ||
2260 | |||
2261 | for (i = 0; i < cam->nbuffers; i++) | ||
2262 | if (cam->frame[i].vma_use_count) { | ||
2263 | DBG(3, "VIDIOC_REQBUFS failed. " | ||
2264 | "Previous buffers are still mapped.") | ||
2265 | return -EINVAL; | ||
2266 | } | ||
2267 | |||
2268 | if (cam->stream == STREAM_ON) | ||
2269 | if ((err = sn9c102_stream_interrupt(cam))) | ||
2270 | return err; | ||
2271 | |||
2272 | sn9c102_empty_framequeues(cam); | ||
2273 | |||
2274 | sn9c102_release_buffers(cam); | ||
2275 | if (rb.count) | ||
2276 | rb.count = sn9c102_request_buffers(cam, rb.count, | ||
2277 | IO_MMAP); | ||
2278 | |||
2279 | if (copy_to_user(arg, &rb, sizeof(rb))) { | ||
2280 | sn9c102_release_buffers(cam); | ||
2281 | cam->io = IO_NONE; | ||
2282 | return -EFAULT; | ||
2283 | } | ||
2284 | |||
2285 | cam->io = rb.count ? IO_MMAP : IO_NONE; | ||
2286 | |||
2287 | return 0; | ||
2288 | } | ||
2289 | |||
2290 | case VIDIOC_QUERYBUF: | ||
2291 | { | ||
2292 | struct v4l2_buffer b; | ||
2293 | |||
2294 | if (copy_from_user(&b, arg, sizeof(b))) | ||
2295 | return -EFAULT; | ||
2296 | |||
2297 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
2298 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
2299 | return -EINVAL; | ||
2300 | |||
2301 | memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); | ||
2302 | |||
2303 | if (cam->frame[b.index].vma_use_count) | ||
2304 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
2305 | |||
2306 | if (cam->frame[b.index].state == F_DONE) | ||
2307 | b.flags |= V4L2_BUF_FLAG_DONE; | ||
2308 | else if (cam->frame[b.index].state != F_UNUSED) | ||
2309 | b.flags |= V4L2_BUF_FLAG_QUEUED; | ||
2310 | |||
2311 | if (copy_to_user(arg, &b, sizeof(b))) | ||
2312 | return -EFAULT; | ||
2313 | |||
2314 | return 0; | ||
2315 | } | ||
2316 | |||
2317 | case VIDIOC_QBUF: | ||
2318 | { | ||
2319 | struct v4l2_buffer b; | ||
2320 | unsigned long lock_flags; | ||
2321 | |||
2322 | if (copy_from_user(&b, arg, sizeof(b))) | ||
2323 | return -EFAULT; | ||
2324 | |||
2325 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
2326 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
2327 | return -EINVAL; | ||
2328 | |||
2329 | if (cam->frame[b.index].state != F_UNUSED) | ||
2330 | return -EINVAL; | ||
2331 | |||
2332 | cam->frame[b.index].state = F_QUEUED; | ||
2333 | |||
2334 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
2335 | list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); | ||
2336 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
2337 | |||
2338 | PDBGG("Frame #%lu queued", (unsigned long)b.index) | ||
2339 | |||
2340 | return 0; | ||
2341 | } | ||
2342 | |||
2343 | case VIDIOC_DQBUF: | ||
2344 | { | ||
2345 | struct v4l2_buffer b; | ||
2346 | struct sn9c102_frame_t *f; | ||
2347 | unsigned long lock_flags; | ||
2348 | int err = 0; | ||
2349 | |||
2350 | if (copy_from_user(&b, arg, sizeof(b))) | ||
2351 | return -EFAULT; | ||
2352 | |||
2353 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP) | ||
2354 | return -EINVAL; | ||
2355 | |||
2356 | if (list_empty(&cam->outqueue)) { | ||
2357 | if (cam->stream == STREAM_OFF) | ||
2358 | return -EINVAL; | ||
2359 | if (filp->f_flags & O_NONBLOCK) | ||
2360 | return -EAGAIN; | ||
2361 | err = wait_event_interruptible | ||
2362 | ( cam->wait_frame, | ||
2363 | (!list_empty(&cam->outqueue)) || | ||
2364 | (cam->state & DEV_DISCONNECTED) || | ||
2365 | (cam->state & DEV_MISCONFIGURED) ); | ||
2366 | if (err) | ||
2367 | return err; | ||
2368 | if (cam->state & DEV_DISCONNECTED) | ||
2369 | return -ENODEV; | ||
2370 | if (cam->state & DEV_MISCONFIGURED) | ||
2371 | return -EIO; | ||
2372 | } | ||
2373 | |||
2374 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
2375 | f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, | ||
2376 | frame); | ||
2377 | list_del(cam->outqueue.next); | ||
2378 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
2379 | |||
2380 | f->state = F_UNUSED; | ||
2381 | |||
2382 | memcpy(&b, &f->buf, sizeof(b)); | ||
2383 | if (f->vma_use_count) | ||
2384 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
2385 | |||
2386 | if (copy_to_user(arg, &b, sizeof(b))) | ||
2387 | return -EFAULT; | ||
2388 | |||
2389 | PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index) | ||
2390 | |||
2391 | return 0; | ||
2392 | } | ||
2393 | |||
2394 | case VIDIOC_STREAMON: | ||
2395 | { | ||
2396 | int type; | ||
2397 | |||
2398 | if (copy_from_user(&type, arg, sizeof(type))) | ||
2399 | return -EFAULT; | ||
2400 | |||
2401 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
2402 | return -EINVAL; | ||
2403 | |||
2404 | if (list_empty(&cam->inqueue)) | ||
2405 | return -EINVAL; | ||
2406 | |||
2407 | cam->stream = STREAM_ON; | ||
2408 | |||
2409 | DBG(3, "Stream on") | ||
2410 | |||
2411 | return 0; | ||
2412 | } | ||
2413 | |||
2414 | case VIDIOC_STREAMOFF: | ||
2415 | { | ||
2416 | int type, err; | ||
2417 | |||
2418 | if (copy_from_user(&type, arg, sizeof(type))) | ||
2419 | return -EFAULT; | ||
2420 | |||
2421 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
2422 | return -EINVAL; | ||
2423 | |||
2424 | if (cam->stream == STREAM_ON) | ||
2425 | if ((err = sn9c102_stream_interrupt(cam))) | ||
2426 | return err; | ||
2427 | |||
2428 | sn9c102_empty_framequeues(cam); | ||
2429 | |||
2430 | DBG(3, "Stream off") | ||
2431 | |||
2432 | return 0; | ||
2433 | } | ||
2434 | |||
2435 | case VIDIOC_G_PARM: | ||
2436 | { | ||
2437 | struct v4l2_streamparm sp; | ||
2438 | |||
2439 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
2440 | return -EFAULT; | ||
2441 | |||
2442 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2443 | return -EINVAL; | ||
2444 | |||
2445 | sp.parm.capture.extendedmode = 0; | ||
2446 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
2447 | |||
2448 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
2449 | return -EFAULT; | ||
2450 | |||
2451 | return 0; | ||
2452 | } | ||
2453 | |||
2454 | case VIDIOC_S_PARM_OLD: | ||
2455 | case VIDIOC_S_PARM: | ||
2456 | { | ||
2457 | struct v4l2_streamparm sp; | ||
2458 | |||
2459 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
2460 | return -EFAULT; | ||
2461 | |||
2462 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2463 | return -EINVAL; | ||
2464 | |||
2465 | sp.parm.capture.extendedmode = 0; | ||
2466 | |||
2467 | if (sp.parm.capture.readbuffers == 0) | ||
2468 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
2469 | |||
2470 | if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES) | ||
2471 | sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES; | ||
2472 | |||
2473 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
2474 | return -EFAULT; | ||
2475 | |||
2476 | cam->nreadbuffers = sp.parm.capture.readbuffers; | ||
2477 | |||
2478 | return 0; | ||
2479 | } | ||
2480 | |||
2481 | case VIDIOC_G_STD: | ||
2482 | case VIDIOC_S_STD: | ||
2483 | case VIDIOC_QUERYSTD: | ||
2484 | case VIDIOC_ENUMSTD: | ||
2485 | case VIDIOC_QUERYMENU: | ||
2486 | return -EINVAL; | ||
2487 | |||
2488 | default: | ||
2489 | return -EINVAL; | ||
2490 | |||
2491 | } | ||
2492 | } | ||
2493 | |||
2494 | |||
2495 | static int sn9c102_ioctl(struct inode* inode, struct file* filp, | ||
2496 | unsigned int cmd, unsigned long arg) | ||
2497 | { | ||
2498 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
2499 | int err = 0; | ||
2500 | |||
2501 | if (down_interruptible(&cam->fileop_sem)) | ||
2502 | return -ERESTARTSYS; | ||
2503 | |||
2504 | if (cam->state & DEV_DISCONNECTED) { | ||
2505 | DBG(1, "Device not present") | ||
2506 | up(&cam->fileop_sem); | ||
2507 | return -ENODEV; | ||
2508 | } | ||
2509 | |||
2510 | if (cam->state & DEV_MISCONFIGURED) { | ||
2511 | DBG(1, "The camera is misconfigured. Close and open it again.") | ||
2512 | up(&cam->fileop_sem); | ||
2513 | return -EIO; | ||
2514 | } | ||
2515 | |||
2516 | err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg); | ||
2517 | |||
2518 | up(&cam->fileop_sem); | ||
2519 | |||
2520 | return err; | ||
2521 | } | ||
2522 | |||
2523 | |||
2524 | static struct file_operations sn9c102_fops = { | ||
2525 | .owner = THIS_MODULE, | ||
2526 | .open = sn9c102_open, | ||
2527 | .release = sn9c102_release, | ||
2528 | .ioctl = sn9c102_ioctl, | ||
2529 | .read = sn9c102_read, | ||
2530 | .poll = sn9c102_poll, | ||
2531 | .mmap = sn9c102_mmap, | ||
2532 | .llseek = no_llseek, | ||
2533 | }; | ||
2534 | |||
2535 | /*****************************************************************************/ | ||
2536 | |||
2537 | /* It exists a single interface only. We do not need to validate anything. */ | ||
2538 | static int | ||
2539 | sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | ||
2540 | { | ||
2541 | struct usb_device *udev = interface_to_usbdev(intf); | ||
2542 | struct sn9c102_device* cam; | ||
2543 | static unsigned int dev_nr = 0; | ||
2544 | unsigned int i, n; | ||
2545 | int err = 0, r; | ||
2546 | |||
2547 | n = sizeof(sn9c102_id_table)/sizeof(sn9c102_id_table[0]); | ||
2548 | for (i = 0; i < n-1; i++) | ||
2549 | if (le16_to_cpu(udev->descriptor.idVendor) == | ||
2550 | sn9c102_id_table[i].idVendor && | ||
2551 | le16_to_cpu(udev->descriptor.idProduct) == | ||
2552 | sn9c102_id_table[i].idProduct) | ||
2553 | break; | ||
2554 | if (i == n-1) | ||
2555 | return -ENODEV; | ||
2556 | |||
2557 | if (!(cam = kmalloc(sizeof(struct sn9c102_device), GFP_KERNEL))) | ||
2558 | return -ENOMEM; | ||
2559 | memset(cam, 0, sizeof(*cam)); | ||
2560 | |||
2561 | cam->usbdev = udev; | ||
2562 | |||
2563 | memcpy(&cam->dev, &udev->dev, sizeof(struct device)); | ||
2564 | |||
2565 | if (!(cam->control_buffer = kmalloc(8, GFP_KERNEL))) { | ||
2566 | DBG(1, "kmalloc() failed") | ||
2567 | err = -ENOMEM; | ||
2568 | goto fail; | ||
2569 | } | ||
2570 | memset(cam->control_buffer, 0, 8); | ||
2571 | |||
2572 | if (!(cam->v4ldev = video_device_alloc())) { | ||
2573 | DBG(1, "video_device_alloc() failed") | ||
2574 | err = -ENOMEM; | ||
2575 | goto fail; | ||
2576 | } | ||
2577 | |||
2578 | init_MUTEX(&cam->dev_sem); | ||
2579 | |||
2580 | r = sn9c102_read_reg(cam, 0x00); | ||
2581 | if (r < 0 || r != 0x10) { | ||
2582 | DBG(1, "Sorry, this is not a SN9C10x based camera " | ||
2583 | "(vid/pid 0x%04X/0x%04X)", | ||
2584 | sn9c102_id_table[i].idVendor,sn9c102_id_table[i].idProduct) | ||
2585 | err = -ENODEV; | ||
2586 | goto fail; | ||
2587 | } | ||
2588 | |||
2589 | cam->bridge = (sn9c102_id_table[i].idProduct & 0xffc0) == 0x6080 ? | ||
2590 | BRIDGE_SN9C103 : BRIDGE_SN9C102; | ||
2591 | switch (cam->bridge) { | ||
2592 | case BRIDGE_SN9C101: | ||
2593 | case BRIDGE_SN9C102: | ||
2594 | DBG(2, "SN9C10[12] PC Camera Controller detected " | ||
2595 | "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor, | ||
2596 | sn9c102_id_table[i].idProduct) | ||
2597 | break; | ||
2598 | case BRIDGE_SN9C103: | ||
2599 | DBG(2, "SN9C103 PC Camera Controller detected " | ||
2600 | "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor, | ||
2601 | sn9c102_id_table[i].idProduct) | ||
2602 | break; | ||
2603 | } | ||
2604 | |||
2605 | for (i = 0; sn9c102_sensor_table[i]; i++) { | ||
2606 | err = sn9c102_sensor_table[i](cam); | ||
2607 | if (!err) | ||
2608 | break; | ||
2609 | } | ||
2610 | |||
2611 | if (!err && cam->sensor) { | ||
2612 | DBG(2, "%s image sensor detected", cam->sensor->name) | ||
2613 | DBG(3, "Support for %s maintained by %s", | ||
2614 | cam->sensor->name, cam->sensor->maintainer) | ||
2615 | } else { | ||
2616 | DBG(1, "No supported image sensor detected") | ||
2617 | err = -ENODEV; | ||
2618 | goto fail; | ||
2619 | } | ||
2620 | |||
2621 | if (sn9c102_init(cam)) { | ||
2622 | DBG(1, "Initialization failed. I will retry on open().") | ||
2623 | cam->state |= DEV_MISCONFIGURED; | ||
2624 | } | ||
2625 | |||
2626 | strcpy(cam->v4ldev->name, "SN9C10x PC Camera"); | ||
2627 | cam->v4ldev->owner = THIS_MODULE; | ||
2628 | cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; | ||
2629 | cam->v4ldev->hardware = VID_HARDWARE_SN9C102; | ||
2630 | cam->v4ldev->fops = &sn9c102_fops; | ||
2631 | cam->v4ldev->minor = video_nr[dev_nr]; | ||
2632 | cam->v4ldev->release = video_device_release; | ||
2633 | video_set_drvdata(cam->v4ldev, cam); | ||
2634 | |||
2635 | down(&cam->dev_sem); | ||
2636 | |||
2637 | err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, | ||
2638 | video_nr[dev_nr]); | ||
2639 | if (err) { | ||
2640 | DBG(1, "V4L2 device registration failed") | ||
2641 | if (err == -ENFILE && video_nr[dev_nr] == -1) | ||
2642 | DBG(1, "Free /dev/videoX node not found") | ||
2643 | video_nr[dev_nr] = -1; | ||
2644 | dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
2645 | up(&cam->dev_sem); | ||
2646 | goto fail; | ||
2647 | } | ||
2648 | |||
2649 | DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor) | ||
2650 | |||
2651 | cam->module_param.force_munmap = force_munmap[dev_nr]; | ||
2652 | |||
2653 | dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
2654 | |||
2655 | sn9c102_create_sysfs(cam); | ||
2656 | DBG(2, "Optional device control through 'sysfs' interface ready") | ||
2657 | |||
2658 | usb_set_intfdata(intf, cam); | ||
2659 | |||
2660 | up(&cam->dev_sem); | ||
2661 | |||
2662 | return 0; | ||
2663 | |||
2664 | fail: | ||
2665 | if (cam) { | ||
2666 | kfree(cam->control_buffer); | ||
2667 | if (cam->v4ldev) | ||
2668 | video_device_release(cam->v4ldev); | ||
2669 | kfree(cam); | ||
2670 | } | ||
2671 | return err; | ||
2672 | } | ||
2673 | |||
2674 | |||
2675 | static void sn9c102_usb_disconnect(struct usb_interface* intf) | ||
2676 | { | ||
2677 | struct sn9c102_device* cam = usb_get_intfdata(intf); | ||
2678 | |||
2679 | if (!cam) | ||
2680 | return; | ||
2681 | |||
2682 | down_write(&sn9c102_disconnect); | ||
2683 | |||
2684 | down(&cam->dev_sem); | ||
2685 | |||
2686 | DBG(2, "Disconnecting %s...", cam->v4ldev->name) | ||
2687 | |||
2688 | wake_up_interruptible_all(&cam->open); | ||
2689 | |||
2690 | if (cam->users) { | ||
2691 | DBG(2, "Device /dev/video%d is open! Deregistration and " | ||
2692 | "memory deallocation are deferred on close.", | ||
2693 | cam->v4ldev->minor) | ||
2694 | cam->state |= DEV_MISCONFIGURED; | ||
2695 | sn9c102_stop_transfer(cam); | ||
2696 | cam->state |= DEV_DISCONNECTED; | ||
2697 | wake_up_interruptible(&cam->wait_frame); | ||
2698 | wake_up_interruptible(&cam->wait_stream); | ||
2699 | } else { | ||
2700 | cam->state |= DEV_DISCONNECTED; | ||
2701 | sn9c102_release_resources(cam); | ||
2702 | } | ||
2703 | |||
2704 | up(&cam->dev_sem); | ||
2705 | |||
2706 | if (!cam->users) | ||
2707 | kfree(cam); | ||
2708 | |||
2709 | up_write(&sn9c102_disconnect); | ||
2710 | } | ||
2711 | |||
2712 | |||
2713 | static struct usb_driver sn9c102_usb_driver = { | ||
2714 | .owner = THIS_MODULE, | ||
2715 | .name = "sn9c102", | ||
2716 | .id_table = sn9c102_id_table, | ||
2717 | .probe = sn9c102_usb_probe, | ||
2718 | .disconnect = sn9c102_usb_disconnect, | ||
2719 | }; | ||
2720 | |||
2721 | /*****************************************************************************/ | ||
2722 | |||
2723 | static int __init sn9c102_module_init(void) | ||
2724 | { | ||
2725 | int err = 0; | ||
2726 | |||
2727 | KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION) | ||
2728 | KDBG(3, SN9C102_MODULE_AUTHOR) | ||
2729 | |||
2730 | if ((err = usb_register(&sn9c102_usb_driver))) | ||
2731 | KDBG(1, "usb_register() failed") | ||
2732 | |||
2733 | return err; | ||
2734 | } | ||
2735 | |||
2736 | |||
2737 | static void __exit sn9c102_module_exit(void) | ||
2738 | { | ||
2739 | usb_deregister(&sn9c102_usb_driver); | ||
2740 | } | ||
2741 | |||
2742 | |||
2743 | module_init(sn9c102_module_init); | ||
2744 | module_exit(sn9c102_module_exit); | ||
diff --git a/drivers/usb/media/sn9c102_hv7131d.c b/drivers/usb/media/sn9c102_hv7131d.c new file mode 100644 index 000000000000..18070d5333cf --- /dev/null +++ b/drivers/usb/media/sn9c102_hv7131d.c | |||
@@ -0,0 +1,271 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004-2005 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 new file mode 100644 index 000000000000..86676abf3547 --- /dev/null +++ b/drivers/usb/media/sn9c102_mi0343.c | |||
@@ -0,0 +1,363 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004-2005 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_pas106b.c b/drivers/usb/media/sn9c102_pas106b.c new file mode 100644 index 000000000000..48e3ec39d4e2 --- /dev/null +++ b/drivers/usb/media/sn9c102_pas106b.c | |||
@@ -0,0 +1,307 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004-2005 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_pas202bcb.c b/drivers/usb/media/sn9c102_pas202bcb.c new file mode 100644 index 000000000000..5ca54c7daaf2 --- /dev/null +++ b/drivers/usb/media/sn9c102_pas202bcb.c | |||
@@ -0,0 +1,293 @@ | |||
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 new file mode 100644 index 000000000000..16f7483559f0 --- /dev/null +++ b/drivers/usb/media/sn9c102_sensor.h | |||
@@ -0,0 +1,373 @@ | |||
1 | /*************************************************************************** | ||
2 | * API for image sensors connected to the SN9C10x PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2004-2005 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_pas106b(struct sn9c102_device* cam); | ||
68 | extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); | ||
69 | extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); | ||
70 | extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); | ||
71 | |||
72 | /* | ||
73 | Add the above entries to this table. Be sure to add the entry in the right | ||
74 | place, since, on failure, the next probing routine is called according to | ||
75 | the order of the list below, from top to bottom. | ||
76 | */ | ||
77 | #define SN9C102_SENSOR_TABLE \ | ||
78 | static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \ | ||
79 | &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ \ | ||
80 | &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \ | ||
81 | &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \ | ||
82 | &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ \ | ||
83 | &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \ | ||
84 | &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \ | ||
85 | NULL, \ | ||
86 | }; | ||
87 | |||
88 | /* Attach a probed sensor to the camera. */ | ||
89 | extern void | ||
90 | sn9c102_attach_sensor(struct sn9c102_device* cam, | ||
91 | struct sn9c102_sensor* sensor); | ||
92 | |||
93 | /* Each SN9C10X camera has proper PID/VID identifiers. Add them here in case.*/ | ||
94 | #define SN9C102_ID_TABLE \ | ||
95 | static const struct usb_device_id sn9c102_id_table[] = { \ | ||
96 | { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */ \ | ||
97 | { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */ \ | ||
98 | { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */ \ | ||
99 | { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */ \ | ||
100 | { USB_DEVICE(0x0c45, 0x6024), }, \ | ||
101 | { USB_DEVICE(0x0c45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */ \ | ||
102 | { USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */ \ | ||
103 | { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \ | ||
104 | { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */ \ | ||
105 | { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */ \ | ||
106 | { USB_DEVICE(0x0c45, 0x602c), }, /* OV7620 */ \ | ||
107 | { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \ | ||
108 | { USB_DEVICE(0x0c45, 0x6080), }, \ | ||
109 | { USB_DEVICE(0x0c45, 0x6082), }, /* MI0343 and MI0360 */ \ | ||
110 | { USB_DEVICE(0x0c45, 0x6083), }, /* HV7131[D|E1] */ \ | ||
111 | { USB_DEVICE(0x0c45, 0x6088), }, \ | ||
112 | { USB_DEVICE(0x0c45, 0x608a), }, \ | ||
113 | { USB_DEVICE(0x0c45, 0x608b), }, \ | ||
114 | { USB_DEVICE(0x0c45, 0x608c), }, /* HV7131x */ \ | ||
115 | { USB_DEVICE(0x0c45, 0x608e), }, /* CIS-VF10 */ \ | ||
116 | { USB_DEVICE(0x0c45, 0x608f), }, /* OV7630 */ \ | ||
117 | { USB_DEVICE(0x0c45, 0x60a0), }, \ | ||
118 | { USB_DEVICE(0x0c45, 0x60a2), }, \ | ||
119 | { USB_DEVICE(0x0c45, 0x60a3), }, \ | ||
120 | { USB_DEVICE(0x0c45, 0x60a8), }, /* PAS106B */ \ | ||
121 | { USB_DEVICE(0x0c45, 0x60aa), }, /* TAS5130D1B */ \ | ||
122 | { USB_DEVICE(0x0c45, 0x60ab), }, /* TAS5110C1B */ \ | ||
123 | { USB_DEVICE(0x0c45, 0x60ac), }, \ | ||
124 | { USB_DEVICE(0x0c45, 0x60ae), }, \ | ||
125 | { USB_DEVICE(0x0c45, 0x60af), }, /* PAS202BCB */ \ | ||
126 | { USB_DEVICE(0x0c45, 0x60b0), }, \ | ||
127 | { USB_DEVICE(0x0c45, 0x60b2), }, \ | ||
128 | { USB_DEVICE(0x0c45, 0x60b3), }, \ | ||
129 | { USB_DEVICE(0x0c45, 0x60b8), }, \ | ||
130 | { USB_DEVICE(0x0c45, 0x60ba), }, \ | ||
131 | { USB_DEVICE(0x0c45, 0x60bb), }, \ | ||
132 | { USB_DEVICE(0x0c45, 0x60bc), }, \ | ||
133 | { USB_DEVICE(0x0c45, 0x60be), }, \ | ||
134 | { } \ | ||
135 | }; | ||
136 | |||
137 | /*****************************************************************************/ | ||
138 | |||
139 | /* | ||
140 | Read/write routines: they always return -1 on error, 0 or the read value | ||
141 | otherwise. NOTE that a real read operation is not supported by the SN9C10X | ||
142 | chip for some of its registers. To work around this problem, a pseudo-read | ||
143 | call is provided instead: it returns the last successfully written value | ||
144 | on the register (0 if it has never been written), the usual -1 on error. | ||
145 | */ | ||
146 | |||
147 | /* The "try" I2C I/O versions are used when probing the sensor */ | ||
148 | extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*, | ||
149 | u8 address, u8 value); | ||
150 | extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*, | ||
151 | u8 address); | ||
152 | |||
153 | /* | ||
154 | These must be used if and only if the sensor doesn't implement the standard | ||
155 | I2C protocol. There are a number of good reasons why you must use the | ||
156 | single-byte versions of these functions: do not abuse. The first function | ||
157 | writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C10X | ||
158 | chip. The second one programs the registers 0x09 and 0x10 with data0 and | ||
159 | data1, and places the n bytes read from the sensor register table in the | ||
160 | buffer pointed by 'buffer'. Both the functions return -1 on error; the write | ||
161 | version returns 0 on success, while the read version returns the first read | ||
162 | byte. | ||
163 | */ | ||
164 | extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, | ||
165 | struct sn9c102_sensor* sensor, u8 n, | ||
166 | u8 data0, u8 data1, u8 data2, u8 data3, | ||
167 | u8 data4, u8 data5); | ||
168 | extern int sn9c102_i2c_try_raw_read(struct sn9c102_device* cam, | ||
169 | struct sn9c102_sensor* sensor, u8 data0, | ||
170 | u8 data1, u8 n, u8 buffer[]); | ||
171 | |||
172 | /* To be used after the sensor struct has been attached to the camera struct */ | ||
173 | extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value); | ||
174 | extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address); | ||
175 | |||
176 | /* I/O on registers in the bridge. Could be used by the sensor methods too */ | ||
177 | extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); | ||
178 | extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); | ||
179 | |||
180 | /* | ||
181 | NOTE: there are no exported debugging functions. To uniform the output you | ||
182 | must use the dev_info()/dev_warn()/dev_err() macros defined in device.h, | ||
183 | already included here, the argument being the struct device 'dev' of the | ||
184 | sensor structure. Do NOT use these macros before the sensor is attached or | ||
185 | the kernel will crash! However, you should not need to notify the user about | ||
186 | common errors or other messages, since this is done by the master module. | ||
187 | */ | ||
188 | |||
189 | /*****************************************************************************/ | ||
190 | |||
191 | enum sn9c102_i2c_sysfs_ops { | ||
192 | SN9C102_I2C_READ = 0x01, | ||
193 | SN9C102_I2C_WRITE = 0x02, | ||
194 | }; | ||
195 | |||
196 | enum sn9c102_i2c_frequency { /* sensors may support both the frequencies */ | ||
197 | SN9C102_I2C_100KHZ = 0x01, | ||
198 | SN9C102_I2C_400KHZ = 0x02, | ||
199 | }; | ||
200 | |||
201 | enum sn9c102_i2c_interface { | ||
202 | SN9C102_I2C_2WIRES, | ||
203 | SN9C102_I2C_3WIRES, | ||
204 | }; | ||
205 | |||
206 | struct sn9c102_sensor { | ||
207 | char name[32], /* sensor name */ | ||
208 | maintainer[64]; /* name of the mantainer <email> */ | ||
209 | |||
210 | /* Supported operations through the 'sysfs' interface */ | ||
211 | enum sn9c102_i2c_sysfs_ops sysfs_ops; | ||
212 | |||
213 | /* | ||
214 | These sensor capabilities must be provided if the SN9C10X controller | ||
215 | needs to communicate through the sensor serial interface by using | ||
216 | at least one of the i2c functions available. | ||
217 | */ | ||
218 | enum sn9c102_i2c_frequency frequency; | ||
219 | enum sn9c102_i2c_interface interface; | ||
220 | |||
221 | /* | ||
222 | This identifier must be provided if the image sensor implements | ||
223 | the standard I2C protocol. | ||
224 | */ | ||
225 | u8 i2c_slave_id; /* reg. 0x09 */ | ||
226 | |||
227 | /* | ||
228 | NOTE: Where not noted,most of the functions below are not mandatory. | ||
229 | Set to null if you do not implement them. If implemented, | ||
230 | they must return 0 on success, the proper error otherwise. | ||
231 | */ | ||
232 | |||
233 | int (*init)(struct sn9c102_device* cam); | ||
234 | /* | ||
235 | This function will be called after the sensor has been attached. | ||
236 | It should be used to initialize the sensor only, but may also | ||
237 | configure part of the SN9C10X chip if necessary. You don't need to | ||
238 | setup picture settings like brightness, contrast, etc.. here, if | ||
239 | the corrisponding controls are implemented (see below), since | ||
240 | they are adjusted in the core driver by calling the set_ctrl() | ||
241 | method after init(), where the arguments are the default values | ||
242 | specified in the v4l2_queryctrl list of supported controls; | ||
243 | Same suggestions apply for other settings, _if_ the corresponding | ||
244 | methods are present; if not, the initialization must configure the | ||
245 | sensor according to the default configuration structures below. | ||
246 | */ | ||
247 | |||
248 | struct v4l2_queryctrl qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; | ||
249 | /* | ||
250 | Optional list of default controls, defined as indicated in the | ||
251 | V4L2 API. Menu type controls are not handled by this interface. | ||
252 | */ | ||
253 | |||
254 | int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl); | ||
255 | int (*set_ctrl)(struct sn9c102_device* cam, | ||
256 | const struct v4l2_control* ctrl); | ||
257 | /* | ||
258 | You must implement at least the set_ctrl method if you have defined | ||
259 | the list above. The returned value must follow the V4L2 | ||
260 | specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER | ||
261 | are not supported by this driver, so do not implement them. Also, | ||
262 | you don't have to check whether the passed values are out of bounds, | ||
263 | given that this is done by the core module. | ||
264 | */ | ||
265 | |||
266 | struct v4l2_cropcap cropcap; | ||
267 | /* | ||
268 | Think the image sensor as a grid of R,G,B monochromatic pixels | ||
269 | disposed according to a particular Bayer pattern, which describes | ||
270 | the complete array of pixels, from (0,0) to (xmax, ymax). We will | ||
271 | use this coordinate system from now on. It is assumed the sensor | ||
272 | chip can be programmed to capture/transmit a subsection of that | ||
273 | array of pixels: we will call this subsection "active window". | ||
274 | It is not always true that the largest achievable active window can | ||
275 | cover the whole array of pixels. The V4L2 API defines another | ||
276 | area called "source rectangle", which, in turn, is a subrectangle of | ||
277 | the active window. The SN9C10X chip is always programmed to read the | ||
278 | source rectangle. | ||
279 | The bounds of both the active window and the source rectangle are | ||
280 | specified in the cropcap substructures 'bounds' and 'defrect'. | ||
281 | By default, the source rectangle should cover the largest possible | ||
282 | area. Again, it is not always true that the largest source rectangle | ||
283 | can cover the entire active window, although it is a rare case for | ||
284 | the hardware we have. The bounds of the source rectangle _must_ be | ||
285 | multiple of 16 and must use the same coordinate system as indicated | ||
286 | before; their centers shall align initially. | ||
287 | If necessary, the sensor chip must be initialized during init() to | ||
288 | set the bounds of the active sensor window; however, by default, it | ||
289 | usually covers the largest achievable area (maxwidth x maxheight) | ||
290 | of pixels, so no particular initialization is needed, if you have | ||
291 | defined the correct default bounds in the structures. | ||
292 | See the V4L2 API for further details. | ||
293 | NOTE: once you have defined the bounds of the active window | ||
294 | (struct cropcap.bounds) you must not change them.anymore. | ||
295 | Only 'bounds' and 'defrect' fields are mandatory, other fields | ||
296 | will be ignored. | ||
297 | */ | ||
298 | |||
299 | int (*set_crop)(struct sn9c102_device* cam, | ||
300 | const struct v4l2_rect* rect); | ||
301 | /* | ||
302 | To be called on VIDIOC_C_SETCROP. The core module always calls a | ||
303 | default routine which configures the appropriate SN9C10X regs (also | ||
304 | scaling), but you may need to override/adjust specific stuff. | ||
305 | 'rect' contains width and height values that are multiple of 16: in | ||
306 | case you override the default function, you always have to program | ||
307 | the chip to match those values; on error return the corresponding | ||
308 | error code without rolling back. | ||
309 | NOTE: in case, you must program the SN9C10X chip to get rid of | ||
310 | blank pixels or blank lines at the _start_ of each line or | ||
311 | frame after each HSYNC or VSYNC, so that the image starts with | ||
312 | real RGB data (see regs 0x12, 0x13) (having set H_SIZE and, | ||
313 | V_SIZE you don't have to care about blank pixels or blank | ||
314 | lines at the end of each line or frame). | ||
315 | */ | ||
316 | |||
317 | struct v4l2_pix_format pix_format; | ||
318 | /* | ||
319 | What you have to define here are: 1) initial 'width' and 'height' of | ||
320 | the target rectangle 2) the initial 'pixelformat', which can be | ||
321 | either V4L2_PIX_FMT_SN9C10X (for compressed video) or | ||
322 | V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the | ||
323 | number of bits per pixel for uncompressed video, 8 or 9 (despite the | ||
324 | current value of 'pixelformat'). | ||
325 | NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4 | ||
326 | of cropcap.defrect.width and cropcap.defrect.height. I | ||
327 | suggest 1/1. | ||
328 | NOTE 2: The initial compression quality is defined by the first bit | ||
329 | of reg 0x17 during the initialization of the image sensor. | ||
330 | NOTE 3: as said above, you have to program the SN9C10X chip to get | ||
331 | rid of any blank pixels, so that the output of the sensor | ||
332 | matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). | ||
333 | */ | ||
334 | |||
335 | int (*set_pix_format)(struct sn9c102_device* cam, | ||
336 | const struct v4l2_pix_format* pix); | ||
337 | /* | ||
338 | To be called on VIDIOC_S_FMT, when switching from the SBGGR8 to | ||
339 | SN9C10X pixel format or viceversa. On error return the corresponding | ||
340 | error code without rolling back. | ||
341 | */ | ||
342 | |||
343 | const struct device* dev; | ||
344 | /* | ||
345 | This is the argument for dev_err(), dev_info() and dev_warn(). It | ||
346 | is used for debugging purposes. You must not access the struct | ||
347 | before the sensor is attached. | ||
348 | */ | ||
349 | |||
350 | const struct usb_device* usbdev; | ||
351 | /* | ||
352 | Points to the usb_device struct after the sensor is attached. | ||
353 | Do not touch unless you know what you are doing. | ||
354 | */ | ||
355 | |||
356 | /* | ||
357 | Do NOT write to the data below, it's READ ONLY. It is used by the | ||
358 | core module to store successfully updated values of the above | ||
359 | settings, for rollbacks..etc..in case of errors during atomic I/O | ||
360 | */ | ||
361 | struct v4l2_queryctrl _qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; | ||
362 | struct v4l2_rect _rect; | ||
363 | }; | ||
364 | |||
365 | /*****************************************************************************/ | ||
366 | |||
367 | /* Private ioctl's for control settings supported by some image sensors */ | ||
368 | #define SN9C102_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE | ||
369 | #define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1 | ||
370 | #define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2 | ||
371 | #define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3 | ||
372 | |||
373 | #endif /* _SN9C102_SENSOR_H_ */ | ||
diff --git a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c new file mode 100644 index 000000000000..690d62192273 --- /dev/null +++ b/drivers/usb/media/sn9c102_tas5110c1b.c | |||
@@ -0,0 +1,174 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004-2005 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 | static struct v4l2_control tas5110c1b_gain; | ||
28 | |||
29 | |||
30 | static int tas5110c1b_init(struct sn9c102_device* cam) | ||
31 | { | ||
32 | int err = 0; | ||
33 | |||
34 | err += sn9c102_write_reg(cam, 0x01, 0x01); | ||
35 | err += sn9c102_write_reg(cam, 0x44, 0x01); | ||
36 | err += sn9c102_write_reg(cam, 0x00, 0x10); | ||
37 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
38 | err += sn9c102_write_reg(cam, 0x0a, 0x14); | ||
39 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
40 | err += sn9c102_write_reg(cam, 0x06, 0x18); | ||
41 | err += sn9c102_write_reg(cam, 0xfb, 0x19); | ||
42 | |||
43 | err += sn9c102_i2c_write(cam, 0xc0, 0x80); | ||
44 | |||
45 | return err; | ||
46 | } | ||
47 | |||
48 | |||
49 | static int tas5110c1b_get_ctrl(struct sn9c102_device* cam, | ||
50 | struct v4l2_control* ctrl) | ||
51 | { | ||
52 | switch (ctrl->id) { | ||
53 | case V4L2_CID_GAIN: | ||
54 | ctrl->value = tas5110c1b_gain.value; | ||
55 | break; | ||
56 | default: | ||
57 | return -EINVAL; | ||
58 | } | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | |||
64 | static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, | ||
65 | const struct v4l2_control* ctrl) | ||
66 | { | ||
67 | int err = 0; | ||
68 | |||
69 | switch (ctrl->id) { | ||
70 | case V4L2_CID_GAIN: | ||
71 | if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value))) | ||
72 | tas5110c1b_gain.value = ctrl->value; | ||
73 | break; | ||
74 | default: | ||
75 | return -EINVAL; | ||
76 | } | ||
77 | |||
78 | return err ? -EIO : 0; | ||
79 | } | ||
80 | |||
81 | |||
82 | static int tas5110c1b_set_crop(struct sn9c102_device* cam, | ||
83 | const struct v4l2_rect* rect) | ||
84 | { | ||
85 | struct sn9c102_sensor* s = &tas5110c1b; | ||
86 | int err = 0; | ||
87 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, | ||
88 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; | ||
89 | |||
90 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
91 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
92 | |||
93 | /* Don't change ! */ | ||
94 | err += sn9c102_write_reg(cam, 0x14, 0x1a); | ||
95 | err += sn9c102_write_reg(cam, 0x0a, 0x1b); | ||
96 | err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19); | ||
97 | |||
98 | return err; | ||
99 | } | ||
100 | |||
101 | |||
102 | static int tas5110c1b_set_pix_format(struct sn9c102_device* cam, | ||
103 | const struct v4l2_pix_format* pix) | ||
104 | { | ||
105 | int err = 0; | ||
106 | |||
107 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
108 | err += sn9c102_write_reg(cam, 0x2b, 0x19); | ||
109 | else | ||
110 | err += sn9c102_write_reg(cam, 0xfb, 0x19); | ||
111 | |||
112 | return err; | ||
113 | } | ||
114 | |||
115 | |||
116 | static struct sn9c102_sensor tas5110c1b = { | ||
117 | .name = "TAS5110C1B", | ||
118 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
119 | .sysfs_ops = SN9C102_I2C_WRITE, | ||
120 | .frequency = SN9C102_I2C_100KHZ, | ||
121 | .interface = SN9C102_I2C_3WIRES, | ||
122 | .init = &tas5110c1b_init, | ||
123 | .qctrl = { | ||
124 | { | ||
125 | .id = V4L2_CID_GAIN, | ||
126 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
127 | .name = "global gain", | ||
128 | .minimum = 0x00, | ||
129 | .maximum = 0xf6, | ||
130 | .step = 0x01, | ||
131 | .default_value = 0x40, | ||
132 | .flags = 0, | ||
133 | }, | ||
134 | }, | ||
135 | .set_ctrl = &tas5110c1b_set_ctrl, | ||
136 | .cropcap = { | ||
137 | .bounds = { | ||
138 | .left = 0, | ||
139 | .top = 0, | ||
140 | .width = 352, | ||
141 | .height = 288, | ||
142 | }, | ||
143 | .defrect = { | ||
144 | .left = 0, | ||
145 | .top = 0, | ||
146 | .width = 352, | ||
147 | .height = 288, | ||
148 | }, | ||
149 | }, | ||
150 | .get_ctrl = &tas5110c1b_get_ctrl, | ||
151 | .set_crop = &tas5110c1b_set_crop, | ||
152 | .pix_format = { | ||
153 | .width = 352, | ||
154 | .height = 288, | ||
155 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
156 | .priv = 8, | ||
157 | }, | ||
158 | .set_pix_format = &tas5110c1b_set_pix_format | ||
159 | }; | ||
160 | |||
161 | |||
162 | int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) | ||
163 | { | ||
164 | /* This sensor has no identifiers, so let's attach it anyway */ | ||
165 | sn9c102_attach_sensor(cam, &tas5110c1b); | ||
166 | |||
167 | /* Sensor detection is based on USB pid/vid */ | ||
168 | if (le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6001 && | ||
169 | le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6005 && | ||
170 | le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x60ab) | ||
171 | return -ENODEV; | ||
172 | |||
173 | return 0; | ||
174 | } | ||
diff --git a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c new file mode 100644 index 000000000000..b378e941bbe8 --- /dev/null +++ b/drivers/usb/media/sn9c102_tas5130d1b.c | |||
@@ -0,0 +1,188 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004-2005 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 | static struct v4l2_control tas5130d1b_gain, tas5130d1b_exposure; | ||
28 | |||
29 | |||
30 | static int tas5130d1b_init(struct sn9c102_device* cam) | ||
31 | { | ||
32 | int err = 0; | ||
33 | |||
34 | err += sn9c102_write_reg(cam, 0x01, 0x01); | ||
35 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
36 | err += sn9c102_write_reg(cam, 0x04, 0x01); | ||
37 | err += sn9c102_write_reg(cam, 0x01, 0x10); | ||
38 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
39 | err += sn9c102_write_reg(cam, 0x00, 0x14); | ||
40 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
41 | err += sn9c102_write_reg(cam, 0x07, 0x18); | ||
42 | |||
43 | return err; | ||
44 | } | ||
45 | |||
46 | |||
47 | static int tas5130d1b_get_ctrl(struct sn9c102_device* cam, | ||
48 | struct v4l2_control* ctrl) | ||
49 | { | ||
50 | switch (ctrl->id) { | ||
51 | case V4L2_CID_GAIN: | ||
52 | ctrl->value = tas5130d1b_gain.value; | ||
53 | break; | ||
54 | case V4L2_CID_EXPOSURE: | ||
55 | ctrl->value = tas5130d1b_exposure.value; | ||
56 | break; | ||
57 | default: | ||
58 | return -EINVAL; | ||
59 | } | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | |||
65 | static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, | ||
66 | const struct v4l2_control* ctrl) | ||
67 | { | ||
68 | int err = 0; | ||
69 | |||
70 | switch (ctrl->id) { | ||
71 | case V4L2_CID_GAIN: | ||
72 | if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value))) | ||
73 | tas5130d1b_gain.value = ctrl->value; | ||
74 | break; | ||
75 | case V4L2_CID_EXPOSURE: | ||
76 | if (!(err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value))) | ||
77 | tas5130d1b_exposure.value = ctrl->value; | ||
78 | break; | ||
79 | default: | ||
80 | return -EINVAL; | ||
81 | } | ||
82 | |||
83 | return err ? -EIO : 0; | ||
84 | } | ||
85 | |||
86 | |||
87 | static int tas5130d1b_set_crop(struct sn9c102_device* cam, | ||
88 | const struct v4l2_rect* rect) | ||
89 | { | ||
90 | struct sn9c102_sensor* s = &tas5130d1b; | ||
91 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104, | ||
92 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12; | ||
93 | int err = 0; | ||
94 | |||
95 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
96 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
97 | |||
98 | /* Do NOT change! */ | ||
99 | err += sn9c102_write_reg(cam, 0x1f, 0x1a); | ||
100 | err += sn9c102_write_reg(cam, 0x1a, 0x1b); | ||
101 | err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19); | ||
102 | |||
103 | return err; | ||
104 | } | ||
105 | |||
106 | |||
107 | static int tas5130d1b_set_pix_format(struct sn9c102_device* cam, | ||
108 | const struct v4l2_pix_format* pix) | ||
109 | { | ||
110 | int err = 0; | ||
111 | |||
112 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
113 | err += sn9c102_write_reg(cam, 0x63, 0x19); | ||
114 | else | ||
115 | err += sn9c102_write_reg(cam, 0xf3, 0x19); | ||
116 | |||
117 | return err; | ||
118 | } | ||
119 | |||
120 | |||
121 | static struct sn9c102_sensor tas5130d1b = { | ||
122 | .name = "TAS5130D1B", | ||
123 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
124 | .sysfs_ops = SN9C102_I2C_WRITE, | ||
125 | .frequency = SN9C102_I2C_100KHZ, | ||
126 | .interface = SN9C102_I2C_3WIRES, | ||
127 | .init = &tas5130d1b_init, | ||
128 | .qctrl = { | ||
129 | { | ||
130 | .id = V4L2_CID_GAIN, | ||
131 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
132 | .name = "global gain", | ||
133 | .minimum = 0x00, | ||
134 | .maximum = 0xf6, | ||
135 | .step = 0x02, | ||
136 | .default_value = 0x00, | ||
137 | .flags = 0, | ||
138 | }, | ||
139 | { | ||
140 | .id = V4L2_CID_EXPOSURE, | ||
141 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
142 | .name = "exposure", | ||
143 | .minimum = 0x00, | ||
144 | .maximum = 0x47, | ||
145 | .step = 0x01, | ||
146 | .default_value = 0x00, | ||
147 | .flags = 0, | ||
148 | }, | ||
149 | }, | ||
150 | .get_ctrl = &tas5130d1b_get_ctrl, | ||
151 | .set_ctrl = &tas5130d1b_set_ctrl, | ||
152 | .cropcap = { | ||
153 | .bounds = { | ||
154 | .left = 0, | ||
155 | .top = 0, | ||
156 | .width = 640, | ||
157 | .height = 480, | ||
158 | }, | ||
159 | .defrect = { | ||
160 | .left = 0, | ||
161 | .top = 0, | ||
162 | .width = 640, | ||
163 | .height = 480, | ||
164 | }, | ||
165 | }, | ||
166 | .set_crop = &tas5130d1b_set_crop, | ||
167 | .pix_format = { | ||
168 | .width = 640, | ||
169 | .height = 480, | ||
170 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
171 | .priv = 8, | ||
172 | }, | ||
173 | .set_pix_format = &tas5130d1b_set_pix_format | ||
174 | }; | ||
175 | |||
176 | |||
177 | int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam) | ||
178 | { | ||
179 | /* This sensor has no identifiers, so let's attach it anyway */ | ||
180 | sn9c102_attach_sensor(cam, &tas5130d1b); | ||
181 | |||
182 | /* Sensor detection is based on USB pid/vid */ | ||
183 | if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6025 && | ||
184 | le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x60aa) | ||
185 | return -ENODEV; | ||
186 | |||
187 | return 0; | ||
188 | } | ||
diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c new file mode 100644 index 000000000000..ae455c8e3702 --- /dev/null +++ b/drivers/usb/media/stv680.c | |||
@@ -0,0 +1,1506 @@ | |||
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 | |||
71 | #include "stv680.h" | ||
72 | |||
73 | static int video_nr = -1; | ||
74 | static int swapRGB = 0; /* default for auto sleect */ | ||
75 | static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */ | ||
76 | |||
77 | static unsigned int debug = 0; | ||
78 | |||
79 | #define PDEBUG(level, fmt, args...) \ | ||
80 | do { \ | ||
81 | if (debug >= level) \ | ||
82 | info("[%s:%d] " fmt, __FUNCTION__, __LINE__ , ## args); \ | ||
83 | } while (0) | ||
84 | |||
85 | |||
86 | /* | ||
87 | * Version Information | ||
88 | */ | ||
89 | #define DRIVER_VERSION "v0.25" | ||
90 | #define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>" | ||
91 | #define DRIVER_DESC "STV0680 USB Camera Driver" | ||
92 | |||
93 | MODULE_AUTHOR (DRIVER_AUTHOR); | ||
94 | MODULE_DESCRIPTION (DRIVER_DESC); | ||
95 | MODULE_LICENSE ("GPL"); | ||
96 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
97 | MODULE_PARM_DESC (debug, "Debug enabled or not"); | ||
98 | module_param(swapRGB_on, int, 0); | ||
99 | MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never"); | ||
100 | module_param(video_nr, int, 0); | ||
101 | |||
102 | /******************************************************************** | ||
103 | * | ||
104 | * Memory management | ||
105 | * | ||
106 | * This is a shameless copy from the USB-cpia driver (linux kernel | ||
107 | * version 2.3.29 or so, I have no idea what this code actually does ;). | ||
108 | * Actually it seems to be a copy of a shameless copy of the bttv-driver. | ||
109 | * Or that is a copy of a shameless copy of ... (To the powers: is there | ||
110 | * no generic kernel-function to do this sort of stuff?) | ||
111 | * | ||
112 | * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says | ||
113 | * there will be one, but apparentely not yet -jerdfelt | ||
114 | * | ||
115 | * So I copied it again for the ov511 driver -claudio | ||
116 | * | ||
117 | * Same for the se401 driver -Jeroen | ||
118 | * | ||
119 | * And the STV0680 driver - Kevin | ||
120 | ********************************************************************/ | ||
121 | static void *rvmalloc (unsigned long size) | ||
122 | { | ||
123 | void *mem; | ||
124 | unsigned long adr; | ||
125 | |||
126 | size = PAGE_ALIGN(size); | ||
127 | mem = vmalloc_32 (size); | ||
128 | if (!mem) | ||
129 | return NULL; | ||
130 | |||
131 | memset (mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
132 | adr = (unsigned long) mem; | ||
133 | while (size > 0) { | ||
134 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
135 | adr += PAGE_SIZE; | ||
136 | size -= PAGE_SIZE; | ||
137 | } | ||
138 | return mem; | ||
139 | } | ||
140 | |||
141 | static void rvfree (void *mem, unsigned long size) | ||
142 | { | ||
143 | unsigned long adr; | ||
144 | |||
145 | if (!mem) | ||
146 | return; | ||
147 | |||
148 | adr = (unsigned long) mem; | ||
149 | while ((long) size > 0) { | ||
150 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
151 | adr += PAGE_SIZE; | ||
152 | size -= PAGE_SIZE; | ||
153 | } | ||
154 | vfree (mem); | ||
155 | } | ||
156 | |||
157 | |||
158 | /********************************************************************* | ||
159 | * pencam read/write functions | ||
160 | ********************************************************************/ | ||
161 | |||
162 | static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size) | ||
163 | { | ||
164 | int ret = -1; | ||
165 | |||
166 | switch (set) { | ||
167 | case 0: /* 0xc1 */ | ||
168 | ret = usb_control_msg (stv680->udev, | ||
169 | usb_rcvctrlpipe (stv680->udev, 0), | ||
170 | req, | ||
171 | (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT), | ||
172 | value, 0, buffer, size, PENCAM_TIMEOUT); | ||
173 | break; | ||
174 | |||
175 | case 1: /* 0x41 */ | ||
176 | ret = usb_control_msg (stv680->udev, | ||
177 | usb_sndctrlpipe (stv680->udev, 0), | ||
178 | req, | ||
179 | (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT), | ||
180 | value, 0, buffer, size, PENCAM_TIMEOUT); | ||
181 | break; | ||
182 | |||
183 | case 2: /* 0x80 */ | ||
184 | ret = usb_control_msg (stv680->udev, | ||
185 | usb_rcvctrlpipe (stv680->udev, 0), | ||
186 | req, | ||
187 | (USB_DIR_IN | USB_RECIP_DEVICE), | ||
188 | value, 0, buffer, size, PENCAM_TIMEOUT); | ||
189 | break; | ||
190 | |||
191 | case 3: /* 0x40 */ | ||
192 | ret = usb_control_msg (stv680->udev, | ||
193 | usb_sndctrlpipe (stv680->udev, 0), | ||
194 | req, | ||
195 | (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE), | ||
196 | value, 0, buffer, size, PENCAM_TIMEOUT); | ||
197 | break; | ||
198 | |||
199 | } | ||
200 | if ((ret < 0) && (req != 0x0a)) { | ||
201 | PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret); | ||
202 | } | ||
203 | return ret; | ||
204 | } | ||
205 | |||
206 | static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate) | ||
207 | { | ||
208 | |||
209 | if (configuration != dev->udev->actconfig->desc.bConfigurationValue | ||
210 | || usb_reset_configuration (dev->udev) < 0) { | ||
211 | PDEBUG (1, "STV(e): FAILED to reset configuration %i", configuration); | ||
212 | return -1; | ||
213 | } | ||
214 | if (usb_set_interface (dev->udev, interface, alternate) < 0) { | ||
215 | PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate); | ||
216 | return -1; | ||
217 | } | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int stv_stop_video (struct usb_stv *dev) | ||
222 | { | ||
223 | int i; | ||
224 | unsigned char *buf; | ||
225 | |||
226 | buf = kmalloc (40, GFP_KERNEL); | ||
227 | if (buf == NULL) { | ||
228 | PDEBUG (0, "STV(e): Out of (small buf) memory"); | ||
229 | return -1; | ||
230 | } | ||
231 | |||
232 | /* this is a high priority command; it stops all lower order commands */ | ||
233 | if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) { | ||
234 | i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02); /* Get Last Error; 2 = busy */ | ||
235 | PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buf[0], buf[1]); | ||
236 | } else { | ||
237 | PDEBUG (1, "STV(i): Camera reset to idle mode."); | ||
238 | } | ||
239 | |||
240 | if ((i = stv_set_config (dev, 1, 0, 0)) < 0) | ||
241 | PDEBUG (1, "STV(e): Reset config during exit failed"); | ||
242 | |||
243 | /* get current mode */ | ||
244 | buf[0] = 0xf0; | ||
245 | if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08) /* get mode */ | ||
246 | PDEBUG (0, "STV(e): Stop_video: problem setting original mode"); | ||
247 | if (dev->origMode != buf[0]) { | ||
248 | memset (buf, 0, 8); | ||
249 | buf[0] = (unsigned char) dev->origMode; | ||
250 | if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) { | ||
251 | PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed"); | ||
252 | i = -1; | ||
253 | } | ||
254 | buf[0] = 0xf0; | ||
255 | i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08); | ||
256 | if ((i != 0x08) || (buf[0] != dev->origMode)) { | ||
257 | PDEBUG (0, "STV(e): camera NOT set to original resolution."); | ||
258 | i = -1; | ||
259 | } else | ||
260 | PDEBUG (0, "STV(i): Camera set to original resolution"); | ||
261 | } | ||
262 | /* origMode */ | ||
263 | kfree (buf); | ||
264 | return i; | ||
265 | } | ||
266 | |||
267 | static int stv_set_video_mode (struct usb_stv *dev) | ||
268 | { | ||
269 | int i, stop_video = 1; | ||
270 | unsigned char *buf; | ||
271 | |||
272 | buf = kmalloc (40, GFP_KERNEL); | ||
273 | if (buf == NULL) { | ||
274 | PDEBUG (0, "STV(e): Out of (small buf) memory"); | ||
275 | return -1; | ||
276 | } | ||
277 | |||
278 | if ((i = stv_set_config (dev, 1, 0, 0)) < 0) { | ||
279 | kfree (buf); | ||
280 | return i; | ||
281 | } | ||
282 | |||
283 | i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12); | ||
284 | if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) { | ||
285 | PDEBUG (1, "STV(e): Could not get descriptor 0100."); | ||
286 | goto error; | ||
287 | } | ||
288 | |||
289 | /* set alternate interface 1 */ | ||
290 | if ((i = stv_set_config (dev, 1, 0, 1)) < 0) | ||
291 | goto error; | ||
292 | |||
293 | if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10) | ||
294 | goto error; | ||
295 | PDEBUG (1, "STV(i): Setting video mode."); | ||
296 | /* Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240) */ | ||
297 | if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) { | ||
298 | stop_video = 0; | ||
299 | goto error; | ||
300 | } | ||
301 | goto exit; | ||
302 | |||
303 | error: | ||
304 | kfree (buf); | ||
305 | if (stop_video == 1) | ||
306 | stv_stop_video (dev); | ||
307 | return -1; | ||
308 | |||
309 | exit: | ||
310 | kfree (buf); | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int stv_init (struct usb_stv *stv680) | ||
315 | { | ||
316 | int i = 0; | ||
317 | unsigned char *buffer; | ||
318 | unsigned long int bufsize; | ||
319 | |||
320 | buffer = kmalloc (40, GFP_KERNEL); | ||
321 | if (buffer == NULL) { | ||
322 | PDEBUG (0, "STV(e): Out of (small buf) memory"); | ||
323 | return -1; | ||
324 | } | ||
325 | memset (buffer, 0, 40); | ||
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 | down (&stv680->lock); | ||
1262 | |||
1263 | if (stv680->udev == NULL) { | ||
1264 | up (&stv680->lock); | ||
1265 | return -EIO; | ||
1266 | } | ||
1267 | if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1) | ||
1268 | & ~(PAGE_SIZE - 1))) { | ||
1269 | up (&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 | up (&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 | up (&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 | .llseek = no_llseek, | ||
1347 | }; | ||
1348 | static struct video_device stv680_template = { | ||
1349 | .owner = THIS_MODULE, | ||
1350 | .name = "STV0680 USB camera", | ||
1351 | .type = VID_TYPE_CAPTURE, | ||
1352 | .hardware = VID_HARDWARE_SE401, | ||
1353 | .fops = &stv680_fops, | ||
1354 | .release = video_device_release, | ||
1355 | .minor = -1, | ||
1356 | }; | ||
1357 | |||
1358 | static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id) | ||
1359 | { | ||
1360 | struct usb_device *dev = interface_to_usbdev(intf); | ||
1361 | struct usb_host_interface *interface; | ||
1362 | struct usb_stv *stv680 = NULL; | ||
1363 | char *camera_name = NULL; | ||
1364 | int retval = 0; | ||
1365 | |||
1366 | /* We don't handle multi-config cameras */ | ||
1367 | if (dev->descriptor.bNumConfigurations != 1) { | ||
1368 | PDEBUG (0, "STV(e): Number of Configurations != 1"); | ||
1369 | return -ENODEV; | ||
1370 | } | ||
1371 | |||
1372 | interface = &intf->altsetting[0]; | ||
1373 | /* Is it a STV680? */ | ||
1374 | if ((le16_to_cpu(dev->descriptor.idVendor) == USB_PENCAM_VENDOR_ID) && | ||
1375 | (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) { | ||
1376 | camera_name = "STV0680"; | ||
1377 | PDEBUG (0, "STV(i): STV0680 camera found."); | ||
1378 | } else { | ||
1379 | PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 values."); | ||
1380 | PDEBUG (0, "STV(e): Check that the STV0680 camera is connected to the computer."); | ||
1381 | retval = -ENODEV; | ||
1382 | goto error; | ||
1383 | } | ||
1384 | /* We found one */ | ||
1385 | if ((stv680 = kmalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) { | ||
1386 | PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct."); | ||
1387 | retval = -ENOMEM; | ||
1388 | goto error; | ||
1389 | } | ||
1390 | |||
1391 | memset (stv680, 0, sizeof (*stv680)); | ||
1392 | |||
1393 | stv680->udev = dev; | ||
1394 | stv680->camera_name = camera_name; | ||
1395 | |||
1396 | stv680->vdev = video_device_alloc(); | ||
1397 | if (!stv680->vdev) { | ||
1398 | retval = -ENOMEM; | ||
1399 | goto error; | ||
1400 | } | ||
1401 | memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template)); | ||
1402 | stv680->vdev->dev = &intf->dev; | ||
1403 | video_set_drvdata(stv680->vdev, stv680); | ||
1404 | |||
1405 | memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name)); | ||
1406 | init_waitqueue_head (&stv680->wq); | ||
1407 | init_MUTEX (&stv680->lock); | ||
1408 | wmb (); | ||
1409 | |||
1410 | if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { | ||
1411 | PDEBUG (0, "STV(e): video_register_device failed"); | ||
1412 | retval = -EIO; | ||
1413 | goto error_vdev; | ||
1414 | } | ||
1415 | PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor); | ||
1416 | |||
1417 | usb_set_intfdata (intf, stv680); | ||
1418 | stv680_create_sysfs_files(stv680->vdev); | ||
1419 | return 0; | ||
1420 | |||
1421 | error_vdev: | ||
1422 | video_device_release(stv680->vdev); | ||
1423 | error: | ||
1424 | kfree(stv680); | ||
1425 | return retval; | ||
1426 | } | ||
1427 | |||
1428 | static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680) | ||
1429 | { | ||
1430 | int i; | ||
1431 | |||
1432 | stv680->udev = NULL; | ||
1433 | stv680->frame[0].grabstate = FRAME_ERROR; | ||
1434 | stv680->frame[1].grabstate = FRAME_ERROR; | ||
1435 | stv680->streaming = 0; | ||
1436 | |||
1437 | wake_up_interruptible (&stv680->wq); | ||
1438 | |||
1439 | for (i = 0; i < STV680_NUMSBUF; i++) | ||
1440 | if (stv680->urb[i]) { | ||
1441 | usb_kill_urb (stv680->urb[i]); | ||
1442 | usb_free_urb (stv680->urb[i]); | ||
1443 | stv680->urb[i] = NULL; | ||
1444 | kfree (stv680->sbuf[i].data); | ||
1445 | } | ||
1446 | for (i = 0; i < STV680_NUMSCRATCH; i++) | ||
1447 | kfree (stv680->scratch[i].data); | ||
1448 | PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name); | ||
1449 | |||
1450 | /* Free the memory */ | ||
1451 | kfree (stv680); | ||
1452 | } | ||
1453 | |||
1454 | static void stv680_disconnect (struct usb_interface *intf) | ||
1455 | { | ||
1456 | struct usb_stv *stv680 = usb_get_intfdata (intf); | ||
1457 | |||
1458 | usb_set_intfdata (intf, NULL); | ||
1459 | |||
1460 | if (stv680) { | ||
1461 | /* We don't want people trying to open up the device */ | ||
1462 | if (stv680->vdev) { | ||
1463 | stv680_remove_sysfs_files(stv680->vdev); | ||
1464 | video_unregister_device(stv680->vdev); | ||
1465 | stv680->vdev = NULL; | ||
1466 | } | ||
1467 | if (!stv680->user) { | ||
1468 | usb_stv680_remove_disconnected (stv680); | ||
1469 | } else { | ||
1470 | stv680->removed = 1; | ||
1471 | } | ||
1472 | } | ||
1473 | } | ||
1474 | |||
1475 | static struct usb_driver stv680_driver = { | ||
1476 | .owner = THIS_MODULE, | ||
1477 | .name = "stv680", | ||
1478 | .probe = stv680_probe, | ||
1479 | .disconnect = stv680_disconnect, | ||
1480 | .id_table = device_table | ||
1481 | }; | ||
1482 | |||
1483 | /******************************************************************** | ||
1484 | * Module routines | ||
1485 | ********************************************************************/ | ||
1486 | |||
1487 | static int __init usb_stv680_init (void) | ||
1488 | { | ||
1489 | if (usb_register (&stv680_driver) < 0) { | ||
1490 | PDEBUG (0, "STV(e): Could not setup STV0680 driver"); | ||
1491 | return -1; | ||
1492 | } | ||
1493 | PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION); | ||
1494 | |||
1495 | info(DRIVER_DESC " " DRIVER_VERSION); | ||
1496 | return 0; | ||
1497 | } | ||
1498 | |||
1499 | static void __exit usb_stv680_exit (void) | ||
1500 | { | ||
1501 | usb_deregister (&stv680_driver); | ||
1502 | PDEBUG (0, "STV(i): driver deregistered"); | ||
1503 | } | ||
1504 | |||
1505 | module_init (usb_stv680_init); | ||
1506 | module_exit (usb_stv680_exit); | ||
diff --git a/drivers/usb/media/stv680.h b/drivers/usb/media/stv680.h new file mode 100644 index 000000000000..7e0e314dcf12 --- /dev/null +++ b/drivers/usb/media/stv680.h | |||
@@ -0,0 +1,222 @@ | |||
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 | #define PENCAM_TIMEOUT 1000 | ||
45 | /* fmt 4 */ | ||
46 | #define STV_VIDEO_PALETTE VIDEO_PALETTE_RGB24 | ||
47 | |||
48 | static struct usb_device_id device_table[] = { | ||
49 | {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)}, | ||
50 | {} | ||
51 | }; | ||
52 | MODULE_DEVICE_TABLE (usb, device_table); | ||
53 | |||
54 | struct stv680_sbuf { | ||
55 | unsigned char *data; | ||
56 | }; | ||
57 | |||
58 | enum { | ||
59 | FRAME_UNUSED, /* Unused (no MCAPTURE) */ | ||
60 | FRAME_READY, /* Ready to start grabbing */ | ||
61 | FRAME_GRABBING, /* In the process of being grabbed into */ | ||
62 | FRAME_DONE, /* Finished grabbing, but not been synced yet */ | ||
63 | FRAME_ERROR, /* Something bad happened while processing */ | ||
64 | }; | ||
65 | |||
66 | enum { | ||
67 | BUFFER_UNUSED, | ||
68 | BUFFER_READY, | ||
69 | BUFFER_BUSY, | ||
70 | BUFFER_DONE, | ||
71 | }; | ||
72 | |||
73 | /* raw camera data <- sbuf (urb transfer buf) */ | ||
74 | struct stv680_scratch { | ||
75 | unsigned char *data; | ||
76 | volatile int state; | ||
77 | int offset; | ||
78 | int length; | ||
79 | }; | ||
80 | |||
81 | /* processed data for display ends up here, after bayer */ | ||
82 | struct stv680_frame { | ||
83 | unsigned char *data; /* Frame buffer */ | ||
84 | volatile int grabstate; /* State of grabbing */ | ||
85 | unsigned char *curline; | ||
86 | int curlinepix; | ||
87 | int curpix; | ||
88 | }; | ||
89 | |||
90 | /* this is almost the video structure uvd_t, with extra parameters for stv */ | ||
91 | struct usb_stv { | ||
92 | struct video_device *vdev; | ||
93 | |||
94 | struct usb_device *udev; | ||
95 | |||
96 | unsigned char bulk_in_endpointAddr; /* __u8 the address of the bulk in endpoint */ | ||
97 | char *camera_name; | ||
98 | |||
99 | unsigned int VideoMode; /* 0x0100 = VGA, 0x0000 = CIF, 0x0300 = QVGA */ | ||
100 | int SupportedModes; | ||
101 | int CIF; | ||
102 | int VGA; | ||
103 | int QVGA; | ||
104 | int cwidth; /* camera width */ | ||
105 | int cheight; /* camera height */ | ||
106 | int maxwidth; /* max video width */ | ||
107 | int maxheight; /* max video height */ | ||
108 | int vwidth; /* current width for video window */ | ||
109 | int vheight; /* current height for video window */ | ||
110 | unsigned long int rawbufsize; | ||
111 | unsigned long int maxframesize; /* rawbufsize * 3 for RGB */ | ||
112 | |||
113 | int origGain; | ||
114 | int origMode; /* original camera mode */ | ||
115 | |||
116 | struct semaphore lock; /* to lock the structure */ | ||
117 | int user; /* user count for exclusive use */ | ||
118 | int removed; /* device disconnected */ | ||
119 | int streaming; /* Are we streaming video? */ | ||
120 | char *fbuf; /* Videodev buffer area */ | ||
121 | struct urb *urb[STV680_NUMSBUF]; /* # of queued bulk transfers */ | ||
122 | int curframe; /* Current receiving frame */ | ||
123 | struct stv680_frame frame[STV680_NUMFRAMES]; /* # frames supported by v4l part */ | ||
124 | int readcount; | ||
125 | int framecount; | ||
126 | int error; | ||
127 | int dropped; | ||
128 | int scratch_next; | ||
129 | int scratch_use; | ||
130 | int scratch_overflow; | ||
131 | struct stv680_scratch scratch[STV680_NUMSCRATCH]; /* for decoders */ | ||
132 | struct stv680_sbuf sbuf[STV680_NUMSBUF]; | ||
133 | |||
134 | unsigned int brightness; | ||
135 | unsigned int chgbright; | ||
136 | unsigned int whiteness; | ||
137 | unsigned int colour; | ||
138 | unsigned int contrast; | ||
139 | unsigned int hue; | ||
140 | unsigned int palette; | ||
141 | unsigned int depth; /* rgb24 in bits */ | ||
142 | |||
143 | wait_queue_head_t wq; /* Processes waiting */ | ||
144 | |||
145 | int nullpackets; | ||
146 | }; | ||
147 | |||
148 | |||
149 | static unsigned char red[256] = { | ||
150 | 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, | ||
151 | 18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, | ||
152 | 44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, | ||
153 | 71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, | ||
154 | 88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, | ||
155 | 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, | ||
156 | 114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, | ||
157 | 125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, | ||
158 | 134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, | ||
159 | 143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, | ||
160 | 152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, | ||
161 | 159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, | ||
162 | 167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, | ||
163 | 173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, | ||
164 | 180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, | ||
165 | 187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, | ||
166 | 192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, | ||
167 | 198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, | ||
168 | 204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, | ||
169 | 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, | ||
170 | 215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, | ||
171 | 220, 220, 221, 221 | ||
172 | }; | ||
173 | |||
174 | static unsigned char green[256] = { | ||
175 | 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, | ||
176 | 21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, | ||
177 | 50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, | ||
178 | 79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, | ||
179 | 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, | ||
180 | 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, | ||
181 | 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, | ||
182 | 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, | ||
183 | 150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, | ||
184 | 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, | ||
185 | 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, | ||
186 | 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, | ||
187 | 186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, | ||
188 | 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, | ||
189 | 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, | ||
190 | 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, | ||
191 | 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, | ||
192 | 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, | ||
193 | 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, | ||
194 | 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, | ||
195 | 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, | ||
196 | 245, 245, 246, 246 | ||
197 | }; | ||
198 | |||
199 | static unsigned char blue[256] = { | ||
200 | 0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, | ||
201 | 23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, | ||
202 | 55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, | ||
203 | 86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, | ||
204 | 107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, | ||
205 | 125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, | ||
206 | 139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, | ||
207 | 152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, | ||
208 | 165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, | ||
209 | 176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, | ||
210 | 185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, | ||
211 | 194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, | ||
212 | 204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, | ||
213 | 212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, | ||
214 | 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, | ||
215 | 228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, | ||
216 | 235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, | ||
217 | 243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, | ||
218 | 249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, | ||
219 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||
220 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||
221 | 255, 255, 255, 255 | ||
222 | }; | ||
diff --git a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c new file mode 100644 index 000000000000..75ff755224df --- /dev/null +++ b/drivers/usb/media/ultracam.c | |||
@@ -0,0 +1,679 @@ | |||
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 new file mode 100644 index 000000000000..298484aa27d2 --- /dev/null +++ b/drivers/usb/media/usbvideo.c | |||
@@ -0,0 +1,2192 @@ | |||
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 *) kmalloc(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 | memset(cams, 0, base_size); | ||
701 | |||
702 | /* Copy callbacks, apply defaults for those that are not set */ | ||
703 | memmove(&cams->cb, cbTbl, sizeof(cams->cb)); | ||
704 | if (cams->cb.getFrame == NULL) | ||
705 | cams->cb.getFrame = usbvideo_GetFrame; | ||
706 | if (cams->cb.disconnect == NULL) | ||
707 | cams->cb.disconnect = usbvideo_Disconnect; | ||
708 | if (cams->cb.startDataPump == NULL) | ||
709 | cams->cb.startDataPump = usbvideo_StartDataPump; | ||
710 | if (cams->cb.stopDataPump == NULL) | ||
711 | cams->cb.stopDataPump = usbvideo_StopDataPump; | ||
712 | |||
713 | cams->num_cameras = num_cams; | ||
714 | cams->cam = (struct uvd *) &cams[1]; | ||
715 | cams->md_module = md; | ||
716 | if (cams->md_module == NULL) | ||
717 | warn("%s: module == NULL!", __FUNCTION__); | ||
718 | init_MUTEX(&cams->lock); /* to 1 == available */ | ||
719 | |||
720 | for (i = 0; i < num_cams; i++) { | ||
721 | struct uvd *up = &cams->cam[i]; | ||
722 | |||
723 | up->handle = cams; | ||
724 | |||
725 | /* Allocate user_data separately because of kmalloc's limits */ | ||
726 | if (num_extra > 0) { | ||
727 | up->user_size = num_cams * num_extra; | ||
728 | up->user_data = (char *) kmalloc(up->user_size, GFP_KERNEL); | ||
729 | if (up->user_data == NULL) { | ||
730 | err("%s: Failed to allocate user_data (%d. bytes)", | ||
731 | __FUNCTION__, up->user_size); | ||
732 | while (i) { | ||
733 | up = &cams->cam[--i]; | ||
734 | kfree(up->user_data); | ||
735 | } | ||
736 | kfree(cams); | ||
737 | return -ENOMEM; | ||
738 | } | ||
739 | dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)", | ||
740 | __FUNCTION__, i, up->user_data, up->user_size); | ||
741 | } | ||
742 | } | ||
743 | |||
744 | /* | ||
745 | * Register ourselves with USB stack. | ||
746 | */ | ||
747 | strcpy(cams->drvName, (driverName != NULL) ? driverName : "Unknown"); | ||
748 | cams->usbdrv.name = cams->drvName; | ||
749 | cams->usbdrv.probe = cams->cb.probe; | ||
750 | cams->usbdrv.disconnect = cams->cb.disconnect; | ||
751 | cams->usbdrv.id_table = id_table; | ||
752 | |||
753 | /* | ||
754 | * Update global handle to usbvideo. This is very important | ||
755 | * because probe() can be called before usb_register() returns. | ||
756 | * If the handle is not yet updated then the probe() will fail. | ||
757 | */ | ||
758 | *pCams = cams; | ||
759 | result = usb_register(&cams->usbdrv); | ||
760 | if (result) { | ||
761 | for (i = 0; i < num_cams; i++) { | ||
762 | struct uvd *up = &cams->cam[i]; | ||
763 | kfree(up->user_data); | ||
764 | } | ||
765 | kfree(cams); | ||
766 | } | ||
767 | |||
768 | return result; | ||
769 | } | ||
770 | |||
771 | EXPORT_SYMBOL(usbvideo_register); | ||
772 | |||
773 | /* | ||
774 | * usbvideo_Deregister() | ||
775 | * | ||
776 | * Procedure frees all usbvideo and user data structures. Be warned that | ||
777 | * if you had some dynamically allocated components in ->user field then | ||
778 | * you should free them before calling here. | ||
779 | */ | ||
780 | void usbvideo_Deregister(struct usbvideo **pCams) | ||
781 | { | ||
782 | struct usbvideo *cams; | ||
783 | int i; | ||
784 | |||
785 | if (pCams == NULL) { | ||
786 | err("%s: pCams == NULL", __FUNCTION__); | ||
787 | return; | ||
788 | } | ||
789 | cams = *pCams; | ||
790 | if (cams == NULL) { | ||
791 | err("%s: cams == NULL", __FUNCTION__); | ||
792 | return; | ||
793 | } | ||
794 | |||
795 | dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName); | ||
796 | usb_deregister(&cams->usbdrv); | ||
797 | |||
798 | dbg("%s: Deallocating cams=$%p (%d. cameras)", __FUNCTION__, cams, cams->num_cameras); | ||
799 | for (i=0; i < cams->num_cameras; i++) { | ||
800 | struct uvd *up = &cams->cam[i]; | ||
801 | int warning = 0; | ||
802 | |||
803 | if (up->user_data != NULL) { | ||
804 | if (up->user_size <= 0) | ||
805 | ++warning; | ||
806 | } else { | ||
807 | if (up->user_size > 0) | ||
808 | ++warning; | ||
809 | } | ||
810 | if (warning) { | ||
811 | err("%s: Warning: user_data=$%p user_size=%d.", | ||
812 | __FUNCTION__, up->user_data, up->user_size); | ||
813 | } else { | ||
814 | dbg("%s: Freeing %d. $%p->user_data=$%p", | ||
815 | __FUNCTION__, i, up, up->user_data); | ||
816 | kfree(up->user_data); | ||
817 | } | ||
818 | } | ||
819 | /* Whole array was allocated in one chunk */ | ||
820 | dbg("%s: Freed %d uvd structures", | ||
821 | __FUNCTION__, cams->num_cameras); | ||
822 | kfree(cams); | ||
823 | *pCams = NULL; | ||
824 | } | ||
825 | |||
826 | EXPORT_SYMBOL(usbvideo_Deregister); | ||
827 | |||
828 | /* | ||
829 | * usbvideo_Disconnect() | ||
830 | * | ||
831 | * This procedure stops all driver activity. Deallocation of | ||
832 | * the interface-private structure (pointed by 'ptr') is done now | ||
833 | * (if we don't have any open files) or later, when those files | ||
834 | * are closed. After that driver should be removable. | ||
835 | * | ||
836 | * This code handles surprise removal. The uvd->user is a counter which | ||
837 | * increments on open() and decrements on close(). If we see here that | ||
838 | * this counter is not 0 then we have a client who still has us opened. | ||
839 | * We set uvd->remove_pending flag as early as possible, and after that | ||
840 | * all access to the camera will gracefully fail. These failures should | ||
841 | * prompt client to (eventually) close the video device, and then - in | ||
842 | * usbvideo_v4l_close() - we decrement uvd->uvd_used and usage counter. | ||
843 | * | ||
844 | * History: | ||
845 | * 22-Jan-2000 Added polling of MOD_IN_USE to delay removal until all users gone. | ||
846 | * 27-Jan-2000 Reworked to allow pending disconnects; see xxx_close() | ||
847 | * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). | ||
848 | * 19-Oct-2000 Moved to usbvideo module. | ||
849 | */ | ||
850 | static void usbvideo_Disconnect(struct usb_interface *intf) | ||
851 | { | ||
852 | struct uvd *uvd = usb_get_intfdata (intf); | ||
853 | int i; | ||
854 | |||
855 | if (uvd == NULL) { | ||
856 | err("%s($%p): Illegal call.", __FUNCTION__, intf); | ||
857 | return; | ||
858 | } | ||
859 | |||
860 | usb_set_intfdata (intf, NULL); | ||
861 | |||
862 | usbvideo_ClientIncModCount(uvd); | ||
863 | if (uvd->debug > 0) | ||
864 | info("%s(%p.)", __FUNCTION__, intf); | ||
865 | |||
866 | down(&uvd->lock); | ||
867 | uvd->remove_pending = 1; /* Now all ISO data will be ignored */ | ||
868 | |||
869 | /* At this time we ask to cancel outstanding URBs */ | ||
870 | GET_CALLBACK(uvd, stopDataPump)(uvd); | ||
871 | |||
872 | for (i=0; i < USBVIDEO_NUMSBUF; i++) | ||
873 | usb_free_urb(uvd->sbuf[i].urb); | ||
874 | |||
875 | usb_put_dev(uvd->dev); | ||
876 | uvd->dev = NULL; /* USB device is no more */ | ||
877 | |||
878 | video_unregister_device(&uvd->vdev); | ||
879 | if (uvd->debug > 0) | ||
880 | info("%s: Video unregistered.", __FUNCTION__); | ||
881 | |||
882 | if (uvd->user) | ||
883 | info("%s: In use, disconnect pending.", __FUNCTION__); | ||
884 | else | ||
885 | usbvideo_CameraRelease(uvd); | ||
886 | up(&uvd->lock); | ||
887 | info("USB camera disconnected."); | ||
888 | |||
889 | usbvideo_ClientDecModCount(uvd); | ||
890 | } | ||
891 | |||
892 | /* | ||
893 | * usbvideo_CameraRelease() | ||
894 | * | ||
895 | * This code does final release of uvd. This happens | ||
896 | * after the device is disconnected -and- all clients | ||
897 | * closed their files. | ||
898 | * | ||
899 | * History: | ||
900 | * 27-Jan-2000 Created. | ||
901 | */ | ||
902 | static void usbvideo_CameraRelease(struct uvd *uvd) | ||
903 | { | ||
904 | if (uvd == NULL) { | ||
905 | err("%s: Illegal call", __FUNCTION__); | ||
906 | return; | ||
907 | } | ||
908 | |||
909 | RingQueue_Free(&uvd->dp); | ||
910 | if (VALID_CALLBACK(uvd, userFree)) | ||
911 | GET_CALLBACK(uvd, userFree)(uvd); | ||
912 | uvd->uvd_used = 0; /* This is atomic, no need to take mutex */ | ||
913 | } | ||
914 | |||
915 | /* | ||
916 | * usbvideo_find_struct() | ||
917 | * | ||
918 | * This code searches the array of preallocated (static) structures | ||
919 | * and returns index of the first one that isn't in use. Returns -1 | ||
920 | * if there are no free structures. | ||
921 | * | ||
922 | * History: | ||
923 | * 27-Jan-2000 Created. | ||
924 | */ | ||
925 | static int usbvideo_find_struct(struct usbvideo *cams) | ||
926 | { | ||
927 | int u, rv = -1; | ||
928 | |||
929 | if (cams == NULL) { | ||
930 | err("No usbvideo handle?"); | ||
931 | return -1; | ||
932 | } | ||
933 | down(&cams->lock); | ||
934 | for (u = 0; u < cams->num_cameras; u++) { | ||
935 | struct uvd *uvd = &cams->cam[u]; | ||
936 | if (!uvd->uvd_used) /* This one is free */ | ||
937 | { | ||
938 | uvd->uvd_used = 1; /* In use now */ | ||
939 | init_MUTEX(&uvd->lock); /* to 1 == available */ | ||
940 | uvd->dev = NULL; | ||
941 | rv = u; | ||
942 | break; | ||
943 | } | ||
944 | } | ||
945 | up(&cams->lock); | ||
946 | return rv; | ||
947 | } | ||
948 | |||
949 | static struct file_operations usbvideo_fops = { | ||
950 | .owner = THIS_MODULE, | ||
951 | .open = usbvideo_v4l_open, | ||
952 | .release =usbvideo_v4l_close, | ||
953 | .read = usbvideo_v4l_read, | ||
954 | .mmap = usbvideo_v4l_mmap, | ||
955 | .ioctl = usbvideo_v4l_ioctl, | ||
956 | .llseek = no_llseek, | ||
957 | }; | ||
958 | static 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 | down(&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 | up (&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 | down(&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 | if (uvd->sbuf[i].data != NULL) { | ||
1173 | kfree (uvd->sbuf[i].data); | ||
1174 | uvd->sbuf[i].data = NULL; | ||
1175 | } | ||
1176 | } | ||
1177 | } | ||
1178 | } | ||
1179 | |||
1180 | /* If so far no errors then we shall start the camera */ | ||
1181 | if (errCode == 0) { | ||
1182 | /* Start data pump if we have valid endpoint */ | ||
1183 | if (uvd->video_endp != 0) | ||
1184 | errCode = GET_CALLBACK(uvd, startDataPump)(uvd); | ||
1185 | if (errCode == 0) { | ||
1186 | if (VALID_CALLBACK(uvd, setupOnOpen)) { | ||
1187 | if (uvd->debug > 1) | ||
1188 | info("%s: setupOnOpen callback", __FUNCTION__); | ||
1189 | errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd); | ||
1190 | if (errCode < 0) { | ||
1191 | err("%s: setupOnOpen callback failed (%d.).", | ||
1192 | __FUNCTION__, errCode); | ||
1193 | } else if (uvd->debug > 1) { | ||
1194 | info("%s: setupOnOpen callback successful", __FUNCTION__); | ||
1195 | } | ||
1196 | } | ||
1197 | if (errCode == 0) { | ||
1198 | uvd->settingsAdjusted = 0; | ||
1199 | if (uvd->debug > 1) | ||
1200 | info("%s: Open succeeded.", __FUNCTION__); | ||
1201 | uvd->user++; | ||
1202 | file->private_data = uvd; | ||
1203 | } | ||
1204 | } | ||
1205 | } | ||
1206 | up(&uvd->lock); | ||
1207 | if (errCode != 0) | ||
1208 | usbvideo_ClientDecModCount(uvd); | ||
1209 | if (uvd->debug > 0) | ||
1210 | info("%s: Returning %d.", __FUNCTION__, errCode); | ||
1211 | return errCode; | ||
1212 | } | ||
1213 | |||
1214 | /* | ||
1215 | * usbvideo_v4l_close() | ||
1216 | * | ||
1217 | * This is part of Video 4 Linux API. The procedure | ||
1218 | * stops streaming and deallocates all buffers that were earlier | ||
1219 | * allocated in usbvideo_v4l_open(). | ||
1220 | * | ||
1221 | * History: | ||
1222 | * 22-Jan-2000 Moved scratch buffer deallocation here. | ||
1223 | * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. | ||
1224 | * 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep. | ||
1225 | */ | ||
1226 | static int usbvideo_v4l_close(struct inode *inode, struct file *file) | ||
1227 | { | ||
1228 | struct video_device *dev = file->private_data; | ||
1229 | struct uvd *uvd = (struct uvd *) dev; | ||
1230 | int i; | ||
1231 | |||
1232 | if (uvd->debug > 1) | ||
1233 | info("%s($%p)", __FUNCTION__, dev); | ||
1234 | |||
1235 | down(&uvd->lock); | ||
1236 | GET_CALLBACK(uvd, stopDataPump)(uvd); | ||
1237 | usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size); | ||
1238 | uvd->fbuf = NULL; | ||
1239 | RingQueue_Free(&uvd->dp); | ||
1240 | |||
1241 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
1242 | kfree(uvd->sbuf[i].data); | ||
1243 | uvd->sbuf[i].data = NULL; | ||
1244 | } | ||
1245 | |||
1246 | #if USBVIDEO_REPORT_STATS | ||
1247 | usbvideo_ReportStatistics(uvd); | ||
1248 | #endif | ||
1249 | |||
1250 | uvd->user--; | ||
1251 | if (uvd->remove_pending) { | ||
1252 | if (uvd->debug > 0) | ||
1253 | info("usbvideo_v4l_close: Final disconnect."); | ||
1254 | usbvideo_CameraRelease(uvd); | ||
1255 | } | ||
1256 | up(&uvd->lock); | ||
1257 | usbvideo_ClientDecModCount(uvd); | ||
1258 | |||
1259 | if (uvd->debug > 1) | ||
1260 | info("%s: Completed.", __FUNCTION__); | ||
1261 | file->private_data = NULL; | ||
1262 | return 0; | ||
1263 | } | ||
1264 | |||
1265 | /* | ||
1266 | * usbvideo_v4l_ioctl() | ||
1267 | * | ||
1268 | * This is part of Video 4 Linux API. The procedure handles ioctl() calls. | ||
1269 | * | ||
1270 | * History: | ||
1271 | * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings. | ||
1272 | */ | ||
1273 | static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file, | ||
1274 | unsigned int cmd, void *arg) | ||
1275 | { | ||
1276 | struct uvd *uvd = file->private_data; | ||
1277 | |||
1278 | if (!CAMERA_IS_OPERATIONAL(uvd)) | ||
1279 | return -EIO; | ||
1280 | |||
1281 | switch (cmd) { | ||
1282 | case VIDIOCGCAP: | ||
1283 | { | ||
1284 | struct video_capability *b = arg; | ||
1285 | *b = uvd->vcap; | ||
1286 | return 0; | ||
1287 | } | ||
1288 | case VIDIOCGCHAN: | ||
1289 | { | ||
1290 | struct video_channel *v = arg; | ||
1291 | *v = uvd->vchan; | ||
1292 | return 0; | ||
1293 | } | ||
1294 | case VIDIOCSCHAN: | ||
1295 | { | ||
1296 | struct video_channel *v = arg; | ||
1297 | if (v->channel != 0) | ||
1298 | return -EINVAL; | ||
1299 | return 0; | ||
1300 | } | ||
1301 | case VIDIOCGPICT: | ||
1302 | { | ||
1303 | struct video_picture *pic = arg; | ||
1304 | *pic = uvd->vpic; | ||
1305 | return 0; | ||
1306 | } | ||
1307 | case VIDIOCSPICT: | ||
1308 | { | ||
1309 | struct video_picture *pic = arg; | ||
1310 | /* | ||
1311 | * Use temporary 'video_picture' structure to preserve our | ||
1312 | * own settings (such as color depth, palette) that we | ||
1313 | * aren't allowing everyone (V4L client) to change. | ||
1314 | */ | ||
1315 | uvd->vpic.brightness = pic->brightness; | ||
1316 | uvd->vpic.hue = pic->hue; | ||
1317 | uvd->vpic.colour = pic->colour; | ||
1318 | uvd->vpic.contrast = pic->contrast; | ||
1319 | uvd->settingsAdjusted = 0; /* Will force new settings */ | ||
1320 | return 0; | ||
1321 | } | ||
1322 | case VIDIOCSWIN: | ||
1323 | { | ||
1324 | struct video_window *vw = arg; | ||
1325 | |||
1326 | if(VALID_CALLBACK(uvd, setVideoMode)) { | ||
1327 | return GET_CALLBACK(uvd, setVideoMode)(uvd, vw); | ||
1328 | } | ||
1329 | |||
1330 | if (vw->flags) | ||
1331 | return -EINVAL; | ||
1332 | if (vw->clipcount) | ||
1333 | return -EINVAL; | ||
1334 | if (vw->width != VIDEOSIZE_X(uvd->canvas)) | ||
1335 | return -EINVAL; | ||
1336 | if (vw->height != VIDEOSIZE_Y(uvd->canvas)) | ||
1337 | return -EINVAL; | ||
1338 | |||
1339 | return 0; | ||
1340 | } | ||
1341 | case VIDIOCGWIN: | ||
1342 | { | ||
1343 | struct video_window *vw = arg; | ||
1344 | |||
1345 | vw->x = 0; | ||
1346 | vw->y = 0; | ||
1347 | vw->width = VIDEOSIZE_X(uvd->videosize); | ||
1348 | vw->height = VIDEOSIZE_Y(uvd->videosize); | ||
1349 | vw->chromakey = 0; | ||
1350 | if (VALID_CALLBACK(uvd, getFPS)) | ||
1351 | vw->flags = GET_CALLBACK(uvd, getFPS)(uvd); | ||
1352 | else | ||
1353 | vw->flags = 10; /* FIXME: do better! */ | ||
1354 | return 0; | ||
1355 | } | ||
1356 | case VIDIOCGMBUF: | ||
1357 | { | ||
1358 | struct video_mbuf *vm = arg; | ||
1359 | int i; | ||
1360 | |||
1361 | memset(vm, 0, sizeof(*vm)); | ||
1362 | vm->size = uvd->max_frame_size * USBVIDEO_NUMFRAMES; | ||
1363 | vm->frames = USBVIDEO_NUMFRAMES; | ||
1364 | for(i = 0; i < USBVIDEO_NUMFRAMES; i++) | ||
1365 | vm->offsets[i] = i * uvd->max_frame_size; | ||
1366 | |||
1367 | return 0; | ||
1368 | } | ||
1369 | case VIDIOCMCAPTURE: | ||
1370 | { | ||
1371 | struct video_mmap *vm = arg; | ||
1372 | |||
1373 | if (uvd->debug >= 1) { | ||
1374 | info("VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.", | ||
1375 | vm->frame, vm->width, vm->height, vm->format); | ||
1376 | } | ||
1377 | /* | ||
1378 | * Check if the requested size is supported. If the requestor | ||
1379 | * requests too big a frame then we may be tricked into accessing | ||
1380 | * outside of own preallocated frame buffer (in uvd->frame). | ||
1381 | * This will cause oops or a security hole. Theoretically, we | ||
1382 | * could only clamp the size down to acceptable bounds, but then | ||
1383 | * we'd need to figure out how to insert our smaller buffer into | ||
1384 | * larger caller's buffer... this is not an easy question. So we | ||
1385 | * here just flatly reject too large requests, assuming that the | ||
1386 | * caller will resubmit with smaller size. Callers should know | ||
1387 | * what size we support (returned by VIDIOCGCAP). However vidcat, | ||
1388 | * for one, does not care and allows to ask for any size. | ||
1389 | */ | ||
1390 | if ((vm->width > VIDEOSIZE_X(uvd->canvas)) || | ||
1391 | (vm->height > VIDEOSIZE_Y(uvd->canvas))) { | ||
1392 | if (uvd->debug > 0) { | ||
1393 | info("VIDIOCMCAPTURE: Size=%dx%d too large; " | ||
1394 | "allowed only up to %ldx%ld", vm->width, vm->height, | ||
1395 | VIDEOSIZE_X(uvd->canvas), VIDEOSIZE_Y(uvd->canvas)); | ||
1396 | } | ||
1397 | return -EINVAL; | ||
1398 | } | ||
1399 | /* Check if the palette is supported */ | ||
1400 | if (((1L << vm->format) & uvd->paletteBits) == 0) { | ||
1401 | if (uvd->debug > 0) { | ||
1402 | info("VIDIOCMCAPTURE: format=%d. not supported" | ||
1403 | " (paletteBits=$%08lx)", | ||
1404 | vm->format, uvd->paletteBits); | ||
1405 | } | ||
1406 | return -EINVAL; | ||
1407 | } | ||
1408 | if ((vm->frame < 0) || (vm->frame >= USBVIDEO_NUMFRAMES)) { | ||
1409 | err("VIDIOCMCAPTURE: vm.frame=%d. !E [0-%d]", vm->frame, USBVIDEO_NUMFRAMES-1); | ||
1410 | return -EINVAL; | ||
1411 | } | ||
1412 | if (uvd->frame[vm->frame].frameState == FrameState_Grabbing) { | ||
1413 | /* Not an error - can happen */ | ||
1414 | } | ||
1415 | uvd->frame[vm->frame].request = VIDEOSIZE(vm->width, vm->height); | ||
1416 | uvd->frame[vm->frame].palette = vm->format; | ||
1417 | |||
1418 | /* Mark it as ready */ | ||
1419 | uvd->frame[vm->frame].frameState = FrameState_Ready; | ||
1420 | |||
1421 | return usbvideo_NewFrame(uvd, vm->frame); | ||
1422 | } | ||
1423 | case VIDIOCSYNC: | ||
1424 | { | ||
1425 | int *frameNum = arg; | ||
1426 | int ret; | ||
1427 | |||
1428 | if (*frameNum < 0 || *frameNum >= USBVIDEO_NUMFRAMES) | ||
1429 | return -EINVAL; | ||
1430 | |||
1431 | if (uvd->debug >= 1) | ||
1432 | info("VIDIOCSYNC: syncing to frame %d.", *frameNum); | ||
1433 | if (uvd->flags & FLAGS_NO_DECODING) | ||
1434 | ret = usbvideo_GetFrame(uvd, *frameNum); | ||
1435 | else if (VALID_CALLBACK(uvd, getFrame)) { | ||
1436 | ret = GET_CALLBACK(uvd, getFrame)(uvd, *frameNum); | ||
1437 | if ((ret < 0) && (uvd->debug >= 1)) { | ||
1438 | err("VIDIOCSYNC: getFrame() returned %d.", ret); | ||
1439 | } | ||
1440 | } else { | ||
1441 | err("VIDIOCSYNC: getFrame is not set"); | ||
1442 | ret = -EFAULT; | ||
1443 | } | ||
1444 | |||
1445 | /* | ||
1446 | * The frame is in FrameState_Done_Hold state. Release it | ||
1447 | * right now because its data is already mapped into | ||
1448 | * the user space and it's up to the application to | ||
1449 | * make use of it until it asks for another frame. | ||
1450 | */ | ||
1451 | uvd->frame[*frameNum].frameState = FrameState_Unused; | ||
1452 | return ret; | ||
1453 | } | ||
1454 | case VIDIOCGFBUF: | ||
1455 | { | ||
1456 | struct video_buffer *vb = arg; | ||
1457 | |||
1458 | memset(vb, 0, sizeof(*vb)); | ||
1459 | return 0; | ||
1460 | } | ||
1461 | case VIDIOCKEY: | ||
1462 | return 0; | ||
1463 | |||
1464 | case VIDIOCCAPTURE: | ||
1465 | return -EINVAL; | ||
1466 | |||
1467 | case VIDIOCSFBUF: | ||
1468 | |||
1469 | case VIDIOCGTUNER: | ||
1470 | case VIDIOCSTUNER: | ||
1471 | |||
1472 | case VIDIOCGFREQ: | ||
1473 | case VIDIOCSFREQ: | ||
1474 | |||
1475 | case VIDIOCGAUDIO: | ||
1476 | case VIDIOCSAUDIO: | ||
1477 | return -EINVAL; | ||
1478 | |||
1479 | default: | ||
1480 | return -ENOIOCTLCMD; | ||
1481 | } | ||
1482 | return 0; | ||
1483 | } | ||
1484 | |||
1485 | static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file, | ||
1486 | unsigned int cmd, unsigned long arg) | ||
1487 | { | ||
1488 | return video_usercopy(inode, file, cmd, arg, usbvideo_v4l_do_ioctl); | ||
1489 | } | ||
1490 | |||
1491 | /* | ||
1492 | * usbvideo_v4l_read() | ||
1493 | * | ||
1494 | * This is mostly boring stuff. We simply ask for a frame and when it | ||
1495 | * arrives copy all the video data from it into user space. There is | ||
1496 | * no obvious need to override this method. | ||
1497 | * | ||
1498 | * History: | ||
1499 | * 20-Oct-2000 Created. | ||
1500 | * 01-Nov-2000 Added mutex (uvd->lock). | ||
1501 | */ | ||
1502 | static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf, | ||
1503 | size_t count, loff_t *ppos) | ||
1504 | { | ||
1505 | struct uvd *uvd = file->private_data; | ||
1506 | int noblock = file->f_flags & O_NONBLOCK; | ||
1507 | int frmx = -1, i; | ||
1508 | struct usbvideo_frame *frame; | ||
1509 | |||
1510 | if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL)) | ||
1511 | return -EFAULT; | ||
1512 | |||
1513 | if (uvd->debug >= 1) | ||
1514 | info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock); | ||
1515 | |||
1516 | down(&uvd->lock); | ||
1517 | |||
1518 | /* See if a frame is completed, then use it. */ | ||
1519 | for(i = 0; i < USBVIDEO_NUMFRAMES; i++) { | ||
1520 | if ((uvd->frame[i].frameState == FrameState_Done) || | ||
1521 | (uvd->frame[i].frameState == FrameState_Done_Hold) || | ||
1522 | (uvd->frame[i].frameState == FrameState_Error)) { | ||
1523 | frmx = i; | ||
1524 | break; | ||
1525 | } | ||
1526 | } | ||
1527 | |||
1528 | /* FIXME: If we don't start a frame here then who ever does? */ | ||
1529 | if (noblock && (frmx == -1)) { | ||
1530 | count = -EAGAIN; | ||
1531 | goto read_done; | ||
1532 | } | ||
1533 | |||
1534 | /* | ||
1535 | * If no FrameState_Done, look for a FrameState_Grabbing state. | ||
1536 | * See if a frame is in process (grabbing), then use it. | ||
1537 | * We will need to wait until it becomes cooked, of course. | ||
1538 | */ | ||
1539 | if (frmx == -1) { | ||
1540 | for(i = 0; i < USBVIDEO_NUMFRAMES; i++) { | ||
1541 | if (uvd->frame[i].frameState == FrameState_Grabbing) { | ||
1542 | frmx = i; | ||
1543 | break; | ||
1544 | } | ||
1545 | } | ||
1546 | } | ||
1547 | |||
1548 | /* | ||
1549 | * If no frame is active, start one. We don't care which one | ||
1550 | * it will be, so #0 is as good as any. | ||
1551 | * In read access mode we don't have convenience of VIDIOCMCAPTURE | ||
1552 | * to specify the requested palette (video format) on per-frame | ||
1553 | * basis. This means that we have to return data in -some- format | ||
1554 | * and just hope that the client knows what to do with it. | ||
1555 | * The default format is configured in uvd->defaultPalette field | ||
1556 | * as one of VIDEO_PALETTE_xxx values. We stuff it into the new | ||
1557 | * frame and initiate the frame filling process. | ||
1558 | */ | ||
1559 | if (frmx == -1) { | ||
1560 | if (uvd->defaultPalette == 0) { | ||
1561 | err("%s: No default palette; don't know what to do!", __FUNCTION__); | ||
1562 | count = -EFAULT; | ||
1563 | goto read_done; | ||
1564 | } | ||
1565 | frmx = 0; | ||
1566 | /* | ||
1567 | * We have no per-frame control over video size. | ||
1568 | * Therefore we only can use whatever size was | ||
1569 | * specified as default. | ||
1570 | */ | ||
1571 | uvd->frame[frmx].request = uvd->videosize; | ||
1572 | uvd->frame[frmx].palette = uvd->defaultPalette; | ||
1573 | uvd->frame[frmx].frameState = FrameState_Ready; | ||
1574 | usbvideo_NewFrame(uvd, frmx); | ||
1575 | /* Now frame 0 is supposed to start filling... */ | ||
1576 | } | ||
1577 | |||
1578 | /* | ||
1579 | * Get a pointer to the active frame. It is either previously | ||
1580 | * completed frame or frame in progress but not completed yet. | ||
1581 | */ | ||
1582 | frame = &uvd->frame[frmx]; | ||
1583 | |||
1584 | /* | ||
1585 | * Sit back & wait until the frame gets filled and postprocessed. | ||
1586 | * If we fail to get the picture [in time] then return the error. | ||
1587 | * In this call we specify that we want the frame to be waited for, | ||
1588 | * postprocessed and switched into FrameState_Done_Hold state. This | ||
1589 | * state is used to hold the frame as "fully completed" between | ||
1590 | * subsequent partial reads of the same frame. | ||
1591 | */ | ||
1592 | if (frame->frameState != FrameState_Done_Hold) { | ||
1593 | long rv = -EFAULT; | ||
1594 | if (uvd->flags & FLAGS_NO_DECODING) | ||
1595 | rv = usbvideo_GetFrame(uvd, frmx); | ||
1596 | else if (VALID_CALLBACK(uvd, getFrame)) | ||
1597 | rv = GET_CALLBACK(uvd, getFrame)(uvd, frmx); | ||
1598 | else | ||
1599 | err("getFrame is not set"); | ||
1600 | if ((rv != 0) || (frame->frameState != FrameState_Done_Hold)) { | ||
1601 | count = rv; | ||
1602 | goto read_done; | ||
1603 | } | ||
1604 | } | ||
1605 | |||
1606 | /* | ||
1607 | * Copy bytes to user space. We allow for partial reads, which | ||
1608 | * means that the user application can request read less than | ||
1609 | * the full frame size. It is up to the application to issue | ||
1610 | * subsequent calls until entire frame is read. | ||
1611 | * | ||
1612 | * First things first, make sure we don't copy more than we | ||
1613 | * have - even if the application wants more. That would be | ||
1614 | * a big security embarassment! | ||
1615 | */ | ||
1616 | if ((count + frame->seqRead_Index) > frame->seqRead_Length) | ||
1617 | count = frame->seqRead_Length - frame->seqRead_Index; | ||
1618 | |||
1619 | /* | ||
1620 | * Copy requested amount of data to user space. We start | ||
1621 | * copying from the position where we last left it, which | ||
1622 | * will be zero for a new frame (not read before). | ||
1623 | */ | ||
1624 | if (copy_to_user(buf, frame->data + frame->seqRead_Index, count)) { | ||
1625 | count = -EFAULT; | ||
1626 | goto read_done; | ||
1627 | } | ||
1628 | |||
1629 | /* Update last read position */ | ||
1630 | frame->seqRead_Index += count; | ||
1631 | if (uvd->debug >= 1) { | ||
1632 | err("%s: {copy} count used=%Zd, new seqRead_Index=%ld", | ||
1633 | __FUNCTION__, count, frame->seqRead_Index); | ||
1634 | } | ||
1635 | |||
1636 | /* Finally check if the frame is done with and "release" it */ | ||
1637 | if (frame->seqRead_Index >= frame->seqRead_Length) { | ||
1638 | /* All data has been read */ | ||
1639 | frame->seqRead_Index = 0; | ||
1640 | |||
1641 | /* Mark it as available to be used again. */ | ||
1642 | uvd->frame[frmx].frameState = FrameState_Unused; | ||
1643 | if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) { | ||
1644 | err("%s: usbvideo_NewFrame failed.", __FUNCTION__); | ||
1645 | } | ||
1646 | } | ||
1647 | read_done: | ||
1648 | up(&uvd->lock); | ||
1649 | return count; | ||
1650 | } | ||
1651 | |||
1652 | /* | ||
1653 | * Make all of the blocks of data contiguous | ||
1654 | */ | ||
1655 | static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb) | ||
1656 | { | ||
1657 | char *cdata; | ||
1658 | int i, totlen = 0; | ||
1659 | |||
1660 | for (i = 0; i < urb->number_of_packets; i++) { | ||
1661 | int n = urb->iso_frame_desc[i].actual_length; | ||
1662 | int st = urb->iso_frame_desc[i].status; | ||
1663 | |||
1664 | cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; | ||
1665 | |||
1666 | /* Detect and ignore errored packets */ | ||
1667 | if (st < 0) { | ||
1668 | if (uvd->debug >= 1) | ||
1669 | err("Data error: packet=%d. len=%d. status=%d.", i, n, st); | ||
1670 | uvd->stats.iso_err_count++; | ||
1671 | continue; | ||
1672 | } | ||
1673 | |||
1674 | /* Detect and ignore empty packets */ | ||
1675 | if (n <= 0) { | ||
1676 | uvd->stats.iso_skip_count++; | ||
1677 | continue; | ||
1678 | } | ||
1679 | totlen += n; /* Little local accounting */ | ||
1680 | RingQueue_Enqueue(&uvd->dp, cdata, n); | ||
1681 | } | ||
1682 | return totlen; | ||
1683 | } | ||
1684 | |||
1685 | static void usbvideo_IsocIrq(struct urb *urb, struct pt_regs *regs) | ||
1686 | { | ||
1687 | int i, ret, len; | ||
1688 | struct uvd *uvd = urb->context; | ||
1689 | |||
1690 | /* We don't want to do anything if we are about to be removed! */ | ||
1691 | if (!CAMERA_IS_OPERATIONAL(uvd)) | ||
1692 | return; | ||
1693 | #if 0 | ||
1694 | if (urb->actual_length > 0) { | ||
1695 | info("urb=$%p status=%d. errcount=%d. length=%d.", | ||
1696 | urb, urb->status, urb->error_count, urb->actual_length); | ||
1697 | } else { | ||
1698 | static int c = 0; | ||
1699 | if (c++ % 100 == 0) | ||
1700 | info("No Isoc data"); | ||
1701 | } | ||
1702 | #endif | ||
1703 | |||
1704 | if (!uvd->streaming) { | ||
1705 | if (uvd->debug >= 1) | ||
1706 | info("Not streaming, but interrupt!"); | ||
1707 | return; | ||
1708 | } | ||
1709 | |||
1710 | uvd->stats.urb_count++; | ||
1711 | if (urb->actual_length <= 0) | ||
1712 | goto urb_done_with; | ||
1713 | |||
1714 | /* Copy the data received into ring queue */ | ||
1715 | len = usbvideo_CompressIsochronous(uvd, urb); | ||
1716 | uvd->stats.urb_length = len; | ||
1717 | if (len <= 0) | ||
1718 | goto urb_done_with; | ||
1719 | |||
1720 | /* Here we got some data */ | ||
1721 | uvd->stats.data_count += len; | ||
1722 | RingQueue_WakeUpInterruptible(&uvd->dp); | ||
1723 | |||
1724 | urb_done_with: | ||
1725 | for (i = 0; i < FRAMES_PER_DESC; i++) { | ||
1726 | urb->iso_frame_desc[i].status = 0; | ||
1727 | urb->iso_frame_desc[i].actual_length = 0; | ||
1728 | } | ||
1729 | urb->status = 0; | ||
1730 | urb->dev = uvd->dev; | ||
1731 | ret = usb_submit_urb (urb, GFP_KERNEL); | ||
1732 | if(ret) | ||
1733 | err("usb_submit_urb error (%d)", ret); | ||
1734 | return; | ||
1735 | } | ||
1736 | |||
1737 | /* | ||
1738 | * usbvideo_StartDataPump() | ||
1739 | * | ||
1740 | * History: | ||
1741 | * 27-Jan-2000 Used ibmcam->iface, ibmcam->ifaceAltActive instead | ||
1742 | * of hardcoded values. Simplified by using for loop, | ||
1743 | * allowed any number of URBs. | ||
1744 | */ | ||
1745 | static int usbvideo_StartDataPump(struct uvd *uvd) | ||
1746 | { | ||
1747 | struct usb_device *dev = uvd->dev; | ||
1748 | int i, errFlag; | ||
1749 | |||
1750 | if (uvd->debug > 1) | ||
1751 | info("%s($%p)", __FUNCTION__, uvd); | ||
1752 | |||
1753 | if (!CAMERA_IS_OPERATIONAL(uvd)) { | ||
1754 | err("%s: Camera is not operational", __FUNCTION__); | ||
1755 | return -EFAULT; | ||
1756 | } | ||
1757 | uvd->curframe = -1; | ||
1758 | |||
1759 | /* Alternate interface 1 is is the biggest frame size */ | ||
1760 | i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive); | ||
1761 | if (i < 0) { | ||
1762 | err("%s: usb_set_interface error", __FUNCTION__); | ||
1763 | uvd->last_error = i; | ||
1764 | return -EBUSY; | ||
1765 | } | ||
1766 | if (VALID_CALLBACK(uvd, videoStart)) | ||
1767 | GET_CALLBACK(uvd, videoStart)(uvd); | ||
1768 | else | ||
1769 | err("%s: videoStart not set", __FUNCTION__); | ||
1770 | |||
1771 | /* We double buffer the Iso lists */ | ||
1772 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
1773 | int j, k; | ||
1774 | struct urb *urb = uvd->sbuf[i].urb; | ||
1775 | urb->dev = dev; | ||
1776 | urb->context = uvd; | ||
1777 | urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp); | ||
1778 | urb->interval = 1; | ||
1779 | urb->transfer_flags = URB_ISO_ASAP; | ||
1780 | urb->transfer_buffer = uvd->sbuf[i].data; | ||
1781 | urb->complete = usbvideo_IsocIrq; | ||
1782 | urb->number_of_packets = FRAMES_PER_DESC; | ||
1783 | urb->transfer_buffer_length = uvd->iso_packet_len * FRAMES_PER_DESC; | ||
1784 | for (j=k=0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) { | ||
1785 | urb->iso_frame_desc[j].offset = k; | ||
1786 | urb->iso_frame_desc[j].length = uvd->iso_packet_len; | ||
1787 | } | ||
1788 | } | ||
1789 | |||
1790 | /* Submit all URBs */ | ||
1791 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
1792 | errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL); | ||
1793 | if (errFlag) | ||
1794 | err("%s: usb_submit_isoc(%d) ret %d", __FUNCTION__, i, errFlag); | ||
1795 | } | ||
1796 | |||
1797 | uvd->streaming = 1; | ||
1798 | if (uvd->debug > 1) | ||
1799 | info("%s: streaming=1 video_endp=$%02x", __FUNCTION__, uvd->video_endp); | ||
1800 | return 0; | ||
1801 | } | ||
1802 | |||
1803 | /* | ||
1804 | * usbvideo_StopDataPump() | ||
1805 | * | ||
1806 | * This procedure stops streaming and deallocates URBs. Then it | ||
1807 | * activates zero-bandwidth alt. setting of the video interface. | ||
1808 | * | ||
1809 | * History: | ||
1810 | * 22-Jan-2000 Corrected order of actions to work after surprise removal. | ||
1811 | * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values. | ||
1812 | */ | ||
1813 | static void usbvideo_StopDataPump(struct uvd *uvd) | ||
1814 | { | ||
1815 | int i, j; | ||
1816 | |||
1817 | if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL)) | ||
1818 | return; | ||
1819 | |||
1820 | if (uvd->debug > 1) | ||
1821 | info("%s($%p)", __FUNCTION__, uvd); | ||
1822 | |||
1823 | /* Unschedule all of the iso td's */ | ||
1824 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
1825 | usb_kill_urb(uvd->sbuf[i].urb); | ||
1826 | } | ||
1827 | if (uvd->debug > 1) | ||
1828 | info("%s: streaming=0", __FUNCTION__); | ||
1829 | uvd->streaming = 0; | ||
1830 | |||
1831 | if (!uvd->remove_pending) { | ||
1832 | /* Invoke minidriver's magic to stop the camera */ | ||
1833 | if (VALID_CALLBACK(uvd, videoStop)) | ||
1834 | GET_CALLBACK(uvd, videoStop)(uvd); | ||
1835 | else | ||
1836 | err("%s: videoStop not set", __FUNCTION__); | ||
1837 | |||
1838 | /* Set packet size to 0 */ | ||
1839 | j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive); | ||
1840 | if (j < 0) { | ||
1841 | err("%s: usb_set_interface() error %d.", __FUNCTION__, j); | ||
1842 | uvd->last_error = j; | ||
1843 | } | ||
1844 | } | ||
1845 | } | ||
1846 | |||
1847 | /* | ||
1848 | * usbvideo_NewFrame() | ||
1849 | * | ||
1850 | * History: | ||
1851 | * 29-Mar-00 Added copying of previous frame into the current one. | ||
1852 | * 6-Aug-00 Added model 3 video sizes, removed redundant width, height. | ||
1853 | */ | ||
1854 | static int usbvideo_NewFrame(struct uvd *uvd, int framenum) | ||
1855 | { | ||
1856 | struct usbvideo_frame *frame; | ||
1857 | int n; | ||
1858 | |||
1859 | if (uvd->debug > 1) | ||
1860 | info("usbvideo_NewFrame($%p,%d.)", uvd, framenum); | ||
1861 | |||
1862 | /* If we're not grabbing a frame right now and the other frame is */ | ||
1863 | /* ready to be grabbed into, then use it instead */ | ||
1864 | if (uvd->curframe != -1) | ||
1865 | return 0; | ||
1866 | |||
1867 | /* If necessary we adjust picture settings between frames */ | ||
1868 | if (!uvd->settingsAdjusted) { | ||
1869 | if (VALID_CALLBACK(uvd, adjustPicture)) | ||
1870 | GET_CALLBACK(uvd, adjustPicture)(uvd); | ||
1871 | uvd->settingsAdjusted = 1; | ||
1872 | } | ||
1873 | |||
1874 | n = (framenum + 1) % USBVIDEO_NUMFRAMES; | ||
1875 | if (uvd->frame[n].frameState == FrameState_Ready) | ||
1876 | framenum = n; | ||
1877 | |||
1878 | frame = &uvd->frame[framenum]; | ||
1879 | |||
1880 | frame->frameState = FrameState_Grabbing; | ||
1881 | frame->scanstate = ScanState_Scanning; | ||
1882 | frame->seqRead_Length = 0; /* Accumulated in xxx_parse_data() */ | ||
1883 | frame->deinterlace = Deinterlace_None; | ||
1884 | frame->flags = 0; /* No flags yet, up to minidriver (or us) to set them */ | ||
1885 | uvd->curframe = framenum; | ||
1886 | |||
1887 | /* | ||
1888 | * Normally we would want to copy previous frame into the current one | ||
1889 | * before we even start filling it with data; this allows us to stop | ||
1890 | * filling at any moment; top portion of the frame will be new and | ||
1891 | * bottom portion will stay as it was in previous frame. If we don't | ||
1892 | * do that then missing chunks of video stream will result in flickering | ||
1893 | * portions of old data whatever it was before. | ||
1894 | * | ||
1895 | * If we choose not to copy previous frame (to, for example, save few | ||
1896 | * bus cycles - the frame can be pretty large!) then we have an option | ||
1897 | * to clear the frame before using. If we experience losses in this | ||
1898 | * mode then missing picture will be black (no flickering). | ||
1899 | * | ||
1900 | * Finally, if user chooses not to clean the current frame before | ||
1901 | * filling it with data then the old data will be visible if we fail | ||
1902 | * to refill entire frame with new data. | ||
1903 | */ | ||
1904 | if (!(uvd->flags & FLAGS_SEPARATE_FRAMES)) { | ||
1905 | /* This copies previous frame into this one to mask losses */ | ||
1906 | int prev = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES; | ||
1907 | memmove(frame->data, uvd->frame[prev].data, uvd->max_frame_size); | ||
1908 | } else { | ||
1909 | if (uvd->flags & FLAGS_CLEAN_FRAMES) { | ||
1910 | /* This provides a "clean" frame but slows things down */ | ||
1911 | memset(frame->data, 0, uvd->max_frame_size); | ||
1912 | } | ||
1913 | } | ||
1914 | return 0; | ||
1915 | } | ||
1916 | |||
1917 | /* | ||
1918 | * usbvideo_CollectRawData() | ||
1919 | * | ||
1920 | * This procedure can be used instead of 'processData' callback if you | ||
1921 | * only want to dump the raw data from the camera into the output | ||
1922 | * device (frame buffer). You can look at it with V4L client, but the | ||
1923 | * image will be unwatchable. The main purpose of this code and of the | ||
1924 | * mode FLAGS_NO_DECODING is debugging and capturing of datastreams from | ||
1925 | * new, unknown cameras. This procedure will be automatically invoked | ||
1926 | * instead of the specified callback handler when uvd->flags has bit | ||
1927 | * FLAGS_NO_DECODING set. Therefore, any regular build of any driver | ||
1928 | * based on usbvideo can use this feature at any time. | ||
1929 | */ | ||
1930 | static void usbvideo_CollectRawData(struct uvd *uvd, struct usbvideo_frame *frame) | ||
1931 | { | ||
1932 | int n; | ||
1933 | |||
1934 | assert(uvd != NULL); | ||
1935 | assert(frame != NULL); | ||
1936 | |||
1937 | /* Try to move data from queue into frame buffer */ | ||
1938 | n = RingQueue_GetLength(&uvd->dp); | ||
1939 | if (n > 0) { | ||
1940 | int m; | ||
1941 | /* See how much space we have left */ | ||
1942 | m = uvd->max_frame_size - frame->seqRead_Length; | ||
1943 | if (n > m) | ||
1944 | n = m; | ||
1945 | /* Now move that much data into frame buffer */ | ||
1946 | RingQueue_Dequeue( | ||
1947 | &uvd->dp, | ||
1948 | frame->data + frame->seqRead_Length, | ||
1949 | m); | ||
1950 | frame->seqRead_Length += m; | ||
1951 | } | ||
1952 | /* See if we filled the frame */ | ||
1953 | if (frame->seqRead_Length >= uvd->max_frame_size) { | ||
1954 | frame->frameState = FrameState_Done; | ||
1955 | uvd->curframe = -1; | ||
1956 | uvd->stats.frame_num++; | ||
1957 | } | ||
1958 | } | ||
1959 | |||
1960 | static int usbvideo_GetFrame(struct uvd *uvd, int frameNum) | ||
1961 | { | ||
1962 | struct usbvideo_frame *frame = &uvd->frame[frameNum]; | ||
1963 | |||
1964 | if (uvd->debug >= 2) | ||
1965 | info("%s($%p,%d.)", __FUNCTION__, uvd, frameNum); | ||
1966 | |||
1967 | switch (frame->frameState) { | ||
1968 | case FrameState_Unused: | ||
1969 | if (uvd->debug >= 2) | ||
1970 | info("%s: FrameState_Unused", __FUNCTION__); | ||
1971 | return -EINVAL; | ||
1972 | case FrameState_Ready: | ||
1973 | case FrameState_Grabbing: | ||
1974 | case FrameState_Error: | ||
1975 | { | ||
1976 | int ntries, signalPending; | ||
1977 | redo: | ||
1978 | if (!CAMERA_IS_OPERATIONAL(uvd)) { | ||
1979 | if (uvd->debug >= 2) | ||
1980 | info("%s: Camera is not operational (1)", __FUNCTION__); | ||
1981 | return -EIO; | ||
1982 | } | ||
1983 | ntries = 0; | ||
1984 | do { | ||
1985 | RingQueue_InterruptibleSleepOn(&uvd->dp); | ||
1986 | signalPending = signal_pending(current); | ||
1987 | if (!CAMERA_IS_OPERATIONAL(uvd)) { | ||
1988 | if (uvd->debug >= 2) | ||
1989 | info("%s: Camera is not operational (2)", __FUNCTION__); | ||
1990 | return -EIO; | ||
1991 | } | ||
1992 | assert(uvd->fbuf != NULL); | ||
1993 | if (signalPending) { | ||
1994 | if (uvd->debug >= 2) | ||
1995 | info("%s: Signal=$%08x", __FUNCTION__, signalPending); | ||
1996 | if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) { | ||
1997 | usbvideo_TestPattern(uvd, 1, 0); | ||
1998 | uvd->curframe = -1; | ||
1999 | uvd->stats.frame_num++; | ||
2000 | if (uvd->debug >= 2) | ||
2001 | info("%s: Forced test pattern screen", __FUNCTION__); | ||
2002 | return 0; | ||
2003 | } else { | ||
2004 | /* Standard answer: Interrupted! */ | ||
2005 | if (uvd->debug >= 2) | ||
2006 | info("%s: Interrupted!", __FUNCTION__); | ||
2007 | return -EINTR; | ||
2008 | } | ||
2009 | } else { | ||
2010 | /* No signals - we just got new data in dp queue */ | ||
2011 | if (uvd->flags & FLAGS_NO_DECODING) | ||
2012 | usbvideo_CollectRawData(uvd, frame); | ||
2013 | else if (VALID_CALLBACK(uvd, processData)) | ||
2014 | GET_CALLBACK(uvd, processData)(uvd, frame); | ||
2015 | else | ||
2016 | err("%s: processData not set", __FUNCTION__); | ||
2017 | } | ||
2018 | } while (frame->frameState == FrameState_Grabbing); | ||
2019 | if (uvd->debug >= 2) { | ||
2020 | info("%s: Grabbing done; state=%d. (%lu. bytes)", | ||
2021 | __FUNCTION__, frame->frameState, frame->seqRead_Length); | ||
2022 | } | ||
2023 | if (frame->frameState == FrameState_Error) { | ||
2024 | int ret = usbvideo_NewFrame(uvd, frameNum); | ||
2025 | if (ret < 0) { | ||
2026 | err("%s: usbvideo_NewFrame() failed (%d.)", __FUNCTION__, ret); | ||
2027 | return ret; | ||
2028 | } | ||
2029 | goto redo; | ||
2030 | } | ||
2031 | /* Note that we fall through to meet our destiny below */ | ||
2032 | } | ||
2033 | case FrameState_Done: | ||
2034 | /* | ||
2035 | * Do all necessary postprocessing of data prepared in | ||
2036 | * "interrupt" code and the collecting code above. The | ||
2037 | * frame gets marked as FrameState_Done by queue parsing code. | ||
2038 | * This status means that we collected enough data and | ||
2039 | * most likely processed it as we went through. However | ||
2040 | * the data may need postprocessing, such as deinterlacing | ||
2041 | * or picture adjustments implemented in software (horror!) | ||
2042 | * | ||
2043 | * As soon as the frame becomes "final" it gets promoted to | ||
2044 | * FrameState_Done_Hold status where it will remain until the | ||
2045 | * caller consumed all the video data from the frame. Then | ||
2046 | * the empty shell of ex-frame is thrown out for dogs to eat. | ||
2047 | * But we, worried about pets, will recycle the frame! | ||
2048 | */ | ||
2049 | uvd->stats.frame_num++; | ||
2050 | if ((uvd->flags & FLAGS_NO_DECODING) == 0) { | ||
2051 | if (VALID_CALLBACK(uvd, postProcess)) | ||
2052 | GET_CALLBACK(uvd, postProcess)(uvd, frame); | ||
2053 | if (frame->flags & USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST) | ||
2054 | usbvideo_SoftwareContrastAdjustment(uvd, frame); | ||
2055 | } | ||
2056 | frame->frameState = FrameState_Done_Hold; | ||
2057 | if (uvd->debug >= 2) | ||
2058 | info("%s: Entered FrameState_Done_Hold state.", __FUNCTION__); | ||
2059 | return 0; | ||
2060 | |||
2061 | case FrameState_Done_Hold: | ||
2062 | /* | ||
2063 | * We stay in this state indefinitely until someone external, | ||
2064 | * like ioctl() or read() call finishes digesting the frame | ||
2065 | * data. Then it will mark the frame as FrameState_Unused and | ||
2066 | * it will be released back into the wild to roam freely. | ||
2067 | */ | ||
2068 | if (uvd->debug >= 2) | ||
2069 | info("%s: FrameState_Done_Hold state.", __FUNCTION__); | ||
2070 | return 0; | ||
2071 | } | ||
2072 | |||
2073 | /* Catch-all for other cases. We shall not be here. */ | ||
2074 | err("%s: Invalid state %d.", __FUNCTION__, frame->frameState); | ||
2075 | frame->frameState = FrameState_Unused; | ||
2076 | return 0; | ||
2077 | } | ||
2078 | |||
2079 | /* | ||
2080 | * usbvideo_DeinterlaceFrame() | ||
2081 | * | ||
2082 | * This procedure deinterlaces the given frame. Some cameras produce | ||
2083 | * only half of scanlines - sometimes only even lines, sometimes only | ||
2084 | * odd lines. The deinterlacing method is stored in frame->deinterlace | ||
2085 | * variable. | ||
2086 | * | ||
2087 | * Here we scan the frame vertically and replace missing scanlines with | ||
2088 | * average between surrounding ones - before and after. If we have no | ||
2089 | * line above then we just copy next line. Similarly, if we need to | ||
2090 | * create a last line then preceding line is used. | ||
2091 | */ | ||
2092 | void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame) | ||
2093 | { | ||
2094 | if ((uvd == NULL) || (frame == NULL)) | ||
2095 | return; | ||
2096 | |||
2097 | if ((frame->deinterlace == Deinterlace_FillEvenLines) || | ||
2098 | (frame->deinterlace == Deinterlace_FillOddLines)) | ||
2099 | { | ||
2100 | const int v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; | ||
2101 | int i = (frame->deinterlace == Deinterlace_FillEvenLines) ? 0 : 1; | ||
2102 | |||
2103 | for (; i < VIDEOSIZE_Y(frame->request); i += 2) { | ||
2104 | const unsigned char *fs1, *fs2; | ||
2105 | unsigned char *fd; | ||
2106 | int ip, in, j; /* Previous and next lines */ | ||
2107 | |||
2108 | /* | ||
2109 | * Need to average lines before and after 'i'. | ||
2110 | * If we go out of bounds seeking those lines then | ||
2111 | * we point back to existing line. | ||
2112 | */ | ||
2113 | ip = i - 1; /* First, get rough numbers */ | ||
2114 | in = i + 1; | ||
2115 | |||
2116 | /* Now validate */ | ||
2117 | if (ip < 0) | ||
2118 | ip = in; | ||
2119 | if (in >= VIDEOSIZE_Y(frame->request)) | ||
2120 | in = ip; | ||
2121 | |||
2122 | /* Sanity check */ | ||
2123 | if ((ip < 0) || (in < 0) || | ||
2124 | (ip >= VIDEOSIZE_Y(frame->request)) || | ||
2125 | (in >= VIDEOSIZE_Y(frame->request))) | ||
2126 | { | ||
2127 | err("Error: ip=%d. in=%d. req.height=%ld.", | ||
2128 | ip, in, VIDEOSIZE_Y(frame->request)); | ||
2129 | break; | ||
2130 | } | ||
2131 | |||
2132 | /* Now we need to average lines 'ip' and 'in' to produce line 'i' */ | ||
2133 | fs1 = frame->data + (v4l_linesize * ip); | ||
2134 | fs2 = frame->data + (v4l_linesize * in); | ||
2135 | fd = frame->data + (v4l_linesize * i); | ||
2136 | |||
2137 | /* Average lines around destination */ | ||
2138 | for (j=0; j < v4l_linesize; j++) { | ||
2139 | fd[j] = (unsigned char)((((unsigned) fs1[j]) + | ||
2140 | ((unsigned)fs2[j])) >> 1); | ||
2141 | } | ||
2142 | } | ||
2143 | } | ||
2144 | |||
2145 | /* Optionally display statistics on the screen */ | ||
2146 | if (uvd->flags & FLAGS_OVERLAY_STATS) | ||
2147 | usbvideo_OverlayStats(uvd, frame); | ||
2148 | } | ||
2149 | |||
2150 | EXPORT_SYMBOL(usbvideo_DeinterlaceFrame); | ||
2151 | |||
2152 | /* | ||
2153 | * usbvideo_SoftwareContrastAdjustment() | ||
2154 | * | ||
2155 | * This code adjusts the contrast of the frame, assuming RGB24 format. | ||
2156 | * As most software image processing, this job is CPU-intensive. | ||
2157 | * Get a camera that supports hardware adjustment! | ||
2158 | * | ||
2159 | * History: | ||
2160 | * 09-Feb-2001 Created. | ||
2161 | */ | ||
2162 | static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, | ||
2163 | struct usbvideo_frame *frame) | ||
2164 | { | ||
2165 | int i, j, v4l_linesize; | ||
2166 | signed long adj; | ||
2167 | const int ccm = 128; /* Color correction median - see below */ | ||
2168 | |||
2169 | if ((uvd == NULL) || (frame == NULL)) { | ||
2170 | err("%s: Illegal call.", __FUNCTION__); | ||
2171 | return; | ||
2172 | } | ||
2173 | adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ | ||
2174 | RESTRICT_TO_RANGE(adj, -ccm, ccm+1); | ||
2175 | if (adj == 0) { | ||
2176 | /* In rare case of no adjustment */ | ||
2177 | return; | ||
2178 | } | ||
2179 | v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; | ||
2180 | for (i=0; i < VIDEOSIZE_Y(frame->request); i++) { | ||
2181 | unsigned char *fd = frame->data + (v4l_linesize * i); | ||
2182 | for (j=0; j < v4l_linesize; j++) { | ||
2183 | signed long v = (signed long) fd[j]; | ||
2184 | /* Magnify up to 2 times, reduce down to zero */ | ||
2185 | v = 128 + ((ccm + adj) * (v - 128)) / ccm; | ||
2186 | RESTRICT_TO_RANGE(v, 0, 0xFF); /* Must flatten tails */ | ||
2187 | fd[j] = (unsigned char) v; | ||
2188 | } | ||
2189 | } | ||
2190 | } | ||
2191 | |||
2192 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/media/usbvideo.h b/drivers/usb/media/usbvideo.h new file mode 100644 index 000000000000..6c390a1f981b --- /dev/null +++ b/drivers/usb/media/usbvideo.h | |||
@@ -0,0 +1,393 @@ | |||
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 | |||
23 | /* Most helpful debugging aid */ | ||
24 | #define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__)))) | ||
25 | |||
26 | #define USBVIDEO_REPORT_STATS 1 /* Set to 0 to block statistics on close */ | ||
27 | |||
28 | /* Bit flags (options) */ | ||
29 | #define FLAGS_RETRY_VIDIOCSYNC (1 << 0) | ||
30 | #define FLAGS_MONOCHROME (1 << 1) | ||
31 | #define FLAGS_DISPLAY_HINTS (1 << 2) | ||
32 | #define FLAGS_OVERLAY_STATS (1 << 3) | ||
33 | #define FLAGS_FORCE_TESTPATTERN (1 << 4) | ||
34 | #define FLAGS_SEPARATE_FRAMES (1 << 5) | ||
35 | #define FLAGS_CLEAN_FRAMES (1 << 6) | ||
36 | #define FLAGS_NO_DECODING (1 << 7) | ||
37 | |||
38 | /* Bit flags for frames (apply to the frame where they are specified) */ | ||
39 | #define USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST (1 << 0) | ||
40 | |||
41 | /* Camera capabilities (maximum) */ | ||
42 | #define CAMERA_URB_FRAMES 32 | ||
43 | #define CAMERA_MAX_ISO_PACKET 1023 /* 1022 actually sent by camera */ | ||
44 | #define FRAMES_PER_DESC (CAMERA_URB_FRAMES) | ||
45 | #define FRAME_SIZE_PER_DESC (CAMERA_MAX_ISO_PACKET) | ||
46 | |||
47 | /* This macro restricts an int variable to an inclusive range */ | ||
48 | #define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); } | ||
49 | |||
50 | #define V4L_BYTES_PER_PIXEL 3 /* Because we produce RGB24 */ | ||
51 | |||
52 | /* | ||
53 | * Use this macro to construct constants for different video sizes. | ||
54 | * We have to deal with different video sizes that have to be | ||
55 | * configured in the device or compared against when we receive | ||
56 | * a data. Normally one would define a bunch of VIDEOSIZE_x_by_y | ||
57 | * #defines and that's the end of story. However this solution | ||
58 | * does not allow to convert between real pixel sizes and the | ||
59 | * constant (integer) value that may be used to tag a frame or | ||
60 | * whatever. The set of macros below constructs videosize constants | ||
61 | * from the pixel size and allows to reconstruct the pixel size | ||
62 | * from the combined value later. | ||
63 | */ | ||
64 | #define VIDEOSIZE(x,y) (((x) & 0xFFFFL) | (((y) & 0xFFFFL) << 16)) | ||
65 | #define VIDEOSIZE_X(vs) ((vs) & 0xFFFFL) | ||
66 | #define VIDEOSIZE_Y(vs) (((vs) >> 16) & 0xFFFFL) | ||
67 | typedef unsigned long videosize_t; | ||
68 | |||
69 | /* | ||
70 | * This macro checks if the camera is still operational. The 'uvd' | ||
71 | * pointer must be valid, uvd->dev must be valid, we are not | ||
72 | * removing the device and the device has not erred on us. | ||
73 | */ | ||
74 | #define CAMERA_IS_OPERATIONAL(uvd) (\ | ||
75 | (uvd != NULL) && \ | ||
76 | ((uvd)->dev != NULL) && \ | ||
77 | ((uvd)->last_error == 0) && \ | ||
78 | (!(uvd)->remove_pending)) | ||
79 | |||
80 | /* | ||
81 | * We use macros to do YUV -> RGB conversion because this is | ||
82 | * very important for speed and totally unimportant for size. | ||
83 | * | ||
84 | * YUV -> RGB Conversion | ||
85 | * --------------------- | ||
86 | * | ||
87 | * B = 1.164*(Y-16) + 2.018*(V-128) | ||
88 | * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128) | ||
89 | * R = 1.164*(Y-16) + 1.596*(U-128) | ||
90 | * | ||
91 | * If you fancy integer arithmetics (as you should), hear this: | ||
92 | * | ||
93 | * 65536*B = 76284*(Y-16) + 132252*(V-128) | ||
94 | * 65536*G = 76284*(Y-16) - 53281*(U-128) - 25625*(V-128) | ||
95 | * 65536*R = 76284*(Y-16) + 104595*(U-128) | ||
96 | * | ||
97 | * Make sure the output values are within [0..255] range. | ||
98 | */ | ||
99 | #define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x))) | ||
100 | #define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \ | ||
101 | int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \ | ||
102 | mm_y = (my) - 16; \ | ||
103 | mm_u = (mu) - 128; \ | ||
104 | mm_v = (mv) - 128; \ | ||
105 | mm_yc= mm_y * 76284; \ | ||
106 | mm_b = (mm_yc + 132252*mm_v ) >> 16; \ | ||
107 | mm_g = (mm_yc - 53281*mm_u - 25625*mm_v ) >> 16; \ | ||
108 | mm_r = (mm_yc + 104595*mm_u ) >> 16; \ | ||
109 | mb = LIMIT_RGB(mm_b); \ | ||
110 | mg = LIMIT_RGB(mm_g); \ | ||
111 | mr = LIMIT_RGB(mm_r); \ | ||
112 | } | ||
113 | |||
114 | #define RING_QUEUE_SIZE (128*1024) /* Must be a power of 2 */ | ||
115 | #define RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1) | ||
116 | #define RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n) | ||
117 | #define RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)]) | ||
118 | |||
119 | struct RingQueue { | ||
120 | unsigned char *queue; /* Data from the Isoc data pump */ | ||
121 | int length; /* How many bytes allocated for the queue */ | ||
122 | int wi; /* That's where we write */ | ||
123 | int ri; /* Read from here until you hit write index */ | ||
124 | wait_queue_head_t wqh; /* Processes waiting */ | ||
125 | }; | ||
126 | |||
127 | enum ScanState { | ||
128 | ScanState_Scanning, /* Scanning for header */ | ||
129 | ScanState_Lines /* Parsing lines */ | ||
130 | }; | ||
131 | |||
132 | /* Completion states of the data parser */ | ||
133 | enum ParseState { | ||
134 | scan_Continue, /* Just parse next item */ | ||
135 | scan_NextFrame, /* Frame done, send it to V4L */ | ||
136 | scan_Out, /* Not enough data for frame */ | ||
137 | scan_EndParse /* End parsing */ | ||
138 | }; | ||
139 | |||
140 | enum FrameState { | ||
141 | FrameState_Unused, /* Unused (no MCAPTURE) */ | ||
142 | FrameState_Ready, /* Ready to start grabbing */ | ||
143 | FrameState_Grabbing, /* In the process of being grabbed into */ | ||
144 | FrameState_Done, /* Finished grabbing, but not been synced yet */ | ||
145 | FrameState_Done_Hold, /* Are syncing or reading */ | ||
146 | FrameState_Error, /* Something bad happened while processing */ | ||
147 | }; | ||
148 | |||
149 | /* | ||
150 | * Some frames may contain only even or odd lines. This type | ||
151 | * specifies what type of deinterlacing is required. | ||
152 | */ | ||
153 | enum Deinterlace { | ||
154 | Deinterlace_None=0, | ||
155 | Deinterlace_FillOddLines, | ||
156 | Deinterlace_FillEvenLines | ||
157 | }; | ||
158 | |||
159 | #define USBVIDEO_NUMFRAMES 2 /* How many frames we work with */ | ||
160 | #define USBVIDEO_NUMSBUF 2 /* How many URBs linked in a ring */ | ||
161 | |||
162 | /* This structure represents one Isoc request - URB and buffer */ | ||
163 | struct usbvideo_sbuf { | ||
164 | char *data; | ||
165 | struct urb *urb; | ||
166 | }; | ||
167 | |||
168 | struct usbvideo_frame { | ||
169 | char *data; /* Frame buffer */ | ||
170 | unsigned long header; /* Significant bits from the header */ | ||
171 | |||
172 | videosize_t canvas; /* The canvas (max. image) allocated */ | ||
173 | videosize_t request; /* That's what the application asked for */ | ||
174 | unsigned short palette; /* The desired format */ | ||
175 | |||
176 | enum FrameState frameState;/* State of grabbing */ | ||
177 | enum ScanState scanstate; /* State of scanning */ | ||
178 | enum Deinterlace deinterlace; | ||
179 | int flags; /* USBVIDEO_FRAME_FLAG_xxx bit flags */ | ||
180 | |||
181 | int curline; /* Line of frame we're working on */ | ||
182 | |||
183 | long seqRead_Length; /* Raw data length of frame */ | ||
184 | long seqRead_Index; /* Amount of data that has been already read */ | ||
185 | |||
186 | void *user; /* Additional data that user may need */ | ||
187 | }; | ||
188 | |||
189 | /* Statistics that can be overlaid on screen */ | ||
190 | struct usbvideo_statistics { | ||
191 | unsigned long frame_num; /* Sequential number of the frame */ | ||
192 | unsigned long urb_count; /* How many URBs we received so far */ | ||
193 | unsigned long urb_length; /* Length of last URB */ | ||
194 | unsigned long data_count; /* How many bytes we received */ | ||
195 | unsigned long header_count; /* How many frame headers we found */ | ||
196 | unsigned long iso_skip_count; /* How many empty ISO packets received */ | ||
197 | unsigned long iso_err_count; /* How many bad ISO packets received */ | ||
198 | }; | ||
199 | |||
200 | struct usbvideo; | ||
201 | |||
202 | struct uvd { | ||
203 | struct video_device vdev; /* Must be the first field! */ | ||
204 | struct usb_device *dev; | ||
205 | struct usbvideo *handle; /* Points back to the struct usbvideo */ | ||
206 | void *user_data; /* Camera-dependent data */ | ||
207 | int user_size; /* Size of that camera-dependent data */ | ||
208 | int debug; /* Debug level for usbvideo */ | ||
209 | unsigned char iface; /* Video interface number */ | ||
210 | unsigned char video_endp; | ||
211 | unsigned char ifaceAltActive; | ||
212 | unsigned char ifaceAltInactive; /* Alt settings */ | ||
213 | unsigned long flags; /* FLAGS_USBVIDEO_xxx */ | ||
214 | unsigned long paletteBits; /* Which palettes we accept? */ | ||
215 | unsigned short defaultPalette; /* What palette to use for read() */ | ||
216 | struct semaphore lock; | ||
217 | int user; /* user count for exclusive use */ | ||
218 | |||
219 | videosize_t videosize; /* Current setting */ | ||
220 | videosize_t canvas; /* This is the width,height of the V4L canvas */ | ||
221 | int max_frame_size; /* Bytes in one video frame */ | ||
222 | |||
223 | int uvd_used; /* Is this structure in use? */ | ||
224 | int streaming; /* Are we streaming Isochronous? */ | ||
225 | int grabbing; /* Are we grabbing? */ | ||
226 | int settingsAdjusted; /* Have we adjusted contrast etc.? */ | ||
227 | int last_error; /* What calamity struck us? */ | ||
228 | |||
229 | char *fbuf; /* Videodev buffer area */ | ||
230 | int fbuf_size; /* Videodev buffer size */ | ||
231 | |||
232 | int curframe; | ||
233 | int iso_packet_len; /* Videomode-dependent, saves bus bandwidth */ | ||
234 | |||
235 | struct RingQueue dp; /* Isoc data pump */ | ||
236 | struct usbvideo_frame frame[USBVIDEO_NUMFRAMES]; | ||
237 | struct usbvideo_sbuf sbuf[USBVIDEO_NUMSBUF]; | ||
238 | |||
239 | volatile int remove_pending; /* If set then about to exit */ | ||
240 | |||
241 | struct video_picture vpic, vpic_old; /* Picture settings */ | ||
242 | struct video_capability vcap; /* Video capabilities */ | ||
243 | struct video_channel vchan; /* May be used for tuner support */ | ||
244 | struct usbvideo_statistics stats; | ||
245 | char videoName[32]; /* Holds name like "video7" */ | ||
246 | }; | ||
247 | |||
248 | /* | ||
249 | * usbvideo callbacks (virtual methods). They are set when usbvideo | ||
250 | * services are registered. All of these default to NULL, except those | ||
251 | * that default to usbvideo-provided methods. | ||
252 | */ | ||
253 | struct usbvideo_cb { | ||
254 | int (*probe)(struct usb_interface *, const struct usb_device_id *); | ||
255 | void (*userFree)(struct uvd *); | ||
256 | void (*disconnect)(struct usb_interface *); | ||
257 | int (*setupOnOpen)(struct uvd *); | ||
258 | void (*videoStart)(struct uvd *); | ||
259 | void (*videoStop)(struct uvd *); | ||
260 | void (*processData)(struct uvd *, struct usbvideo_frame *); | ||
261 | void (*postProcess)(struct uvd *, struct usbvideo_frame *); | ||
262 | void (*adjustPicture)(struct uvd *); | ||
263 | int (*getFPS)(struct uvd *); | ||
264 | int (*overlayHook)(struct uvd *, struct usbvideo_frame *); | ||
265 | int (*getFrame)(struct uvd *, int); | ||
266 | int (*startDataPump)(struct uvd *uvd); | ||
267 | void (*stopDataPump)(struct uvd *uvd); | ||
268 | int (*setVideoMode)(struct uvd *uvd, struct video_window *vw); | ||
269 | }; | ||
270 | |||
271 | struct usbvideo { | ||
272 | int num_cameras; /* As allocated */ | ||
273 | struct usb_driver usbdrv; /* Interface to the USB stack */ | ||
274 | char drvName[80]; /* Driver name */ | ||
275 | struct semaphore lock; /* Mutex protecting camera structures */ | ||
276 | struct usbvideo_cb cb; /* Table of callbacks (virtual methods) */ | ||
277 | struct video_device vdt; /* Video device template */ | ||
278 | struct uvd *cam; /* Array of camera structures */ | ||
279 | struct module *md_module; /* Minidriver module */ | ||
280 | }; | ||
281 | |||
282 | |||
283 | /* | ||
284 | * This macro retrieves callback address from the struct uvd object. | ||
285 | * No validity checks are done here, so be sure to check the | ||
286 | * callback beforehand with VALID_CALLBACK. | ||
287 | */ | ||
288 | #define GET_CALLBACK(uvd,cbName) ((uvd)->handle->cb.cbName) | ||
289 | |||
290 | /* | ||
291 | * This macro returns either callback pointer or NULL. This is safe | ||
292 | * macro, meaning that most of components of data structures involved | ||
293 | * may be NULL - this only results in NULL being returned. You may | ||
294 | * wish to use this macro to make sure that the callback is callable. | ||
295 | * However keep in mind that those checks take time. | ||
296 | */ | ||
297 | #define VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \ | ||
298 | ((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL) | ||
299 | |||
300 | int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len); | ||
301 | int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n); | ||
302 | void RingQueue_WakeUpInterruptible(struct RingQueue *rq); | ||
303 | void RingQueue_Flush(struct RingQueue *rq); | ||
304 | |||
305 | static inline int RingQueue_GetLength(const struct RingQueue *rq) | ||
306 | { | ||
307 | return (rq->wi - rq->ri + rq->length) & (rq->length-1); | ||
308 | } | ||
309 | |||
310 | static inline int RingQueue_GetFreeSpace(const struct RingQueue *rq) | ||
311 | { | ||
312 | return rq->length - RingQueue_GetLength(rq); | ||
313 | } | ||
314 | |||
315 | void usbvideo_DrawLine( | ||
316 | struct usbvideo_frame *frame, | ||
317 | int x1, int y1, | ||
318 | int x2, int y2, | ||
319 | unsigned char cr, unsigned char cg, unsigned char cb); | ||
320 | void usbvideo_HexDump(const unsigned char *data, int len); | ||
321 | void usbvideo_SayAndWait(const char *what); | ||
322 | void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode); | ||
323 | |||
324 | /* Memory allocation routines */ | ||
325 | unsigned long usbvideo_kvirt_to_pa(unsigned long adr); | ||
326 | |||
327 | int usbvideo_register( | ||
328 | struct usbvideo **pCams, | ||
329 | const int num_cams, | ||
330 | const int num_extra, | ||
331 | const char *driverName, | ||
332 | const struct usbvideo_cb *cbTable, | ||
333 | struct module *md, | ||
334 | const struct usb_device_id *id_table); | ||
335 | struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams); | ||
336 | int usbvideo_RegisterVideoDevice(struct uvd *uvd); | ||
337 | void usbvideo_Deregister(struct usbvideo **uvt); | ||
338 | |||
339 | int usbvideo_v4l_initialize(struct video_device *dev); | ||
340 | |||
341 | void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame); | ||
342 | |||
343 | /* | ||
344 | * This code performs bounds checking - use it when working with | ||
345 | * new formats, or else you may get oopses all over the place. | ||
346 | * If pixel falls out of bounds then it gets shoved back (as close | ||
347 | * to place of offence as possible) and is painted bright red. | ||
348 | * | ||
349 | * There are two important concepts: frame width, height and | ||
350 | * V4L canvas width, height. The former is the area requested by | ||
351 | * the application -for this very frame-. The latter is the largest | ||
352 | * possible frame that we can serve (we advertise that via V4L ioctl). | ||
353 | * The frame data is expected to be formatted as lines of length | ||
354 | * VIDEOSIZE_X(fr->request), total VIDEOSIZE_Y(frame->request) lines. | ||
355 | */ | ||
356 | static inline void RGB24_PUTPIXEL( | ||
357 | struct usbvideo_frame *fr, | ||
358 | int ix, int iy, | ||
359 | unsigned char vr, | ||
360 | unsigned char vg, | ||
361 | unsigned char vb) | ||
362 | { | ||
363 | register unsigned char *pf; | ||
364 | int limiter = 0, mx, my; | ||
365 | mx = ix; | ||
366 | my = iy; | ||
367 | if (mx < 0) { | ||
368 | mx=0; | ||
369 | limiter++; | ||
370 | } else if (mx >= VIDEOSIZE_X((fr)->request)) { | ||
371 | mx= VIDEOSIZE_X((fr)->request) - 1; | ||
372 | limiter++; | ||
373 | } | ||
374 | if (my < 0) { | ||
375 | my = 0; | ||
376 | limiter++; | ||
377 | } else if (my >= VIDEOSIZE_Y((fr)->request)) { | ||
378 | my = VIDEOSIZE_Y((fr)->request) - 1; | ||
379 | limiter++; | ||
380 | } | ||
381 | pf = (fr)->data + V4L_BYTES_PER_PIXEL*((iy)*VIDEOSIZE_X((fr)->request) + (ix)); | ||
382 | if (limiter) { | ||
383 | *pf++ = 0; | ||
384 | *pf++ = 0; | ||
385 | *pf++ = 0xFF; | ||
386 | } else { | ||
387 | *pf++ = (vb); | ||
388 | *pf++ = (vg); | ||
389 | *pf++ = (vr); | ||
390 | } | ||
391 | } | ||
392 | |||
393 | #endif /* usbvideo_h */ | ||
diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c new file mode 100644 index 000000000000..4a5857c53f11 --- /dev/null +++ b/drivers/usb/media/vicam.c | |||
@@ -0,0 +1,1409 @@ | |||
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 "usbvideo.h" | ||
46 | |||
47 | // #define VICAM_DEBUG | ||
48 | |||
49 | #ifdef VICAM_DEBUG | ||
50 | #define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args) | ||
51 | #define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args) | ||
52 | #else | ||
53 | #define DBG(fmn,args...) do {} while(0) | ||
54 | #endif | ||
55 | |||
56 | #define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org" | ||
57 | #define DRIVER_DESC "ViCam WebCam Driver" | ||
58 | |||
59 | /* Define these values to match your device */ | ||
60 | #define USB_VICAM_VENDOR_ID 0x04c1 | ||
61 | #define USB_VICAM_PRODUCT_ID 0x009d | ||
62 | |||
63 | #define VICAM_BYTES_PER_PIXEL 3 | ||
64 | #define VICAM_MAX_READ_SIZE (512*242+128) | ||
65 | #define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240) | ||
66 | #define VICAM_FRAMES 2 | ||
67 | |||
68 | #define VICAM_HEADER_SIZE 64 | ||
69 | |||
70 | #define clamp( x, l, h ) max_t( __typeof__( x ), \ | ||
71 | ( l ), \ | ||
72 | min_t( __typeof__( x ), \ | ||
73 | ( h ), \ | ||
74 | ( x ) ) ) | ||
75 | |||
76 | /* Not sure what all the bytes in these char | ||
77 | * arrays do, but they're necessary to make | ||
78 | * the camera work. | ||
79 | */ | ||
80 | |||
81 | static unsigned char setup1[] = { | ||
82 | 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67, | ||
83 | 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00, | ||
84 | 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17, | ||
85 | 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00, | ||
86 | 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00 | ||
87 | }; | ||
88 | |||
89 | static unsigned char setup2[] = { | ||
90 | 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00, | ||
91 | 0x00, 0x00 | ||
92 | }; | ||
93 | |||
94 | static unsigned char setup3[] = { | ||
95 | 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00 | ||
96 | }; | ||
97 | |||
98 | static unsigned char setup4[] = { | ||
99 | 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07, | ||
100 | 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00, | ||
101 | 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00, | ||
102 | 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07, | ||
103 | 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00, | ||
104 | 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00, | ||
105 | 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07, | ||
106 | 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, | ||
107 | 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0, | ||
108 | 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07, | ||
109 | 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00, | ||
110 | 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0, | ||
111 | 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1, | ||
112 | 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09, | ||
113 | 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, | ||
114 | 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF, | ||
115 | 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02, | ||
116 | 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, | ||
117 | 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF, | ||
118 | 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00, | ||
119 | 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00, | ||
120 | 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05, | ||
121 | 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA, | ||
122 | 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06, | ||
123 | 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF, | ||
124 | 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05, | ||
125 | 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01, | ||
126 | 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09, | ||
127 | 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06, | ||
128 | 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05, | ||
129 | 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA, | ||
130 | 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05, | ||
131 | 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, | ||
132 | 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00, | ||
133 | 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF, | ||
134 | 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00, | ||
135 | 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0, | ||
136 | 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06, | ||
137 | 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00, | ||
138 | 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07, | ||
139 | 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF, | ||
140 | 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00, | ||
141 | 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06, | ||
142 | 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57, | ||
143 | 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57, | ||
144 | 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00, | ||
145 | 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0, | ||
146 | 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B, | ||
147 | 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06, | ||
148 | 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, | ||
149 | 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E, | ||
150 | 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, | ||
151 | 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, | ||
152 | 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00, | ||
153 | 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06, | ||
154 | 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF, | ||
155 | 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0, | ||
156 | 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, | ||
157 | 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05, | ||
158 | 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF, | ||
159 | 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0, | ||
160 | 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07, | ||
161 | 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07, | ||
162 | 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF, | ||
163 | 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF, | ||
164 | 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, | ||
165 | 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01, | ||
166 | 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1, | ||
167 | 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67, | ||
168 | 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00, | ||
169 | 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07, | ||
170 | 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07, | ||
171 | 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07, | ||
172 | 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00, | ||
173 | 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06, | ||
174 | 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67, | ||
175 | 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8, | ||
176 | 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, | ||
177 | 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF, | ||
178 | 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02, | ||
179 | 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07, | ||
180 | 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06, | ||
181 | 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05, | ||
182 | 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80, | ||
183 | 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00, | ||
184 | 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06, | ||
185 | 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07, | ||
186 | 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05, | ||
187 | 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05, | ||
188 | 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80, | ||
189 | 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04, | ||
190 | 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF, | ||
191 | 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06, | ||
192 | 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, | ||
193 | 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00, | ||
194 | 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05, | ||
195 | 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07, | ||
196 | 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07, | ||
197 | 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07, | ||
198 | 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF, | ||
199 | 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07, | ||
200 | 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06, | ||
201 | 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05, | ||
202 | 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07, | ||
203 | 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00, | ||
204 | 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00, | ||
205 | 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77, | ||
206 | 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04, | ||
207 | 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0, | ||
208 | 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1, | ||
209 | 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07, | ||
210 | 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF, | ||
211 | 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, | ||
212 | 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, | ||
213 | 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, | ||
214 | 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77, | ||
215 | 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1, | ||
216 | 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07, | ||
217 | 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, | ||
218 | 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06, | ||
219 | 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, | ||
220 | 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, | ||
221 | 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07, | ||
222 | 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00, | ||
223 | 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00, | ||
224 | 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, | ||
225 | 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, | ||
226 | 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F, | ||
227 | 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00, | ||
228 | 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00, | ||
229 | 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA, | ||
230 | 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, | ||
231 | 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06, | ||
232 | 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF, | ||
233 | 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B, | ||
234 | 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, | ||
235 | 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09, | ||
236 | 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05, | ||
237 | 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07, | ||
238 | 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00, | ||
239 | 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF, | ||
240 | 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05, | ||
241 | 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00, | ||
242 | 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00, | ||
243 | 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05, | ||
244 | 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05, | ||
245 | 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00, | ||
246 | 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF, | ||
247 | 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09, | ||
248 | 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, | ||
249 | 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1, | ||
250 | 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00, | ||
251 | 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05, | ||
252 | 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00, | ||
253 | 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00, | ||
254 | 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05, | ||
255 | 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0, | ||
256 | 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67, | ||
257 | 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87, | ||
258 | 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9, | ||
259 | 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1, | ||
260 | 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF, | ||
261 | 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00, | ||
262 | 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0, | ||
263 | 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87, | ||
264 | 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, | ||
265 | 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67, | ||
266 | 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, | ||
267 | 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, | ||
268 | 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67, | ||
269 | 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, | ||
270 | 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, | ||
271 | 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01, | ||
272 | 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00, | ||
273 | 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF, | ||
274 | 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, | ||
275 | 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67, | ||
276 | 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09, | ||
277 | 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, | ||
278 | 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA, | ||
279 | 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87, | ||
280 | 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07, | ||
281 | 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80, | ||
282 | 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07, | ||
283 | 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80, | ||
284 | 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02, | ||
285 | 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09, | ||
286 | 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, | ||
287 | 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00, | ||
288 | 0x00, 0x00, 0x00, 0x00, 0x00, 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, | ||
310 | }; | ||
311 | |||
312 | static unsigned char setup5[] = { | ||
313 | 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00, | ||
314 | 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, | ||
315 | 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00, | ||
316 | 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00, | ||
317 | 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00, | ||
318 | 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00, | ||
319 | 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00, | ||
320 | 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01, | ||
321 | 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01, | ||
322 | 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01, | ||
323 | 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01, | ||
324 | 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01, | ||
325 | 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01, | ||
326 | 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01, | ||
327 | 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01, | ||
328 | 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02, | ||
329 | 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02, | ||
330 | 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02, | ||
331 | 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02, | ||
332 | 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02, | ||
333 | 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02, | ||
334 | 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02, | ||
335 | 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02, | ||
336 | 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03, | ||
337 | 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03, | ||
338 | 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03, | ||
339 | 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03, | ||
340 | 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03, | ||
341 | 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03, | ||
342 | 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03, | ||
343 | 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04, | ||
344 | 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04, | ||
345 | 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04, | ||
346 | 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04, | ||
347 | 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04, | ||
348 | 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04, | ||
349 | 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04, | ||
350 | 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05, | ||
351 | 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00 | ||
352 | }; | ||
353 | |||
354 | /* rvmalloc / rvfree copied from usbvideo.c | ||
355 | * | ||
356 | * Not sure why these are not yet non-statics which I can reference through | ||
357 | * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime | ||
358 | * in the future. | ||
359 | * | ||
360 | */ | ||
361 | static void *rvmalloc(unsigned long size) | ||
362 | { | ||
363 | void *mem; | ||
364 | unsigned long adr; | ||
365 | |||
366 | size = PAGE_ALIGN(size); | ||
367 | mem = vmalloc_32(size); | ||
368 | if (!mem) | ||
369 | return NULL; | ||
370 | |||
371 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
372 | adr = (unsigned long) mem; | ||
373 | while (size > 0) { | ||
374 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
375 | adr += PAGE_SIZE; | ||
376 | size -= PAGE_SIZE; | ||
377 | } | ||
378 | |||
379 | return mem; | ||
380 | } | ||
381 | |||
382 | static void rvfree(void *mem, unsigned long size) | ||
383 | { | ||
384 | unsigned long adr; | ||
385 | |||
386 | if (!mem) | ||
387 | return; | ||
388 | |||
389 | adr = (unsigned long) mem; | ||
390 | while ((long) size > 0) { | ||
391 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
392 | adr += PAGE_SIZE; | ||
393 | size -= PAGE_SIZE; | ||
394 | } | ||
395 | vfree(mem); | ||
396 | } | ||
397 | |||
398 | struct vicam_camera { | ||
399 | u16 shutter_speed; // capture shutter speed | ||
400 | u16 gain; // capture gain | ||
401 | |||
402 | u8 *raw_image; // raw data captured from the camera | ||
403 | u8 *framebuf; // processed data in RGB24 format | ||
404 | u8 *cntrlbuf; // area used to send control msgs | ||
405 | |||
406 | struct video_device vdev; // v4l video device | ||
407 | struct usb_device *udev; // usb device | ||
408 | |||
409 | /* guard against simultaneous accesses to the camera */ | ||
410 | struct semaphore cam_lock; | ||
411 | |||
412 | int is_initialized; | ||
413 | u8 open_count; | ||
414 | u8 bulkEndpoint; | ||
415 | int needsDummyRead; | ||
416 | |||
417 | #if defined(CONFIG_VIDEO_PROC_FS) | ||
418 | struct proc_dir_entry *proc_dir; | ||
419 | #endif | ||
420 | |||
421 | }; | ||
422 | |||
423 | static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id); | ||
424 | static void vicam_disconnect(struct usb_interface *intf); | ||
425 | static void read_frame(struct vicam_camera *cam, int framenum); | ||
426 | static void vicam_decode_color(const u8 *, u8 *); | ||
427 | |||
428 | static int __send_control_msg(struct vicam_camera *cam, | ||
429 | u8 request, | ||
430 | u16 value, | ||
431 | u16 index, | ||
432 | unsigned char *cp, | ||
433 | u16 size) | ||
434 | { | ||
435 | int status; | ||
436 | |||
437 | /* cp must be memory that has been allocated by kmalloc */ | ||
438 | |||
439 | status = usb_control_msg(cam->udev, | ||
440 | usb_sndctrlpipe(cam->udev, 0), | ||
441 | request, | ||
442 | USB_DIR_OUT | USB_TYPE_VENDOR | | ||
443 | USB_RECIP_DEVICE, value, index, | ||
444 | cp, size, 1000); | ||
445 | |||
446 | status = min(status, 0); | ||
447 | |||
448 | if (status < 0) { | ||
449 | printk(KERN_INFO "Failed sending control message, error %d.\n", | ||
450 | status); | ||
451 | } | ||
452 | |||
453 | return status; | ||
454 | } | ||
455 | |||
456 | static int send_control_msg(struct vicam_camera *cam, | ||
457 | u8 request, | ||
458 | u16 value, | ||
459 | u16 index, | ||
460 | unsigned char *cp, | ||
461 | u16 size) | ||
462 | { | ||
463 | int status = -ENODEV; | ||
464 | down(&cam->cam_lock); | ||
465 | if (cam->udev) { | ||
466 | status = __send_control_msg(cam, request, value, | ||
467 | index, cp, size); | ||
468 | } | ||
469 | up(&cam->cam_lock); | ||
470 | return status; | ||
471 | } | ||
472 | static int | ||
473 | initialize_camera(struct vicam_camera *cam) | ||
474 | { | ||
475 | const struct { | ||
476 | u8 *data; | ||
477 | u32 size; | ||
478 | } firmware[] = { | ||
479 | { .data = setup1, .size = sizeof(setup1) }, | ||
480 | { .data = setup2, .size = sizeof(setup2) }, | ||
481 | { .data = setup3, .size = sizeof(setup3) }, | ||
482 | { .data = setup4, .size = sizeof(setup4) }, | ||
483 | { .data = setup5, .size = sizeof(setup5) }, | ||
484 | { .data = setup3, .size = sizeof(setup3) }, | ||
485 | { .data = NULL, .size = 0 } | ||
486 | }; | ||
487 | |||
488 | int err, i; | ||
489 | |||
490 | for (i = 0, err = 0; firmware[i].data && !err; i++) { | ||
491 | memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size); | ||
492 | |||
493 | err = send_control_msg(cam, 0xff, 0, 0, | ||
494 | cam->cntrlbuf, firmware[i].size); | ||
495 | } | ||
496 | |||
497 | return err; | ||
498 | } | ||
499 | |||
500 | static int | ||
501 | set_camera_power(struct vicam_camera *cam, int state) | ||
502 | { | ||
503 | int status; | ||
504 | |||
505 | if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0) | ||
506 | return status; | ||
507 | |||
508 | if (state) { | ||
509 | send_control_msg(cam, 0x55, 1, 0, NULL, 0); | ||
510 | } | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | static int | ||
516 | vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg) | ||
517 | { | ||
518 | void __user *user_arg = (void __user *)arg; | ||
519 | struct vicam_camera *cam = file->private_data; | ||
520 | int retval = 0; | ||
521 | |||
522 | if (!cam) | ||
523 | return -ENODEV; | ||
524 | |||
525 | switch (ioctlnr) { | ||
526 | /* query capabilities */ | ||
527 | case VIDIOCGCAP: | ||
528 | { | ||
529 | struct video_capability b; | ||
530 | |||
531 | DBG("VIDIOCGCAP\n"); | ||
532 | memset(&b, 0, sizeof(b)); | ||
533 | strcpy(b.name, "ViCam-based Camera"); | ||
534 | b.type = VID_TYPE_CAPTURE; | ||
535 | b.channels = 1; | ||
536 | b.audios = 0; | ||
537 | b.maxwidth = 320; /* VIDEOSIZE_CIF */ | ||
538 | b.maxheight = 240; | ||
539 | b.minwidth = 320; /* VIDEOSIZE_48_48 */ | ||
540 | b.minheight = 240; | ||
541 | |||
542 | if (copy_to_user(user_arg, &b, sizeof(b))) | ||
543 | retval = -EFAULT; | ||
544 | |||
545 | break; | ||
546 | } | ||
547 | /* get/set video source - we are a camera and nothing else */ | ||
548 | case VIDIOCGCHAN: | ||
549 | { | ||
550 | struct video_channel v; | ||
551 | |||
552 | DBG("VIDIOCGCHAN\n"); | ||
553 | if (copy_from_user(&v, user_arg, sizeof(v))) { | ||
554 | retval = -EFAULT; | ||
555 | break; | ||
556 | } | ||
557 | if (v.channel != 0) { | ||
558 | retval = -EINVAL; | ||
559 | break; | ||
560 | } | ||
561 | |||
562 | v.channel = 0; | ||
563 | strcpy(v.name, "Camera"); | ||
564 | v.tuners = 0; | ||
565 | v.flags = 0; | ||
566 | v.type = VIDEO_TYPE_CAMERA; | ||
567 | v.norm = 0; | ||
568 | |||
569 | if (copy_to_user(user_arg, &v, sizeof(v))) | ||
570 | retval = -EFAULT; | ||
571 | break; | ||
572 | } | ||
573 | |||
574 | case VIDIOCSCHAN: | ||
575 | { | ||
576 | int v; | ||
577 | |||
578 | if (copy_from_user(&v, user_arg, sizeof(v))) | ||
579 | retval = -EFAULT; | ||
580 | DBG("VIDIOCSCHAN %d\n", v); | ||
581 | |||
582 | if (retval == 0 && v != 0) | ||
583 | retval = -EINVAL; | ||
584 | |||
585 | break; | ||
586 | } | ||
587 | |||
588 | /* image properties */ | ||
589 | case VIDIOCGPICT: | ||
590 | { | ||
591 | struct video_picture vp; | ||
592 | DBG("VIDIOCGPICT\n"); | ||
593 | memset(&vp, 0, sizeof (struct video_picture)); | ||
594 | vp.brightness = cam->gain << 8; | ||
595 | vp.depth = 24; | ||
596 | vp.palette = VIDEO_PALETTE_RGB24; | ||
597 | if (copy_to_user(user_arg, &vp, sizeof (struct video_picture))) | ||
598 | retval = -EFAULT; | ||
599 | break; | ||
600 | } | ||
601 | |||
602 | case VIDIOCSPICT: | ||
603 | { | ||
604 | struct video_picture vp; | ||
605 | |||
606 | if (copy_from_user(&vp, user_arg, sizeof(vp))) { | ||
607 | retval = -EFAULT; | ||
608 | break; | ||
609 | } | ||
610 | |||
611 | DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth, | ||
612 | vp.palette); | ||
613 | |||
614 | cam->gain = vp.brightness >> 8; | ||
615 | |||
616 | if (vp.depth != 24 | ||
617 | || vp.palette != VIDEO_PALETTE_RGB24) | ||
618 | retval = -EINVAL; | ||
619 | |||
620 | break; | ||
621 | } | ||
622 | |||
623 | /* get/set capture window */ | ||
624 | case VIDIOCGWIN: | ||
625 | { | ||
626 | struct video_window vw; | ||
627 | vw.x = 0; | ||
628 | vw.y = 0; | ||
629 | vw.width = 320; | ||
630 | vw.height = 240; | ||
631 | vw.chromakey = 0; | ||
632 | vw.flags = 0; | ||
633 | vw.clips = NULL; | ||
634 | vw.clipcount = 0; | ||
635 | |||
636 | DBG("VIDIOCGWIN\n"); | ||
637 | |||
638 | if (copy_to_user(user_arg, (void *)&vw, sizeof(vw))) | ||
639 | retval = -EFAULT; | ||
640 | |||
641 | // I'm not sure what the deal with a capture window is, it is very poorly described | ||
642 | // in the doc. So I won't support it now. | ||
643 | break; | ||
644 | } | ||
645 | |||
646 | case VIDIOCSWIN: | ||
647 | { | ||
648 | |||
649 | struct video_window vw; | ||
650 | |||
651 | if (copy_from_user(&vw, user_arg, sizeof(vw))) { | ||
652 | retval = -EFAULT; | ||
653 | break; | ||
654 | } | ||
655 | |||
656 | DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height); | ||
657 | |||
658 | if ( vw.width != 320 || vw.height != 240 ) | ||
659 | retval = -EFAULT; | ||
660 | |||
661 | break; | ||
662 | } | ||
663 | |||
664 | /* mmap interface */ | ||
665 | case VIDIOCGMBUF: | ||
666 | { | ||
667 | struct video_mbuf vm; | ||
668 | int i; | ||
669 | |||
670 | DBG("VIDIOCGMBUF\n"); | ||
671 | memset(&vm, 0, sizeof (vm)); | ||
672 | vm.size = | ||
673 | VICAM_MAX_FRAME_SIZE * VICAM_FRAMES; | ||
674 | vm.frames = VICAM_FRAMES; | ||
675 | for (i = 0; i < VICAM_FRAMES; i++) | ||
676 | vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i; | ||
677 | |||
678 | if (copy_to_user(user_arg, (void *)&vm, sizeof(vm))) | ||
679 | retval = -EFAULT; | ||
680 | |||
681 | break; | ||
682 | } | ||
683 | |||
684 | case VIDIOCMCAPTURE: | ||
685 | { | ||
686 | struct video_mmap vm; | ||
687 | // int video_size; | ||
688 | |||
689 | if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) { | ||
690 | retval = -EFAULT; | ||
691 | break; | ||
692 | } | ||
693 | |||
694 | DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format); | ||
695 | |||
696 | if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 ) | ||
697 | retval = -EINVAL; | ||
698 | |||
699 | // in theory right here we'd start the image capturing | ||
700 | // (fill in a bulk urb and submit it asynchronously) | ||
701 | // | ||
702 | // Instead we're going to do a total hack job for now and | ||
703 | // retrieve the frame in VIDIOCSYNC | ||
704 | |||
705 | break; | ||
706 | } | ||
707 | |||
708 | case VIDIOCSYNC: | ||
709 | { | ||
710 | int frame; | ||
711 | |||
712 | if (copy_from_user((void *)&frame, user_arg, sizeof(int))) { | ||
713 | retval = -EFAULT; | ||
714 | break; | ||
715 | } | ||
716 | DBG("VIDIOCSYNC: %d\n", frame); | ||
717 | |||
718 | read_frame(cam, frame); | ||
719 | vicam_decode_color(cam->raw_image, | ||
720 | cam->framebuf + | ||
721 | frame * VICAM_MAX_FRAME_SIZE ); | ||
722 | |||
723 | break; | ||
724 | } | ||
725 | |||
726 | /* pointless to implement overlay with this camera */ | ||
727 | case VIDIOCCAPTURE: | ||
728 | case VIDIOCGFBUF: | ||
729 | case VIDIOCSFBUF: | ||
730 | case VIDIOCKEY: | ||
731 | retval = -EINVAL; | ||
732 | break; | ||
733 | |||
734 | /* tuner interface - we have none */ | ||
735 | case VIDIOCGTUNER: | ||
736 | case VIDIOCSTUNER: | ||
737 | case VIDIOCGFREQ: | ||
738 | case VIDIOCSFREQ: | ||
739 | retval = -EINVAL; | ||
740 | break; | ||
741 | |||
742 | /* audio interface - we have none */ | ||
743 | case VIDIOCGAUDIO: | ||
744 | case VIDIOCSAUDIO: | ||
745 | retval = -EINVAL; | ||
746 | break; | ||
747 | default: | ||
748 | retval = -ENOIOCTLCMD; | ||
749 | break; | ||
750 | } | ||
751 | |||
752 | return retval; | ||
753 | } | ||
754 | |||
755 | static int | ||
756 | vicam_open(struct inode *inode, struct file *file) | ||
757 | { | ||
758 | struct video_device *dev = video_devdata(file); | ||
759 | struct vicam_camera *cam = | ||
760 | (struct vicam_camera *) dev->priv; | ||
761 | DBG("open\n"); | ||
762 | |||
763 | if (!cam) { | ||
764 | printk(KERN_ERR | ||
765 | "vicam video_device improperly initialized"); | ||
766 | } | ||
767 | |||
768 | /* the videodev_lock held above us protects us from | ||
769 | * simultaneous opens...for now. we probably shouldn't | ||
770 | * rely on this fact forever. | ||
771 | */ | ||
772 | |||
773 | if (cam->open_count > 0) { | ||
774 | printk(KERN_INFO | ||
775 | "vicam_open called on already opened camera"); | ||
776 | return -EBUSY; | ||
777 | } | ||
778 | |||
779 | cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL); | ||
780 | if (!cam->raw_image) { | ||
781 | return -ENOMEM; | ||
782 | } | ||
783 | |||
784 | cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); | ||
785 | if (!cam->framebuf) { | ||
786 | kfree(cam->raw_image); | ||
787 | return -ENOMEM; | ||
788 | } | ||
789 | |||
790 | cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
791 | if (!cam->cntrlbuf) { | ||
792 | kfree(cam->raw_image); | ||
793 | rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); | ||
794 | return -ENOMEM; | ||
795 | } | ||
796 | |||
797 | // First upload firmware, then turn the camera on | ||
798 | |||
799 | if (!cam->is_initialized) { | ||
800 | initialize_camera(cam); | ||
801 | |||
802 | cam->is_initialized = 1; | ||
803 | } | ||
804 | |||
805 | set_camera_power(cam, 1); | ||
806 | |||
807 | cam->needsDummyRead = 1; | ||
808 | cam->open_count++; | ||
809 | |||
810 | file->private_data = cam; | ||
811 | |||
812 | return 0; | ||
813 | } | ||
814 | |||
815 | static int | ||
816 | vicam_close(struct inode *inode, struct file *file) | ||
817 | { | ||
818 | struct vicam_camera *cam = file->private_data; | ||
819 | int open_count; | ||
820 | struct usb_device *udev; | ||
821 | |||
822 | DBG("close\n"); | ||
823 | |||
824 | /* it's not the end of the world if | ||
825 | * we fail to turn the camera off. | ||
826 | */ | ||
827 | |||
828 | set_camera_power(cam, 0); | ||
829 | |||
830 | kfree(cam->raw_image); | ||
831 | rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); | ||
832 | kfree(cam->cntrlbuf); | ||
833 | |||
834 | down(&cam->cam_lock); | ||
835 | |||
836 | cam->open_count--; | ||
837 | open_count = cam->open_count; | ||
838 | udev = cam->udev; | ||
839 | |||
840 | up(&cam->cam_lock); | ||
841 | |||
842 | if (!open_count && !udev) { | ||
843 | kfree(cam); | ||
844 | } | ||
845 | |||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | static void vicam_decode_color(const u8 *data, u8 *rgb) | ||
850 | { | ||
851 | /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB | ||
852 | * Copyright (C) 2002 Monroe Williams (monroe@pobox.com) | ||
853 | */ | ||
854 | |||
855 | int i, prevY, nextY; | ||
856 | |||
857 | prevY = 512; | ||
858 | nextY = 512; | ||
859 | |||
860 | data += VICAM_HEADER_SIZE; | ||
861 | |||
862 | for( i = 0; i < 240; i++, data += 512 ) { | ||
863 | const int y = ( i * 242 ) / 240; | ||
864 | |||
865 | int j, prevX, nextX; | ||
866 | int Y, Cr, Cb; | ||
867 | |||
868 | if ( y == 242 - 1 ) { | ||
869 | nextY = -512; | ||
870 | } | ||
871 | |||
872 | prevX = 1; | ||
873 | nextX = 1; | ||
874 | |||
875 | for ( j = 0; j < 320; j++, rgb += 3 ) { | ||
876 | const int x = ( j * 512 ) / 320; | ||
877 | const u8 * const src = &data[x]; | ||
878 | |||
879 | if ( x == 512 - 1 ) { | ||
880 | nextX = -1; | ||
881 | } | ||
882 | |||
883 | Cr = ( src[prevX] - src[0] ) + | ||
884 | ( src[nextX] - src[0] ); | ||
885 | Cr /= 2; | ||
886 | |||
887 | Cb = ( src[prevY] - src[prevX + prevY] ) + | ||
888 | ( src[prevY] - src[nextX + prevY] ) + | ||
889 | ( src[nextY] - src[prevX + nextY] ) + | ||
890 | ( src[nextY] - src[nextX + nextY] ); | ||
891 | Cb /= 4; | ||
892 | |||
893 | Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 ); | ||
894 | |||
895 | if ( i & 1 ) { | ||
896 | int Ct = Cr; | ||
897 | Cr = Cb; | ||
898 | Cb = Ct; | ||
899 | } | ||
900 | |||
901 | if ( ( x ^ i ) & 1 ) { | ||
902 | Cr = -Cr; | ||
903 | Cb = -Cb; | ||
904 | } | ||
905 | |||
906 | rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) + | ||
907 | 500 ) / 900, 0, 255 ); | ||
908 | rgb[1] = clamp( ( ( Y - ( 392 * Cb ) - | ||
909 | ( 813 * Cr ) ) + | ||
910 | 500 ) / 1000, 0, 255 ); | ||
911 | rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) + | ||
912 | 500 ) / 1300, 0, 255 ); | ||
913 | |||
914 | prevX = -1; | ||
915 | } | ||
916 | |||
917 | prevY = -512; | ||
918 | } | ||
919 | } | ||
920 | |||
921 | static void | ||
922 | read_frame(struct vicam_camera *cam, int framenum) | ||
923 | { | ||
924 | unsigned char *request = cam->cntrlbuf; | ||
925 | int realShutter; | ||
926 | int n; | ||
927 | int actual_length; | ||
928 | |||
929 | if (cam->needsDummyRead) { | ||
930 | cam->needsDummyRead = 0; | ||
931 | read_frame(cam, framenum); | ||
932 | } | ||
933 | |||
934 | memset(request, 0, 16); | ||
935 | request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain | ||
936 | |||
937 | request[1] = 0; // 512x242 capture | ||
938 | |||
939 | request[2] = 0x90; // the function of these two bytes | ||
940 | request[3] = 0x07; // is not yet understood | ||
941 | |||
942 | if (cam->shutter_speed > 60) { | ||
943 | // Short exposure | ||
944 | realShutter = | ||
945 | ((-15631900 / cam->shutter_speed) + 260533) / 1000; | ||
946 | request[4] = realShutter & 0xFF; | ||
947 | request[5] = (realShutter >> 8) & 0xFF; | ||
948 | request[6] = 0x03; | ||
949 | request[7] = 0x01; | ||
950 | } else { | ||
951 | // Long exposure | ||
952 | realShutter = 15600 / cam->shutter_speed - 1; | ||
953 | request[4] = 0; | ||
954 | request[5] = 0; | ||
955 | request[6] = realShutter & 0xFF; | ||
956 | request[7] = realShutter >> 8; | ||
957 | } | ||
958 | |||
959 | // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0 | ||
960 | request[8] = 0; | ||
961 | // bytes 9-15 do not seem to affect exposure or image quality | ||
962 | |||
963 | down(&cam->cam_lock); | ||
964 | |||
965 | if (!cam->udev) { | ||
966 | goto done; | ||
967 | } | ||
968 | |||
969 | n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16); | ||
970 | |||
971 | if (n < 0) { | ||
972 | printk(KERN_ERR | ||
973 | " Problem sending frame capture control message"); | ||
974 | goto done; | ||
975 | } | ||
976 | |||
977 | n = usb_bulk_msg(cam->udev, | ||
978 | usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint), | ||
979 | cam->raw_image, | ||
980 | 512 * 242 + 128, &actual_length, 10000); | ||
981 | |||
982 | if (n < 0) { | ||
983 | printk(KERN_ERR "Problem during bulk read of frame data: %d\n", | ||
984 | n); | ||
985 | } | ||
986 | |||
987 | done: | ||
988 | up(&cam->cam_lock); | ||
989 | } | ||
990 | |||
991 | static ssize_t | ||
992 | vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos ) | ||
993 | { | ||
994 | struct vicam_camera *cam = file->private_data; | ||
995 | |||
996 | DBG("read %d bytes.\n", (int) count); | ||
997 | |||
998 | if (*ppos >= VICAM_MAX_FRAME_SIZE) { | ||
999 | *ppos = 0; | ||
1000 | return 0; | ||
1001 | } | ||
1002 | |||
1003 | if (*ppos == 0) { | ||
1004 | read_frame(cam, 0); | ||
1005 | vicam_decode_color(cam->raw_image, | ||
1006 | cam->framebuf + | ||
1007 | 0 * VICAM_MAX_FRAME_SIZE); | ||
1008 | } | ||
1009 | |||
1010 | count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos); | ||
1011 | |||
1012 | if (copy_to_user(buf, &cam->framebuf[*ppos], count)) { | ||
1013 | count = -EFAULT; | ||
1014 | } else { | ||
1015 | *ppos += count; | ||
1016 | } | ||
1017 | |||
1018 | if (count == VICAM_MAX_FRAME_SIZE) { | ||
1019 | *ppos = 0; | ||
1020 | } | ||
1021 | |||
1022 | return count; | ||
1023 | } | ||
1024 | |||
1025 | |||
1026 | static int | ||
1027 | vicam_mmap(struct file *file, struct vm_area_struct *vma) | ||
1028 | { | ||
1029 | // TODO: allocate the raw frame buffer if necessary | ||
1030 | unsigned long page, pos; | ||
1031 | unsigned long start = vma->vm_start; | ||
1032 | unsigned long size = vma->vm_end-vma->vm_start; | ||
1033 | struct vicam_camera *cam = file->private_data; | ||
1034 | |||
1035 | if (!cam) | ||
1036 | return -ENODEV; | ||
1037 | |||
1038 | DBG("vicam_mmap: %ld\n", size); | ||
1039 | |||
1040 | /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes | ||
1041 | * to the size the application requested for mmap and it was screwing apps up. | ||
1042 | if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE) | ||
1043 | return -EINVAL; | ||
1044 | */ | ||
1045 | |||
1046 | pos = (unsigned long)cam->framebuf; | ||
1047 | while (size > 0) { | ||
1048 | page = vmalloc_to_pfn((void *)pos); | ||
1049 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) | ||
1050 | return -EAGAIN; | ||
1051 | |||
1052 | start += PAGE_SIZE; | ||
1053 | pos += PAGE_SIZE; | ||
1054 | if (size > PAGE_SIZE) | ||
1055 | size -= PAGE_SIZE; | ||
1056 | else | ||
1057 | size = 0; | ||
1058 | } | ||
1059 | |||
1060 | return 0; | ||
1061 | } | ||
1062 | |||
1063 | #if defined(CONFIG_VIDEO_PROC_FS) | ||
1064 | |||
1065 | static struct proc_dir_entry *vicam_proc_root = NULL; | ||
1066 | |||
1067 | static int vicam_read_helper(char *page, char **start, off_t off, | ||
1068 | int count, int *eof, int value) | ||
1069 | { | ||
1070 | char *out = page; | ||
1071 | int len; | ||
1072 | |||
1073 | out += sprintf(out, "%d",value); | ||
1074 | |||
1075 | len = out - page; | ||
1076 | len -= off; | ||
1077 | if (len < count) { | ||
1078 | *eof = 1; | ||
1079 | if (len <= 0) | ||
1080 | return 0; | ||
1081 | } else | ||
1082 | len = count; | ||
1083 | |||
1084 | *start = page + off; | ||
1085 | return len; | ||
1086 | } | ||
1087 | |||
1088 | static int vicam_read_proc_shutter(char *page, char **start, off_t off, | ||
1089 | int count, int *eof, void *data) | ||
1090 | { | ||
1091 | return vicam_read_helper(page,start,off,count,eof, | ||
1092 | ((struct vicam_camera *)data)->shutter_speed); | ||
1093 | } | ||
1094 | |||
1095 | static int vicam_read_proc_gain(char *page, char **start, off_t off, | ||
1096 | int count, int *eof, void *data) | ||
1097 | { | ||
1098 | return vicam_read_helper(page,start,off,count,eof, | ||
1099 | ((struct vicam_camera *)data)->gain); | ||
1100 | } | ||
1101 | |||
1102 | static int | ||
1103 | vicam_write_proc_shutter(struct file *file, const char *buffer, | ||
1104 | unsigned long count, void *data) | ||
1105 | { | ||
1106 | u16 stmp; | ||
1107 | char kbuf[8]; | ||
1108 | struct vicam_camera *cam = (struct vicam_camera *) data; | ||
1109 | |||
1110 | if (count > 6) | ||
1111 | return -EINVAL; | ||
1112 | |||
1113 | if (copy_from_user(kbuf, buffer, count)) | ||
1114 | return -EFAULT; | ||
1115 | |||
1116 | stmp = (u16) simple_strtoul(kbuf, NULL, 10); | ||
1117 | if (stmp < 4 || stmp > 32000) | ||
1118 | return -EINVAL; | ||
1119 | |||
1120 | cam->shutter_speed = stmp; | ||
1121 | |||
1122 | return count; | ||
1123 | } | ||
1124 | |||
1125 | static int | ||
1126 | vicam_write_proc_gain(struct file *file, const char *buffer, | ||
1127 | unsigned long count, void *data) | ||
1128 | { | ||
1129 | u16 gtmp; | ||
1130 | char kbuf[8]; | ||
1131 | |||
1132 | struct vicam_camera *cam = (struct vicam_camera *) data; | ||
1133 | |||
1134 | if (count > 4) | ||
1135 | return -EINVAL; | ||
1136 | |||
1137 | if (copy_from_user(kbuf, buffer, count)) | ||
1138 | return -EFAULT; | ||
1139 | |||
1140 | gtmp = (u16) simple_strtoul(kbuf, NULL, 10); | ||
1141 | if (gtmp > 255) | ||
1142 | return -EINVAL; | ||
1143 | cam->gain = gtmp; | ||
1144 | |||
1145 | return count; | ||
1146 | } | ||
1147 | |||
1148 | static void | ||
1149 | vicam_create_proc_root(void) | ||
1150 | { | ||
1151 | vicam_proc_root = create_proc_entry("video/vicam", S_IFDIR, 0); | ||
1152 | |||
1153 | if (vicam_proc_root) | ||
1154 | vicam_proc_root->owner = THIS_MODULE; | ||
1155 | else | ||
1156 | printk(KERN_ERR | ||
1157 | "could not create /proc entry for vicam!"); | ||
1158 | } | ||
1159 | |||
1160 | static void | ||
1161 | vicam_destroy_proc_root(void) | ||
1162 | { | ||
1163 | if (vicam_proc_root) | ||
1164 | remove_proc_entry("video/vicam", 0); | ||
1165 | } | ||
1166 | |||
1167 | static void | ||
1168 | vicam_create_proc_entry(struct vicam_camera *cam) | ||
1169 | { | ||
1170 | char name[64]; | ||
1171 | struct proc_dir_entry *ent; | ||
1172 | |||
1173 | DBG(KERN_INFO "vicam: creating proc entry\n"); | ||
1174 | |||
1175 | if (!vicam_proc_root || !cam) { | ||
1176 | printk(KERN_INFO | ||
1177 | "vicam: could not create proc entry, %s pointer is null.\n", | ||
1178 | (!cam ? "camera" : "root")); | ||
1179 | return; | ||
1180 | } | ||
1181 | |||
1182 | sprintf(name, "video%d", cam->vdev.minor); | ||
1183 | |||
1184 | cam->proc_dir = create_proc_entry(name, S_IFDIR, vicam_proc_root); | ||
1185 | |||
1186 | if ( !cam->proc_dir ) | ||
1187 | return; // FIXME: We should probably return an error here | ||
1188 | |||
1189 | ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR, | ||
1190 | cam->proc_dir); | ||
1191 | if (ent) { | ||
1192 | ent->data = cam; | ||
1193 | ent->read_proc = vicam_read_proc_shutter; | ||
1194 | ent->write_proc = vicam_write_proc_shutter; | ||
1195 | ent->size = 64; | ||
1196 | } | ||
1197 | |||
1198 | ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR, | ||
1199 | cam->proc_dir); | ||
1200 | if (ent) { | ||
1201 | ent->data = cam; | ||
1202 | ent->read_proc = vicam_read_proc_gain; | ||
1203 | ent->write_proc = vicam_write_proc_gain; | ||
1204 | ent->size = 64; | ||
1205 | } | ||
1206 | } | ||
1207 | |||
1208 | static void | ||
1209 | vicam_destroy_proc_entry(void *ptr) | ||
1210 | { | ||
1211 | struct vicam_camera *cam = (struct vicam_camera *) ptr; | ||
1212 | char name[16]; | ||
1213 | |||
1214 | if ( !cam->proc_dir ) | ||
1215 | return; | ||
1216 | |||
1217 | sprintf(name, "video%d", cam->vdev.minor); | ||
1218 | remove_proc_entry("shutter", cam->proc_dir); | ||
1219 | remove_proc_entry("gain", cam->proc_dir); | ||
1220 | remove_proc_entry(name,vicam_proc_root); | ||
1221 | cam->proc_dir = NULL; | ||
1222 | |||
1223 | } | ||
1224 | |||
1225 | #else | ||
1226 | static inline void vicam_create_proc_root(void) { } | ||
1227 | static inline void vicam_destroy_proc_root(void) { } | ||
1228 | static inline void vicam_create_proc_entry(struct vicam_camera *cam) { } | ||
1229 | static inline void vicam_destroy_proc_entry(void *ptr) { } | ||
1230 | #endif | ||
1231 | |||
1232 | static struct file_operations vicam_fops = { | ||
1233 | .owner = THIS_MODULE, | ||
1234 | .open = vicam_open, | ||
1235 | .release = vicam_close, | ||
1236 | .read = vicam_read, | ||
1237 | .mmap = vicam_mmap, | ||
1238 | .ioctl = vicam_ioctl, | ||
1239 | .llseek = no_llseek, | ||
1240 | }; | ||
1241 | |||
1242 | static struct video_device vicam_template = { | ||
1243 | .owner = THIS_MODULE, | ||
1244 | .name = "ViCam-based USB Camera", | ||
1245 | .type = VID_TYPE_CAPTURE, | ||
1246 | .hardware = VID_HARDWARE_VICAM, | ||
1247 | .fops = &vicam_fops, | ||
1248 | .minor = -1, | ||
1249 | }; | ||
1250 | |||
1251 | /* table of devices that work with this driver */ | ||
1252 | static struct usb_device_id vicam_table[] = { | ||
1253 | {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)}, | ||
1254 | {} /* Terminating entry */ | ||
1255 | }; | ||
1256 | |||
1257 | MODULE_DEVICE_TABLE(usb, vicam_table); | ||
1258 | |||
1259 | static struct usb_driver vicam_driver = { | ||
1260 | .owner = THIS_MODULE, | ||
1261 | .name = "vicam", | ||
1262 | .probe = vicam_probe, | ||
1263 | .disconnect = vicam_disconnect, | ||
1264 | .id_table = vicam_table | ||
1265 | }; | ||
1266 | |||
1267 | /** | ||
1268 | * vicam_probe | ||
1269 | * @intf: the interface | ||
1270 | * @id: the device id | ||
1271 | * | ||
1272 | * Called by the usb core when a new device is connected that it thinks | ||
1273 | * this driver might be interested in. | ||
1274 | */ | ||
1275 | static int | ||
1276 | vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) | ||
1277 | { | ||
1278 | struct usb_device *dev = interface_to_usbdev(intf); | ||
1279 | int bulkEndpoint = 0; | ||
1280 | const struct usb_host_interface *interface; | ||
1281 | const struct usb_endpoint_descriptor *endpoint; | ||
1282 | struct vicam_camera *cam; | ||
1283 | |||
1284 | printk(KERN_INFO "ViCam based webcam connected\n"); | ||
1285 | |||
1286 | interface = intf->cur_altsetting; | ||
1287 | |||
1288 | DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n", | ||
1289 | interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints)); | ||
1290 | endpoint = &interface->endpoint[0].desc; | ||
1291 | |||
1292 | if ((endpoint->bEndpointAddress & 0x80) && | ||
1293 | ((endpoint->bmAttributes & 3) == 0x02)) { | ||
1294 | /* we found a bulk in endpoint */ | ||
1295 | bulkEndpoint = endpoint->bEndpointAddress; | ||
1296 | } else { | ||
1297 | printk(KERN_ERR | ||
1298 | "No bulk in endpoint was found ?! (this is bad)\n"); | ||
1299 | } | ||
1300 | |||
1301 | if ((cam = | ||
1302 | kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) { | ||
1303 | printk(KERN_WARNING | ||
1304 | "could not allocate kernel memory for vicam_camera struct\n"); | ||
1305 | return -ENOMEM; | ||
1306 | } | ||
1307 | |||
1308 | memset(cam, 0, sizeof (struct vicam_camera)); | ||
1309 | |||
1310 | cam->shutter_speed = 15; | ||
1311 | |||
1312 | init_MUTEX(&cam->cam_lock); | ||
1313 | |||
1314 | memcpy(&cam->vdev, &vicam_template, | ||
1315 | sizeof (vicam_template)); | ||
1316 | cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only | ||
1317 | |||
1318 | cam->udev = dev; | ||
1319 | cam->bulkEndpoint = bulkEndpoint; | ||
1320 | |||
1321 | if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) { | ||
1322 | kfree(cam); | ||
1323 | printk(KERN_WARNING "video_register_device failed\n"); | ||
1324 | return -EIO; | ||
1325 | } | ||
1326 | |||
1327 | vicam_create_proc_entry(cam); | ||
1328 | |||
1329 | printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor); | ||
1330 | |||
1331 | usb_set_intfdata (intf, cam); | ||
1332 | |||
1333 | return 0; | ||
1334 | } | ||
1335 | |||
1336 | static void | ||
1337 | vicam_disconnect(struct usb_interface *intf) | ||
1338 | { | ||
1339 | int open_count; | ||
1340 | struct vicam_camera *cam = usb_get_intfdata (intf); | ||
1341 | usb_set_intfdata (intf, NULL); | ||
1342 | |||
1343 | /* we must unregister the device before taking its | ||
1344 | * cam_lock. This is because the video open call | ||
1345 | * holds the same lock as video unregister. if we | ||
1346 | * unregister inside of the cam_lock and open also | ||
1347 | * uses the cam_lock, we get deadlock. | ||
1348 | */ | ||
1349 | |||
1350 | video_unregister_device(&cam->vdev); | ||
1351 | |||
1352 | /* stop the camera from being used */ | ||
1353 | |||
1354 | down(&cam->cam_lock); | ||
1355 | |||
1356 | /* mark the camera as gone */ | ||
1357 | |||
1358 | cam->udev = NULL; | ||
1359 | |||
1360 | vicam_destroy_proc_entry(cam); | ||
1361 | |||
1362 | /* the only thing left to do is synchronize with | ||
1363 | * our close/release function on who should release | ||
1364 | * the camera memory. if there are any users using the | ||
1365 | * camera, it's their job. if there are no users, | ||
1366 | * it's ours. | ||
1367 | */ | ||
1368 | |||
1369 | open_count = cam->open_count; | ||
1370 | |||
1371 | up(&cam->cam_lock); | ||
1372 | |||
1373 | if (!open_count) { | ||
1374 | kfree(cam); | ||
1375 | } | ||
1376 | |||
1377 | printk(KERN_DEBUG "ViCam-based WebCam disconnected\n"); | ||
1378 | } | ||
1379 | |||
1380 | /* | ||
1381 | */ | ||
1382 | static int __init | ||
1383 | usb_vicam_init(void) | ||
1384 | { | ||
1385 | int retval; | ||
1386 | DBG(KERN_INFO "ViCam-based WebCam driver startup\n"); | ||
1387 | vicam_create_proc_root(); | ||
1388 | retval = usb_register(&vicam_driver); | ||
1389 | if (retval) | ||
1390 | printk(KERN_WARNING "usb_register failed!\n"); | ||
1391 | return retval; | ||
1392 | } | ||
1393 | |||
1394 | static void __exit | ||
1395 | usb_vicam_exit(void) | ||
1396 | { | ||
1397 | DBG(KERN_INFO | ||
1398 | "ViCam-based WebCam driver shutdown\n"); | ||
1399 | |||
1400 | usb_deregister(&vicam_driver); | ||
1401 | vicam_destroy_proc_root(); | ||
1402 | } | ||
1403 | |||
1404 | module_init(usb_vicam_init); | ||
1405 | module_exit(usb_vicam_exit); | ||
1406 | |||
1407 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
1408 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
1409 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c new file mode 100644 index 000000000000..689e79e4bcee --- /dev/null +++ b/drivers/usb/media/w9968cf.c | |||
@@ -0,0 +1,3822 @@ | |||
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/version.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/kmod.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/fs.h> | ||
34 | #include <linux/vmalloc.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/mm.h> | ||
37 | #include <linux/string.h> | ||
38 | #include <linux/errno.h> | ||
39 | #include <linux/sched.h> | ||
40 | #include <linux/ioctl.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <linux/stddef.h> | ||
43 | #include <asm/page.h> | ||
44 | #include <asm/uaccess.h> | ||
45 | #include <linux/page-flags.h> | ||
46 | #include <linux/moduleparam.h> | ||
47 | |||
48 | #include "w9968cf.h" | ||
49 | #include "w9968cf_decoder.h" | ||
50 | |||
51 | |||
52 | |||
53 | /**************************************************************************** | ||
54 | * Module macros and parameters * | ||
55 | ****************************************************************************/ | ||
56 | |||
57 | MODULE_DEVICE_TABLE(usb, winbond_id_table); | ||
58 | |||
59 | MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL); | ||
60 | MODULE_DESCRIPTION(W9968CF_MODULE_NAME); | ||
61 | MODULE_VERSION(W9968CF_MODULE_VERSION); | ||
62 | MODULE_LICENSE(W9968CF_MODULE_LICENSE); | ||
63 | MODULE_SUPPORTED_DEVICE("Video"); | ||
64 | |||
65 | static int ovmod_load = W9968CF_OVMOD_LOAD; | ||
66 | static int vppmod_load = W9968CF_VPPMOD_LOAD; | ||
67 | static unsigned short simcams = W9968CF_SIMCAMS; | ||
68 | static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/ | ||
69 | static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
70 | W9968CF_PACKET_SIZE}; | ||
71 | static unsigned short max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
72 | W9968CF_BUFFERS}; | ||
73 | static int double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
74 | W9968CF_DOUBLE_BUFFER}; | ||
75 | static int clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING}; | ||
76 | static unsigned short filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] = | ||
77 | W9968CF_FILTER_TYPE}; | ||
78 | static int largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW}; | ||
79 | static unsigned short decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
80 | W9968CF_DECOMPRESSION}; | ||
81 | static int upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING}; | ||
82 | static unsigned short force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0}; | ||
83 | static int force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB}; | ||
84 | static int autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT}; | ||
85 | static int autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP}; | ||
86 | static unsigned short lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
87 | W9968CF_LIGHTFREQ}; | ||
88 | static int bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]= | ||
89 | W9968CF_BANDINGFILTER}; | ||
90 | static short clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV}; | ||
91 | static int backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT}; | ||
92 | static int mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR}; | ||
93 | static int monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME}; | ||
94 | static unsigned int brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
95 | W9968CF_BRIGHTNESS}; | ||
96 | static unsigned int hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE}; | ||
97 | static unsigned int colour[]={[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR}; | ||
98 | static unsigned int contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
99 | W9968CF_CONTRAST}; | ||
100 | static unsigned int whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
101 | W9968CF_WHITENESS}; | ||
102 | #ifdef W9968CF_DEBUG | ||
103 | static unsigned short debug = W9968CF_DEBUG_LEVEL; | ||
104 | static int specific_debug = W9968CF_SPECIFIC_DEBUG; | ||
105 | #endif | ||
106 | |||
107 | static unsigned int param_nv[24]; /* number of values per parameter */ | ||
108 | |||
109 | #ifdef CONFIG_KMOD | ||
110 | module_param(ovmod_load, bool, 0644); | ||
111 | module_param(vppmod_load, bool, 0444); | ||
112 | #endif | ||
113 | module_param(simcams, ushort, 0644); | ||
114 | module_param_array(video_nr, short, ¶m_nv[0], 0444); | ||
115 | module_param_array(packet_size, uint, ¶m_nv[1], 0444); | ||
116 | module_param_array(max_buffers, ushort, ¶m_nv[2], 0444); | ||
117 | module_param_array(double_buffer, bool, ¶m_nv[3], 0444); | ||
118 | module_param_array(clamping, bool, ¶m_nv[4], 0444); | ||
119 | module_param_array(filter_type, ushort, ¶m_nv[5], 0444); | ||
120 | module_param_array(largeview, bool, ¶m_nv[6], 0444); | ||
121 | module_param_array(decompression, ushort, ¶m_nv[7], 0444); | ||
122 | module_param_array(upscaling, bool, ¶m_nv[8], 0444); | ||
123 | module_param_array(force_palette, ushort, ¶m_nv[9], 0444); | ||
124 | module_param_array(force_rgb, ushort, ¶m_nv[10], 0444); | ||
125 | module_param_array(autobright, bool, ¶m_nv[11], 0444); | ||
126 | module_param_array(autoexp, bool, ¶m_nv[12], 0444); | ||
127 | module_param_array(lightfreq, ushort, ¶m_nv[13], 0444); | ||
128 | module_param_array(bandingfilter, bool, ¶m_nv[14], 0444); | ||
129 | module_param_array(clockdiv, short, ¶m_nv[15], 0444); | ||
130 | module_param_array(backlight, bool, ¶m_nv[16], 0444); | ||
131 | module_param_array(mirror, bool, ¶m_nv[17], 0444); | ||
132 | module_param_array(monochrome, bool, ¶m_nv[18], 0444); | ||
133 | module_param_array(brightness, uint, ¶m_nv[19], 0444); | ||
134 | module_param_array(hue, uint, ¶m_nv[20], 0444); | ||
135 | module_param_array(colour, uint, ¶m_nv[21], 0444); | ||
136 | module_param_array(contrast, uint, ¶m_nv[22], 0444); | ||
137 | module_param_array(whiteness, uint, ¶m_nv[23], 0444); | ||
138 | #ifdef W9968CF_DEBUG | ||
139 | module_param(debug, ushort, 0644); | ||
140 | module_param(specific_debug, bool, 0644); | ||
141 | #endif | ||
142 | |||
143 | #ifdef CONFIG_KMOD | ||
144 | MODULE_PARM_DESC(ovmod_load, | ||
145 | "\n<0|1> Automatic 'ovcamchip' module loading." | ||
146 | "\n0 disabled, 1 enabled." | ||
147 | "\nIf enabled,'insmod' searches for the required 'ovcamchip'" | ||
148 | "\nmodule in the system, according to its configuration, and" | ||
149 | "\nattempts to load that module automatically. This action is" | ||
150 | "\nperformed once as soon as the 'w9968cf' module is loaded" | ||
151 | "\ninto memory." | ||
152 | "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"." | ||
153 | "\n"); | ||
154 | MODULE_PARM_DESC(vppmod_load, | ||
155 | "\n<0|1> Automatic 'w9968cf-vpp' module loading." | ||
156 | "\n0 disabled, 1 enabled." | ||
157 | "\nIf enabled, every time an application attempts to open a" | ||
158 | "\ncamera, 'insmod' searches for the video post-processing" | ||
159 | "\nmodule in the system and loads it automatically (if" | ||
160 | "\npresent). The optional 'w9968cf-vpp' module adds extra" | ||
161 | "\n image manipulation functions to the 'w9968cf' module,like" | ||
162 | "\nsoftware up-scaling,colour conversions and video decoding" | ||
163 | "\nfor very high frame rates." | ||
164 | "\nDefault value is "__MODULE_STRING(W9968CF_VPPMOD_LOAD)"." | ||
165 | "\n"); | ||
166 | #endif | ||
167 | MODULE_PARM_DESC(simcams, | ||
168 | "\n<n> Number of cameras allowed to stream simultaneously." | ||
169 | "\nn may vary from 0 to " | ||
170 | __MODULE_STRING(W9968CF_MAX_DEVICES)"." | ||
171 | "\nDefault value is "__MODULE_STRING(W9968CF_SIMCAMS)"." | ||
172 | "\n"); | ||
173 | MODULE_PARM_DESC(video_nr, | ||
174 | "\n<-1|n[,...]> Specify V4L minor mode number." | ||
175 | "\n -1 = use next available (default)" | ||
176 | "\n n = use minor number n (integer >= 0)" | ||
177 | "\nYou can specify up to "__MODULE_STRING(W9968CF_MAX_DEVICES) | ||
178 | " cameras this way." | ||
179 | "\nFor example:" | ||
180 | "\nvideo_nr=-1,2,-1 would assign minor number 2 to" | ||
181 | "\nthe second camera and use auto for the first" | ||
182 | "\none and for every other camera." | ||
183 | "\n"); | ||
184 | MODULE_PARM_DESC(packet_size, | ||
185 | "\n<n[,...]> Specify the maximum data payload" | ||
186 | "\nsize in bytes for alternate settings, for each device." | ||
187 | "\nn is scaled between 63 and 1023 " | ||
188 | "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")." | ||
189 | "\n"); | ||
190 | MODULE_PARM_DESC(max_buffers, | ||
191 | "\n<n[,...]> For advanced users." | ||
192 | "\nSpecify the maximum number of video frame buffers" | ||
193 | "\nto allocate for each device, from 2 to " | ||
194 | __MODULE_STRING(W9968CF_MAX_BUFFERS) | ||
195 | ". (default is "__MODULE_STRING(W9968CF_BUFFERS)")." | ||
196 | "\n"); | ||
197 | MODULE_PARM_DESC(double_buffer, | ||
198 | "\n<0|1[,...]> " | ||
199 | "Hardware double buffering: 0 disabled, 1 enabled." | ||
200 | "\nIt should be enabled if you want smooth video output: if" | ||
201 | "\nyou obtain out of sync. video, disable it, or try to" | ||
202 | "\ndecrease the 'clockdiv' module parameter value." | ||
203 | "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER) | ||
204 | " for every device." | ||
205 | "\n"); | ||
206 | MODULE_PARM_DESC(clamping, | ||
207 | "\n<0|1[,...]> Video data clamping: 0 disabled, 1 enabled." | ||
208 | "\nDefault value is "__MODULE_STRING(W9968CF_CLAMPING) | ||
209 | " for every device." | ||
210 | "\n"); | ||
211 | MODULE_PARM_DESC(filter_type, | ||
212 | "\n<0|1|2[,...]> Video filter type." | ||
213 | "\n0 none, 1 (1-2-1) 3-tap filter, " | ||
214 | "2 (2-3-6-3-2) 5-tap filter." | ||
215 | "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE) | ||
216 | " for every device." | ||
217 | "\nThe filter is used to reduce noise and aliasing artifacts" | ||
218 | "\nproduced by the CCD or CMOS image sensor, and the scaling" | ||
219 | " process." | ||
220 | "\n"); | ||
221 | MODULE_PARM_DESC(largeview, | ||
222 | "\n<0|1[,...]> Large view: 0 disabled, 1 enabled." | ||
223 | "\nDefault value is "__MODULE_STRING(W9968CF_LARGEVIEW) | ||
224 | " for every device." | ||
225 | "\n"); | ||
226 | MODULE_PARM_DESC(upscaling, | ||
227 | "\n<0|1[,...]> Software scaling (for non-compressed video):" | ||
228 | "\n0 disabled, 1 enabled." | ||
229 | "\nDisable it if you have a slow CPU or you don't have" | ||
230 | " enough memory." | ||
231 | "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING) | ||
232 | " for every device." | ||
233 | "\nIf 'w9968cf-vpp' is not present, this parameter is" | ||
234 | " set to 0." | ||
235 | "\n"); | ||
236 | MODULE_PARM_DESC(decompression, | ||
237 | "\n<0|1|2[,...]> Software video decompression:" | ||
238 | "\n- 0 disables decompression (doesn't allow formats needing" | ||
239 | " decompression)" | ||
240 | "\n- 1 forces decompression (allows formats needing" | ||
241 | " decompression only);" | ||
242 | "\n- 2 allows any permitted formats." | ||
243 | "\nFormats supporting compressed video are YUV422P and" | ||
244 | " YUV420P/YUV420 " | ||
245 | "\nin any resolutions where both width and height are " | ||
246 | "a multiple of 16." | ||
247 | "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION) | ||
248 | " for every device." | ||
249 | "\nIf 'w9968cf-vpp' is not present, forcing decompression is " | ||
250 | "\nnot allowed; in this case this parameter is set to 2." | ||
251 | "\n"); | ||
252 | MODULE_PARM_DESC(force_palette, | ||
253 | "\n<0" | ||
254 | "|" __MODULE_STRING(VIDEO_PALETTE_UYVY) | ||
255 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV420) | ||
256 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV422P) | ||
257 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV420P) | ||
258 | "|" __MODULE_STRING(VIDEO_PALETTE_YUYV) | ||
259 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV422) | ||
260 | "|" __MODULE_STRING(VIDEO_PALETTE_GREY) | ||
261 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB555) | ||
262 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB565) | ||
263 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB24) | ||
264 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB32) | ||
265 | "[,...]>" | ||
266 | " Force picture palette." | ||
267 | "\nIn order:" | ||
268 | "\n- 0 allows any of the following formats:" | ||
269 | "\n- UYVY 16 bpp - Original video, compression disabled" | ||
270 | "\n- YUV420 12 bpp - Original video, compression enabled" | ||
271 | "\n- YUV422P 16 bpp - Original video, compression enabled" | ||
272 | "\n- YUV420P 12 bpp - Original video, compression enabled" | ||
273 | "\n- YUVY 16 bpp - Software conversion from UYVY" | ||
274 | "\n- YUV422 16 bpp - Software conversion from UYVY" | ||
275 | "\n- GREY 8 bpp - Software conversion from UYVY" | ||
276 | "\n- RGB555 16 bpp - Software conversion from UYVY" | ||
277 | "\n- RGB565 16 bpp - Software conversion from UYVY" | ||
278 | "\n- RGB24 24 bpp - Software conversion from UYVY" | ||
279 | "\n- RGB32 32 bpp - Software conversion from UYVY" | ||
280 | "\nWhen not 0, this parameter will override 'decompression'." | ||
281 | "\nDefault value is 0 for every device." | ||
282 | "\nInitial palette is " | ||
283 | __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"." | ||
284 | "\nIf 'w9968cf-vpp' is not present, this parameter is" | ||
285 | " set to 9 (UYVY)." | ||
286 | "\n"); | ||
287 | MODULE_PARM_DESC(force_rgb, | ||
288 | "\n<0|1[,...]> Read RGB video data instead of BGR:" | ||
289 | "\n 1 = use RGB component ordering." | ||
290 | "\n 0 = use BGR component ordering." | ||
291 | "\nThis parameter has effect when using RGBX palettes only." | ||
292 | "\nDefault value is "__MODULE_STRING(W9968CF_FORCE_RGB) | ||
293 | " for every device." | ||
294 | "\n"); | ||
295 | MODULE_PARM_DESC(autobright, | ||
296 | "\n<0|1[,...]> Image sensor automatically changes brightness:" | ||
297 | "\n 0 = no, 1 = yes" | ||
298 | "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT) | ||
299 | " for every device." | ||
300 | "\n"); | ||
301 | MODULE_PARM_DESC(autoexp, | ||
302 | "\n<0|1[,...]> Image sensor automatically changes exposure:" | ||
303 | "\n 0 = no, 1 = yes" | ||
304 | "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP) | ||
305 | " for every device." | ||
306 | "\n"); | ||
307 | MODULE_PARM_DESC(lightfreq, | ||
308 | "\n<50|60[,...]> Light frequency in Hz:" | ||
309 | "\n 50 for European and Asian lighting," | ||
310 | " 60 for American lighting." | ||
311 | "\nDefault value is "__MODULE_STRING(W9968CF_LIGHTFREQ) | ||
312 | " for every device." | ||
313 | "\n"); | ||
314 | MODULE_PARM_DESC(bandingfilter, | ||
315 | "\n<0|1[,...]> Banding filter to reduce effects of" | ||
316 | " fluorescent lighting:" | ||
317 | "\n 0 disabled, 1 enabled." | ||
318 | "\nThis filter tries to reduce the pattern of horizontal" | ||
319 | "\nlight/dark bands caused by some (usually fluorescent)" | ||
320 | " lighting." | ||
321 | "\nDefault value is "__MODULE_STRING(W9968CF_BANDINGFILTER) | ||
322 | " for every device." | ||
323 | "\n"); | ||
324 | MODULE_PARM_DESC(clockdiv, | ||
325 | "\n<-1|n[,...]> " | ||
326 | "Force pixel clock divisor to a specific value (for experts):" | ||
327 | "\n n may vary from 0 to 127." | ||
328 | "\n -1 for automatic value." | ||
329 | "\nSee also the 'double_buffer' module parameter." | ||
330 | "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV) | ||
331 | " for every device." | ||
332 | "\n"); | ||
333 | MODULE_PARM_DESC(backlight, | ||
334 | "\n<0|1[,...]> Objects are lit from behind:" | ||
335 | "\n 0 = no, 1 = yes" | ||
336 | "\nDefault value is "__MODULE_STRING(W9968CF_BACKLIGHT) | ||
337 | " for every device." | ||
338 | "\n"); | ||
339 | MODULE_PARM_DESC(mirror, | ||
340 | "\n<0|1[,...]> Reverse image horizontally:" | ||
341 | "\n 0 = no, 1 = yes" | ||
342 | "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR) | ||
343 | " for every device." | ||
344 | "\n"); | ||
345 | MODULE_PARM_DESC(monochrome, | ||
346 | "\n<0|1[,...]> Use image sensor as monochrome sensor:" | ||
347 | "\n 0 = no, 1 = yes" | ||
348 | "\nNot all the sensors support monochrome color." | ||
349 | "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME) | ||
350 | " for every device." | ||
351 | "\n"); | ||
352 | MODULE_PARM_DESC(brightness, | ||
353 | "\n<n[,...]> Set picture brightness (0-65535)." | ||
354 | "\nDefault value is "__MODULE_STRING(W9968CF_BRIGHTNESS) | ||
355 | " for every device." | ||
356 | "\nThis parameter has no effect if 'autobright' is enabled." | ||
357 | "\n"); | ||
358 | MODULE_PARM_DESC(hue, | ||
359 | "\n<n[,...]> Set picture hue (0-65535)." | ||
360 | "\nDefault value is "__MODULE_STRING(W9968CF_HUE) | ||
361 | " for every device." | ||
362 | "\n"); | ||
363 | MODULE_PARM_DESC(colour, | ||
364 | "\n<n[,...]> Set picture saturation (0-65535)." | ||
365 | "\nDefault value is "__MODULE_STRING(W9968CF_COLOUR) | ||
366 | " for every device." | ||
367 | "\n"); | ||
368 | MODULE_PARM_DESC(contrast, | ||
369 | "\n<n[,...]> Set picture contrast (0-65535)." | ||
370 | "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST) | ||
371 | " for every device." | ||
372 | "\n"); | ||
373 | MODULE_PARM_DESC(whiteness, | ||
374 | "\n<n[,...]> Set picture whiteness (0-65535)." | ||
375 | "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS) | ||
376 | " for every device." | ||
377 | "\n"); | ||
378 | #ifdef W9968CF_DEBUG | ||
379 | MODULE_PARM_DESC(debug, | ||
380 | "\n<n> Debugging information level, from 0 to 6:" | ||
381 | "\n0 = none (use carefully)" | ||
382 | "\n1 = critical errors" | ||
383 | "\n2 = significant informations" | ||
384 | "\n3 = configuration or general messages" | ||
385 | "\n4 = warnings" | ||
386 | "\n5 = called functions" | ||
387 | "\n6 = function internals" | ||
388 | "\nLevel 5 and 6 are useful for testing only, when only " | ||
389 | "one device is used." | ||
390 | "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"." | ||
391 | "\n"); | ||
392 | MODULE_PARM_DESC(specific_debug, | ||
393 | "\n<0|1> Enable or disable specific debugging messages:" | ||
394 | "\n0 = print messages concerning every level" | ||
395 | " <= 'debug' level." | ||
396 | "\n1 = print messages concerning the level" | ||
397 | " indicated by 'debug'." | ||
398 | "\nDefault value is " | ||
399 | __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"." | ||
400 | "\n"); | ||
401 | #endif /* W9968CF_DEBUG */ | ||
402 | |||
403 | |||
404 | |||
405 | /**************************************************************************** | ||
406 | * Some prototypes * | ||
407 | ****************************************************************************/ | ||
408 | |||
409 | /* Video4linux interface */ | ||
410 | static struct file_operations w9968cf_fops; | ||
411 | static int w9968cf_open(struct inode*, struct file*); | ||
412 | static int w9968cf_release(struct inode*, struct file*); | ||
413 | static int w9968cf_mmap(struct file*, struct vm_area_struct*); | ||
414 | static int w9968cf_ioctl(struct inode*, struct file*, unsigned, unsigned long); | ||
415 | static ssize_t w9968cf_read(struct file*, char __user *, size_t, loff_t*); | ||
416 | static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int, | ||
417 | void __user *); | ||
418 | |||
419 | /* USB-specific */ | ||
420 | static int w9968cf_start_transfer(struct w9968cf_device*); | ||
421 | static int w9968cf_stop_transfer(struct w9968cf_device*); | ||
422 | static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index); | ||
423 | static int w9968cf_read_reg(struct w9968cf_device*, u16 index); | ||
424 | static int w9968cf_write_fsb(struct w9968cf_device*, u16* data); | ||
425 | static int w9968cf_write_sb(struct w9968cf_device*, u16 value); | ||
426 | static int w9968cf_read_sb(struct w9968cf_device*); | ||
427 | static int w9968cf_upload_quantizationtables(struct w9968cf_device*); | ||
428 | static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs); | ||
429 | |||
430 | /* Low-level I2C (SMBus) I/O */ | ||
431 | static int w9968cf_smbus_start(struct w9968cf_device*); | ||
432 | static int w9968cf_smbus_stop(struct w9968cf_device*); | ||
433 | static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v); | ||
434 | static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v); | ||
435 | static int w9968cf_smbus_write_ack(struct w9968cf_device*); | ||
436 | static int w9968cf_smbus_read_ack(struct w9968cf_device*); | ||
437 | static int w9968cf_smbus_refresh_bus(struct w9968cf_device*); | ||
438 | static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam, | ||
439 | u16 address, u8* value); | ||
440 | static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address, | ||
441 | u8 subaddress, u8* value); | ||
442 | static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*, | ||
443 | u16 address, u8 subaddress); | ||
444 | static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*, | ||
445 | u16 address, u8 subaddress, | ||
446 | u8 value); | ||
447 | |||
448 | /* I2C interface to kernel */ | ||
449 | static int w9968cf_i2c_init(struct w9968cf_device*); | ||
450 | static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr, | ||
451 | unsigned short flags, char read_write, | ||
452 | u8 command, int size, union i2c_smbus_data*); | ||
453 | static u32 w9968cf_i2c_func(struct i2c_adapter*); | ||
454 | static int w9968cf_i2c_attach_inform(struct i2c_client*); | ||
455 | static int w9968cf_i2c_detach_inform(struct i2c_client*); | ||
456 | static int w9968cf_i2c_control(struct i2c_adapter*, unsigned int cmd, | ||
457 | unsigned long arg); | ||
458 | |||
459 | /* Memory management */ | ||
460 | static void* rvmalloc(unsigned long size); | ||
461 | static void rvfree(void *mem, unsigned long size); | ||
462 | static void w9968cf_deallocate_memory(struct w9968cf_device*); | ||
463 | static int w9968cf_allocate_memory(struct w9968cf_device*); | ||
464 | |||
465 | /* High-level image sensor control functions */ | ||
466 | static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val); | ||
467 | static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val); | ||
468 | static int w9968cf_sensor_cmd(struct w9968cf_device*, | ||
469 | unsigned int cmd, void *arg); | ||
470 | static int w9968cf_sensor_init(struct w9968cf_device*); | ||
471 | static int w9968cf_sensor_update_settings(struct w9968cf_device*); | ||
472 | static int w9968cf_sensor_get_picture(struct w9968cf_device*); | ||
473 | static int w9968cf_sensor_update_picture(struct w9968cf_device*, | ||
474 | struct video_picture pict); | ||
475 | |||
476 | /* Other helper functions */ | ||
477 | static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*, | ||
478 | enum w9968cf_model_id, | ||
479 | const unsigned short dev_nr); | ||
480 | static void w9968cf_adjust_configuration(struct w9968cf_device*); | ||
481 | static int w9968cf_turn_on_led(struct w9968cf_device*); | ||
482 | static int w9968cf_init_chip(struct w9968cf_device*); | ||
483 | static inline u16 w9968cf_valid_palette(u16 palette); | ||
484 | static inline u16 w9968cf_valid_depth(u16 palette); | ||
485 | static inline u8 w9968cf_need_decompression(u16 palette); | ||
486 | static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture); | ||
487 | static int w9968cf_set_window(struct w9968cf_device*, struct video_window); | ||
488 | static int w9968cf_postprocess_frame(struct w9968cf_device*, | ||
489 | struct w9968cf_frame_t*); | ||
490 | static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h); | ||
491 | static void w9968cf_init_framelist(struct w9968cf_device*); | ||
492 | static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num); | ||
493 | static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**); | ||
494 | static void w9968cf_release_resources(struct w9968cf_device*); | ||
495 | |||
496 | /* Intermodule communication */ | ||
497 | static int w9968cf_vppmod_detect(struct w9968cf_device*); | ||
498 | static void w9968cf_vppmod_release(struct w9968cf_device*); | ||
499 | |||
500 | |||
501 | |||
502 | /**************************************************************************** | ||
503 | * Symbolic names * | ||
504 | ****************************************************************************/ | ||
505 | |||
506 | /* Used to represent a list of values and their respective symbolic names */ | ||
507 | struct w9968cf_symbolic_list { | ||
508 | const int num; | ||
509 | const char *name; | ||
510 | }; | ||
511 | |||
512 | /*-------------------------------------------------------------------------- | ||
513 | Returns the name of the matching element in the symbolic_list array. The | ||
514 | end of the list must be marked with an element that has a NULL name. | ||
515 | --------------------------------------------------------------------------*/ | ||
516 | static inline const char * | ||
517 | symbolic(struct w9968cf_symbolic_list list[], const int num) | ||
518 | { | ||
519 | int i; | ||
520 | |||
521 | for (i = 0; list[i].name != NULL; i++) | ||
522 | if (list[i].num == num) | ||
523 | return (list[i].name); | ||
524 | |||
525 | return "Unknown"; | ||
526 | } | ||
527 | |||
528 | static struct w9968cf_symbolic_list camlist[] = { | ||
529 | { W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" }, | ||
530 | { W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" }, | ||
531 | |||
532 | /* Other cameras (having the same descriptors as Generic W996[87]CF) */ | ||
533 | { W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" }, | ||
534 | { W9986CF_MOD_AAU, "AVerMedia AVerTV USB" }, | ||
535 | { W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" }, | ||
536 | { W9968CF_MOD_LL, "Lebon LDC-035A" }, | ||
537 | { W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" }, | ||
538 | { W9968CF_MOD_OOE, "OmniVision OV8610-EDE" }, | ||
539 | { W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" }, | ||
540 | { W9968CF_MOD_PDPII, "Pretec Digi Pen-II" }, | ||
541 | { W9968CF_MOD_PDP480, "Pretec DigiPen-480" }, | ||
542 | |||
543 | { -1, NULL } | ||
544 | }; | ||
545 | |||
546 | static struct w9968cf_symbolic_list senlist[] = { | ||
547 | { CC_OV76BE, "OV76BE" }, | ||
548 | { CC_OV7610, "OV7610" }, | ||
549 | { CC_OV7620, "OV7620" }, | ||
550 | { CC_OV7620AE, "OV7620AE" }, | ||
551 | { CC_OV6620, "OV6620" }, | ||
552 | { CC_OV6630, "OV6630" }, | ||
553 | { CC_OV6630AE, "OV6630AE" }, | ||
554 | { CC_OV6630AF, "OV6630AF" }, | ||
555 | { -1, NULL } | ||
556 | }; | ||
557 | |||
558 | /* Video4Linux1 palettes */ | ||
559 | static struct w9968cf_symbolic_list v4l1_plist[] = { | ||
560 | { VIDEO_PALETTE_GREY, "GREY" }, | ||
561 | { VIDEO_PALETTE_HI240, "HI240" }, | ||
562 | { VIDEO_PALETTE_RGB565, "RGB565" }, | ||
563 | { VIDEO_PALETTE_RGB24, "RGB24" }, | ||
564 | { VIDEO_PALETTE_RGB32, "RGB32" }, | ||
565 | { VIDEO_PALETTE_RGB555, "RGB555" }, | ||
566 | { VIDEO_PALETTE_YUV422, "YUV422" }, | ||
567 | { VIDEO_PALETTE_YUYV, "YUYV" }, | ||
568 | { VIDEO_PALETTE_UYVY, "UYVY" }, | ||
569 | { VIDEO_PALETTE_YUV420, "YUV420" }, | ||
570 | { VIDEO_PALETTE_YUV411, "YUV411" }, | ||
571 | { VIDEO_PALETTE_RAW, "RAW" }, | ||
572 | { VIDEO_PALETTE_YUV422P, "YUV422P" }, | ||
573 | { VIDEO_PALETTE_YUV411P, "YUV411P" }, | ||
574 | { VIDEO_PALETTE_YUV420P, "YUV420P" }, | ||
575 | { VIDEO_PALETTE_YUV410P, "YUV410P" }, | ||
576 | { -1, NULL } | ||
577 | }; | ||
578 | |||
579 | /* Decoder error codes: */ | ||
580 | static struct w9968cf_symbolic_list decoder_errlist[] = { | ||
581 | { W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" }, | ||
582 | { W9968CF_DEC_ERR_BUF_OVERFLOW, "Buffer overflow" }, | ||
583 | { W9968CF_DEC_ERR_NO_SOI, "SOI marker not found" }, | ||
584 | { W9968CF_DEC_ERR_NO_SOF0, "SOF0 marker not found" }, | ||
585 | { W9968CF_DEC_ERR_NO_SOS, "SOS marker not found" }, | ||
586 | { W9968CF_DEC_ERR_NO_EOI, "EOI marker not found" }, | ||
587 | { -1, NULL } | ||
588 | }; | ||
589 | |||
590 | /* URB error codes: */ | ||
591 | static struct w9968cf_symbolic_list urb_errlist[] = { | ||
592 | { -ENOMEM, "No memory for allocation of internal structures" }, | ||
593 | { -ENOSPC, "The host controller's bandwidth is already consumed" }, | ||
594 | { -ENOENT, "URB was canceled by unlink_urb" }, | ||
595 | { -EXDEV, "ISO transfer only partially completed" }, | ||
596 | { -EAGAIN, "Too match scheduled for the future" }, | ||
597 | { -ENXIO, "URB already queued" }, | ||
598 | { -EFBIG, "Too much ISO frames requested" }, | ||
599 | { -ENOSR, "Buffer error (overrun)" }, | ||
600 | { -EPIPE, "Specified endpoint is stalled (device not responding)"}, | ||
601 | { -EOVERFLOW, "Babble (bad cable?)" }, | ||
602 | { -EPROTO, "Bit-stuff error (bad cable?)" }, | ||
603 | { -EILSEQ, "CRC/Timeout" }, | ||
604 | { -ETIMEDOUT, "NAK (device does not respond)" }, | ||
605 | { -1, NULL } | ||
606 | }; | ||
607 | |||
608 | |||
609 | |||
610 | /**************************************************************************** | ||
611 | * Memory management functions * | ||
612 | ****************************************************************************/ | ||
613 | static void* rvmalloc(unsigned long size) | ||
614 | { | ||
615 | void* mem; | ||
616 | unsigned long adr; | ||
617 | |||
618 | size = PAGE_ALIGN(size); | ||
619 | mem = vmalloc_32(size); | ||
620 | if (!mem) | ||
621 | return NULL; | ||
622 | |||
623 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
624 | adr = (unsigned long) mem; | ||
625 | while (size > 0) { | ||
626 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
627 | adr += PAGE_SIZE; | ||
628 | size -= PAGE_SIZE; | ||
629 | } | ||
630 | |||
631 | return mem; | ||
632 | } | ||
633 | |||
634 | |||
635 | static void rvfree(void* mem, unsigned long size) | ||
636 | { | ||
637 | unsigned long adr; | ||
638 | |||
639 | if (!mem) | ||
640 | return; | ||
641 | |||
642 | adr = (unsigned long) mem; | ||
643 | while ((long) size > 0) { | ||
644 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
645 | adr += PAGE_SIZE; | ||
646 | size -= PAGE_SIZE; | ||
647 | } | ||
648 | vfree(mem); | ||
649 | } | ||
650 | |||
651 | |||
652 | /*-------------------------------------------------------------------------- | ||
653 | Deallocate previously allocated memory. | ||
654 | --------------------------------------------------------------------------*/ | ||
655 | static void w9968cf_deallocate_memory(struct w9968cf_device* cam) | ||
656 | { | ||
657 | u8 i; | ||
658 | |||
659 | /* Free the isochronous transfer buffers */ | ||
660 | for (i = 0; i < W9968CF_URBS; i++) { | ||
661 | kfree(cam->transfer_buffer[i]); | ||
662 | cam->transfer_buffer[i] = NULL; | ||
663 | } | ||
664 | |||
665 | /* Free temporary frame buffer */ | ||
666 | if (cam->frame_tmp.buffer) { | ||
667 | rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size); | ||
668 | cam->frame_tmp.buffer = NULL; | ||
669 | } | ||
670 | |||
671 | /* Free helper buffer */ | ||
672 | if (cam->frame_vpp.buffer) { | ||
673 | rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size); | ||
674 | cam->frame_vpp.buffer = NULL; | ||
675 | } | ||
676 | |||
677 | /* Free video frame buffers */ | ||
678 | if (cam->frame[0].buffer) { | ||
679 | rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size); | ||
680 | cam->frame[0].buffer = NULL; | ||
681 | } | ||
682 | |||
683 | cam->nbuffers = 0; | ||
684 | |||
685 | DBG(5, "Memory successfully deallocated") | ||
686 | } | ||
687 | |||
688 | |||
689 | /*-------------------------------------------------------------------------- | ||
690 | Allocate memory buffers for USB transfers and video frames. | ||
691 | This function is called by open() only. | ||
692 | Return 0 on success, a negative number otherwise. | ||
693 | --------------------------------------------------------------------------*/ | ||
694 | static int w9968cf_allocate_memory(struct w9968cf_device* cam) | ||
695 | { | ||
696 | const u16 p_size = wMaxPacketSize[cam->altsetting-1]; | ||
697 | void* buff = NULL; | ||
698 | unsigned long hw_bufsize, vpp_bufsize; | ||
699 | u8 i, bpp; | ||
700 | |||
701 | /* NOTE: Deallocation is done elsewhere in case of error */ | ||
702 | |||
703 | /* Calculate the max amount of raw data per frame from the device */ | ||
704 | hw_bufsize = cam->maxwidth*cam->maxheight*2; | ||
705 | |||
706 | /* Calculate the max buf. size needed for post-processing routines */ | ||
707 | bpp = (w9968cf_vpp) ? 4 : 2; | ||
708 | if (cam->upscaling) | ||
709 | vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp, | ||
710 | cam->maxwidth*cam->maxheight*bpp); | ||
711 | else | ||
712 | vpp_bufsize = cam->maxwidth*cam->maxheight*bpp; | ||
713 | |||
714 | /* Allocate memory for the isochronous transfer buffers */ | ||
715 | for (i = 0; i < W9968CF_URBS; i++) { | ||
716 | if (!(cam->transfer_buffer[i] = | ||
717 | kmalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) { | ||
718 | DBG(1, "Couldn't allocate memory for the isochronous " | ||
719 | "transfer buffers (%u bytes)", | ||
720 | p_size * W9968CF_ISO_PACKETS) | ||
721 | return -ENOMEM; | ||
722 | } | ||
723 | memset(cam->transfer_buffer[i], 0, W9968CF_ISO_PACKETS*p_size); | ||
724 | } | ||
725 | |||
726 | /* Allocate memory for the temporary frame buffer */ | ||
727 | if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) { | ||
728 | DBG(1, "Couldn't allocate memory for the temporary " | ||
729 | "video frame buffer (%lu bytes)", hw_bufsize) | ||
730 | return -ENOMEM; | ||
731 | } | ||
732 | cam->frame_tmp.size = hw_bufsize; | ||
733 | cam->frame_tmp.number = -1; | ||
734 | |||
735 | /* Allocate memory for the helper buffer */ | ||
736 | if (w9968cf_vpp) { | ||
737 | if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) { | ||
738 | DBG(1, "Couldn't allocate memory for the helper buffer" | ||
739 | " (%lu bytes)", vpp_bufsize) | ||
740 | return -ENOMEM; | ||
741 | } | ||
742 | cam->frame_vpp.size = vpp_bufsize; | ||
743 | } else | ||
744 | cam->frame_vpp.buffer = NULL; | ||
745 | |||
746 | /* Allocate memory for video frame buffers */ | ||
747 | cam->nbuffers = cam->max_buffers; | ||
748 | while (cam->nbuffers >= 2) { | ||
749 | if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize))) | ||
750 | break; | ||
751 | else | ||
752 | cam->nbuffers--; | ||
753 | } | ||
754 | |||
755 | if (!buff) { | ||
756 | DBG(1, "Couldn't allocate memory for the video frame buffers") | ||
757 | cam->nbuffers = 0; | ||
758 | return -ENOMEM; | ||
759 | } | ||
760 | |||
761 | if (cam->nbuffers != cam->max_buffers) | ||
762 | DBG(2, "Couldn't allocate memory for %u video frame buffers. " | ||
763 | "Only memory for %u buffers has been allocated", | ||
764 | cam->max_buffers, cam->nbuffers) | ||
765 | |||
766 | for (i = 0; i < cam->nbuffers; i++) { | ||
767 | cam->frame[i].buffer = buff + i*vpp_bufsize; | ||
768 | cam->frame[i].size = vpp_bufsize; | ||
769 | cam->frame[i].number = i; | ||
770 | /* Circular list */ | ||
771 | if (i != cam->nbuffers-1) | ||
772 | cam->frame[i].next = &cam->frame[i+1]; | ||
773 | else | ||
774 | cam->frame[i].next = &cam->frame[0]; | ||
775 | cam->frame[i].status = F_UNUSED; | ||
776 | } | ||
777 | |||
778 | DBG(5, "Memory successfully allocated") | ||
779 | return 0; | ||
780 | } | ||
781 | |||
782 | |||
783 | |||
784 | /**************************************************************************** | ||
785 | * USB-specific functions * | ||
786 | ****************************************************************************/ | ||
787 | |||
788 | /*-------------------------------------------------------------------------- | ||
789 | This is an handler function which is called after the URBs are completed. | ||
790 | It collects multiple data packets coming from the camera by putting them | ||
791 | into frame buffers: one or more zero data length data packets are used to | ||
792 | mark the end of a video frame; the first non-zero data packet is the start | ||
793 | of the next video frame; if an error is encountered in a packet, the entire | ||
794 | video frame is discarded and grabbed again. | ||
795 | If there are no requested frames in the FIFO list, packets are collected into | ||
796 | a temporary buffer. | ||
797 | --------------------------------------------------------------------------*/ | ||
798 | static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs) | ||
799 | { | ||
800 | struct w9968cf_device* cam = (struct w9968cf_device*)urb->context; | ||
801 | struct w9968cf_frame_t** f; | ||
802 | unsigned int len, status; | ||
803 | void* pos; | ||
804 | u8 i; | ||
805 | int err = 0; | ||
806 | |||
807 | if ((!cam->streaming) || cam->disconnected) { | ||
808 | DBG(4, "Got interrupt, but not streaming") | ||
809 | return; | ||
810 | } | ||
811 | |||
812 | /* "(*f)" will be used instead of "cam->frame_current" */ | ||
813 | f = &cam->frame_current; | ||
814 | |||
815 | /* If a frame has been requested and we are grabbing into | ||
816 | the temporary frame, we'll switch to that requested frame */ | ||
817 | if ((*f) == &cam->frame_tmp && *cam->requested_frame) { | ||
818 | if (cam->frame_tmp.status == F_GRABBING) { | ||
819 | w9968cf_pop_frame(cam, &cam->frame_current); | ||
820 | (*f)->status = F_GRABBING; | ||
821 | (*f)->length = cam->frame_tmp.length; | ||
822 | memcpy((*f)->buffer, cam->frame_tmp.buffer, | ||
823 | (*f)->length); | ||
824 | DBG(6, "Switched from temp. frame to frame #%d", | ||
825 | (*f)->number) | ||
826 | } | ||
827 | } | ||
828 | |||
829 | for (i = 0; i < urb->number_of_packets; i++) { | ||
830 | len = urb->iso_frame_desc[i].actual_length; | ||
831 | status = urb->iso_frame_desc[i].status; | ||
832 | pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; | ||
833 | |||
834 | if (status && len != 0) { | ||
835 | DBG(4, "URB failed, error in data packet " | ||
836 | "(error #%u, %s)", | ||
837 | status, symbolic(urb_errlist, status)) | ||
838 | (*f)->status = F_ERROR; | ||
839 | continue; | ||
840 | } | ||
841 | |||
842 | if (len) { /* start of frame */ | ||
843 | |||
844 | if ((*f)->status == F_UNUSED) { | ||
845 | (*f)->status = F_GRABBING; | ||
846 | (*f)->length = 0; | ||
847 | } | ||
848 | |||
849 | /* Buffer overflows shouldn't happen, however...*/ | ||
850 | if ((*f)->length + len > (*f)->size) { | ||
851 | DBG(4, "Buffer overflow: bad data packets") | ||
852 | (*f)->status = F_ERROR; | ||
853 | } | ||
854 | |||
855 | if ((*f)->status == F_GRABBING) { | ||
856 | memcpy((*f)->buffer + (*f)->length, pos, len); | ||
857 | (*f)->length += len; | ||
858 | } | ||
859 | |||
860 | } else if ((*f)->status == F_GRABBING) { /* end of frame */ | ||
861 | |||
862 | DBG(6, "Frame #%d successfully grabbed", (*f)->number) | ||
863 | |||
864 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | ||
865 | err = w9968cf_vpp->check_headers((*f)->buffer, | ||
866 | (*f)->length); | ||
867 | if (err) { | ||
868 | DBG(4, "Skip corrupted frame: %s", | ||
869 | symbolic(decoder_errlist, err)) | ||
870 | (*f)->status = F_UNUSED; | ||
871 | continue; /* grab this frame again */ | ||
872 | } | ||
873 | } | ||
874 | |||
875 | (*f)->status = F_READY; | ||
876 | (*f)->queued = 0; | ||
877 | |||
878 | /* Take a pointer to the new frame from the FIFO list. | ||
879 | If the list is empty,we'll use the temporary frame*/ | ||
880 | if (*cam->requested_frame) | ||
881 | w9968cf_pop_frame(cam, &cam->frame_current); | ||
882 | else { | ||
883 | cam->frame_current = &cam->frame_tmp; | ||
884 | (*f)->status = F_UNUSED; | ||
885 | } | ||
886 | |||
887 | } else if ((*f)->status == F_ERROR) | ||
888 | (*f)->status = F_UNUSED; /* grab it again */ | ||
889 | |||
890 | PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d", | ||
891 | (unsigned long)(*f)->length, i, len, (*f)->status) | ||
892 | |||
893 | } /* end for */ | ||
894 | |||
895 | /* Resubmit this URB */ | ||
896 | urb->dev = cam->usbdev; | ||
897 | urb->status = 0; | ||
898 | spin_lock(&cam->urb_lock); | ||
899 | if (cam->streaming) | ||
900 | if ((err = usb_submit_urb(urb, GFP_ATOMIC))) { | ||
901 | cam->misconfigured = 1; | ||
902 | DBG(1, "Couldn't resubmit the URB: error %d, %s", | ||
903 | err, symbolic(urb_errlist, err)) | ||
904 | } | ||
905 | spin_unlock(&cam->urb_lock); | ||
906 | |||
907 | /* Wake up the user process */ | ||
908 | wake_up_interruptible(&cam->wait_queue); | ||
909 | } | ||
910 | |||
911 | |||
912 | /*--------------------------------------------------------------------------- | ||
913 | Setup the URB structures for the isochronous transfer. | ||
914 | Submit the URBs so that the data transfer begins. | ||
915 | Return 0 on success, a negative number otherwise. | ||
916 | ---------------------------------------------------------------------------*/ | ||
917 | static int w9968cf_start_transfer(struct w9968cf_device* cam) | ||
918 | { | ||
919 | struct usb_device *udev = cam->usbdev; | ||
920 | struct urb* urb; | ||
921 | const u16 p_size = wMaxPacketSize[cam->altsetting-1]; | ||
922 | u16 w, h, d; | ||
923 | int vidcapt; | ||
924 | u32 t_size; | ||
925 | int err = 0; | ||
926 | s8 i, j; | ||
927 | |||
928 | for (i = 0; i < W9968CF_URBS; i++) { | ||
929 | urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL); | ||
930 | cam->urb[i] = urb; | ||
931 | if (!urb) { | ||
932 | for (j = 0; j < i; j++) | ||
933 | usb_free_urb(cam->urb[j]); | ||
934 | DBG(1, "Couldn't allocate the URB structures") | ||
935 | return -ENOMEM; | ||
936 | } | ||
937 | |||
938 | urb->dev = udev; | ||
939 | urb->context = (void*)cam; | ||
940 | urb->pipe = usb_rcvisocpipe(udev, 1); | ||
941 | urb->transfer_flags = URB_ISO_ASAP; | ||
942 | urb->number_of_packets = W9968CF_ISO_PACKETS; | ||
943 | urb->complete = w9968cf_urb_complete; | ||
944 | urb->transfer_buffer = cam->transfer_buffer[i]; | ||
945 | urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS; | ||
946 | urb->interval = 1; | ||
947 | for (j = 0; j < W9968CF_ISO_PACKETS; j++) { | ||
948 | urb->iso_frame_desc[j].offset = p_size*j; | ||
949 | urb->iso_frame_desc[j].length = p_size; | ||
950 | } | ||
951 | } | ||
952 | |||
953 | /* Transfer size per frame, in WORD ! */ | ||
954 | d = cam->hw_depth; | ||
955 | w = cam->hw_width; | ||
956 | h = cam->hw_height; | ||
957 | |||
958 | t_size = (w*h*d)/16; | ||
959 | |||
960 | err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ | ||
961 | err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ | ||
962 | |||
963 | /* Transfer size */ | ||
964 | err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */ | ||
965 | err += w9968cf_write_reg(cam, t_size >> 16, 0x3e); /* high bits */ | ||
966 | |||
967 | if (cam->vpp_flag & VPP_DECOMPRESSION) | ||
968 | err += w9968cf_upload_quantizationtables(cam); | ||
969 | |||
970 | vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */ | ||
971 | err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */ | ||
972 | |||
973 | err += usb_set_interface(udev, 0, cam->altsetting); | ||
974 | err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */ | ||
975 | |||
976 | if (err || (vidcapt < 0)) { | ||
977 | for (i = 0; i < W9968CF_URBS; i++) | ||
978 | usb_free_urb(cam->urb[i]); | ||
979 | DBG(1, "Couldn't tell the camera to start the data transfer") | ||
980 | return err; | ||
981 | } | ||
982 | |||
983 | w9968cf_init_framelist(cam); | ||
984 | |||
985 | /* Begin to grab into the temporary buffer */ | ||
986 | cam->frame_tmp.status = F_UNUSED; | ||
987 | cam->frame_tmp.queued = 0; | ||
988 | cam->frame_current = &cam->frame_tmp; | ||
989 | |||
990 | if (!(cam->vpp_flag & VPP_DECOMPRESSION)) | ||
991 | DBG(5, "Isochronous transfer size: %lu bytes/frame", | ||
992 | (unsigned long)t_size*2) | ||
993 | |||
994 | DBG(5, "Starting the isochronous transfer...") | ||
995 | |||
996 | cam->streaming = 1; | ||
997 | |||
998 | /* Submit the URBs */ | ||
999 | for (i = 0; i < W9968CF_URBS; i++) { | ||
1000 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); | ||
1001 | if (err) { | ||
1002 | cam->streaming = 0; | ||
1003 | for (j = i-1; j >= 0; j--) { | ||
1004 | usb_kill_urb(cam->urb[j]); | ||
1005 | usb_free_urb(cam->urb[j]); | ||
1006 | } | ||
1007 | DBG(1, "Couldn't send a transfer request to the " | ||
1008 | "USB core (error #%d, %s)", err, | ||
1009 | symbolic(urb_errlist, err)) | ||
1010 | return err; | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | return 0; | ||
1015 | } | ||
1016 | |||
1017 | |||
1018 | /*-------------------------------------------------------------------------- | ||
1019 | Stop the isochronous transfer and set alternate setting to 0 (0Mb/s). | ||
1020 | Return 0 on success, a negative number otherwise. | ||
1021 | --------------------------------------------------------------------------*/ | ||
1022 | static int w9968cf_stop_transfer(struct w9968cf_device* cam) | ||
1023 | { | ||
1024 | struct usb_device *udev = cam->usbdev; | ||
1025 | unsigned long lock_flags; | ||
1026 | int err = 0; | ||
1027 | s8 i; | ||
1028 | |||
1029 | if (!cam->streaming) | ||
1030 | return 0; | ||
1031 | |||
1032 | /* This avoids race conditions with usb_submit_urb() | ||
1033 | in the URB completition handler */ | ||
1034 | spin_lock_irqsave(&cam->urb_lock, lock_flags); | ||
1035 | cam->streaming = 0; | ||
1036 | spin_unlock_irqrestore(&cam->urb_lock, lock_flags); | ||
1037 | |||
1038 | for (i = W9968CF_URBS-1; i >= 0; i--) | ||
1039 | if (cam->urb[i]) { | ||
1040 | usb_kill_urb(cam->urb[i]); | ||
1041 | usb_free_urb(cam->urb[i]); | ||
1042 | cam->urb[i] = NULL; | ||
1043 | } | ||
1044 | |||
1045 | if (cam->disconnected) | ||
1046 | goto exit; | ||
1047 | |||
1048 | err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */ | ||
1049 | err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */ | ||
1050 | err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */ | ||
1051 | err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */ | ||
1052 | |||
1053 | if (err) { | ||
1054 | DBG(2, "Failed to tell the camera to stop the isochronous " | ||
1055 | "transfer. However this is not a critical error.") | ||
1056 | return -EIO; | ||
1057 | } | ||
1058 | |||
1059 | exit: | ||
1060 | DBG(5, "Isochronous transfer stopped") | ||
1061 | return 0; | ||
1062 | } | ||
1063 | |||
1064 | |||
1065 | /*-------------------------------------------------------------------------- | ||
1066 | Write a W9968CF register. | ||
1067 | Return 0 on success, -1 otherwise. | ||
1068 | --------------------------------------------------------------------------*/ | ||
1069 | static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index) | ||
1070 | { | ||
1071 | struct usb_device* udev = cam->usbdev; | ||
1072 | int res; | ||
1073 | |||
1074 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, | ||
1075 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | ||
1076 | value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT); | ||
1077 | |||
1078 | if (res < 0) | ||
1079 | DBG(4, "Failed to write a register " | ||
1080 | "(value 0x%04X, index 0x%02X, error #%d, %s)", | ||
1081 | value, index, res, symbolic(urb_errlist, res)) | ||
1082 | |||
1083 | return (res >= 0) ? 0 : -1; | ||
1084 | } | ||
1085 | |||
1086 | |||
1087 | /*-------------------------------------------------------------------------- | ||
1088 | Read a W9968CF register. | ||
1089 | Return the register value on success, -1 otherwise. | ||
1090 | --------------------------------------------------------------------------*/ | ||
1091 | static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index) | ||
1092 | { | ||
1093 | struct usb_device* udev = cam->usbdev; | ||
1094 | u16* buff = cam->control_buffer; | ||
1095 | int res; | ||
1096 | |||
1097 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1, | ||
1098 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
1099 | 0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT); | ||
1100 | |||
1101 | if (res < 0) | ||
1102 | DBG(4, "Failed to read a register " | ||
1103 | "(index 0x%02X, error #%d, %s)", | ||
1104 | index, res, symbolic(urb_errlist, res)) | ||
1105 | |||
1106 | return (res >= 0) ? (int)(*buff) : -1; | ||
1107 | } | ||
1108 | |||
1109 | |||
1110 | /*-------------------------------------------------------------------------- | ||
1111 | Write 64-bit data to the fast serial bus registers. | ||
1112 | Return 0 on success, -1 otherwise. | ||
1113 | --------------------------------------------------------------------------*/ | ||
1114 | static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data) | ||
1115 | { | ||
1116 | struct usb_device* udev = cam->usbdev; | ||
1117 | u16 value; | ||
1118 | int res; | ||
1119 | |||
1120 | value = *data++; | ||
1121 | |||
1122 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, | ||
1123 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | ||
1124 | value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT); | ||
1125 | |||
1126 | if (res < 0) | ||
1127 | DBG(4, "Failed to write the FSB registers " | ||
1128 | "(error #%d, %s)", res, symbolic(urb_errlist, res)) | ||
1129 | |||
1130 | return (res >= 0) ? 0 : -1; | ||
1131 | } | ||
1132 | |||
1133 | |||
1134 | /*-------------------------------------------------------------------------- | ||
1135 | Write data to the serial bus control register. | ||
1136 | Return 0 on success, a negative number otherwise. | ||
1137 | --------------------------------------------------------------------------*/ | ||
1138 | static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value) | ||
1139 | { | ||
1140 | int err = 0; | ||
1141 | |||
1142 | err = w9968cf_write_reg(cam, value, 0x01); | ||
1143 | udelay(W9968CF_I2C_BUS_DELAY); | ||
1144 | |||
1145 | return err; | ||
1146 | } | ||
1147 | |||
1148 | |||
1149 | /*-------------------------------------------------------------------------- | ||
1150 | Read data from the serial bus control register. | ||
1151 | Return 0 on success, a negative number otherwise. | ||
1152 | --------------------------------------------------------------------------*/ | ||
1153 | static int w9968cf_read_sb(struct w9968cf_device* cam) | ||
1154 | { | ||
1155 | int v = 0; | ||
1156 | |||
1157 | v = w9968cf_read_reg(cam, 0x01); | ||
1158 | udelay(W9968CF_I2C_BUS_DELAY); | ||
1159 | |||
1160 | return v; | ||
1161 | } | ||
1162 | |||
1163 | |||
1164 | /*-------------------------------------------------------------------------- | ||
1165 | Upload quantization tables for the JPEG compression. | ||
1166 | This function is called by w9968cf_start_transfer(). | ||
1167 | Return 0 on success, a negative number otherwise. | ||
1168 | --------------------------------------------------------------------------*/ | ||
1169 | static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam) | ||
1170 | { | ||
1171 | u16 a, b; | ||
1172 | int err = 0, i, j; | ||
1173 | |||
1174 | err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */ | ||
1175 | |||
1176 | for (i = 0, j = 0; i < 32; i++, j += 2) { | ||
1177 | a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8); | ||
1178 | b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8); | ||
1179 | err += w9968cf_write_reg(cam, a, 0x40+i); | ||
1180 | err += w9968cf_write_reg(cam, b, 0x60+i); | ||
1181 | } | ||
1182 | err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */ | ||
1183 | |||
1184 | return err; | ||
1185 | } | ||
1186 | |||
1187 | |||
1188 | |||
1189 | /**************************************************************************** | ||
1190 | * Low-level I2C I/O functions. * | ||
1191 | * The adapter supports the following I2C transfer functions: * | ||
1192 | * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only) * | ||
1193 | * i2c_adap_read_byte_data() * | ||
1194 | * i2c_adap_read_byte() * | ||
1195 | ****************************************************************************/ | ||
1196 | |||
1197 | static int w9968cf_smbus_start(struct w9968cf_device* cam) | ||
1198 | { | ||
1199 | int err = 0; | ||
1200 | |||
1201 | err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ | ||
1202 | err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ | ||
1203 | |||
1204 | return err; | ||
1205 | } | ||
1206 | |||
1207 | |||
1208 | static int w9968cf_smbus_stop(struct w9968cf_device* cam) | ||
1209 | { | ||
1210 | int err = 0; | ||
1211 | |||
1212 | err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ | ||
1213 | err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */ | ||
1214 | |||
1215 | return err; | ||
1216 | } | ||
1217 | |||
1218 | |||
1219 | static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v) | ||
1220 | { | ||
1221 | u8 bit; | ||
1222 | int err = 0, sda; | ||
1223 | |||
1224 | for (bit = 0 ; bit < 8 ; bit++) { | ||
1225 | sda = (v & 0x80) ? 2 : 0; | ||
1226 | v <<= 1; | ||
1227 | /* SDE=1, SDA=sda, SCL=0 */ | ||
1228 | err += w9968cf_write_sb(cam, 0x10 | sda); | ||
1229 | /* SDE=1, SDA=sda, SCL=1 */ | ||
1230 | err += w9968cf_write_sb(cam, 0x11 | sda); | ||
1231 | /* SDE=1, SDA=sda, SCL=0 */ | ||
1232 | err += w9968cf_write_sb(cam, 0x10 | sda); | ||
1233 | } | ||
1234 | |||
1235 | return err; | ||
1236 | } | ||
1237 | |||
1238 | |||
1239 | static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v) | ||
1240 | { | ||
1241 | u8 bit; | ||
1242 | int err = 0; | ||
1243 | |||
1244 | *v = 0; | ||
1245 | for (bit = 0 ; bit < 8 ; bit++) { | ||
1246 | *v <<= 1; | ||
1247 | err += w9968cf_write_sb(cam, 0x0013); | ||
1248 | *v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0; | ||
1249 | err += w9968cf_write_sb(cam, 0x0012); | ||
1250 | } | ||
1251 | |||
1252 | return err; | ||
1253 | } | ||
1254 | |||
1255 | |||
1256 | static int w9968cf_smbus_write_ack(struct w9968cf_device* cam) | ||
1257 | { | ||
1258 | int err = 0; | ||
1259 | |||
1260 | err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ | ||
1261 | err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ | ||
1262 | err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ | ||
1263 | |||
1264 | return err; | ||
1265 | } | ||
1266 | |||
1267 | |||
1268 | static int w9968cf_smbus_read_ack(struct w9968cf_device* cam) | ||
1269 | { | ||
1270 | int err = 0, sda; | ||
1271 | |||
1272 | err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */ | ||
1273 | sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */ | ||
1274 | err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */ | ||
1275 | if (sda < 0) | ||
1276 | err += sda; | ||
1277 | if (sda == 1) { | ||
1278 | DBG(6, "Couldn't receive the ACK") | ||
1279 | err += -1; | ||
1280 | } | ||
1281 | |||
1282 | return err; | ||
1283 | } | ||
1284 | |||
1285 | |||
1286 | /* This seems to refresh the communication through the serial bus */ | ||
1287 | static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam) | ||
1288 | { | ||
1289 | int err = 0, j; | ||
1290 | |||
1291 | for (j = 1; j <= 10; j++) { | ||
1292 | err = w9968cf_write_reg(cam, 0x0020, 0x01); | ||
1293 | err += w9968cf_write_reg(cam, 0x0000, 0x01); | ||
1294 | if (err) | ||
1295 | break; | ||
1296 | } | ||
1297 | |||
1298 | return err; | ||
1299 | } | ||
1300 | |||
1301 | |||
1302 | /* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */ | ||
1303 | static int | ||
1304 | w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam, | ||
1305 | u16 address, u8 subaddress,u8 value) | ||
1306 | { | ||
1307 | u16* data = cam->data_buffer; | ||
1308 | int err = 0; | ||
1309 | |||
1310 | err += w9968cf_smbus_refresh_bus(cam); | ||
1311 | |||
1312 | /* Enable SBUS outputs */ | ||
1313 | err += w9968cf_write_sb(cam, 0x0020); | ||
1314 | |||
1315 | data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0); | ||
1316 | data[0] |= (address & 0x40) ? 0x4000 : 0x0; | ||
1317 | data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0); | ||
1318 | data[1] |= (address & 0x20) ? 0x0150 : 0x0; | ||
1319 | data[1] |= (address & 0x10) ? 0x5400 : 0x0; | ||
1320 | data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0); | ||
1321 | data[2] |= (address & 0x04) ? 0x0540 : 0x0; | ||
1322 | data[2] |= (address & 0x02) ? 0x5000 : 0x0; | ||
1323 | data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0); | ||
1324 | data[3] |= (address & 0x01) ? 0x0054 : 0x0; | ||
1325 | |||
1326 | err += w9968cf_write_fsb(cam, data); | ||
1327 | |||
1328 | data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0); | ||
1329 | data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0; | ||
1330 | data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0; | ||
1331 | data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0); | ||
1332 | data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0; | ||
1333 | data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0; | ||
1334 | data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0; | ||
1335 | data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0); | ||
1336 | data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0; | ||
1337 | data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0; | ||
1338 | data[3] = 0x001d; | ||
1339 | |||
1340 | err += w9968cf_write_fsb(cam, data); | ||
1341 | |||
1342 | data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0); | ||
1343 | data[0] |= (value & 0x40) ? 0x0540 : 0x0; | ||
1344 | data[0] |= (value & 0x20) ? 0x5000 : 0x0; | ||
1345 | data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0); | ||
1346 | data[1] |= (value & 0x10) ? 0x0054 : 0x0; | ||
1347 | data[1] |= (value & 0x08) ? 0x1500 : 0x0; | ||
1348 | data[1] |= (value & 0x04) ? 0x4000 : 0x0; | ||
1349 | data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0); | ||
1350 | data[2] |= (value & 0x02) ? 0x0150 : 0x0; | ||
1351 | data[2] |= (value & 0x01) ? 0x5400 : 0x0; | ||
1352 | data[3] = 0xfe1d; | ||
1353 | |||
1354 | err += w9968cf_write_fsb(cam, data); | ||
1355 | |||
1356 | /* Disable SBUS outputs */ | ||
1357 | err += w9968cf_write_sb(cam, 0x0000); | ||
1358 | |||
1359 | if (!err) | ||
1360 | DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X " | ||
1361 | "value 0x%02X", address, subaddress, value) | ||
1362 | else | ||
1363 | DBG(5, "I2C write byte data failed, addr.0x%04X, " | ||
1364 | "subaddr.0x%02X, value 0x%02X", | ||
1365 | address, subaddress, value) | ||
1366 | |||
1367 | return err; | ||
1368 | } | ||
1369 | |||
1370 | |||
1371 | /* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */ | ||
1372 | static int | ||
1373 | w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam, | ||
1374 | u16 address, u8 subaddress, | ||
1375 | u8* value) | ||
1376 | { | ||
1377 | int err = 0; | ||
1378 | |||
1379 | /* Serial data enable */ | ||
1380 | err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */ | ||
1381 | |||
1382 | err += w9968cf_smbus_start(cam); | ||
1383 | err += w9968cf_smbus_write_byte(cam, address); | ||
1384 | err += w9968cf_smbus_read_ack(cam); | ||
1385 | err += w9968cf_smbus_write_byte(cam, subaddress); | ||
1386 | err += w9968cf_smbus_read_ack(cam); | ||
1387 | err += w9968cf_smbus_stop(cam); | ||
1388 | err += w9968cf_smbus_start(cam); | ||
1389 | err += w9968cf_smbus_write_byte(cam, address + 1); | ||
1390 | err += w9968cf_smbus_read_ack(cam); | ||
1391 | err += w9968cf_smbus_read_byte(cam, value); | ||
1392 | err += w9968cf_smbus_write_ack(cam); | ||
1393 | err += w9968cf_smbus_stop(cam); | ||
1394 | |||
1395 | /* Serial data disable */ | ||
1396 | err += w9968cf_write_sb(cam, 0x0000); | ||
1397 | |||
1398 | if (!err) | ||
1399 | DBG(5, "I2C read byte data done, addr.0x%04X, " | ||
1400 | "subaddr.0x%02X, value 0x%02X", | ||
1401 | address, subaddress, *value) | ||
1402 | else | ||
1403 | DBG(5, "I2C read byte data failed, addr.0x%04X, " | ||
1404 | "subaddr.0x%02X, wrong value 0x%02X", | ||
1405 | address, subaddress, *value) | ||
1406 | |||
1407 | return err; | ||
1408 | } | ||
1409 | |||
1410 | |||
1411 | /* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */ | ||
1412 | static int | ||
1413 | w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam, | ||
1414 | u16 address, u8* value) | ||
1415 | { | ||
1416 | int err = 0; | ||
1417 | |||
1418 | /* Serial data enable */ | ||
1419 | err += w9968cf_write_sb(cam, 0x0013); | ||
1420 | |||
1421 | err += w9968cf_smbus_start(cam); | ||
1422 | err += w9968cf_smbus_write_byte(cam, address + 1); | ||
1423 | err += w9968cf_smbus_read_ack(cam); | ||
1424 | err += w9968cf_smbus_read_byte(cam, value); | ||
1425 | err += w9968cf_smbus_write_ack(cam); | ||
1426 | err += w9968cf_smbus_stop(cam); | ||
1427 | |||
1428 | /* Serial data disable */ | ||
1429 | err += w9968cf_write_sb(cam, 0x0000); | ||
1430 | |||
1431 | if (!err) | ||
1432 | DBG(5, "I2C read byte done, addr.0x%04X, " | ||
1433 | "value 0x%02X", address, *value) | ||
1434 | else | ||
1435 | DBG(5, "I2C read byte failed, addr.0x%04X, " | ||
1436 | "wrong value 0x%02X", address, *value) | ||
1437 | |||
1438 | return err; | ||
1439 | } | ||
1440 | |||
1441 | |||
1442 | /* SMBus protocol: S Addr Wr [A] Value [A] P */ | ||
1443 | static int | ||
1444 | w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam, | ||
1445 | u16 address, u8 value) | ||
1446 | { | ||
1447 | DBG(4, "i2c_write_byte() is an unsupported transfer mode") | ||
1448 | return -EINVAL; | ||
1449 | } | ||
1450 | |||
1451 | |||
1452 | |||
1453 | /**************************************************************************** | ||
1454 | * I2C interface to kernel * | ||
1455 | ****************************************************************************/ | ||
1456 | |||
1457 | static int | ||
1458 | w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, | ||
1459 | unsigned short flags, char read_write, u8 command, | ||
1460 | int size, union i2c_smbus_data *data) | ||
1461 | { | ||
1462 | struct w9968cf_device* cam = i2c_get_adapdata(adapter); | ||
1463 | u8 i; | ||
1464 | int err = 0; | ||
1465 | |||
1466 | switch (addr) { | ||
1467 | case OV6xx0_SID: | ||
1468 | case OV7xx0_SID: | ||
1469 | break; | ||
1470 | default: | ||
1471 | DBG(4, "Rejected slave ID 0x%04X", addr) | ||
1472 | return -EINVAL; | ||
1473 | } | ||
1474 | |||
1475 | if (size == I2C_SMBUS_BYTE) { | ||
1476 | /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */ | ||
1477 | addr <<= 1; | ||
1478 | |||
1479 | if (read_write == I2C_SMBUS_WRITE) | ||
1480 | err = w9968cf_i2c_adap_write_byte(cam, addr, command); | ||
1481 | else if (read_write == I2C_SMBUS_READ) | ||
1482 | err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte); | ||
1483 | |||
1484 | } else if (size == I2C_SMBUS_BYTE_DATA) { | ||
1485 | addr <<= 1; | ||
1486 | |||
1487 | if (read_write == I2C_SMBUS_WRITE) | ||
1488 | err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr, | ||
1489 | command, data->byte); | ||
1490 | else if (read_write == I2C_SMBUS_READ) { | ||
1491 | for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) { | ||
1492 | err = w9968cf_i2c_adap_read_byte_data(cam,addr, | ||
1493 | command, &data->byte); | ||
1494 | if (err) { | ||
1495 | if (w9968cf_smbus_refresh_bus(cam)) { | ||
1496 | err = -EIO; | ||
1497 | break; | ||
1498 | } | ||
1499 | } else | ||
1500 | break; | ||
1501 | } | ||
1502 | |||
1503 | } else | ||
1504 | return -EINVAL; | ||
1505 | |||
1506 | } else { | ||
1507 | DBG(4, "Unsupported I2C transfer mode (%d)", size) | ||
1508 | return -EINVAL; | ||
1509 | } | ||
1510 | |||
1511 | return err; | ||
1512 | } | ||
1513 | |||
1514 | |||
1515 | static u32 w9968cf_i2c_func(struct i2c_adapter* adap) | ||
1516 | { | ||
1517 | return I2C_FUNC_SMBUS_READ_BYTE | | ||
1518 | I2C_FUNC_SMBUS_READ_BYTE_DATA | | ||
1519 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA; | ||
1520 | } | ||
1521 | |||
1522 | |||
1523 | static int w9968cf_i2c_attach_inform(struct i2c_client* client) | ||
1524 | { | ||
1525 | struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); | ||
1526 | const char* clientname = i2c_clientname(client); | ||
1527 | int id = client->driver->id, err = 0; | ||
1528 | |||
1529 | if (id == I2C_DRIVERID_OVCAMCHIP) { | ||
1530 | cam->sensor_client = client; | ||
1531 | err = w9968cf_sensor_init(cam); | ||
1532 | if (err) { | ||
1533 | cam->sensor_client = NULL; | ||
1534 | return err; | ||
1535 | } | ||
1536 | } else { | ||
1537 | DBG(4, "Rejected client [%s] with driver [%s]", | ||
1538 | clientname, client->driver->name) | ||
1539 | return -EINVAL; | ||
1540 | } | ||
1541 | |||
1542 | DBG(5, "I2C attach client [%s] with driver [%s]", | ||
1543 | clientname, client->driver->name) | ||
1544 | |||
1545 | return 0; | ||
1546 | } | ||
1547 | |||
1548 | |||
1549 | static int w9968cf_i2c_detach_inform(struct i2c_client* client) | ||
1550 | { | ||
1551 | struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); | ||
1552 | const char* clientname = i2c_clientname(client); | ||
1553 | |||
1554 | if (cam->sensor_client == client) | ||
1555 | cam->sensor_client = NULL; | ||
1556 | |||
1557 | DBG(5, "I2C detach client [%s]", clientname) | ||
1558 | |||
1559 | return 0; | ||
1560 | } | ||
1561 | |||
1562 | |||
1563 | static int | ||
1564 | w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd, | ||
1565 | unsigned long arg) | ||
1566 | { | ||
1567 | return 0; | ||
1568 | } | ||
1569 | |||
1570 | |||
1571 | static int w9968cf_i2c_init(struct w9968cf_device* cam) | ||
1572 | { | ||
1573 | int err = 0; | ||
1574 | |||
1575 | static struct i2c_algorithm algo = { | ||
1576 | .name = "W996[87]CF algorithm", | ||
1577 | .id = I2C_ALGO_SMBUS, | ||
1578 | .smbus_xfer = w9968cf_i2c_smbus_xfer, | ||
1579 | .algo_control = w9968cf_i2c_control, | ||
1580 | .functionality = w9968cf_i2c_func, | ||
1581 | }; | ||
1582 | |||
1583 | static struct i2c_adapter adap = { | ||
1584 | .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_W9968CF, | ||
1585 | .class = I2C_CLASS_CAM_DIGITAL, | ||
1586 | .owner = THIS_MODULE, | ||
1587 | .client_register = w9968cf_i2c_attach_inform, | ||
1588 | .client_unregister = w9968cf_i2c_detach_inform, | ||
1589 | .algo = &algo, | ||
1590 | }; | ||
1591 | |||
1592 | memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter)); | ||
1593 | strcpy(cam->i2c_adapter.name, "w9968cf"); | ||
1594 | i2c_set_adapdata(&cam->i2c_adapter, cam); | ||
1595 | |||
1596 | DBG(6, "Registering I2C adapter with kernel...") | ||
1597 | |||
1598 | err = i2c_add_adapter(&cam->i2c_adapter); | ||
1599 | if (err) | ||
1600 | DBG(1, "Failed to register the I2C adapter") | ||
1601 | else | ||
1602 | DBG(5, "I2C adapter registered") | ||
1603 | |||
1604 | return err; | ||
1605 | } | ||
1606 | |||
1607 | |||
1608 | |||
1609 | /**************************************************************************** | ||
1610 | * Helper functions * | ||
1611 | ****************************************************************************/ | ||
1612 | |||
1613 | /*-------------------------------------------------------------------------- | ||
1614 | Turn on the LED on some webcams. A beep should be heard too. | ||
1615 | Return 0 on success, a negative number otherwise. | ||
1616 | --------------------------------------------------------------------------*/ | ||
1617 | static int w9968cf_turn_on_led(struct w9968cf_device* cam) | ||
1618 | { | ||
1619 | int err = 0; | ||
1620 | |||
1621 | err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */ | ||
1622 | err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ | ||
1623 | err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ | ||
1624 | err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */ | ||
1625 | err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */ | ||
1626 | err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */ | ||
1627 | |||
1628 | if (err) | ||
1629 | DBG(2, "Couldn't turn on the LED") | ||
1630 | |||
1631 | DBG(5, "LED turned on") | ||
1632 | |||
1633 | return err; | ||
1634 | } | ||
1635 | |||
1636 | |||
1637 | /*-------------------------------------------------------------------------- | ||
1638 | Write some registers for the device initialization. | ||
1639 | This function is called once on open(). | ||
1640 | Return 0 on success, a negative number otherwise. | ||
1641 | --------------------------------------------------------------------------*/ | ||
1642 | static int w9968cf_init_chip(struct w9968cf_device* cam) | ||
1643 | { | ||
1644 | unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2, | ||
1645 | y0 = 0x0000, | ||
1646 | u0 = y0 + hw_bufsize/2, | ||
1647 | v0 = u0 + hw_bufsize/4, | ||
1648 | y1 = v0 + hw_bufsize/4, | ||
1649 | u1 = y1 + hw_bufsize/2, | ||
1650 | v1 = u1 + hw_bufsize/4; | ||
1651 | int err = 0; | ||
1652 | |||
1653 | err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */ | ||
1654 | err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */ | ||
1655 | |||
1656 | err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */ | ||
1657 | err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */ | ||
1658 | |||
1659 | err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */ | ||
1660 | err += w9968cf_write_reg(cam, y0 >> 16, 0x21); /* Y buf.0, high */ | ||
1661 | err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */ | ||
1662 | err += w9968cf_write_reg(cam, u0 >> 16, 0x25); /* U buf.0, high */ | ||
1663 | err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */ | ||
1664 | err += w9968cf_write_reg(cam, v0 >> 16, 0x29); /* V buf.0, high */ | ||
1665 | |||
1666 | err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */ | ||
1667 | err += w9968cf_write_reg(cam, y1 >> 16, 0x23); /* Y buf.1, high */ | ||
1668 | err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */ | ||
1669 | err += w9968cf_write_reg(cam, u1 >> 16, 0x27); /* U buf.1, high */ | ||
1670 | err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */ | ||
1671 | err += w9968cf_write_reg(cam, v1 >> 16, 0x2b); /* V buf.1, high */ | ||
1672 | |||
1673 | err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */ | ||
1674 | err += w9968cf_write_reg(cam, y1 >> 16, 0x33); /* JPEG buf 0 high */ | ||
1675 | |||
1676 | err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */ | ||
1677 | err += w9968cf_write_reg(cam, y1 >> 16, 0x35); /* JPEG bug 1 high */ | ||
1678 | |||
1679 | err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */ | ||
1680 | err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/ | ||
1681 | err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */ | ||
1682 | err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */ | ||
1683 | |||
1684 | err += w9968cf_set_picture(cam, cam->picture); /* this before */ | ||
1685 | err += w9968cf_set_window(cam, cam->window); | ||
1686 | |||
1687 | if (err) | ||
1688 | DBG(1, "Chip initialization failed") | ||
1689 | else | ||
1690 | DBG(5, "Chip successfully initialized") | ||
1691 | |||
1692 | return err; | ||
1693 | } | ||
1694 | |||
1695 | |||
1696 | /*-------------------------------------------------------------------------- | ||
1697 | Return non-zero if the palette is supported, 0 otherwise. | ||
1698 | --------------------------------------------------------------------------*/ | ||
1699 | static inline u16 w9968cf_valid_palette(u16 palette) | ||
1700 | { | ||
1701 | u8 i = 0; | ||
1702 | while (w9968cf_formatlist[i].palette != 0) { | ||
1703 | if (palette == w9968cf_formatlist[i].palette) | ||
1704 | return palette; | ||
1705 | i++; | ||
1706 | } | ||
1707 | return 0; | ||
1708 | } | ||
1709 | |||
1710 | |||
1711 | /*-------------------------------------------------------------------------- | ||
1712 | Return the depth corresponding to the given palette. | ||
1713 | Palette _must_ be supported ! | ||
1714 | --------------------------------------------------------------------------*/ | ||
1715 | static inline u16 w9968cf_valid_depth(u16 palette) | ||
1716 | { | ||
1717 | u8 i=0; | ||
1718 | while (w9968cf_formatlist[i].palette != palette) | ||
1719 | i++; | ||
1720 | |||
1721 | return w9968cf_formatlist[i].depth; | ||
1722 | } | ||
1723 | |||
1724 | |||
1725 | /*-------------------------------------------------------------------------- | ||
1726 | Return non-zero if the format requires decompression, 0 otherwise. | ||
1727 | --------------------------------------------------------------------------*/ | ||
1728 | static inline u8 w9968cf_need_decompression(u16 palette) | ||
1729 | { | ||
1730 | u8 i = 0; | ||
1731 | while (w9968cf_formatlist[i].palette != 0) { | ||
1732 | if (palette == w9968cf_formatlist[i].palette) | ||
1733 | return w9968cf_formatlist[i].compression; | ||
1734 | i++; | ||
1735 | } | ||
1736 | return 0; | ||
1737 | } | ||
1738 | |||
1739 | |||
1740 | /*-------------------------------------------------------------------------- | ||
1741 | Change the picture settings of the camera. | ||
1742 | Return 0 on success, a negative number otherwise. | ||
1743 | --------------------------------------------------------------------------*/ | ||
1744 | static int | ||
1745 | w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict) | ||
1746 | { | ||
1747 | u16 fmt, hw_depth, hw_palette, reg_v = 0x0000; | ||
1748 | int err = 0; | ||
1749 | |||
1750 | /* Make sure we are using a valid depth */ | ||
1751 | pict.depth = w9968cf_valid_depth(pict.palette); | ||
1752 | |||
1753 | fmt = pict.palette; | ||
1754 | |||
1755 | hw_depth = pict.depth; /* depth used by the winbond chip */ | ||
1756 | hw_palette = pict.palette; /* palette used by the winbond chip */ | ||
1757 | |||
1758 | /* VS & HS polarities */ | ||
1759 | reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11); | ||
1760 | |||
1761 | switch (fmt) | ||
1762 | { | ||
1763 | case VIDEO_PALETTE_UYVY: | ||
1764 | reg_v |= 0x0000; | ||
1765 | cam->vpp_flag = VPP_NONE; | ||
1766 | break; | ||
1767 | case VIDEO_PALETTE_YUV422P: | ||
1768 | reg_v |= 0x0002; | ||
1769 | cam->vpp_flag = VPP_DECOMPRESSION; | ||
1770 | break; | ||
1771 | case VIDEO_PALETTE_YUV420: | ||
1772 | case VIDEO_PALETTE_YUV420P: | ||
1773 | reg_v |= 0x0003; | ||
1774 | cam->vpp_flag = VPP_DECOMPRESSION; | ||
1775 | break; | ||
1776 | case VIDEO_PALETTE_YUYV: | ||
1777 | case VIDEO_PALETTE_YUV422: | ||
1778 | reg_v |= 0x0000; | ||
1779 | cam->vpp_flag = VPP_SWAP_YUV_BYTES; | ||
1780 | hw_palette = VIDEO_PALETTE_UYVY; | ||
1781 | break; | ||
1782 | /* Original video is used instead of RGBX palettes. | ||
1783 | Software conversion later. */ | ||
1784 | case VIDEO_PALETTE_GREY: | ||
1785 | case VIDEO_PALETTE_RGB555: | ||
1786 | case VIDEO_PALETTE_RGB565: | ||
1787 | case VIDEO_PALETTE_RGB24: | ||
1788 | case VIDEO_PALETTE_RGB32: | ||
1789 | reg_v |= 0x0000; /* UYVY 16 bit is used */ | ||
1790 | hw_depth = 16; | ||
1791 | hw_palette = VIDEO_PALETTE_UYVY; | ||
1792 | cam->vpp_flag = VPP_UYVY_TO_RGBX; | ||
1793 | break; | ||
1794 | } | ||
1795 | |||
1796 | /* NOTE: due to memory issues, it is better to disable the hardware | ||
1797 | double buffering during compression */ | ||
1798 | if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION)) | ||
1799 | reg_v |= 0x0080; | ||
1800 | |||
1801 | if (cam->clamping) | ||
1802 | reg_v |= 0x0020; | ||
1803 | |||
1804 | if (cam->filter_type == 1) | ||
1805 | reg_v |= 0x0008; | ||
1806 | else if (cam->filter_type == 2) | ||
1807 | reg_v |= 0x000c; | ||
1808 | |||
1809 | if ((err = w9968cf_write_reg(cam, reg_v, 0x16))) | ||
1810 | goto error; | ||
1811 | |||
1812 | if ((err = w9968cf_sensor_update_picture(cam, pict))) | ||
1813 | goto error; | ||
1814 | |||
1815 | /* If all went well, update the device data structure */ | ||
1816 | memcpy(&cam->picture, &pict, sizeof(pict)); | ||
1817 | cam->hw_depth = hw_depth; | ||
1818 | cam->hw_palette = hw_palette; | ||
1819 | |||
1820 | /* Settings changed, so we clear the frame buffers */ | ||
1821 | memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); | ||
1822 | |||
1823 | DBG(4, "Palette is %s, depth is %u bpp", | ||
1824 | symbolic(v4l1_plist, pict.palette), pict.depth) | ||
1825 | |||
1826 | return 0; | ||
1827 | |||
1828 | error: | ||
1829 | DBG(1, "Failed to change picture settings") | ||
1830 | return err; | ||
1831 | } | ||
1832 | |||
1833 | |||
1834 | /*-------------------------------------------------------------------------- | ||
1835 | Change the capture area size of the camera. | ||
1836 | This function _must_ be called _after_ w9968cf_set_picture(). | ||
1837 | Return 0 on success, a negative number otherwise. | ||
1838 | --------------------------------------------------------------------------*/ | ||
1839 | static int | ||
1840 | w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) | ||
1841 | { | ||
1842 | u16 x, y, w, h, scx, scy, cw, ch, ax, ay; | ||
1843 | unsigned long fw, fh; | ||
1844 | struct ovcamchip_window s_win; | ||
1845 | int err = 0; | ||
1846 | |||
1847 | /* Work around to avoid FP arithmetics */ | ||
1848 | #define __SC(x) ((x) << 10) | ||
1849 | #define __UNSC(x) ((x) >> 10) | ||
1850 | |||
1851 | /* Make sure we are using a supported resolution */ | ||
1852 | if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, | ||
1853 | (u16*)&win.height))) | ||
1854 | goto error; | ||
1855 | |||
1856 | /* Scaling factors */ | ||
1857 | fw = __SC(win.width) / cam->maxwidth; | ||
1858 | fh = __SC(win.height) / cam->maxheight; | ||
1859 | |||
1860 | /* Set up the width and height values used by the chip */ | ||
1861 | if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) { | ||
1862 | cam->vpp_flag |= VPP_UPSCALE; | ||
1863 | /* Calculate largest w,h mantaining the same w/h ratio */ | ||
1864 | w = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh; | ||
1865 | h = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight; | ||
1866 | if (w < cam->minwidth) /* just in case */ | ||
1867 | w = cam->minwidth; | ||
1868 | if (h < cam->minheight) /* just in case */ | ||
1869 | h = cam->minheight; | ||
1870 | } else { | ||
1871 | cam->vpp_flag &= ~VPP_UPSCALE; | ||
1872 | w = win.width; | ||
1873 | h = win.height; | ||
1874 | } | ||
1875 | |||
1876 | /* x,y offsets of the cropped area */ | ||
1877 | scx = cam->start_cropx; | ||
1878 | scy = cam->start_cropy; | ||
1879 | |||
1880 | /* Calculate cropped area manteining the right w/h ratio */ | ||
1881 | if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) { | ||
1882 | cw = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh; | ||
1883 | ch = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight; | ||
1884 | } else { | ||
1885 | cw = w; | ||
1886 | ch = h; | ||
1887 | } | ||
1888 | |||
1889 | /* Setup the window of the sensor */ | ||
1890 | s_win.format = VIDEO_PALETTE_UYVY; | ||
1891 | s_win.width = cam->maxwidth; | ||
1892 | s_win.height = cam->maxheight; | ||
1893 | s_win.quarter = 0; /* full progressive video */ | ||
1894 | |||
1895 | /* Center it */ | ||
1896 | s_win.x = (s_win.width - cw) / 2; | ||
1897 | s_win.y = (s_win.height - ch) / 2; | ||
1898 | |||
1899 | /* Clock divisor */ | ||
1900 | if (cam->clockdiv >= 0) | ||
1901 | s_win.clockdiv = cam->clockdiv; /* manual override */ | ||
1902 | else | ||
1903 | switch (cam->sensor) { | ||
1904 | case CC_OV6620: | ||
1905 | s_win.clockdiv = 0; | ||
1906 | break; | ||
1907 | case CC_OV6630: | ||
1908 | s_win.clockdiv = 0; | ||
1909 | break; | ||
1910 | case CC_OV76BE: | ||
1911 | case CC_OV7610: | ||
1912 | case CC_OV7620: | ||
1913 | s_win.clockdiv = 0; | ||
1914 | break; | ||
1915 | default: | ||
1916 | s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR; | ||
1917 | } | ||
1918 | |||
1919 | /* We have to scale win.x and win.y offsets */ | ||
1920 | if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) | ||
1921 | || (cam->vpp_flag & VPP_UPSCALE) ) { | ||
1922 | ax = __SC(win.x)/fw; | ||
1923 | ay = __SC(win.y)/fh; | ||
1924 | } else { | ||
1925 | ax = win.x; | ||
1926 | ay = win.y; | ||
1927 | } | ||
1928 | |||
1929 | if ((ax + cw) > cam->maxwidth) | ||
1930 | ax = cam->maxwidth - cw; | ||
1931 | |||
1932 | if ((ay + ch) > cam->maxheight) | ||
1933 | ay = cam->maxheight - ch; | ||
1934 | |||
1935 | /* Adjust win.x, win.y */ | ||
1936 | if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) | ||
1937 | || (cam->vpp_flag & VPP_UPSCALE) ) { | ||
1938 | win.x = __UNSC(ax*fw); | ||
1939 | win.y = __UNSC(ay*fh); | ||
1940 | } else { | ||
1941 | win.x = ax; | ||
1942 | win.y = ay; | ||
1943 | } | ||
1944 | |||
1945 | /* Offsets used by the chip */ | ||
1946 | x = ax + s_win.x; | ||
1947 | y = ay + s_win.y; | ||
1948 | |||
1949 | /* Go ! */ | ||
1950 | if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win))) | ||
1951 | goto error; | ||
1952 | |||
1953 | err += w9968cf_write_reg(cam, scx + x, 0x10); | ||
1954 | err += w9968cf_write_reg(cam, scy + y, 0x11); | ||
1955 | err += w9968cf_write_reg(cam, scx + x + cw, 0x12); | ||
1956 | err += w9968cf_write_reg(cam, scy + y + ch, 0x13); | ||
1957 | err += w9968cf_write_reg(cam, w, 0x14); | ||
1958 | err += w9968cf_write_reg(cam, h, 0x15); | ||
1959 | |||
1960 | /* JPEG width & height */ | ||
1961 | err += w9968cf_write_reg(cam, w, 0x30); | ||
1962 | err += w9968cf_write_reg(cam, h, 0x31); | ||
1963 | |||
1964 | /* Y & UV frame buffer strides (in WORD) */ | ||
1965 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | ||
1966 | err += w9968cf_write_reg(cam, w/2, 0x2c); | ||
1967 | err += w9968cf_write_reg(cam, w/4, 0x2d); | ||
1968 | } else | ||
1969 | err += w9968cf_write_reg(cam, w, 0x2c); | ||
1970 | |||
1971 | if (err) | ||
1972 | goto error; | ||
1973 | |||
1974 | /* If all went well, update the device data structure */ | ||
1975 | memcpy(&cam->window, &win, sizeof(win)); | ||
1976 | cam->hw_width = w; | ||
1977 | cam->hw_height = h; | ||
1978 | |||
1979 | /* Settings changed, so we clear the frame buffers */ | ||
1980 | memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); | ||
1981 | |||
1982 | DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)", | ||
1983 | win.width, win.height, win.x, win.y) | ||
1984 | |||
1985 | PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, " | ||
1986 | "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u", | ||
1987 | x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y, | ||
1988 | win.width, win.height) | ||
1989 | |||
1990 | return 0; | ||
1991 | |||
1992 | error: | ||
1993 | DBG(1, "Failed to change the capture area size") | ||
1994 | return err; | ||
1995 | } | ||
1996 | |||
1997 | |||
1998 | /*-------------------------------------------------------------------------- | ||
1999 | Adjust the asked values for window width and height. | ||
2000 | Return 0 on success, -1 otherwise. | ||
2001 | --------------------------------------------------------------------------*/ | ||
2002 | static int | ||
2003 | w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height) | ||
2004 | { | ||
2005 | u16 maxw, maxh; | ||
2006 | |||
2007 | if ((*width < cam->minwidth) || (*height < cam->minheight)) | ||
2008 | return -ERANGE; | ||
2009 | |||
2010 | maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && | ||
2011 | w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) | ||
2012 | : cam->maxwidth; | ||
2013 | maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && | ||
2014 | w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight) | ||
2015 | : cam->maxheight; | ||
2016 | |||
2017 | if (*width > maxw) | ||
2018 | *width = maxw; | ||
2019 | if (*height > maxh) | ||
2020 | *height = maxh; | ||
2021 | |||
2022 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | ||
2023 | *width &= ~15L; /* multiple of 16 */ | ||
2024 | *height &= ~15L; | ||
2025 | } | ||
2026 | |||
2027 | PDBGG("Window size adjusted w=%u, h=%u ", *width, *height) | ||
2028 | |||
2029 | return 0; | ||
2030 | } | ||
2031 | |||
2032 | |||
2033 | /*-------------------------------------------------------------------------- | ||
2034 | Initialize the FIFO list of requested frames. | ||
2035 | --------------------------------------------------------------------------*/ | ||
2036 | static void w9968cf_init_framelist(struct w9968cf_device* cam) | ||
2037 | { | ||
2038 | u8 i; | ||
2039 | |||
2040 | for (i = 0; i < cam->nbuffers; i++) { | ||
2041 | cam->requested_frame[i] = NULL; | ||
2042 | cam->frame[i].queued = 0; | ||
2043 | cam->frame[i].status = F_UNUSED; | ||
2044 | } | ||
2045 | } | ||
2046 | |||
2047 | |||
2048 | /*-------------------------------------------------------------------------- | ||
2049 | Add a frame in the FIFO list of requested frames. | ||
2050 | This function is called in process context. | ||
2051 | --------------------------------------------------------------------------*/ | ||
2052 | static void w9968cf_push_frame(struct w9968cf_device* cam, u8 f_num) | ||
2053 | { | ||
2054 | u8 f; | ||
2055 | unsigned long lock_flags; | ||
2056 | |||
2057 | spin_lock_irqsave(&cam->flist_lock, lock_flags); | ||
2058 | |||
2059 | for (f=0; cam->requested_frame[f] != NULL; f++); | ||
2060 | cam->requested_frame[f] = &cam->frame[f_num]; | ||
2061 | cam->frame[f_num].queued = 1; | ||
2062 | cam->frame[f_num].status = F_UNUSED; /* clear the status */ | ||
2063 | |||
2064 | spin_unlock_irqrestore(&cam->flist_lock, lock_flags); | ||
2065 | |||
2066 | DBG(6, "Frame #%u pushed into the FIFO list. Position %u", f_num, f) | ||
2067 | } | ||
2068 | |||
2069 | |||
2070 | /*-------------------------------------------------------------------------- | ||
2071 | Read, store and remove the first pointer in the FIFO list of requested | ||
2072 | frames. This function is called in interrupt context. | ||
2073 | --------------------------------------------------------------------------*/ | ||
2074 | static void | ||
2075 | w9968cf_pop_frame(struct w9968cf_device* cam, struct w9968cf_frame_t** framep) | ||
2076 | { | ||
2077 | u8 i; | ||
2078 | |||
2079 | spin_lock(&cam->flist_lock); | ||
2080 | |||
2081 | *framep = cam->requested_frame[0]; | ||
2082 | |||
2083 | /* Shift the list of pointers */ | ||
2084 | for (i = 0; i < cam->nbuffers-1; i++) | ||
2085 | cam->requested_frame[i] = cam->requested_frame[i+1]; | ||
2086 | cam->requested_frame[i] = NULL; | ||
2087 | |||
2088 | spin_unlock(&cam->flist_lock); | ||
2089 | |||
2090 | DBG(6,"Popped frame #%d from the list", (*framep)->number) | ||
2091 | } | ||
2092 | |||
2093 | |||
2094 | /*-------------------------------------------------------------------------- | ||
2095 | High-level video post-processing routine on grabbed frames. | ||
2096 | Return 0 on success, a negative number otherwise. | ||
2097 | --------------------------------------------------------------------------*/ | ||
2098 | static int | ||
2099 | w9968cf_postprocess_frame(struct w9968cf_device* cam, | ||
2100 | struct w9968cf_frame_t* fr) | ||
2101 | { | ||
2102 | void *pIn = fr->buffer, *pOut = cam->frame_vpp.buffer, *tmp; | ||
2103 | u16 w = cam->window.width, | ||
2104 | h = cam->window.height, | ||
2105 | d = cam->picture.depth, | ||
2106 | fmt = cam->picture.palette, | ||
2107 | rgb = cam->force_rgb, | ||
2108 | hw_w = cam->hw_width, | ||
2109 | hw_h = cam->hw_height, | ||
2110 | hw_d = cam->hw_depth; | ||
2111 | int err = 0; | ||
2112 | |||
2113 | #define _PSWAP(pIn, pOut) {tmp = (pIn); (pIn) = (pOut); (pOut) = tmp;} | ||
2114 | |||
2115 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | ||
2116 | memcpy(pOut, pIn, fr->length); | ||
2117 | _PSWAP(pIn, pOut) | ||
2118 | err = w9968cf_vpp->decode(pIn, fr->length, hw_w, hw_h, pOut); | ||
2119 | PDBGG("Compressed frame length: %lu",(unsigned long)fr->length) | ||
2120 | fr->length = (hw_w*hw_h*hw_d)/8; | ||
2121 | _PSWAP(pIn, pOut) | ||
2122 | if (err) { | ||
2123 | DBG(4, "An error occurred while decoding the frame: " | ||
2124 | "%s", symbolic(decoder_errlist, err)) | ||
2125 | return err; | ||
2126 | } else | ||
2127 | DBG(6, "Frame decoded") | ||
2128 | } | ||
2129 | |||
2130 | if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) { | ||
2131 | w9968cf_vpp->swap_yuvbytes(pIn, fr->length); | ||
2132 | DBG(6, "Original UYVY component ordering changed") | ||
2133 | } | ||
2134 | |||
2135 | if (cam->vpp_flag & VPP_UPSCALE) { | ||
2136 | w9968cf_vpp->scale_up(pIn, pOut, hw_w, hw_h, hw_d, w, h); | ||
2137 | fr->length = (w*h*hw_d)/8; | ||
2138 | _PSWAP(pIn, pOut) | ||
2139 | DBG(6, "Vertical up-scaling done: %u,%u,%ubpp->%u,%u", | ||
2140 | hw_w, hw_h, hw_d, w, h) | ||
2141 | } | ||
2142 | |||
2143 | if (cam->vpp_flag & VPP_UYVY_TO_RGBX) { | ||
2144 | w9968cf_vpp->uyvy_to_rgbx(pIn, fr->length, pOut, fmt, rgb); | ||
2145 | fr->length = (w*h*d)/8; | ||
2146 | _PSWAP(pIn, pOut) | ||
2147 | DBG(6, "UYVY-16bit to %s conversion done", | ||
2148 | symbolic(v4l1_plist, fmt)) | ||
2149 | } | ||
2150 | |||
2151 | if (pOut == fr->buffer) | ||
2152 | memcpy(fr->buffer, cam->frame_vpp.buffer, fr->length); | ||
2153 | |||
2154 | return 0; | ||
2155 | } | ||
2156 | |||
2157 | |||
2158 | |||
2159 | /**************************************************************************** | ||
2160 | * Image sensor control routines * | ||
2161 | ****************************************************************************/ | ||
2162 | |||
2163 | static int | ||
2164 | w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val) | ||
2165 | { | ||
2166 | struct ovcamchip_control ctl; | ||
2167 | int err; | ||
2168 | |||
2169 | ctl.id = cid; | ||
2170 | ctl.value = val; | ||
2171 | |||
2172 | err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl); | ||
2173 | |||
2174 | return err; | ||
2175 | } | ||
2176 | |||
2177 | |||
2178 | static int | ||
2179 | w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val) | ||
2180 | { | ||
2181 | struct ovcamchip_control ctl; | ||
2182 | int err; | ||
2183 | |||
2184 | ctl.id = cid; | ||
2185 | |||
2186 | err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl); | ||
2187 | if (!err) | ||
2188 | *val = ctl.value; | ||
2189 | |||
2190 | return err; | ||
2191 | } | ||
2192 | |||
2193 | |||
2194 | static int | ||
2195 | w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg) | ||
2196 | { | ||
2197 | struct i2c_client* c = cam->sensor_client; | ||
2198 | int rc = 0; | ||
2199 | |||
2200 | if (!c || !c->driver || !c->driver->command) | ||
2201 | return -EINVAL; | ||
2202 | |||
2203 | rc = c->driver->command(c, cmd, arg); | ||
2204 | /* The I2C driver returns -EPERM on non-supported controls */ | ||
2205 | return (rc < 0 && rc != -EPERM) ? rc : 0; | ||
2206 | } | ||
2207 | |||
2208 | |||
2209 | /*-------------------------------------------------------------------------- | ||
2210 | Update some settings of the image sensor. | ||
2211 | Returns: 0 on success, a negative number otherwise. | ||
2212 | --------------------------------------------------------------------------*/ | ||
2213 | static int w9968cf_sensor_update_settings(struct w9968cf_device* cam) | ||
2214 | { | ||
2215 | int err = 0; | ||
2216 | |||
2217 | /* Auto brightness */ | ||
2218 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT, | ||
2219 | cam->auto_brt); | ||
2220 | if (err) | ||
2221 | return err; | ||
2222 | |||
2223 | /* Auto exposure */ | ||
2224 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP, | ||
2225 | cam->auto_exp); | ||
2226 | if (err) | ||
2227 | return err; | ||
2228 | |||
2229 | /* Banding filter */ | ||
2230 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT, | ||
2231 | cam->bandfilt); | ||
2232 | if (err) | ||
2233 | return err; | ||
2234 | |||
2235 | /* Light frequency */ | ||
2236 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ, | ||
2237 | cam->lightfreq); | ||
2238 | if (err) | ||
2239 | return err; | ||
2240 | |||
2241 | /* Back light */ | ||
2242 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT, | ||
2243 | cam->backlight); | ||
2244 | if (err) | ||
2245 | return err; | ||
2246 | |||
2247 | /* Mirror */ | ||
2248 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR, | ||
2249 | cam->mirror); | ||
2250 | if (err) | ||
2251 | return err; | ||
2252 | |||
2253 | return 0; | ||
2254 | } | ||
2255 | |||
2256 | |||
2257 | /*-------------------------------------------------------------------------- | ||
2258 | Get some current picture settings from the image sensor and update the | ||
2259 | internal 'picture' structure of the camera. | ||
2260 | Returns: 0 on success, a negative number otherwise. | ||
2261 | --------------------------------------------------------------------------*/ | ||
2262 | static int w9968cf_sensor_get_picture(struct w9968cf_device* cam) | ||
2263 | { | ||
2264 | int err, v; | ||
2265 | |||
2266 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v); | ||
2267 | if (err) | ||
2268 | return err; | ||
2269 | cam->picture.contrast = v; | ||
2270 | |||
2271 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v); | ||
2272 | if (err) | ||
2273 | return err; | ||
2274 | cam->picture.brightness = v; | ||
2275 | |||
2276 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v); | ||
2277 | if (err) | ||
2278 | return err; | ||
2279 | cam->picture.colour = v; | ||
2280 | |||
2281 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v); | ||
2282 | if (err) | ||
2283 | return err; | ||
2284 | cam->picture.hue = v; | ||
2285 | |||
2286 | DBG(5, "Got picture settings from the image sensor") | ||
2287 | |||
2288 | PDBGG("Brightness, contrast, hue, colour, whiteness are " | ||
2289 | "%u,%u,%u,%u,%u", cam->picture.brightness,cam->picture.contrast, | ||
2290 | cam->picture.hue, cam->picture.colour, cam->picture.whiteness) | ||
2291 | |||
2292 | return 0; | ||
2293 | } | ||
2294 | |||
2295 | |||
2296 | /*-------------------------------------------------------------------------- | ||
2297 | Update picture settings of the image sensor. | ||
2298 | Returns: 0 on success, a negative number otherwise. | ||
2299 | --------------------------------------------------------------------------*/ | ||
2300 | static int | ||
2301 | w9968cf_sensor_update_picture(struct w9968cf_device* cam, | ||
2302 | struct video_picture pict) | ||
2303 | { | ||
2304 | int err = 0; | ||
2305 | |||
2306 | if ((!cam->sensor_initialized) | ||
2307 | || pict.contrast != cam->picture.contrast) { | ||
2308 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT, | ||
2309 | pict.contrast); | ||
2310 | if (err) | ||
2311 | goto fail; | ||
2312 | DBG(4, "Contrast changed from %u to %u", | ||
2313 | cam->picture.contrast, pict.contrast) | ||
2314 | cam->picture.contrast = pict.contrast; | ||
2315 | } | ||
2316 | |||
2317 | if (((!cam->sensor_initialized) || | ||
2318 | pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) { | ||
2319 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT, | ||
2320 | pict.brightness); | ||
2321 | if (err) | ||
2322 | goto fail; | ||
2323 | DBG(4, "Brightness changed from %u to %u", | ||
2324 | cam->picture.brightness, pict.brightness) | ||
2325 | cam->picture.brightness = pict.brightness; | ||
2326 | } | ||
2327 | |||
2328 | if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) { | ||
2329 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT, | ||
2330 | pict.colour); | ||
2331 | if (err) | ||
2332 | goto fail; | ||
2333 | DBG(4, "Colour changed from %u to %u", | ||
2334 | cam->picture.colour, pict.colour) | ||
2335 | cam->picture.colour = pict.colour; | ||
2336 | } | ||
2337 | |||
2338 | if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) { | ||
2339 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE, | ||
2340 | pict.hue); | ||
2341 | if (err) | ||
2342 | goto fail; | ||
2343 | DBG(4, "Hue changed from %u to %u", | ||
2344 | cam->picture.hue, pict.hue) | ||
2345 | cam->picture.hue = pict.hue; | ||
2346 | } | ||
2347 | |||
2348 | return 0; | ||
2349 | |||
2350 | fail: | ||
2351 | DBG(4, "Failed to change sensor picture setting") | ||
2352 | return err; | ||
2353 | } | ||
2354 | |||
2355 | |||
2356 | |||
2357 | /**************************************************************************** | ||
2358 | * Camera configuration * | ||
2359 | ****************************************************************************/ | ||
2360 | |||
2361 | /*-------------------------------------------------------------------------- | ||
2362 | This function is called when a supported image sensor is detected. | ||
2363 | Return 0 if the initialization succeeds, a negative number otherwise. | ||
2364 | --------------------------------------------------------------------------*/ | ||
2365 | static int w9968cf_sensor_init(struct w9968cf_device* cam) | ||
2366 | { | ||
2367 | int err = 0; | ||
2368 | |||
2369 | if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE, | ||
2370 | &cam->monochrome))) | ||
2371 | goto error; | ||
2372 | |||
2373 | if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE, | ||
2374 | &cam->sensor))) | ||
2375 | goto error; | ||
2376 | |||
2377 | /* NOTE: Make sure width and height are a multiple of 16 */ | ||
2378 | switch (cam->sensor_client->addr) { | ||
2379 | case OV6xx0_SID: | ||
2380 | cam->maxwidth = 352; | ||
2381 | cam->maxheight = 288; | ||
2382 | cam->minwidth = 64; | ||
2383 | cam->minheight = 48; | ||
2384 | break; | ||
2385 | case OV7xx0_SID: | ||
2386 | cam->maxwidth = 640; | ||
2387 | cam->maxheight = 480; | ||
2388 | cam->minwidth = 64; | ||
2389 | cam->minheight = 48; | ||
2390 | break; | ||
2391 | default: | ||
2392 | DBG(1, "Not supported image sensor detected for %s", | ||
2393 | symbolic(camlist, cam->id)) | ||
2394 | return -EINVAL; | ||
2395 | } | ||
2396 | |||
2397 | /* These values depend on the ones in the ovxxx0.c sources */ | ||
2398 | switch (cam->sensor) { | ||
2399 | case CC_OV7620: | ||
2400 | cam->start_cropx = 287; | ||
2401 | cam->start_cropy = 35; | ||
2402 | /* Seems to work around a bug in the image sensor */ | ||
2403 | cam->vs_polarity = 1; | ||
2404 | cam->hs_polarity = 1; | ||
2405 | break; | ||
2406 | default: | ||
2407 | cam->start_cropx = 320; | ||
2408 | cam->start_cropy = 35; | ||
2409 | cam->vs_polarity = 1; | ||
2410 | cam->hs_polarity = 0; | ||
2411 | } | ||
2412 | |||
2413 | if ((err = w9968cf_sensor_update_settings(cam))) | ||
2414 | goto error; | ||
2415 | |||
2416 | if ((err = w9968cf_sensor_update_picture(cam, cam->picture))) | ||
2417 | goto error; | ||
2418 | |||
2419 | cam->sensor_initialized = 1; | ||
2420 | |||
2421 | DBG(2, "%s image sensor initialized", symbolic(senlist, cam->sensor)) | ||
2422 | return 0; | ||
2423 | |||
2424 | error: | ||
2425 | cam->sensor_initialized = 0; | ||
2426 | cam->sensor = CC_UNKNOWN; | ||
2427 | DBG(1, "Image sensor initialization failed for %s (/dev/video%d). " | ||
2428 | "Try to detach and attach this device again", | ||
2429 | symbolic(camlist, cam->id), cam->v4ldev->minor) | ||
2430 | return err; | ||
2431 | } | ||
2432 | |||
2433 | |||
2434 | /*-------------------------------------------------------------------------- | ||
2435 | Fill some basic fields in the main device data structure. | ||
2436 | This function is called once on w9968cf_usb_probe() for each recognized | ||
2437 | camera. | ||
2438 | --------------------------------------------------------------------------*/ | ||
2439 | static void | ||
2440 | w9968cf_configure_camera(struct w9968cf_device* cam, | ||
2441 | struct usb_device* udev, | ||
2442 | enum w9968cf_model_id mod_id, | ||
2443 | const unsigned short dev_nr) | ||
2444 | { | ||
2445 | init_MUTEX(&cam->fileop_sem); | ||
2446 | init_waitqueue_head(&cam->open); | ||
2447 | spin_lock_init(&cam->urb_lock); | ||
2448 | spin_lock_init(&cam->flist_lock); | ||
2449 | |||
2450 | cam->users = 0; | ||
2451 | cam->disconnected = 0; | ||
2452 | cam->id = mod_id; | ||
2453 | cam->sensor = CC_UNKNOWN; | ||
2454 | cam->sensor_initialized = 0; | ||
2455 | |||
2456 | /* Calculate the alternate setting number (from 1 to 16) | ||
2457 | according to the 'packet_size' module parameter */ | ||
2458 | if (packet_size[dev_nr] < W9968CF_MIN_PACKET_SIZE) | ||
2459 | packet_size[dev_nr] = W9968CF_MIN_PACKET_SIZE; | ||
2460 | for (cam->altsetting = 1; | ||
2461 | packet_size[dev_nr] < wMaxPacketSize[cam->altsetting-1]; | ||
2462 | cam->altsetting++); | ||
2463 | |||
2464 | cam->max_buffers = (max_buffers[dev_nr] < 2 || | ||
2465 | max_buffers[dev_nr] > W9968CF_MAX_BUFFERS) | ||
2466 | ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr]; | ||
2467 | |||
2468 | cam->double_buffer = (double_buffer[dev_nr] == 0 || | ||
2469 | double_buffer[dev_nr] == 1) | ||
2470 | ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER; | ||
2471 | |||
2472 | cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1) | ||
2473 | ? (u8)clamping[dev_nr] : W9968CF_CLAMPING; | ||
2474 | |||
2475 | cam->filter_type = (filter_type[dev_nr] == 0 || | ||
2476 | filter_type[dev_nr] == 1 || | ||
2477 | filter_type[dev_nr] == 2) | ||
2478 | ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE; | ||
2479 | |||
2480 | cam->capture = 1; | ||
2481 | |||
2482 | cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1) | ||
2483 | ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW; | ||
2484 | |||
2485 | cam->decompression = (decompression[dev_nr] == 0 || | ||
2486 | decompression[dev_nr] == 1 || | ||
2487 | decompression[dev_nr] == 2) | ||
2488 | ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION; | ||
2489 | |||
2490 | cam->upscaling = (upscaling[dev_nr] == 0 || | ||
2491 | upscaling[dev_nr] == 1) | ||
2492 | ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING; | ||
2493 | |||
2494 | cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1) | ||
2495 | ? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT; | ||
2496 | |||
2497 | cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1) | ||
2498 | ? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP; | ||
2499 | |||
2500 | cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60) | ||
2501 | ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ; | ||
2502 | |||
2503 | cam->bandfilt = (bandingfilter[dev_nr] == 0 || | ||
2504 | bandingfilter[dev_nr] == 1) | ||
2505 | ? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER; | ||
2506 | |||
2507 | cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1) | ||
2508 | ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT; | ||
2509 | |||
2510 | cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0) | ||
2511 | ? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV; | ||
2512 | |||
2513 | cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1) | ||
2514 | ? (u8)mirror[dev_nr] : W9968CF_MIRROR; | ||
2515 | |||
2516 | cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1) | ||
2517 | ? monochrome[dev_nr] : W9968CF_MONOCHROME; | ||
2518 | |||
2519 | cam->picture.brightness = (u16)brightness[dev_nr]; | ||
2520 | cam->picture.hue = (u16)hue[dev_nr]; | ||
2521 | cam->picture.colour = (u16)colour[dev_nr]; | ||
2522 | cam->picture.contrast = (u16)contrast[dev_nr]; | ||
2523 | cam->picture.whiteness = (u16)whiteness[dev_nr]; | ||
2524 | if (w9968cf_valid_palette((u16)force_palette[dev_nr])) { | ||
2525 | cam->picture.palette = (u16)force_palette[dev_nr]; | ||
2526 | cam->force_palette = 1; | ||
2527 | } else { | ||
2528 | cam->force_palette = 0; | ||
2529 | if (cam->decompression == 0) | ||
2530 | cam->picture.palette = W9968CF_PALETTE_DECOMP_OFF; | ||
2531 | else if (cam->decompression == 1) | ||
2532 | cam->picture.palette = W9968CF_PALETTE_DECOMP_FORCE; | ||
2533 | else | ||
2534 | cam->picture.palette = W9968CF_PALETTE_DECOMP_ON; | ||
2535 | } | ||
2536 | cam->picture.depth = w9968cf_valid_depth(cam->picture.palette); | ||
2537 | |||
2538 | cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1) | ||
2539 | ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB; | ||
2540 | |||
2541 | cam->window.x = 0; | ||
2542 | cam->window.y = 0; | ||
2543 | cam->window.width = W9968CF_WIDTH; | ||
2544 | cam->window.height = W9968CF_HEIGHT; | ||
2545 | cam->window.chromakey = 0; | ||
2546 | cam->window.clipcount = 0; | ||
2547 | cam->window.flags = 0; | ||
2548 | |||
2549 | DBG(3, "%s configured with settings #%u:", | ||
2550 | symbolic(camlist, cam->id), dev_nr) | ||
2551 | |||
2552 | DBG(3, "- Data packet size for USB isochrnous transfer: %u bytes", | ||
2553 | wMaxPacketSize[cam->altsetting-1]) | ||
2554 | |||
2555 | DBG(3, "- Number of requested video frame buffers: %u", | ||
2556 | cam->max_buffers) | ||
2557 | |||
2558 | if (cam->double_buffer) | ||
2559 | DBG(3, "- Hardware double buffering enabled") | ||
2560 | else | ||
2561 | DBG(3, "- Hardware double buffering disabled") | ||
2562 | |||
2563 | if (cam->filter_type == 0) | ||
2564 | DBG(3, "- Video filtering disabled") | ||
2565 | else if (cam->filter_type == 1) | ||
2566 | DBG(3, "- Video filtering enabled: type 1-2-1") | ||
2567 | else if (cam->filter_type == 2) | ||
2568 | DBG(3, "- Video filtering enabled: type 2-3-6-3-2") | ||
2569 | |||
2570 | if (cam->clamping) | ||
2571 | DBG(3, "- Video data clamping (CCIR-601 format) enabled") | ||
2572 | else | ||
2573 | DBG(3, "- Video data clamping (CCIR-601 format) disabled") | ||
2574 | |||
2575 | if (cam->largeview) | ||
2576 | DBG(3, "- Large view enabled") | ||
2577 | else | ||
2578 | DBG(3, "- Large view disabled") | ||
2579 | |||
2580 | if ((cam->decompression) == 0 && (!cam->force_palette)) | ||
2581 | DBG(3, "- Decompression disabled") | ||
2582 | else if ((cam->decompression) == 1 && (!cam->force_palette)) | ||
2583 | DBG(3, "- Decompression forced") | ||
2584 | else if ((cam->decompression) == 2 && (!cam->force_palette)) | ||
2585 | DBG(3, "- Decompression allowed") | ||
2586 | |||
2587 | if (cam->upscaling) | ||
2588 | DBG(3, "- Software image scaling enabled") | ||
2589 | else | ||
2590 | DBG(3, "- Software image scaling disabled") | ||
2591 | |||
2592 | if (cam->force_palette) | ||
2593 | DBG(3, "- Image palette forced to %s", | ||
2594 | symbolic(v4l1_plist, cam->picture.palette)) | ||
2595 | |||
2596 | if (cam->force_rgb) | ||
2597 | DBG(3, "- RGB component ordering will be used instead of BGR") | ||
2598 | |||
2599 | if (cam->auto_brt) | ||
2600 | DBG(3, "- Auto brightness enabled") | ||
2601 | else | ||
2602 | DBG(3, "- Auto brightness disabled") | ||
2603 | |||
2604 | if (cam->auto_exp) | ||
2605 | DBG(3, "- Auto exposure enabled") | ||
2606 | else | ||
2607 | DBG(3, "- Auto exposure disabled") | ||
2608 | |||
2609 | if (cam->backlight) | ||
2610 | DBG(3, "- Backlight exposure algorithm enabled") | ||
2611 | else | ||
2612 | DBG(3, "- Backlight exposure algorithm disabled") | ||
2613 | |||
2614 | if (cam->mirror) | ||
2615 | DBG(3, "- Mirror enabled") | ||
2616 | else | ||
2617 | DBG(3, "- Mirror disabled") | ||
2618 | |||
2619 | if (cam->bandfilt) | ||
2620 | DBG(3, "- Banding filter enabled") | ||
2621 | else | ||
2622 | DBG(3, "- Banding filter disabled") | ||
2623 | |||
2624 | DBG(3, "- Power lighting frequency: %u", cam->lightfreq) | ||
2625 | |||
2626 | if (cam->clockdiv == -1) | ||
2627 | DBG(3, "- Automatic clock divisor enabled") | ||
2628 | else | ||
2629 | DBG(3, "- Clock divisor: %d", cam->clockdiv) | ||
2630 | |||
2631 | if (cam->monochrome) | ||
2632 | DBG(3, "- Image sensor used as monochrome") | ||
2633 | else | ||
2634 | DBG(3, "- Image sensor not used as monochrome") | ||
2635 | } | ||
2636 | |||
2637 | |||
2638 | /*-------------------------------------------------------------------------- | ||
2639 | If the video post-processing module is not loaded, some parameters | ||
2640 | must be overridden. | ||
2641 | --------------------------------------------------------------------------*/ | ||
2642 | static void w9968cf_adjust_configuration(struct w9968cf_device* cam) | ||
2643 | { | ||
2644 | if (!w9968cf_vpp) { | ||
2645 | if (cam->decompression == 1) { | ||
2646 | cam->decompression = 2; | ||
2647 | DBG(2, "Video post-processing module not found: " | ||
2648 | "'decompression' parameter forced to 2") | ||
2649 | } | ||
2650 | if (cam->upscaling) { | ||
2651 | cam->upscaling = 0; | ||
2652 | DBG(2, "Video post-processing module not found: " | ||
2653 | "'upscaling' parameter forced to 0") | ||
2654 | } | ||
2655 | if (cam->picture.palette != VIDEO_PALETTE_UYVY) { | ||
2656 | cam->force_palette = 0; | ||
2657 | DBG(2, "Video post-processing module not found: " | ||
2658 | "'force_palette' parameter forced to 0") | ||
2659 | } | ||
2660 | cam->picture.palette = VIDEO_PALETTE_UYVY; | ||
2661 | cam->picture.depth = w9968cf_valid_depth(cam->picture.palette); | ||
2662 | } | ||
2663 | } | ||
2664 | |||
2665 | |||
2666 | /*-------------------------------------------------------------------------- | ||
2667 | Release the resources used by the driver. | ||
2668 | This function is called on disconnect | ||
2669 | (or on close if deallocation has been deferred) | ||
2670 | --------------------------------------------------------------------------*/ | ||
2671 | static void w9968cf_release_resources(struct w9968cf_device* cam) | ||
2672 | { | ||
2673 | down(&w9968cf_devlist_sem); | ||
2674 | |||
2675 | DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor) | ||
2676 | |||
2677 | video_unregister_device(cam->v4ldev); | ||
2678 | list_del(&cam->v4llist); | ||
2679 | i2c_del_adapter(&cam->i2c_adapter); | ||
2680 | w9968cf_deallocate_memory(cam); | ||
2681 | kfree(cam->control_buffer); | ||
2682 | kfree(cam->data_buffer); | ||
2683 | |||
2684 | up(&w9968cf_devlist_sem); | ||
2685 | } | ||
2686 | |||
2687 | |||
2688 | |||
2689 | /**************************************************************************** | ||
2690 | * Video4Linux interface * | ||
2691 | ****************************************************************************/ | ||
2692 | |||
2693 | static int w9968cf_open(struct inode* inode, struct file* filp) | ||
2694 | { | ||
2695 | struct w9968cf_device* cam; | ||
2696 | int err; | ||
2697 | |||
2698 | /* This the only safe way to prevent race conditions with disconnect */ | ||
2699 | if (!down_read_trylock(&w9968cf_disconnect)) | ||
2700 | return -ERESTARTSYS; | ||
2701 | |||
2702 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | ||
2703 | |||
2704 | down(&cam->dev_sem); | ||
2705 | |||
2706 | if (cam->sensor == CC_UNKNOWN) { | ||
2707 | DBG(2, "No supported image sensor has been detected by the " | ||
2708 | "'ovcamchip' module for the %s (/dev/video%d). Make " | ||
2709 | "sure it is loaded *before* (re)connecting the camera.", | ||
2710 | symbolic(camlist, cam->id), cam->v4ldev->minor) | ||
2711 | up(&cam->dev_sem); | ||
2712 | up_read(&w9968cf_disconnect); | ||
2713 | return -ENODEV; | ||
2714 | } | ||
2715 | |||
2716 | if (cam->users) { | ||
2717 | DBG(2, "%s (/dev/video%d) has been already occupied by '%s'", | ||
2718 | symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command) | ||
2719 | if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { | ||
2720 | up(&cam->dev_sem); | ||
2721 | up_read(&w9968cf_disconnect); | ||
2722 | return -EWOULDBLOCK; | ||
2723 | } | ||
2724 | up(&cam->dev_sem); | ||
2725 | err = wait_event_interruptible_exclusive(cam->open, | ||
2726 | cam->disconnected || | ||
2727 | !cam->users); | ||
2728 | if (err) { | ||
2729 | up_read(&w9968cf_disconnect); | ||
2730 | return err; | ||
2731 | } | ||
2732 | if (cam->disconnected) { | ||
2733 | up_read(&w9968cf_disconnect); | ||
2734 | return -ENODEV; | ||
2735 | } | ||
2736 | down(&cam->dev_sem); | ||
2737 | } | ||
2738 | |||
2739 | DBG(5, "Opening '%s', /dev/video%d ...", | ||
2740 | symbolic(camlist, cam->id), cam->v4ldev->minor) | ||
2741 | |||
2742 | cam->streaming = 0; | ||
2743 | cam->misconfigured = 0; | ||
2744 | |||
2745 | if (!w9968cf_vpp) | ||
2746 | if ((err = w9968cf_vppmod_detect(cam))) | ||
2747 | goto out; | ||
2748 | |||
2749 | if ((err = w9968cf_allocate_memory(cam))) | ||
2750 | goto deallocate_memory; | ||
2751 | |||
2752 | if ((err = w9968cf_init_chip(cam))) | ||
2753 | goto deallocate_memory; | ||
2754 | |||
2755 | if ((err = w9968cf_start_transfer(cam))) | ||
2756 | goto deallocate_memory; | ||
2757 | |||
2758 | filp->private_data = cam; | ||
2759 | |||
2760 | cam->users++; | ||
2761 | strcpy(cam->command, current->comm); | ||
2762 | |||
2763 | init_waitqueue_head(&cam->wait_queue); | ||
2764 | |||
2765 | DBG(5, "Video device is open") | ||
2766 | |||
2767 | up(&cam->dev_sem); | ||
2768 | up_read(&w9968cf_disconnect); | ||
2769 | |||
2770 | return 0; | ||
2771 | |||
2772 | deallocate_memory: | ||
2773 | w9968cf_deallocate_memory(cam); | ||
2774 | out: | ||
2775 | DBG(2, "Failed to open the video device") | ||
2776 | up(&cam->dev_sem); | ||
2777 | up_read(&w9968cf_disconnect); | ||
2778 | return err; | ||
2779 | } | ||
2780 | |||
2781 | |||
2782 | static int w9968cf_release(struct inode* inode, struct file* filp) | ||
2783 | { | ||
2784 | struct w9968cf_device* cam; | ||
2785 | |||
2786 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | ||
2787 | |||
2788 | down(&cam->dev_sem); /* prevent disconnect() to be called */ | ||
2789 | |||
2790 | w9968cf_stop_transfer(cam); | ||
2791 | |||
2792 | w9968cf_vppmod_release(cam); | ||
2793 | |||
2794 | if (cam->disconnected) { | ||
2795 | w9968cf_release_resources(cam); | ||
2796 | up(&cam->dev_sem); | ||
2797 | kfree(cam); | ||
2798 | return 0; | ||
2799 | } | ||
2800 | |||
2801 | cam->users--; | ||
2802 | w9968cf_deallocate_memory(cam); | ||
2803 | wake_up_interruptible_nr(&cam->open, 1); | ||
2804 | |||
2805 | DBG(5, "Video device closed") | ||
2806 | up(&cam->dev_sem); | ||
2807 | return 0; | ||
2808 | } | ||
2809 | |||
2810 | |||
2811 | static ssize_t | ||
2812 | w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | ||
2813 | { | ||
2814 | struct w9968cf_device* cam; | ||
2815 | struct w9968cf_frame_t* fr; | ||
2816 | int err = 0; | ||
2817 | |||
2818 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | ||
2819 | |||
2820 | if (filp->f_flags & O_NONBLOCK) | ||
2821 | return -EWOULDBLOCK; | ||
2822 | |||
2823 | if (down_interruptible(&cam->fileop_sem)) | ||
2824 | return -ERESTARTSYS; | ||
2825 | |||
2826 | if (cam->disconnected) { | ||
2827 | DBG(2, "Device not present") | ||
2828 | up(&cam->fileop_sem); | ||
2829 | return -ENODEV; | ||
2830 | } | ||
2831 | |||
2832 | if (cam->misconfigured) { | ||
2833 | DBG(2, "The camera is misconfigured. Close and open it again.") | ||
2834 | up(&cam->fileop_sem); | ||
2835 | return -EIO; | ||
2836 | } | ||
2837 | |||
2838 | if (!cam->frame[0].queued) | ||
2839 | w9968cf_push_frame(cam, 0); | ||
2840 | |||
2841 | if (!cam->frame[1].queued) | ||
2842 | w9968cf_push_frame(cam, 1); | ||
2843 | |||
2844 | err = wait_event_interruptible(cam->wait_queue, | ||
2845 | cam->frame[0].status == F_READY || | ||
2846 | cam->frame[1].status == F_READY || | ||
2847 | cam->disconnected); | ||
2848 | if (err) { | ||
2849 | up(&cam->fileop_sem); | ||
2850 | return err; | ||
2851 | } | ||
2852 | if (cam->disconnected) { | ||
2853 | up(&cam->fileop_sem); | ||
2854 | return -ENODEV; | ||
2855 | } | ||
2856 | |||
2857 | fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1]; | ||
2858 | |||
2859 | if (w9968cf_vpp) | ||
2860 | w9968cf_postprocess_frame(cam, fr); | ||
2861 | |||
2862 | if (count > fr->length) | ||
2863 | count = fr->length; | ||
2864 | |||
2865 | if (copy_to_user(buf, fr->buffer, count)) { | ||
2866 | fr->status = F_UNUSED; | ||
2867 | up(&cam->fileop_sem); | ||
2868 | return -EFAULT; | ||
2869 | } | ||
2870 | *f_pos += count; | ||
2871 | |||
2872 | fr->status = F_UNUSED; | ||
2873 | |||
2874 | DBG(5, "%zu bytes read", count) | ||
2875 | |||
2876 | up(&cam->fileop_sem); | ||
2877 | return count; | ||
2878 | } | ||
2879 | |||
2880 | |||
2881 | static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma) | ||
2882 | { | ||
2883 | struct w9968cf_device* cam = (struct w9968cf_device*) | ||
2884 | video_get_drvdata(video_devdata(filp)); | ||
2885 | unsigned long vsize = vma->vm_end - vma->vm_start, | ||
2886 | psize = cam->nbuffers * cam->frame[0].size, | ||
2887 | start = vma->vm_start, | ||
2888 | pos = (unsigned long)cam->frame[0].buffer, | ||
2889 | page; | ||
2890 | |||
2891 | if (cam->disconnected) { | ||
2892 | DBG(2, "Device not present") | ||
2893 | return -ENODEV; | ||
2894 | } | ||
2895 | |||
2896 | if (cam->misconfigured) { | ||
2897 | DBG(2, "The camera is misconfigured. Close and open it again") | ||
2898 | return -EIO; | ||
2899 | } | ||
2900 | |||
2901 | PDBGG("mmapping %lu bytes...", vsize) | ||
2902 | |||
2903 | if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT)) | ||
2904 | return -EINVAL; | ||
2905 | |||
2906 | while (vsize > 0) { | ||
2907 | page = vmalloc_to_pfn((void *)pos); | ||
2908 | if (remap_pfn_range(vma, start, page + vma->vm_pgoff, | ||
2909 | PAGE_SIZE, vma->vm_page_prot)) | ||
2910 | return -EAGAIN; | ||
2911 | start += PAGE_SIZE; | ||
2912 | pos += PAGE_SIZE; | ||
2913 | vsize -= PAGE_SIZE; | ||
2914 | } | ||
2915 | |||
2916 | DBG(5, "mmap method successfully called") | ||
2917 | return 0; | ||
2918 | } | ||
2919 | |||
2920 | |||
2921 | static int | ||
2922 | w9968cf_ioctl(struct inode* inode, struct file* filp, | ||
2923 | unsigned int cmd, unsigned long arg) | ||
2924 | { | ||
2925 | struct w9968cf_device* cam; | ||
2926 | int err; | ||
2927 | |||
2928 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | ||
2929 | |||
2930 | if (down_interruptible(&cam->fileop_sem)) | ||
2931 | return -ERESTARTSYS; | ||
2932 | |||
2933 | if (cam->disconnected) { | ||
2934 | DBG(2, "Device not present") | ||
2935 | up(&cam->fileop_sem); | ||
2936 | return -ENODEV; | ||
2937 | } | ||
2938 | |||
2939 | if (cam->misconfigured) { | ||
2940 | DBG(2, "The camera is misconfigured. Close and open it again.") | ||
2941 | up(&cam->fileop_sem); | ||
2942 | return -EIO; | ||
2943 | } | ||
2944 | |||
2945 | err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg); | ||
2946 | |||
2947 | up(&cam->fileop_sem); | ||
2948 | return err; | ||
2949 | } | ||
2950 | |||
2951 | |||
2952 | static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp, | ||
2953 | unsigned int cmd, void __user * arg) | ||
2954 | { | ||
2955 | struct w9968cf_device* cam; | ||
2956 | const char* v4l1_ioctls[] = { | ||
2957 | "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", | ||
2958 | "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF", | ||
2959 | "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO", | ||
2960 | "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE", | ||
2961 | "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE", | ||
2962 | "GVBIFMT", "SVBIFMT" | ||
2963 | }; | ||
2964 | |||
2965 | #define V4L1_IOCTL(cmd) \ | ||
2966 | ((_IOC_NR((cmd)) < sizeof(v4l1_ioctls)/sizeof(char*)) ? \ | ||
2967 | v4l1_ioctls[_IOC_NR((cmd))] : "?") | ||
2968 | |||
2969 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | ||
2970 | |||
2971 | switch (cmd) { | ||
2972 | |||
2973 | case VIDIOCGCAP: /* get video capability */ | ||
2974 | { | ||
2975 | struct video_capability cap = { | ||
2976 | .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES, | ||
2977 | .channels = 1, | ||
2978 | .audios = 0, | ||
2979 | .minwidth = cam->minwidth, | ||
2980 | .minheight = cam->minheight, | ||
2981 | }; | ||
2982 | sprintf(cap.name, "W996[87]CF USB Camera #%d", | ||
2983 | cam->v4ldev->minor); | ||
2984 | cap.maxwidth = (cam->upscaling && w9968cf_vpp) | ||
2985 | ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) | ||
2986 | : cam->maxwidth; | ||
2987 | cap.maxheight = (cam->upscaling && w9968cf_vpp) | ||
2988 | ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight) | ||
2989 | : cam->maxheight; | ||
2990 | |||
2991 | if (copy_to_user(arg, &cap, sizeof(cap))) | ||
2992 | return -EFAULT; | ||
2993 | |||
2994 | DBG(5, "VIDIOCGCAP successfully called") | ||
2995 | return 0; | ||
2996 | } | ||
2997 | |||
2998 | case VIDIOCGCHAN: /* get video channel informations */ | ||
2999 | { | ||
3000 | struct video_channel chan; | ||
3001 | if (copy_from_user(&chan, arg, sizeof(chan))) | ||
3002 | return -EFAULT; | ||
3003 | |||
3004 | if (chan.channel != 0) | ||
3005 | return -EINVAL; | ||
3006 | |||
3007 | strcpy(chan.name, "Camera"); | ||
3008 | chan.tuners = 0; | ||
3009 | chan.flags = 0; | ||
3010 | chan.type = VIDEO_TYPE_CAMERA; | ||
3011 | chan.norm = VIDEO_MODE_AUTO; | ||
3012 | |||
3013 | if (copy_to_user(arg, &chan, sizeof(chan))) | ||
3014 | return -EFAULT; | ||
3015 | |||
3016 | DBG(5, "VIDIOCGCHAN successfully called") | ||
3017 | return 0; | ||
3018 | } | ||
3019 | |||
3020 | case VIDIOCSCHAN: /* set active channel */ | ||
3021 | { | ||
3022 | struct video_channel chan; | ||
3023 | |||
3024 | if (copy_from_user(&chan, arg, sizeof(chan))) | ||
3025 | return -EFAULT; | ||
3026 | |||
3027 | if (chan.channel != 0) | ||
3028 | return -EINVAL; | ||
3029 | |||
3030 | DBG(5, "VIDIOCSCHAN successfully called") | ||
3031 | return 0; | ||
3032 | } | ||
3033 | |||
3034 | case VIDIOCGPICT: /* get image properties of the picture */ | ||
3035 | { | ||
3036 | if (w9968cf_sensor_get_picture(cam)) | ||
3037 | return -EIO; | ||
3038 | |||
3039 | if (copy_to_user(arg, &cam->picture, sizeof(cam->picture))) | ||
3040 | return -EFAULT; | ||
3041 | |||
3042 | DBG(5, "VIDIOCGPICT successfully called") | ||
3043 | return 0; | ||
3044 | } | ||
3045 | |||
3046 | case VIDIOCSPICT: /* change picture settings */ | ||
3047 | { | ||
3048 | struct video_picture pict; | ||
3049 | int err = 0; | ||
3050 | |||
3051 | if (copy_from_user(&pict, arg, sizeof(pict))) | ||
3052 | return -EFAULT; | ||
3053 | |||
3054 | if ( (cam->force_palette || !w9968cf_vpp) | ||
3055 | && pict.palette != cam->picture.palette ) { | ||
3056 | DBG(4, "Palette %s rejected: only %s is allowed", | ||
3057 | symbolic(v4l1_plist, pict.palette), | ||
3058 | symbolic(v4l1_plist, cam->picture.palette)) | ||
3059 | return -EINVAL; | ||
3060 | } | ||
3061 | |||
3062 | if (!w9968cf_valid_palette(pict.palette)) { | ||
3063 | DBG(4, "Palette %s not supported. VIDIOCSPICT failed", | ||
3064 | symbolic(v4l1_plist, pict.palette)) | ||
3065 | return -EINVAL; | ||
3066 | } | ||
3067 | |||
3068 | if (!cam->force_palette) { | ||
3069 | if (cam->decompression == 0) { | ||
3070 | if (w9968cf_need_decompression(pict.palette)) { | ||
3071 | DBG(4, "Decompression disabled: palette %s is not " | ||
3072 | "allowed. VIDIOCSPICT failed", | ||
3073 | symbolic(v4l1_plist, pict.palette)) | ||
3074 | return -EINVAL; | ||
3075 | } | ||
3076 | } else if (cam->decompression == 1) { | ||
3077 | if (!w9968cf_need_decompression(pict.palette)) { | ||
3078 | DBG(4, "Decompression forced: palette %s is not " | ||
3079 | "allowed. VIDIOCSPICT failed", | ||
3080 | symbolic(v4l1_plist, pict.palette)) | ||
3081 | return -EINVAL; | ||
3082 | } | ||
3083 | } | ||
3084 | } | ||
3085 | |||
3086 | if (pict.depth != w9968cf_valid_depth(pict.palette)) { | ||
3087 | DBG(4, "Requested depth %u bpp is not valid for %s " | ||
3088 | "palette: ignored and changed to %u bpp", | ||
3089 | pict.depth, symbolic(v4l1_plist, pict.palette), | ||
3090 | w9968cf_valid_depth(pict.palette)) | ||
3091 | pict.depth = w9968cf_valid_depth(pict.palette); | ||
3092 | } | ||
3093 | |||
3094 | if (pict.palette != cam->picture.palette) { | ||
3095 | if(*cam->requested_frame | ||
3096 | || cam->frame_current->queued) { | ||
3097 | err = wait_event_interruptible | ||
3098 | ( cam->wait_queue, | ||
3099 | cam->disconnected || | ||
3100 | (!*cam->requested_frame && | ||
3101 | !cam->frame_current->queued) ); | ||
3102 | if (err) | ||
3103 | return err; | ||
3104 | if (cam->disconnected) | ||
3105 | return -ENODEV; | ||
3106 | } | ||
3107 | |||
3108 | if (w9968cf_stop_transfer(cam)) | ||
3109 | goto ioctl_fail; | ||
3110 | |||
3111 | if (w9968cf_set_picture(cam, pict)) | ||
3112 | goto ioctl_fail; | ||
3113 | |||
3114 | if (w9968cf_start_transfer(cam)) | ||
3115 | goto ioctl_fail; | ||
3116 | |||
3117 | } else if (w9968cf_sensor_update_picture(cam, pict)) | ||
3118 | return -EIO; | ||
3119 | |||
3120 | |||
3121 | DBG(5, "VIDIOCSPICT successfully called") | ||
3122 | return 0; | ||
3123 | } | ||
3124 | |||
3125 | case VIDIOCSWIN: /* set capture area */ | ||
3126 | { | ||
3127 | struct video_window win; | ||
3128 | int err = 0; | ||
3129 | |||
3130 | if (copy_from_user(&win, arg, sizeof(win))) | ||
3131 | return -EFAULT; | ||
3132 | |||
3133 | DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, " | ||
3134 | "x=%u, y=%u, %ux%u", win.clipcount, win.flags, | ||
3135 | win.x, win.y, win.width, win.height) | ||
3136 | |||
3137 | if (win.clipcount != 0 || win.flags != 0) | ||
3138 | return -EINVAL; | ||
3139 | |||
3140 | if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, | ||
3141 | (u16*)&win.height))) { | ||
3142 | DBG(4, "Resolution not supported (%ux%u). " | ||
3143 | "VIDIOCSWIN failed", win.width, win.height) | ||
3144 | return err; | ||
3145 | } | ||
3146 | |||
3147 | if (win.x != cam->window.x || | ||
3148 | win.y != cam->window.y || | ||
3149 | win.width != cam->window.width || | ||
3150 | win.height != cam->window.height) { | ||
3151 | if(*cam->requested_frame | ||
3152 | || cam->frame_current->queued) { | ||
3153 | err = wait_event_interruptible | ||
3154 | ( cam->wait_queue, | ||
3155 | cam->disconnected || | ||
3156 | (!*cam->requested_frame && | ||
3157 | !cam->frame_current->queued) ); | ||
3158 | if (err) | ||
3159 | return err; | ||
3160 | if (cam->disconnected) | ||
3161 | return -ENODEV; | ||
3162 | } | ||
3163 | |||
3164 | if (w9968cf_stop_transfer(cam)) | ||
3165 | goto ioctl_fail; | ||
3166 | |||
3167 | /* This _must_ be called before set_window() */ | ||
3168 | if (w9968cf_set_picture(cam, cam->picture)) | ||
3169 | goto ioctl_fail; | ||
3170 | |||
3171 | if (w9968cf_set_window(cam, win)) | ||
3172 | goto ioctl_fail; | ||
3173 | |||
3174 | if (w9968cf_start_transfer(cam)) | ||
3175 | goto ioctl_fail; | ||
3176 | } | ||
3177 | |||
3178 | DBG(5, "VIDIOCSWIN successfully called. ") | ||
3179 | return 0; | ||
3180 | } | ||
3181 | |||
3182 | case VIDIOCGWIN: /* get current window properties */ | ||
3183 | { | ||
3184 | if (copy_to_user(arg,&cam->window,sizeof(struct video_window))) | ||
3185 | return -EFAULT; | ||
3186 | |||
3187 | DBG(5, "VIDIOCGWIN successfully called") | ||
3188 | return 0; | ||
3189 | } | ||
3190 | |||
3191 | case VIDIOCGMBUF: /* request for memory (mapped) buffer */ | ||
3192 | { | ||
3193 | struct video_mbuf mbuf; | ||
3194 | u8 i; | ||
3195 | |||
3196 | mbuf.size = cam->nbuffers * cam->frame[0].size; | ||
3197 | mbuf.frames = cam->nbuffers; | ||
3198 | for (i = 0; i < cam->nbuffers; i++) | ||
3199 | mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer - | ||
3200 | (unsigned long)cam->frame[0].buffer; | ||
3201 | |||
3202 | if (copy_to_user(arg, &mbuf, sizeof(mbuf))) | ||
3203 | return -EFAULT; | ||
3204 | |||
3205 | DBG(5, "VIDIOCGMBUF successfully called") | ||
3206 | return 0; | ||
3207 | } | ||
3208 | |||
3209 | case VIDIOCMCAPTURE: /* start the capture to a frame */ | ||
3210 | { | ||
3211 | struct video_mmap mmap; | ||
3212 | struct w9968cf_frame_t* fr; | ||
3213 | int err = 0; | ||
3214 | |||
3215 | if (copy_from_user(&mmap, arg, sizeof(mmap))) | ||
3216 | return -EFAULT; | ||
3217 | |||
3218 | DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d", | ||
3219 | mmap.frame, symbolic(v4l1_plist, mmap.format), | ||
3220 | mmap.width, mmap.height) | ||
3221 | |||
3222 | if (mmap.frame >= cam->nbuffers) { | ||
3223 | DBG(4, "Invalid frame number (%u). " | ||
3224 | "VIDIOCMCAPTURE failed", mmap.frame) | ||
3225 | return -EINVAL; | ||
3226 | } | ||
3227 | |||
3228 | if (mmap.format!=cam->picture.palette && | ||
3229 | (cam->force_palette || !w9968cf_vpp)) { | ||
3230 | DBG(4, "Palette %s rejected: only %s is allowed", | ||
3231 | symbolic(v4l1_plist, mmap.format), | ||
3232 | symbolic(v4l1_plist, cam->picture.palette)) | ||
3233 | return -EINVAL; | ||
3234 | } | ||
3235 | |||
3236 | if (!w9968cf_valid_palette(mmap.format)) { | ||
3237 | DBG(4, "Palette %s not supported. " | ||
3238 | "VIDIOCMCAPTURE failed", | ||
3239 | symbolic(v4l1_plist, mmap.format)) | ||
3240 | return -EINVAL; | ||
3241 | } | ||
3242 | |||
3243 | if (!cam->force_palette) { | ||
3244 | if (cam->decompression == 0) { | ||
3245 | if (w9968cf_need_decompression(mmap.format)) { | ||
3246 | DBG(4, "Decompression disabled: palette %s is not " | ||
3247 | "allowed. VIDIOCSPICT failed", | ||
3248 | symbolic(v4l1_plist, mmap.format)) | ||
3249 | return -EINVAL; | ||
3250 | } | ||
3251 | } else if (cam->decompression == 1) { | ||
3252 | if (!w9968cf_need_decompression(mmap.format)) { | ||
3253 | DBG(4, "Decompression forced: palette %s is not " | ||
3254 | "allowed. VIDIOCSPICT failed", | ||
3255 | symbolic(v4l1_plist, mmap.format)) | ||
3256 | return -EINVAL; | ||
3257 | } | ||
3258 | } | ||
3259 | } | ||
3260 | |||
3261 | if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width, | ||
3262 | (u16*)&mmap.height))) { | ||
3263 | DBG(4, "Resolution not supported (%dx%d). " | ||
3264 | "VIDIOCMCAPTURE failed", | ||
3265 | mmap.width, mmap.height) | ||
3266 | return err; | ||
3267 | } | ||
3268 | |||
3269 | fr = &cam->frame[mmap.frame]; | ||
3270 | |||
3271 | if (mmap.width != cam->window.width || | ||
3272 | mmap.height != cam->window.height || | ||
3273 | mmap.format != cam->picture.palette) { | ||
3274 | |||
3275 | struct video_window win; | ||
3276 | struct video_picture pict; | ||
3277 | |||
3278 | if(*cam->requested_frame | ||
3279 | || cam->frame_current->queued) { | ||
3280 | DBG(6, "VIDIOCMCAPTURE. Change settings for " | ||
3281 | "frame #%u: %dx%d, format %s. Wait...", | ||
3282 | mmap.frame, mmap.width, mmap.height, | ||
3283 | symbolic(v4l1_plist, mmap.format)) | ||
3284 | err = wait_event_interruptible | ||
3285 | ( cam->wait_queue, | ||
3286 | cam->disconnected || | ||
3287 | (!*cam->requested_frame && | ||
3288 | !cam->frame_current->queued) ); | ||
3289 | if (err) | ||
3290 | return err; | ||
3291 | if (cam->disconnected) | ||
3292 | return -ENODEV; | ||
3293 | } | ||
3294 | |||
3295 | memcpy(&win, &cam->window, sizeof(win)); | ||
3296 | memcpy(&pict, &cam->picture, sizeof(pict)); | ||
3297 | win.width = mmap.width; | ||
3298 | win.height = mmap.height; | ||
3299 | pict.palette = mmap.format; | ||
3300 | |||
3301 | if (w9968cf_stop_transfer(cam)) | ||
3302 | goto ioctl_fail; | ||
3303 | |||
3304 | /* This before set_window */ | ||
3305 | if (w9968cf_set_picture(cam, pict)) | ||
3306 | goto ioctl_fail; | ||
3307 | |||
3308 | if (w9968cf_set_window(cam, win)) | ||
3309 | goto ioctl_fail; | ||
3310 | |||
3311 | if (w9968cf_start_transfer(cam)) | ||
3312 | goto ioctl_fail; | ||
3313 | |||
3314 | } else if (fr->queued) { | ||
3315 | |||
3316 | DBG(6, "Wait until frame #%u is free", mmap.frame) | ||
3317 | |||
3318 | err = wait_event_interruptible(cam->wait_queue, | ||
3319 | cam->disconnected || | ||
3320 | (!fr->queued)); | ||
3321 | if (err) | ||
3322 | return err; | ||
3323 | if (cam->disconnected) | ||
3324 | return -ENODEV; | ||
3325 | } | ||
3326 | |||
3327 | w9968cf_push_frame(cam, mmap.frame); | ||
3328 | DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame) | ||
3329 | return 0; | ||
3330 | } | ||
3331 | |||
3332 | case VIDIOCSYNC: /* wait until the capture of a frame is finished */ | ||
3333 | { | ||
3334 | unsigned int f_num; | ||
3335 | struct w9968cf_frame_t* fr; | ||
3336 | int err = 0; | ||
3337 | |||
3338 | if (copy_from_user(&f_num, arg, sizeof(f_num))) | ||
3339 | return -EFAULT; | ||
3340 | |||
3341 | if (f_num >= cam->nbuffers) { | ||
3342 | DBG(4, "Invalid frame number (%u). " | ||
3343 | "VIDIOCMCAPTURE failed", f_num) | ||
3344 | return -EINVAL; | ||
3345 | } | ||
3346 | |||
3347 | DBG(6, "VIDIOCSYNC called for frame #%u", f_num) | ||
3348 | |||
3349 | fr = &cam->frame[f_num]; | ||
3350 | |||
3351 | switch (fr->status) { | ||
3352 | case F_UNUSED: | ||
3353 | if (!fr->queued) { | ||
3354 | DBG(4, "VIDIOSYNC: Frame #%u not requested!", | ||
3355 | f_num) | ||
3356 | return -EFAULT; | ||
3357 | } | ||
3358 | case F_ERROR: | ||
3359 | case F_GRABBING: | ||
3360 | err = wait_event_interruptible(cam->wait_queue, | ||
3361 | (fr->status == F_READY) | ||
3362 | || cam->disconnected); | ||
3363 | if (err) | ||
3364 | return err; | ||
3365 | if (cam->disconnected) | ||
3366 | return -ENODEV; | ||
3367 | break; | ||
3368 | case F_READY: | ||
3369 | break; | ||
3370 | } | ||
3371 | |||
3372 | if (w9968cf_vpp) | ||
3373 | w9968cf_postprocess_frame(cam, fr); | ||
3374 | |||
3375 | fr->status = F_UNUSED; | ||
3376 | |||
3377 | DBG(5, "VIDIOCSYNC(%u) successfully called", f_num) | ||
3378 | return 0; | ||
3379 | } | ||
3380 | |||
3381 | case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/ | ||
3382 | { | ||
3383 | struct video_unit unit = { | ||
3384 | .video = cam->v4ldev->minor, | ||
3385 | .vbi = VIDEO_NO_UNIT, | ||
3386 | .radio = VIDEO_NO_UNIT, | ||
3387 | .audio = VIDEO_NO_UNIT, | ||
3388 | .teletext = VIDEO_NO_UNIT, | ||
3389 | }; | ||
3390 | |||
3391 | if (copy_to_user(arg, &unit, sizeof(unit))) | ||
3392 | return -EFAULT; | ||
3393 | |||
3394 | DBG(5, "VIDIOCGUNIT successfully called") | ||
3395 | return 0; | ||
3396 | } | ||
3397 | |||
3398 | case VIDIOCKEY: | ||
3399 | return 0; | ||
3400 | |||
3401 | case VIDIOCGFBUF: | ||
3402 | { | ||
3403 | if (clear_user(arg, sizeof(struct video_buffer))) | ||
3404 | return -EFAULT; | ||
3405 | |||
3406 | DBG(5, "VIDIOCGFBUF successfully called") | ||
3407 | return 0; | ||
3408 | } | ||
3409 | |||
3410 | case VIDIOCGTUNER: | ||
3411 | { | ||
3412 | struct video_tuner tuner; | ||
3413 | if (copy_from_user(&tuner, arg, sizeof(tuner))) | ||
3414 | return -EFAULT; | ||
3415 | |||
3416 | if (tuner.tuner != 0) | ||
3417 | return -EINVAL; | ||
3418 | |||
3419 | strcpy(tuner.name, "no_tuner"); | ||
3420 | tuner.rangelow = 0; | ||
3421 | tuner.rangehigh = 0; | ||
3422 | tuner.flags = VIDEO_TUNER_NORM; | ||
3423 | tuner.mode = VIDEO_MODE_AUTO; | ||
3424 | tuner.signal = 0xffff; | ||
3425 | |||
3426 | if (copy_to_user(arg, &tuner, sizeof(tuner))) | ||
3427 | return -EFAULT; | ||
3428 | |||
3429 | DBG(5, "VIDIOCGTUNER successfully called") | ||
3430 | return 0; | ||
3431 | } | ||
3432 | |||
3433 | case VIDIOCSTUNER: | ||
3434 | { | ||
3435 | struct video_tuner tuner; | ||
3436 | if (copy_from_user(&tuner, arg, sizeof(tuner))) | ||
3437 | return -EFAULT; | ||
3438 | |||
3439 | if (tuner.tuner != 0) | ||
3440 | return -EINVAL; | ||
3441 | |||
3442 | if (tuner.mode != VIDEO_MODE_AUTO) | ||
3443 | return -EINVAL; | ||
3444 | |||
3445 | DBG(5, "VIDIOCSTUNER successfully called") | ||
3446 | return 0; | ||
3447 | } | ||
3448 | |||
3449 | case VIDIOCSFBUF: | ||
3450 | case VIDIOCCAPTURE: | ||
3451 | case VIDIOCGFREQ: | ||
3452 | case VIDIOCSFREQ: | ||
3453 | case VIDIOCGAUDIO: | ||
3454 | case VIDIOCSAUDIO: | ||
3455 | case VIDIOCSPLAYMODE: | ||
3456 | case VIDIOCSWRITEMODE: | ||
3457 | case VIDIOCGPLAYINFO: | ||
3458 | case VIDIOCSMICROCODE: | ||
3459 | case VIDIOCGVBIFMT: | ||
3460 | case VIDIOCSVBIFMT: | ||
3461 | DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s " | ||
3462 | "(type 0x%01X, " | ||
3463 | "n. 0x%01X, " | ||
3464 | "dir. 0x%01X, " | ||
3465 | "size 0x%02X)", | ||
3466 | V4L1_IOCTL(cmd), | ||
3467 | _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd)) | ||
3468 | |||
3469 | return -EINVAL; | ||
3470 | |||
3471 | default: | ||
3472 | DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s " | ||
3473 | "type 0x%01X, " | ||
3474 | "n. 0x%01X, " | ||
3475 | "dir. 0x%01X, " | ||
3476 | "size 0x%02X", | ||
3477 | V4L1_IOCTL(cmd), | ||
3478 | _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd)) | ||
3479 | |||
3480 | return -ENOIOCTLCMD; | ||
3481 | |||
3482 | } /* end of switch */ | ||
3483 | |||
3484 | ioctl_fail: | ||
3485 | cam->misconfigured = 1; | ||
3486 | DBG(1, "VIDIOC%s failed because of hardware problems. " | ||
3487 | "To use the camera, close and open it again.", V4L1_IOCTL(cmd)) | ||
3488 | return -EFAULT; | ||
3489 | } | ||
3490 | |||
3491 | |||
3492 | static struct file_operations w9968cf_fops = { | ||
3493 | .owner = THIS_MODULE, | ||
3494 | .open = w9968cf_open, | ||
3495 | .release = w9968cf_release, | ||
3496 | .read = w9968cf_read, | ||
3497 | .ioctl = w9968cf_ioctl, | ||
3498 | .mmap = w9968cf_mmap, | ||
3499 | .llseek = no_llseek, | ||
3500 | }; | ||
3501 | |||
3502 | |||
3503 | |||
3504 | /**************************************************************************** | ||
3505 | * USB probe and V4L registration, disconnect and id_table[] definition * | ||
3506 | ****************************************************************************/ | ||
3507 | |||
3508 | static int | ||
3509 | w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | ||
3510 | { | ||
3511 | struct usb_device *udev = interface_to_usbdev(intf); | ||
3512 | struct w9968cf_device* cam; | ||
3513 | int err = 0; | ||
3514 | enum w9968cf_model_id mod_id; | ||
3515 | struct list_head* ptr; | ||
3516 | u8 sc = 0; /* number of simultaneous cameras */ | ||
3517 | static unsigned short dev_nr = 0; /* we are handling device number n */ | ||
3518 | |||
3519 | if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[0].idVendor && | ||
3520 | le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct) | ||
3521 | mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */ | ||
3522 | else if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[1].idVendor && | ||
3523 | le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[1].idProduct) | ||
3524 | mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */ | ||
3525 | else | ||
3526 | return -ENODEV; | ||
3527 | |||
3528 | cam = (struct w9968cf_device*) | ||
3529 | kmalloc(sizeof(struct w9968cf_device), GFP_KERNEL); | ||
3530 | if (!cam) | ||
3531 | return -ENOMEM; | ||
3532 | |||
3533 | memset(cam, 0, sizeof(*cam)); | ||
3534 | |||
3535 | init_MUTEX(&cam->dev_sem); | ||
3536 | down(&cam->dev_sem); | ||
3537 | |||
3538 | cam->usbdev = udev; | ||
3539 | /* NOTE: a local copy is used to avoid possible race conditions */ | ||
3540 | memcpy(&cam->dev, &udev->dev, sizeof(struct device)); | ||
3541 | |||
3542 | DBG(2, "%s detected", symbolic(camlist, mod_id)) | ||
3543 | |||
3544 | if (simcams > W9968CF_MAX_DEVICES) | ||
3545 | simcams = W9968CF_SIMCAMS; | ||
3546 | |||
3547 | /* How many cameras are connected ? */ | ||
3548 | down(&w9968cf_devlist_sem); | ||
3549 | list_for_each(ptr, &w9968cf_dev_list) | ||
3550 | sc++; | ||
3551 | up(&w9968cf_devlist_sem); | ||
3552 | |||
3553 | if (sc >= simcams) { | ||
3554 | DBG(2, "Device rejected: too many connected cameras " | ||
3555 | "(max. %u)", simcams) | ||
3556 | err = -EPERM; | ||
3557 | goto fail; | ||
3558 | } | ||
3559 | |||
3560 | |||
3561 | /* Allocate 2 bytes of memory for camera control USB transfers */ | ||
3562 | if (!(cam->control_buffer = (u16*)kmalloc(2, GFP_KERNEL))) { | ||
3563 | DBG(1,"Couldn't allocate memory for camera control transfers") | ||
3564 | err = -ENOMEM; | ||
3565 | goto fail; | ||
3566 | } | ||
3567 | memset(cam->control_buffer, 0, 2); | ||
3568 | |||
3569 | /* Allocate 8 bytes of memory for USB data transfers to the FSB */ | ||
3570 | if (!(cam->data_buffer = (u16*)kmalloc(8, GFP_KERNEL))) { | ||
3571 | DBG(1, "Couldn't allocate memory for data " | ||
3572 | "transfers to the FSB") | ||
3573 | err = -ENOMEM; | ||
3574 | goto fail; | ||
3575 | } | ||
3576 | memset(cam->data_buffer, 0, 8); | ||
3577 | |||
3578 | /* Register the V4L device */ | ||
3579 | cam->v4ldev = video_device_alloc(); | ||
3580 | if (!cam->v4ldev) { | ||
3581 | DBG(1, "Could not allocate memory for a V4L structure") | ||
3582 | err = -ENOMEM; | ||
3583 | goto fail; | ||
3584 | } | ||
3585 | |||
3586 | strcpy(cam->v4ldev->name, symbolic(camlist, mod_id)); | ||
3587 | cam->v4ldev->owner = THIS_MODULE; | ||
3588 | cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; | ||
3589 | cam->v4ldev->hardware = VID_HARDWARE_W9968CF; | ||
3590 | cam->v4ldev->fops = &w9968cf_fops; | ||
3591 | cam->v4ldev->minor = video_nr[dev_nr]; | ||
3592 | cam->v4ldev->release = video_device_release; | ||
3593 | video_set_drvdata(cam->v4ldev, cam); | ||
3594 | cam->v4ldev->dev = &cam->dev; | ||
3595 | |||
3596 | err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, | ||
3597 | video_nr[dev_nr]); | ||
3598 | if (err) { | ||
3599 | DBG(1, "V4L device registration failed") | ||
3600 | if (err == -ENFILE && video_nr[dev_nr] == -1) | ||
3601 | DBG(2, "Couldn't find a free /dev/videoX node") | ||
3602 | video_nr[dev_nr] = -1; | ||
3603 | dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
3604 | goto fail; | ||
3605 | } | ||
3606 | |||
3607 | DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->minor) | ||
3608 | |||
3609 | /* Set some basic constants */ | ||
3610 | w9968cf_configure_camera(cam, udev, mod_id, dev_nr); | ||
3611 | |||
3612 | /* Add a new entry into the list of V4L registered devices */ | ||
3613 | down(&w9968cf_devlist_sem); | ||
3614 | list_add(&cam->v4llist, &w9968cf_dev_list); | ||
3615 | up(&w9968cf_devlist_sem); | ||
3616 | dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
3617 | |||
3618 | w9968cf_turn_on_led(cam); | ||
3619 | |||
3620 | w9968cf_i2c_init(cam); | ||
3621 | |||
3622 | usb_set_intfdata(intf, cam); | ||
3623 | up(&cam->dev_sem); | ||
3624 | return 0; | ||
3625 | |||
3626 | fail: /* Free unused memory */ | ||
3627 | if (cam->control_buffer) | ||
3628 | kfree(cam->control_buffer); | ||
3629 | if (cam->data_buffer) | ||
3630 | kfree(cam->data_buffer); | ||
3631 | if (cam->v4ldev) | ||
3632 | video_device_release(cam->v4ldev); | ||
3633 | up(&cam->dev_sem); | ||
3634 | kfree(cam); | ||
3635 | return err; | ||
3636 | } | ||
3637 | |||
3638 | |||
3639 | static void w9968cf_usb_disconnect(struct usb_interface* intf) | ||
3640 | { | ||
3641 | struct w9968cf_device* cam = | ||
3642 | (struct w9968cf_device*)usb_get_intfdata(intf); | ||
3643 | |||
3644 | down_write(&w9968cf_disconnect); | ||
3645 | |||
3646 | if (cam) { | ||
3647 | /* Prevent concurrent accesses to data */ | ||
3648 | down(&cam->dev_sem); | ||
3649 | |||
3650 | cam->disconnected = 1; | ||
3651 | |||
3652 | DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id)) | ||
3653 | |||
3654 | wake_up_interruptible_all(&cam->open); | ||
3655 | |||
3656 | if (cam->users) { | ||
3657 | DBG(2, "The device is open (/dev/video%d)! " | ||
3658 | "Process name: %s. Deregistration and memory " | ||
3659 | "deallocation are deferred on close.", | ||
3660 | cam->v4ldev->minor, cam->command) | ||
3661 | cam->misconfigured = 1; | ||
3662 | w9968cf_stop_transfer(cam); | ||
3663 | wake_up_interruptible(&cam->wait_queue); | ||
3664 | } else | ||
3665 | w9968cf_release_resources(cam); | ||
3666 | |||
3667 | up(&cam->dev_sem); | ||
3668 | |||
3669 | if (!cam->users) | ||
3670 | kfree(cam); | ||
3671 | } | ||
3672 | |||
3673 | up_write(&w9968cf_disconnect); | ||
3674 | } | ||
3675 | |||
3676 | |||
3677 | static struct usb_driver w9968cf_usb_driver = { | ||
3678 | .owner = THIS_MODULE, | ||
3679 | .name = "w9968cf", | ||
3680 | .id_table = winbond_id_table, | ||
3681 | .probe = w9968cf_usb_probe, | ||
3682 | .disconnect = w9968cf_usb_disconnect, | ||
3683 | }; | ||
3684 | |||
3685 | |||
3686 | |||
3687 | /**************************************************************************** | ||
3688 | * Module init, exit and intermodule communication * | ||
3689 | ****************************************************************************/ | ||
3690 | |||
3691 | static int w9968cf_vppmod_detect(struct w9968cf_device* cam) | ||
3692 | { | ||
3693 | if (!w9968cf_vpp) | ||
3694 | if (vppmod_load) | ||
3695 | request_module("w9968cf-vpp"); | ||
3696 | |||
3697 | down(&w9968cf_vppmod_lock); | ||
3698 | |||
3699 | if (!w9968cf_vpp) { | ||
3700 | DBG(4, "Video post-processing module not detected") | ||
3701 | w9968cf_adjust_configuration(cam); | ||
3702 | goto out; | ||
3703 | } | ||
3704 | |||
3705 | if (!try_module_get(w9968cf_vpp->owner)) { | ||
3706 | DBG(1, "Couldn't increment the reference count of " | ||
3707 | "the video post-processing module") | ||
3708 | up(&w9968cf_vppmod_lock); | ||
3709 | return -ENOSYS; | ||
3710 | } | ||
3711 | |||
3712 | w9968cf_vpp->busy++; | ||
3713 | |||
3714 | DBG(5, "Video post-processing module detected") | ||
3715 | |||
3716 | out: | ||
3717 | up(&w9968cf_vppmod_lock); | ||
3718 | return 0; | ||
3719 | } | ||
3720 | |||
3721 | |||
3722 | static void w9968cf_vppmod_release(struct w9968cf_device* cam) | ||
3723 | { | ||
3724 | down(&w9968cf_vppmod_lock); | ||
3725 | |||
3726 | if (w9968cf_vpp && w9968cf_vpp->busy) { | ||
3727 | module_put(w9968cf_vpp->owner); | ||
3728 | w9968cf_vpp->busy--; | ||
3729 | wake_up(&w9968cf_vppmod_wait); | ||
3730 | DBG(5, "Video post-processing module released") | ||
3731 | } | ||
3732 | |||
3733 | up(&w9968cf_vppmod_lock); | ||
3734 | } | ||
3735 | |||
3736 | |||
3737 | int w9968cf_vppmod_register(struct w9968cf_vpp_t* vpp) | ||
3738 | { | ||
3739 | down(&w9968cf_vppmod_lock); | ||
3740 | |||
3741 | if (w9968cf_vpp) { | ||
3742 | KDBG(1, "Video post-processing module already registered") | ||
3743 | up(&w9968cf_vppmod_lock); | ||
3744 | return -EINVAL; | ||
3745 | } | ||
3746 | |||
3747 | w9968cf_vpp = vpp; | ||
3748 | w9968cf_vpp->busy = 0; | ||
3749 | |||
3750 | KDBG(2, "Video post-processing module registered") | ||
3751 | up(&w9968cf_vppmod_lock); | ||
3752 | return 0; | ||
3753 | } | ||
3754 | |||
3755 | |||
3756 | int w9968cf_vppmod_deregister(struct w9968cf_vpp_t* vpp) | ||
3757 | { | ||
3758 | down(&w9968cf_vppmod_lock); | ||
3759 | |||
3760 | if (!w9968cf_vpp) { | ||
3761 | up(&w9968cf_vppmod_lock); | ||
3762 | return -EINVAL; | ||
3763 | } | ||
3764 | |||
3765 | if (w9968cf_vpp != vpp) { | ||
3766 | KDBG(1, "Only the owner can unregister the video " | ||
3767 | "post-processing module") | ||
3768 | up(&w9968cf_vppmod_lock); | ||
3769 | return -EINVAL; | ||
3770 | } | ||
3771 | |||
3772 | if (w9968cf_vpp->busy) { | ||
3773 | KDBG(2, "Video post-processing module busy. Wait for it to be " | ||
3774 | "released...") | ||
3775 | up(&w9968cf_vppmod_lock); | ||
3776 | wait_event(w9968cf_vppmod_wait, !w9968cf_vpp->busy); | ||
3777 | w9968cf_vpp = NULL; | ||
3778 | goto out; | ||
3779 | } | ||
3780 | |||
3781 | w9968cf_vpp = NULL; | ||
3782 | |||
3783 | up(&w9968cf_vppmod_lock); | ||
3784 | |||
3785 | out: | ||
3786 | KDBG(2, "Video post-processing module unregistered") | ||
3787 | return 0; | ||
3788 | } | ||
3789 | |||
3790 | |||
3791 | static int __init w9968cf_module_init(void) | ||
3792 | { | ||
3793 | int err; | ||
3794 | |||
3795 | KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION) | ||
3796 | KDBG(3, W9968CF_MODULE_AUTHOR) | ||
3797 | |||
3798 | if (ovmod_load) | ||
3799 | request_module("ovcamchip"); | ||
3800 | |||
3801 | if ((err = usb_register(&w9968cf_usb_driver))) | ||
3802 | return err; | ||
3803 | |||
3804 | return 0; | ||
3805 | } | ||
3806 | |||
3807 | |||
3808 | static void __exit w9968cf_module_exit(void) | ||
3809 | { | ||
3810 | /* w9968cf_usb_disconnect() will be called */ | ||
3811 | usb_deregister(&w9968cf_usb_driver); | ||
3812 | |||
3813 | KDBG(2, W9968CF_MODULE_NAME" deregistered") | ||
3814 | } | ||
3815 | |||
3816 | |||
3817 | module_init(w9968cf_module_init); | ||
3818 | module_exit(w9968cf_module_exit); | ||
3819 | |||
3820 | |||
3821 | EXPORT_SYMBOL(w9968cf_vppmod_register); | ||
3822 | EXPORT_SYMBOL(w9968cf_vppmod_deregister); | ||
diff --git a/drivers/usb/media/w9968cf.h b/drivers/usb/media/w9968cf.h new file mode 100644 index 000000000000..8acbfe205bc7 --- /dev/null +++ b/drivers/usb/media/w9968cf.h | |||
@@ -0,0 +1,339 @@ | |||
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 <asm/semaphore.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 | static struct w9968cf_vpp_t* w9968cf_vpp; | ||
198 | static DECLARE_MUTEX(w9968cf_vppmod_lock); | ||
199 | static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait); | ||
200 | |||
201 | static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */ | ||
202 | static DECLARE_MUTEX(w9968cf_devlist_sem); /* semaphore for list traversal */ | ||
203 | |||
204 | static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */ | ||
205 | |||
206 | /* Main device driver structure */ | ||
207 | struct w9968cf_device { | ||
208 | struct device dev; /* device structure */ | ||
209 | |||
210 | enum w9968cf_model_id id; /* private device identifier */ | ||
211 | |||
212 | struct video_device* v4ldev; /* -> V4L structure */ | ||
213 | struct list_head v4llist; /* entry of the list of V4L cameras */ | ||
214 | |||
215 | struct usb_device* usbdev; /* -> main USB structure */ | ||
216 | struct urb* urb[W9968CF_URBS]; /* -> USB request block structs */ | ||
217 | void* transfer_buffer[W9968CF_URBS]; /* -> ISO transfer buffers */ | ||
218 | u16* control_buffer; /* -> buffer for control req.*/ | ||
219 | u16* data_buffer; /* -> data to send to the FSB */ | ||
220 | |||
221 | struct w9968cf_frame_t frame[W9968CF_MAX_BUFFERS]; | ||
222 | struct w9968cf_frame_t frame_tmp; /* temporary frame */ | ||
223 | struct w9968cf_frame_t frame_vpp; /* helper frame.*/ | ||
224 | struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */ | ||
225 | struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS]; | ||
226 | |||
227 | u8 max_buffers, /* number of requested buffers */ | ||
228 | force_palette, /* yes=1/no=0 */ | ||
229 | force_rgb, /* read RGB instead of BGR, yes=1, no=0 */ | ||
230 | double_buffer, /* hardware double buffering yes=1/no=0 */ | ||
231 | clamping, /* video data clamping yes=1/no=0 */ | ||
232 | filter_type, /* 0=disabled, 1=3 tap, 2=5 tap filter */ | ||
233 | capture, /* 0=disabled, 1=enabled */ | ||
234 | largeview, /* 0=disabled, 1=enabled */ | ||
235 | decompression, /* 0=disabled, 1=forced, 2=allowed */ | ||
236 | upscaling; /* software image scaling, 0=enabled, 1=disabled */ | ||
237 | |||
238 | struct video_picture picture; /* current picture settings */ | ||
239 | struct video_window window; /* current window settings */ | ||
240 | |||
241 | u16 hw_depth, /* depth (used by the chip) */ | ||
242 | hw_palette, /* palette (used by the chip) */ | ||
243 | hw_width, /* width (used by the chip) */ | ||
244 | hw_height, /* height (used by the chip) */ | ||
245 | hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */ | ||
246 | vs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */ | ||
247 | start_cropx, /* pixels from HS inactive edge to 1st cropped pixel*/ | ||
248 | start_cropy; /* pixels from VS inactive edge to 1st cropped pixel*/ | ||
249 | |||
250 | enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */ | ||
251 | |||
252 | u8 nbuffers, /* number of allocated frame buffers */ | ||
253 | altsetting, /* camera alternate setting */ | ||
254 | disconnected, /* flag: yes=1, no=0 */ | ||
255 | misconfigured, /* flag: yes=1, no=0 */ | ||
256 | users, /* flag: number of users holding the device */ | ||
257 | streaming; /* flag: yes=1, no=0 */ | ||
258 | |||
259 | u8 sensor_initialized; /* flag: yes=1, no=0 */ | ||
260 | |||
261 | /* Determined by the image sensor type: */ | ||
262 | int sensor, /* type of image sensor chip (CC_*) */ | ||
263 | monochrome; /* image sensor is (probably) monochrome */ | ||
264 | u16 maxwidth, /* maximum width supported by the image sensor */ | ||
265 | maxheight, /* maximum height supported by the image sensor */ | ||
266 | minwidth, /* minimum width supported by the image sensor */ | ||
267 | minheight; /* minimum height supported by the image sensor */ | ||
268 | u8 auto_brt, /* auto brightness enabled flag */ | ||
269 | auto_exp, /* auto exposure enabled flag */ | ||
270 | backlight, /* backlight exposure algorithm flag */ | ||
271 | mirror, /* image is reversed horizontally */ | ||
272 | lightfreq, /* power (lighting) frequency */ | ||
273 | bandfilt; /* banding filter enabled flag */ | ||
274 | s8 clockdiv; /* clock divisor */ | ||
275 | |||
276 | /* I2C interface to kernel */ | ||
277 | struct i2c_adapter i2c_adapter; | ||
278 | struct i2c_client* sensor_client; | ||
279 | |||
280 | /* Locks */ | ||
281 | struct semaphore dev_sem, /* for probe, disconnect,open and close */ | ||
282 | fileop_sem; /* for read and ioctl */ | ||
283 | spinlock_t urb_lock, /* for submit_urb() and unlink_urb() */ | ||
284 | flist_lock; /* for requested frame list accesses */ | ||
285 | wait_queue_head_t open, wait_queue; | ||
286 | |||
287 | char command[16]; /* name of the program holding the device */ | ||
288 | }; | ||
289 | |||
290 | |||
291 | /**************************************************************************** | ||
292 | * Macros for debugging * | ||
293 | ****************************************************************************/ | ||
294 | |||
295 | #undef DBG | ||
296 | #undef KDBG | ||
297 | #ifdef W9968CF_DEBUG | ||
298 | /* For device specific debugging messages */ | ||
299 | # define DBG(level, fmt, args...) \ | ||
300 | { \ | ||
301 | if ( ((specific_debug) && (debug == (level))) || \ | ||
302 | ((!specific_debug) && (debug >= (level))) ) { \ | ||
303 | if ((level) == 1) \ | ||
304 | dev_err(&cam->dev, fmt "\n", ## args); \ | ||
305 | else if ((level) == 2 || (level) == 3) \ | ||
306 | dev_info(&cam->dev, fmt "\n", ## args); \ | ||
307 | else if ((level) == 4) \ | ||
308 | dev_warn(&cam->dev, fmt "\n", ## args); \ | ||
309 | else if ((level) >= 5) \ | ||
310 | dev_info(&cam->dev, "[%s:%d] " fmt "\n", \ | ||
311 | __FUNCTION__, __LINE__ , ## args); \ | ||
312 | } \ | ||
313 | } | ||
314 | /* For generic kernel (not device specific) messages */ | ||
315 | # define KDBG(level, fmt, args...) \ | ||
316 | { \ | ||
317 | if ( ((specific_debug) && (debug == (level))) || \ | ||
318 | ((!specific_debug) && (debug >= (level))) ) { \ | ||
319 | if ((level) >= 1 && (level) <= 4) \ | ||
320 | pr_info("w9968cf: " fmt "\n", ## args); \ | ||
321 | else if ((level) >= 5) \ | ||
322 | pr_debug("w9968cf: [%s:%d] " fmt "\n", __FUNCTION__, \ | ||
323 | __LINE__ , ## args); \ | ||
324 | } \ | ||
325 | } | ||
326 | #else | ||
327 | /* Not debugging: nothing */ | ||
328 | # define DBG(level, fmt, args...) do {;} while(0); | ||
329 | # define KDBG(level, fmt, args...) do {;} while(0); | ||
330 | #endif | ||
331 | |||
332 | #undef PDBG | ||
333 | #define PDBG(fmt, args...) \ | ||
334 | dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args); | ||
335 | |||
336 | #undef PDBGG | ||
337 | #define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */ | ||
338 | |||
339 | #endif /* _W9968CF_H_ */ | ||
diff --git a/drivers/usb/media/w9968cf_decoder.h b/drivers/usb/media/w9968cf_decoder.h new file mode 100644 index 000000000000..31faccbe8f03 --- /dev/null +++ b/drivers/usb/media/w9968cf_decoder.h | |||
@@ -0,0 +1,86 @@ | |||
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 new file mode 100644 index 000000000000..3f5317dc4c29 --- /dev/null +++ b/drivers/usb/media/w9968cf_vpp.h | |||
@@ -0,0 +1,43 @@ | |||
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 | extern int w9968cf_vppmod_register(struct w9968cf_vpp_t*); | ||
41 | extern int w9968cf_vppmod_deregister(struct w9968cf_vpp_t*); | ||
42 | |||
43 | #endif /* _W9968CF_VPP_H_ */ | ||