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