]>
Commit | Line | Data |
---|---|---|
6a7eba24 JFM |
1 | /* |
2 | * Quickcam cameras initialization data | |
3 | * | |
4 | * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> | |
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 | * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | * | |
20 | */ | |
21 | #define MODULE_NAME "tv8532" | |
22 | ||
23 | #include "gspca.h" | |
24 | ||
739570bb JFM |
25 | #define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) |
26 | static const char version[] = "2.1.7"; | |
6a7eba24 JFM |
27 | |
28 | MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); | |
29 | MODULE_DESCRIPTION("TV8532 USB Camera Driver"); | |
30 | MODULE_LICENSE("GPL"); | |
31 | ||
32 | /* specific webcam descriptor */ | |
33 | struct sd { | |
34 | struct gspca_dev gspca_dev; /* !! must be the first item */ | |
35 | ||
36 | int buflen; /* current length of tmpbuf */ | |
37 | __u8 tmpbuf[352 * 288 + 10 * 288]; /* no protection... */ | |
38 | __u8 tmpbuf2[352 * 288]; /* no protection... */ | |
39 | ||
40 | unsigned short brightness; | |
41 | unsigned short contrast; | |
42 | ||
43 | char packet; | |
44 | char synchro; | |
45 | }; | |
46 | ||
47 | /* V4L2 controls supported by the driver */ | |
48 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); | |
49 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); | |
50 | static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); | |
51 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); | |
52 | ||
53 | static struct ctrl sd_ctrls[] = { | |
54 | #define SD_BRIGHTNESS 0 | |
55 | { | |
56 | { | |
57 | .id = V4L2_CID_BRIGHTNESS, | |
58 | .type = V4L2_CTRL_TYPE_INTEGER, | |
59 | .name = "Brightness", | |
60 | .minimum = 1, | |
61 | .maximum = 0x2ff, | |
62 | .step = 1, | |
63 | .default_value = 0x18f, | |
64 | }, | |
65 | .set = sd_setbrightness, | |
66 | .get = sd_getbrightness, | |
67 | }, | |
68 | #define SD_CONTRAST 1 | |
69 | { | |
70 | { | |
71 | .id = V4L2_CID_CONTRAST, | |
72 | .type = V4L2_CTRL_TYPE_INTEGER, | |
73 | .name = "Contrast", | |
74 | .minimum = 0, | |
75 | .maximum = 0xffff, | |
76 | .step = 1, | |
77 | .default_value = 0x7fff, | |
78 | }, | |
79 | .set = sd_setcontrast, | |
80 | .get = sd_getcontrast, | |
81 | }, | |
82 | }; | |
83 | ||
c2446b3e JFM |
84 | static struct v4l2_pix_format sif_mode[] = { |
85 | {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, | |
86 | .bytesperline = 176, | |
87 | .sizeimage = 176 * 144, | |
88 | .colorspace = V4L2_COLORSPACE_SRGB, | |
89 | .priv = 1}, | |
90 | {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, | |
91 | .bytesperline = 352, | |
92 | .sizeimage = 352 * 288, | |
93 | .colorspace = V4L2_COLORSPACE_SRGB, | |
94 | .priv = 0}, | |
6a7eba24 JFM |
95 | }; |
96 | ||
97 | /* | |
98 | * Initialization data: this is the first set-up data written to the | |
99 | * device (before the open data). | |
100 | */ | |
101 | #define TESTCLK 0x10 /* reg 0x2c -> 0x12 //10 */ | |
102 | #define TESTCOMP 0x90 /* reg 0x28 -> 0x80 */ | |
103 | #define TESTLINE 0x81 /* reg 0x29 -> 0x81 */ | |
104 | #define QCIFLINE 0x41 /* reg 0x29 -> 0x81 */ | |
105 | #define TESTPTL 0x14 /* reg 0x2D -> 0x14 */ | |
106 | #define TESTPTH 0x01 /* reg 0x2E -> 0x01 */ | |
107 | #define TESTPTBL 0x12 /* reg 0x2F -> 0x0a */ | |
108 | #define TESTPTBH 0x01 /* reg 0x30 -> 0x01 */ | |
109 | #define ADWIDTHL 0xe8 /* reg 0x0c -> 0xe8 */ | |
110 | #define ADWIDTHH 0x03 /* reg 0x0d -> 0x03 */ | |
111 | #define ADHEIGHL 0x90 /* reg 0x0e -> 0x91 //93 */ | |
112 | #define ADHEIGHH 0x01 /* reg 0x0f -> 0x01 */ | |
113 | #define EXPOL 0x8f /* reg 0x1c -> 0x8f */ | |
114 | #define EXPOH 0x01 /* reg 0x1d -> 0x01 */ | |
115 | #define ADCBEGINL 0x44 /* reg 0x10 -> 0x46 //47 */ | |
116 | #define ADCBEGINH 0x00 /* reg 0x11 -> 0x00 */ | |
117 | #define ADRBEGINL 0x0a /* reg 0x14 -> 0x0b //0x0c */ | |
118 | #define ADRBEGINH 0x00 /* reg 0x15 -> 0x00 */ | |
119 | #define TV8532_CMD_UPDATE 0x84 | |
120 | ||
121 | #define TV8532_EEprom_Add 0x03 | |
122 | #define TV8532_EEprom_DataL 0x04 | |
123 | #define TV8532_EEprom_DataM 0x05 | |
124 | #define TV8532_EEprom_DataH 0x06 | |
125 | #define TV8532_EEprom_TableLength 0x07 | |
126 | #define TV8532_EEprom_Write 0x08 | |
127 | #define TV8532_PART_CTRL 0x00 | |
128 | #define TV8532_CTRL 0x01 | |
129 | #define TV8532_CMD_EEprom_Open 0x30 | |
130 | #define TV8532_CMD_EEprom_Close 0x29 | |
131 | #define TV8532_UDP_UPDATE 0x31 | |
132 | #define TV8532_GPIO 0x39 | |
133 | #define TV8532_GPIO_OE 0x3B | |
134 | #define TV8532_REQ_RegWrite 0x02 | |
135 | #define TV8532_REQ_RegRead 0x03 | |
136 | ||
137 | #define TV8532_ADWIDTH_L 0x0C | |
138 | #define TV8532_ADWIDTH_H 0x0D | |
139 | #define TV8532_ADHEIGHT_L 0x0E | |
140 | #define TV8532_ADHEIGHT_H 0x0F | |
141 | #define TV8532_EXPOSURE 0x1C | |
142 | #define TV8532_QUANT_COMP 0x28 | |
143 | #define TV8532_MODE_PACKET 0x29 | |
144 | #define TV8532_SETCLK 0x2C | |
145 | #define TV8532_POINT_L 0x2D | |
146 | #define TV8532_POINT_H 0x2E | |
147 | #define TV8532_POINTB_L 0x2F | |
148 | #define TV8532_POINTB_H 0x30 | |
149 | #define TV8532_BUDGET_L 0x2A | |
150 | #define TV8532_BUDGET_H 0x2B | |
151 | #define TV8532_VID_L 0x34 | |
152 | #define TV8532_VID_H 0x35 | |
153 | #define TV8532_PID_L 0x36 | |
154 | #define TV8532_PID_H 0x37 | |
155 | #define TV8532_DeviceID 0x83 | |
156 | #define TV8532_AD_SLOPE 0x91 | |
157 | #define TV8532_AD_BITCTRL 0x94 | |
158 | #define TV8532_AD_COLBEGIN_L 0x10 | |
159 | #define TV8532_AD_COLBEGIN_H 0x11 | |
160 | #define TV8532_AD_ROWBEGIN_L 0x14 | |
161 | #define TV8532_AD_ROWBEGIN_H 0x15 | |
162 | ||
a5ae2062 | 163 | static const __u32 tv_8532_eeprom_data[] = { |
6a7eba24 JFM |
164 | /* add dataL dataM dataH */ |
165 | 0x00010001, 0x01018011, 0x02050014, 0x0305001c, | |
166 | 0x040d001e, 0x0505001f, 0x06050519, 0x0705011b, | |
167 | 0x0805091e, 0x090d892e, 0x0a05892f, 0x0b050dd9, | |
168 | 0x0c0509f1, 0 | |
169 | }; | |
170 | ||
739570bb JFM |
171 | static int reg_r(struct gspca_dev *gspca_dev, |
172 | __u16 index) | |
6a7eba24 | 173 | { |
739570bb JFM |
174 | usb_control_msg(gspca_dev->dev, |
175 | usb_rcvctrlpipe(gspca_dev->dev, 0), | |
6a7eba24 JFM |
176 | TV8532_REQ_RegRead, |
177 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
178 | 0, /* value */ | |
739570bb | 179 | index, gspca_dev->usb_buf, 1, |
6a7eba24 | 180 | 500); |
739570bb | 181 | return gspca_dev->usb_buf[0]; |
6a7eba24 JFM |
182 | } |
183 | ||
739570bb JFM |
184 | /* write 1 byte */ |
185 | static void reg_w_1(struct gspca_dev *gspca_dev, | |
186 | __u16 index, __u8 value) | |
6a7eba24 | 187 | { |
739570bb JFM |
188 | gspca_dev->usb_buf[0] = value; |
189 | usb_control_msg(gspca_dev->dev, | |
190 | usb_sndctrlpipe(gspca_dev->dev, 0), | |
6a7eba24 JFM |
191 | TV8532_REQ_RegWrite, |
192 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
193 | 0, /* value */ | |
739570bb JFM |
194 | index, gspca_dev->usb_buf, 1, 500); |
195 | } | |
196 | ||
197 | /* write 2 bytes */ | |
198 | static void reg_w_2(struct gspca_dev *gspca_dev, | |
199 | __u16 index, __u8 val1, __u8 val2) | |
200 | { | |
201 | gspca_dev->usb_buf[0] = val1; | |
202 | gspca_dev->usb_buf[1] = val2; | |
203 | usb_control_msg(gspca_dev->dev, | |
204 | usb_sndctrlpipe(gspca_dev->dev, 0), | |
205 | TV8532_REQ_RegWrite, | |
206 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
207 | 0, /* value */ | |
208 | index, gspca_dev->usb_buf, 2, 500); | |
6a7eba24 JFM |
209 | } |
210 | ||
211 | static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev) | |
212 | { | |
213 | int i = 0; | |
739570bb | 214 | __u8 reg, data0, data1, data2; |
6a7eba24 | 215 | |
739570bb JFM |
216 | reg_w_1(gspca_dev, TV8532_GPIO, 0xb0); |
217 | reg_w_1(gspca_dev, TV8532_CTRL, TV8532_CMD_EEprom_Open); | |
6a7eba24 JFM |
218 | /* msleep(1); */ |
219 | while (tv_8532_eeprom_data[i]) { | |
220 | reg = (tv_8532_eeprom_data[i] & 0xff000000) >> 24; | |
739570bb | 221 | reg_w_1(gspca_dev, TV8532_EEprom_Add, reg); |
6a7eba24 JFM |
222 | /* msleep(1); */ |
223 | data0 = (tv_8532_eeprom_data[i] & 0x000000ff); | |
739570bb | 224 | reg_w_1(gspca_dev, TV8532_EEprom_DataL, data0); |
6a7eba24 | 225 | /* msleep(1); */ |
739570bb JFM |
226 | data1 = (tv_8532_eeprom_data[i] & 0x0000ff00) >> 8; |
227 | reg_w_1(gspca_dev, TV8532_EEprom_DataM, data1); | |
6a7eba24 | 228 | /* msleep(1); */ |
739570bb JFM |
229 | data2 = (tv_8532_eeprom_data[i] & 0x00ff0000) >> 16; |
230 | reg_w_1(gspca_dev, TV8532_EEprom_DataH, data2); | |
6a7eba24 | 231 | /* msleep(1); */ |
739570bb | 232 | reg_w_1(gspca_dev, TV8532_EEprom_Write, 0); |
6a7eba24 JFM |
233 | /* msleep(10); */ |
234 | i++; | |
235 | } | |
739570bb | 236 | reg_w_1(gspca_dev, TV8532_EEprom_TableLength, i); |
6a7eba24 | 237 | /* msleep(1); */ |
739570bb | 238 | reg_w_1(gspca_dev, TV8532_CTRL, TV8532_CMD_EEprom_Close); |
6a7eba24 JFM |
239 | msleep(10); |
240 | } | |
241 | ||
242 | /* this function is called at probe time */ | |
243 | static int sd_config(struct gspca_dev *gspca_dev, | |
244 | const struct usb_device_id *id) | |
245 | { | |
246 | struct sd *sd = (struct sd *) gspca_dev; | |
247 | struct cam *cam; | |
248 | ||
249 | tv_8532WriteEEprom(gspca_dev); | |
250 | ||
251 | cam = &gspca_dev->cam; | |
252 | cam->dev_name = (char *) id->driver_info; | |
253 | cam->epaddr = 1; | |
254 | cam->cam_mode = sif_mode; | |
255 | cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; | |
256 | ||
257 | sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; | |
258 | sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; | |
259 | return 0; | |
260 | } | |
261 | ||
262 | static void tv_8532ReadRegisters(struct gspca_dev *gspca_dev) | |
263 | { | |
a5ae2062 | 264 | __u8 data; |
6a7eba24 | 265 | |
739570bb | 266 | data = reg_r(gspca_dev, 0x0001); |
6a7eba24 | 267 | PDEBUG(D_USBI, "register 0x01-> %x", data); |
739570bb | 268 | data = reg_r(gspca_dev, 0x0002); |
6a7eba24 | 269 | PDEBUG(D_USBI, "register 0x02-> %x", data); |
739570bb JFM |
270 | reg_r(gspca_dev, TV8532_ADWIDTH_L); |
271 | reg_r(gspca_dev, TV8532_ADWIDTH_H); | |
272 | reg_r(gspca_dev, TV8532_QUANT_COMP); | |
273 | reg_r(gspca_dev, TV8532_MODE_PACKET); | |
274 | reg_r(gspca_dev, TV8532_SETCLK); | |
275 | reg_r(gspca_dev, TV8532_POINT_L); | |
276 | reg_r(gspca_dev, TV8532_POINT_H); | |
277 | reg_r(gspca_dev, TV8532_POINTB_L); | |
278 | reg_r(gspca_dev, TV8532_POINTB_H); | |
279 | reg_r(gspca_dev, TV8532_BUDGET_L); | |
280 | reg_r(gspca_dev, TV8532_BUDGET_H); | |
281 | reg_r(gspca_dev, TV8532_VID_L); | |
282 | reg_r(gspca_dev, TV8532_VID_H); | |
283 | reg_r(gspca_dev, TV8532_PID_L); | |
284 | reg_r(gspca_dev, TV8532_PID_H); | |
285 | reg_r(gspca_dev, TV8532_DeviceID); | |
286 | reg_r(gspca_dev, TV8532_AD_COLBEGIN_L); | |
287 | reg_r(gspca_dev, TV8532_AD_COLBEGIN_H); | |
288 | reg_r(gspca_dev, TV8532_AD_ROWBEGIN_L); | |
289 | reg_r(gspca_dev, TV8532_AD_ROWBEGIN_H); | |
6a7eba24 JFM |
290 | } |
291 | ||
292 | static void tv_8532_setReg(struct gspca_dev *gspca_dev) | |
293 | { | |
739570bb JFM |
294 | reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_L, |
295 | ADCBEGINL); /* 0x10 */ | |
296 | reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_H, | |
297 | ADCBEGINH); /* also digital gain */ | |
298 | reg_w_1(gspca_dev, TV8532_PART_CTRL, | |
299 | TV8532_CMD_UPDATE); /* 0x00<-0x84 */ | |
300 | ||
301 | reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0a); | |
6a7eba24 | 302 | /******************************************************/ |
739570bb JFM |
303 | reg_w_1(gspca_dev, TV8532_ADHEIGHT_L, ADHEIGHL); /* 0e */ |
304 | reg_w_1(gspca_dev, TV8532_ADHEIGHT_H, ADHEIGHH); /* 0f */ | |
305 | reg_w_2(gspca_dev, TV8532_EXPOSURE, | |
306 | EXPOL, EXPOH); /* 350d 0x014c; 1c */ | |
307 | reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_L, | |
308 | ADCBEGINL); /* 0x10 */ | |
309 | reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_H, | |
310 | ADCBEGINH); /* also digital gain */ | |
311 | reg_w_1(gspca_dev, TV8532_AD_ROWBEGIN_L, | |
312 | ADRBEGINL); /* 0x14 */ | |
313 | ||
314 | reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x00); /* 0x91 */ | |
315 | reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x02); /* 0x94 */ | |
316 | ||
317 | reg_w_1(gspca_dev, TV8532_CTRL, | |
318 | TV8532_CMD_EEprom_Close); /* 0x01 */ | |
319 | ||
320 | reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x00); /* 0x91 */ | |
321 | reg_w_1(gspca_dev, TV8532_PART_CTRL, | |
322 | TV8532_CMD_UPDATE); /* 0x00<-0x84 */ | |
6a7eba24 JFM |
323 | } |
324 | ||
325 | static void tv_8532_PollReg(struct gspca_dev *gspca_dev) | |
326 | { | |
6a7eba24 JFM |
327 | int i; |
328 | ||
329 | /* strange polling from tgc */ | |
330 | for (i = 0; i < 10; i++) { | |
739570bb JFM |
331 | reg_w_1(gspca_dev, TV8532_SETCLK, |
332 | TESTCLK); /* 0x48; //0x08; 0x2c */ | |
333 | reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE); | |
334 | reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01); /* 0x31 */ | |
6a7eba24 JFM |
335 | } |
336 | } | |
337 | ||
338 | /* this function is called at open time */ | |
339 | static int sd_open(struct gspca_dev *gspca_dev) | |
340 | { | |
739570bb JFM |
341 | reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32); |
342 | reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00); | |
6a7eba24 | 343 | tv_8532ReadRegisters(gspca_dev); |
739570bb JFM |
344 | reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); |
345 | reg_w_2(gspca_dev, TV8532_ADHEIGHT_L, ADHEIGHL, | |
346 | ADHEIGHH); /* 401d 0x0169; 0e */ | |
347 | reg_w_2(gspca_dev, TV8532_EXPOSURE, EXPOL, | |
348 | EXPOH); /* 350d 0x014c; 1c */ | |
349 | reg_w_1(gspca_dev, TV8532_ADWIDTH_L, ADWIDTHL); /* 0x20; 0x0c */ | |
350 | reg_w_1(gspca_dev, TV8532_ADWIDTH_H, ADWIDTHH); /* 0x0d */ | |
6a7eba24 JFM |
351 | |
352 | /*******************************************************************/ | |
739570bb JFM |
353 | reg_w_1(gspca_dev, TV8532_QUANT_COMP, |
354 | TESTCOMP); /* 0x72 compressed mode 0x28 */ | |
355 | reg_w_1(gspca_dev, TV8532_MODE_PACKET, | |
356 | TESTLINE); /* 0x84; // CIF | 4 packet 0x29 */ | |
6a7eba24 JFM |
357 | |
358 | /************************************************/ | |
739570bb JFM |
359 | reg_w_1(gspca_dev, TV8532_SETCLK, |
360 | TESTCLK); /* 0x48; //0x08; 0x2c */ | |
361 | reg_w_1(gspca_dev, TV8532_POINT_L, | |
362 | TESTPTL); /* 0x38; 0x2d */ | |
363 | reg_w_1(gspca_dev, TV8532_POINT_H, | |
364 | TESTPTH); /* 0x04; 0x2e */ | |
365 | reg_w_1(gspca_dev, TV8532_POINTB_L, | |
366 | TESTPTBL); /* 0x04; 0x2f */ | |
367 | reg_w_1(gspca_dev, TV8532_POINTB_H, | |
368 | TESTPTBH); /* 0x04; 0x30 */ | |
369 | reg_w_1(gspca_dev, TV8532_PART_CTRL, | |
370 | TV8532_CMD_UPDATE); /* 0x00<-0x84 */ | |
6a7eba24 | 371 | /*************************************************/ |
739570bb | 372 | reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01); /* 0x31 */ |
6a7eba24 | 373 | msleep(200); |
739570bb | 374 | reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */ |
6a7eba24 JFM |
375 | /*************************************************/ |
376 | tv_8532_setReg(gspca_dev); | |
377 | /*************************************************/ | |
739570bb | 378 | reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); |
6a7eba24 JFM |
379 | /*************************************************/ |
380 | tv_8532_setReg(gspca_dev); | |
381 | /*************************************************/ | |
382 | tv_8532_PollReg(gspca_dev); | |
383 | return 0; | |
384 | } | |
385 | ||
386 | static void setbrightness(struct gspca_dev *gspca_dev) | |
387 | { | |
388 | struct sd *sd = (struct sd *) gspca_dev; | |
6a7eba24 JFM |
389 | int brightness = sd->brightness; |
390 | ||
739570bb JFM |
391 | reg_w_2(gspca_dev, TV8532_EXPOSURE, |
392 | brightness >> 8, brightness); /* 1c */ | |
393 | reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE); | |
6a7eba24 JFM |
394 | } |
395 | ||
396 | /* -- start the camera -- */ | |
397 | static void sd_start(struct gspca_dev *gspca_dev) | |
398 | { | |
739570bb JFM |
399 | reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32); |
400 | reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00); | |
6a7eba24 | 401 | tv_8532ReadRegisters(gspca_dev); |
739570bb JFM |
402 | reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); |
403 | reg_w_2(gspca_dev, TV8532_ADHEIGHT_L, | |
404 | ADHEIGHL, ADHEIGHH); /* 401d 0x0169; 0e */ | |
405 | /* reg_w_2(gspca_dev, TV8532_EXPOSURE, | |
406 | EXPOL, EXPOH); * 350d 0x014c; 1c */ | |
6a7eba24 JFM |
407 | setbrightness(gspca_dev); |
408 | ||
739570bb JFM |
409 | reg_w_1(gspca_dev, TV8532_ADWIDTH_L, ADWIDTHL); /* 0x20; 0x0c */ |
410 | reg_w_1(gspca_dev, TV8532_ADWIDTH_H, ADWIDTHH); /* 0x0d */ | |
6a7eba24 JFM |
411 | |
412 | /************************************************/ | |
739570bb JFM |
413 | reg_w_1(gspca_dev, TV8532_QUANT_COMP, |
414 | TESTCOMP); /* 0x72 compressed mode 0x28 */ | |
c2446b3e | 415 | if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { |
6a7eba24 | 416 | /* 176x144 */ |
739570bb JFM |
417 | reg_w_1(gspca_dev, TV8532_MODE_PACKET, |
418 | QCIFLINE); /* 0x84; // CIF | 4 packet 0x29 */ | |
6a7eba24 JFM |
419 | } else { |
420 | /* 352x288 */ | |
739570bb JFM |
421 | reg_w_1(gspca_dev, TV8532_MODE_PACKET, |
422 | TESTLINE); /* 0x84; // CIF | 4 packet 0x29 */ | |
6a7eba24 JFM |
423 | } |
424 | /************************************************/ | |
739570bb JFM |
425 | reg_w_1(gspca_dev, TV8532_SETCLK, |
426 | TESTCLK); /* 0x48; //0x08; 0x2c */ | |
427 | reg_w_1(gspca_dev, TV8532_POINT_L, | |
428 | TESTPTL); /* 0x38; 0x2d */ | |
429 | reg_w_1(gspca_dev, TV8532_POINT_H, | |
430 | TESTPTH); /* 0x04; 0x2e */ | |
431 | reg_w_1(gspca_dev, TV8532_POINTB_L, | |
432 | TESTPTBL); /* 0x04; 0x2f */ | |
433 | reg_w_1(gspca_dev, TV8532_POINTB_H, | |
434 | TESTPTBH); /* 0x04; 0x30 */ | |
435 | reg_w_1(gspca_dev, TV8532_PART_CTRL, | |
436 | TV8532_CMD_UPDATE); /* 0x00<-0x84 */ | |
6a7eba24 | 437 | /************************************************/ |
739570bb | 438 | reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01); /* 0x31 */ |
6a7eba24 | 439 | msleep(200); |
739570bb | 440 | reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */ |
6a7eba24 JFM |
441 | /************************************************/ |
442 | tv_8532_setReg(gspca_dev); | |
443 | /************************************************/ | |
739570bb | 444 | reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); |
6a7eba24 JFM |
445 | /************************************************/ |
446 | tv_8532_setReg(gspca_dev); | |
447 | /************************************************/ | |
448 | tv_8532_PollReg(gspca_dev); | |
739570bb | 449 | reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */ |
6a7eba24 JFM |
450 | } |
451 | ||
452 | static void sd_stopN(struct gspca_dev *gspca_dev) | |
453 | { | |
739570bb | 454 | reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); |
6a7eba24 JFM |
455 | } |
456 | ||
457 | static void sd_stop0(struct gspca_dev *gspca_dev) | |
458 | { | |
459 | } | |
460 | ||
461 | static void sd_close(struct gspca_dev *gspca_dev) | |
462 | { | |
463 | } | |
464 | ||
465 | static void tv8532_preprocess(struct gspca_dev *gspca_dev) | |
466 | { | |
467 | struct sd *sd = (struct sd *) gspca_dev; | |
468 | /* we should received a whole frame with header and EOL marker | |
469 | * in gspca_dev->tmpbuf and return a GBRG pattern in gspca_dev->tmpbuf2 | |
470 | * sequence 2bytes header the Alternate pixels bayer GB 4 bytes | |
471 | * Alternate pixels bayer RG 4 bytes EOL */ | |
472 | int width = gspca_dev->width; | |
473 | int height = gspca_dev->height; | |
474 | unsigned char *dst = sd->tmpbuf2; | |
475 | unsigned char *data = sd->tmpbuf; | |
476 | int i; | |
477 | ||
478 | /* precompute where is the good bayer line */ | |
479 | if (((data[3] + data[width + 7]) >> 1) | |
480 | + (data[4] >> 2) | |
481 | + (data[width + 6] >> 1) >= ((data[2] + data[width + 6]) >> 1) | |
482 | + (data[3] >> 2) | |
483 | + (data[width + 5] >> 1)) | |
484 | data += 3; | |
485 | else | |
486 | data += 2; | |
487 | for (i = 0; i < height / 2; i++) { | |
488 | memcpy(dst, data, width); | |
489 | data += width + 3; | |
490 | dst += width; | |
491 | memcpy(dst, data, width); | |
492 | data += width + 7; | |
493 | dst += width; | |
494 | } | |
495 | } | |
496 | ||
497 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |
498 | struct gspca_frame *frame, /* target */ | |
499 | __u8 *data, /* isoc packet */ | |
500 | int len) /* iso packet length */ | |
501 | { | |
502 | struct sd *sd = (struct sd *) gspca_dev; | |
503 | ||
504 | if (data[0] != 0x80) { | |
505 | sd->packet++; | |
506 | if (sd->buflen + len > sizeof sd->tmpbuf) { | |
507 | if (gspca_dev->last_packet_type != DISCARD_PACKET) { | |
508 | PDEBUG(D_PACK, "buffer overflow"); | |
509 | gspca_dev->last_packet_type = DISCARD_PACKET; | |
510 | } | |
511 | return; | |
512 | } | |
513 | memcpy(&sd->tmpbuf[sd->buflen], data, len); | |
514 | sd->buflen += len; | |
515 | return; | |
516 | } | |
517 | ||
518 | /* here we detect 0x80 */ | |
519 | /* counter is limited so we need few header for a frame :) */ | |
520 | ||
521 | /* header 0x80 0x80 0x80 0x80 0x80 */ | |
522 | /* packet 00 63 127 145 00 */ | |
523 | /* sof 0 1 1 0 0 */ | |
524 | ||
525 | /* update sequence */ | |
526 | if (sd->packet == 63 || sd->packet == 127) | |
527 | sd->synchro = 1; | |
528 | ||
529 | /* is there a frame start ? */ | |
530 | if (sd->packet >= (gspca_dev->height >> 1) - 1) { | |
531 | PDEBUG(D_PACK, "SOF > %d packet %d", sd->synchro, | |
532 | sd->packet); | |
533 | if (!sd->synchro) { /* start of frame */ | |
534 | if (gspca_dev->last_packet_type == FIRST_PACKET) { | |
535 | tv8532_preprocess(gspca_dev); | |
536 | frame = gspca_frame_add(gspca_dev, | |
537 | LAST_PACKET, | |
538 | frame, sd->tmpbuf2, | |
539 | gspca_dev->width * | |
540 | gspca_dev->width); | |
541 | } | |
542 | gspca_frame_add(gspca_dev, FIRST_PACKET, | |
543 | frame, data, 0); | |
544 | memcpy(sd->tmpbuf, data, len); | |
545 | sd->buflen = len; | |
546 | sd->packet = 0; | |
547 | return; | |
548 | } | |
549 | if (gspca_dev->last_packet_type != DISCARD_PACKET) { | |
550 | PDEBUG(D_PACK, | |
551 | "Warning wrong TV8532 frame detection %d", | |
552 | sd->packet); | |
553 | gspca_dev->last_packet_type = DISCARD_PACKET; | |
554 | } | |
555 | return; | |
556 | } | |
557 | ||
558 | if (!sd->synchro) { | |
559 | /* Drop packet frame corrupt */ | |
560 | PDEBUG(D_PACK, "DROP SOF %d packet %d", | |
561 | sd->synchro, sd->packet); | |
562 | sd->packet = 0; | |
563 | gspca_dev->last_packet_type = DISCARD_PACKET; | |
564 | return; | |
565 | } | |
566 | sd->synchro = 1; | |
567 | sd->packet++; | |
568 | memcpy(&sd->tmpbuf[sd->buflen], data, len); | |
569 | sd->buflen += len; | |
570 | } | |
571 | ||
572 | static void setcontrast(struct gspca_dev *gspca_dev) | |
573 | { | |
574 | } | |
575 | ||
576 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) | |
577 | { | |
578 | struct sd *sd = (struct sd *) gspca_dev; | |
579 | ||
580 | sd->brightness = val; | |
581 | if (gspca_dev->streaming) | |
582 | setbrightness(gspca_dev); | |
583 | return 0; | |
584 | } | |
585 | ||
586 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) | |
587 | { | |
588 | struct sd *sd = (struct sd *) gspca_dev; | |
589 | ||
590 | *val = sd->brightness; | |
591 | return 0; | |
592 | } | |
593 | ||
594 | static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) | |
595 | { | |
596 | struct sd *sd = (struct sd *) gspca_dev; | |
597 | ||
598 | sd->contrast = val; | |
599 | if (gspca_dev->streaming) | |
600 | setcontrast(gspca_dev); | |
601 | return 0; | |
602 | } | |
603 | ||
604 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) | |
605 | { | |
606 | struct sd *sd = (struct sd *) gspca_dev; | |
607 | ||
608 | *val = sd->contrast; | |
609 | return 0; | |
610 | } | |
611 | ||
612 | /* sub-driver description */ | |
a5ae2062 | 613 | static const struct sd_desc sd_desc = { |
6a7eba24 JFM |
614 | .name = MODULE_NAME, |
615 | .ctrls = sd_ctrls, | |
616 | .nctrls = ARRAY_SIZE(sd_ctrls), | |
617 | .config = sd_config, | |
618 | .open = sd_open, | |
619 | .start = sd_start, | |
620 | .stopN = sd_stopN, | |
621 | .stop0 = sd_stop0, | |
622 | .close = sd_close, | |
623 | .pkt_scan = sd_pkt_scan, | |
624 | }; | |
625 | ||
626 | /* -- module initialisation -- */ | |
627 | #define DVNM(name) .driver_info = (kernel_ulong_t) name | |
a5ae2062 | 628 | static const __devinitdata struct usb_device_id device_table[] = { |
6a7eba24 JFM |
629 | {USB_DEVICE(0x046d, 0x0920), DVNM("QC Express")}, |
630 | {USB_DEVICE(0x046d, 0x0921), DVNM("Labtec Webcam")}, | |
631 | {USB_DEVICE(0x0545, 0x808b), DVNM("Veo Stingray")}, | |
632 | {USB_DEVICE(0x0545, 0x8333), DVNM("Veo Stingray")}, | |
633 | {USB_DEVICE(0x0923, 0x010f), DVNM("ICM532 cams")}, | |
634 | {} | |
635 | }; | |
636 | ||
637 | MODULE_DEVICE_TABLE(usb, device_table); | |
638 | ||
639 | /* -- device connect -- */ | |
640 | static int sd_probe(struct usb_interface *intf, | |
641 | const struct usb_device_id *id) | |
642 | { | |
643 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | |
644 | THIS_MODULE); | |
645 | } | |
646 | ||
647 | static struct usb_driver sd_driver = { | |
648 | .name = MODULE_NAME, | |
649 | .id_table = device_table, | |
650 | .probe = sd_probe, | |
651 | .disconnect = gspca_disconnect, | |
652 | }; | |
653 | ||
654 | /* -- module insert / remove -- */ | |
655 | static int __init sd_mod_init(void) | |
656 | { | |
657 | if (usb_register(&sd_driver) < 0) | |
658 | return -1; | |
659 | PDEBUG(D_PROBE, "v%s registered", version); | |
660 | return 0; | |
661 | } | |
662 | ||
663 | static void __exit sd_mod_exit(void) | |
664 | { | |
665 | usb_deregister(&sd_driver); | |
666 | PDEBUG(D_PROBE, "deregistered"); | |
667 | } | |
668 | ||
669 | module_init(sd_mod_init); | |
670 | module_exit(sd_mod_exit); |