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 | 33 | __u16 brightness; |
6a7eba24 | 34 | |
ba13cca7 | 35 | __u8 packet; |
6a7eba24 JFM |
36 | }; |
37 | ||
38 | /* V4L2 controls supported by the driver */ | |
39 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); | |
40 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); | |
6a7eba24 JFM |
41 | |
42 | static struct ctrl sd_ctrls[] = { | |
6a7eba24 JFM |
43 | { |
44 | { | |
45 | .id = V4L2_CID_BRIGHTNESS, | |
46 | .type = V4L2_CTRL_TYPE_INTEGER, | |
47 | .name = "Brightness", | |
48 | .minimum = 1, | |
49 | .maximum = 0x2ff, | |
50 | .step = 1, | |
ca5e578f JFM |
51 | #define BRIGHTNESS_DEF 0x18f |
52 | .default_value = BRIGHTNESS_DEF, | |
6a7eba24 JFM |
53 | }, |
54 | .set = sd_setbrightness, | |
55 | .get = sd_getbrightness, | |
56 | }, | |
6a7eba24 JFM |
57 | }; |
58 | ||
cc611b8a | 59 | static const struct v4l2_pix_format sif_mode[] = { |
c2446b3e JFM |
60 | {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, |
61 | .bytesperline = 176, | |
62 | .sizeimage = 176 * 144, | |
63 | .colorspace = V4L2_COLORSPACE_SRGB, | |
64 | .priv = 1}, | |
65 | {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, | |
66 | .bytesperline = 352, | |
67 | .sizeimage = 352 * 288, | |
68 | .colorspace = V4L2_COLORSPACE_SRGB, | |
69 | .priv = 0}, | |
6a7eba24 JFM |
70 | }; |
71 | ||
ca5e578f JFM |
72 | /* TV-8532A (ICM532A) registers (LE) */ |
73 | #define R00_PART_CONTROL 0x00 | |
74 | #define LATENT_CHANGE 0x80 | |
75 | #define EXPO_CHANGE 0x04 | |
76 | #define R01_TIMING_CONTROL_LOW 0x01 | |
77 | #define CMD_EEprom_Open 0x30 | |
78 | #define CMD_EEprom_Close 0x29 | |
79 | #define R03_TABLE_ADDR 0x03 | |
80 | #define R04_WTRAM_DATA_L 0x04 | |
81 | #define R05_WTRAM_DATA_M 0x05 | |
82 | #define R06_WTRAM_DATA_H 0x06 | |
83 | #define R07_TABLE_LEN 0x07 | |
84 | #define R08_RAM_WRITE_ACTION 0x08 | |
85 | #define R0C_AD_WIDTHL 0x0c | |
86 | #define R0D_AD_WIDTHH 0x0d | |
87 | #define R0E_AD_HEIGHTL 0x0e | |
88 | #define R0F_AD_HEIGHTH 0x0f | |
89 | #define R10_AD_COL_BEGINL 0x10 | |
90 | #define R11_AD_COL_BEGINH 0x11 | |
91 | #define MIRROR 0x04 /* [10] */ | |
92 | #define R14_AD_ROW_BEGINL 0x14 | |
93 | #define R15_AD_ROWBEGINH 0x15 | |
94 | #define R1C_AD_EXPOSE_TIMEL 0x1c | |
95 | #define R28_QUANT 0x28 | |
96 | #define R29_LINE 0x29 | |
97 | #define R2C_POLARITY 0x2c | |
98 | #define R2D_POINT 0x2d | |
99 | #define R2E_POINTH 0x2e | |
100 | #define R2F_POINTB 0x2f | |
101 | #define R30_POINTBH 0x30 | |
102 | #define R31_UPD 0x31 | |
103 | #define R2A_HIGH_BUDGET 0x2a | |
104 | #define R2B_LOW_BUDGET 0x2b | |
105 | #define R34_VID 0x34 | |
106 | #define R35_VIDH 0x35 | |
107 | #define R36_PID 0x36 | |
108 | #define R37_PIDH 0x37 | |
109 | #define R39_Test1 0x39 /* GPIO */ | |
110 | #define R3B_Test3 0x3B /* GPIO */ | |
111 | #define R83_AD_IDH 0x83 | |
112 | #define R91_AD_SLOPEREG 0x91 | |
113 | #define R94_AD_BITCONTROL 0x94 | |
114 | ||
115 | static const u8 eeprom_data[][3] = { | |
116 | /* dataH dataM dataL */ | |
117 | {0x01, 0x00, 0x01}, | |
118 | {0x01, 0x80, 0x11}, | |
119 | {0x05, 0x00, 0x14}, | |
120 | {0x05, 0x00, 0x1c}, | |
121 | {0x0d, 0x00, 0x1e}, | |
122 | {0x05, 0x00, 0x1f}, | |
123 | {0x05, 0x05, 0x19}, | |
124 | {0x05, 0x01, 0x1b}, | |
125 | {0x05, 0x09, 0x1e}, | |
126 | {0x0d, 0x89, 0x2e}, | |
127 | {0x05, 0x89, 0x2f}, | |
128 | {0x05, 0x0d, 0xd9}, | |
129 | {0x05, 0x09, 0xf1}, | |
6a7eba24 JFM |
130 | }; |
131 | ||
739570bb JFM |
132 | static int reg_r(struct gspca_dev *gspca_dev, |
133 | __u16 index) | |
6a7eba24 | 134 | { |
739570bb JFM |
135 | usb_control_msg(gspca_dev->dev, |
136 | usb_rcvctrlpipe(gspca_dev->dev, 0), | |
ca5e578f | 137 | 0x03, |
6a7eba24 JFM |
138 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
139 | 0, /* value */ | |
739570bb | 140 | index, gspca_dev->usb_buf, 1, |
6a7eba24 | 141 | 500); |
739570bb | 142 | return gspca_dev->usb_buf[0]; |
6a7eba24 JFM |
143 | } |
144 | ||
739570bb | 145 | /* write 1 byte */ |
ca5e578f | 146 | static void reg_w1(struct gspca_dev *gspca_dev, |
739570bb | 147 | __u16 index, __u8 value) |
6a7eba24 | 148 | { |
739570bb JFM |
149 | gspca_dev->usb_buf[0] = value; |
150 | usb_control_msg(gspca_dev->dev, | |
151 | usb_sndctrlpipe(gspca_dev->dev, 0), | |
ca5e578f | 152 | 0x02, |
6a7eba24 JFM |
153 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
154 | 0, /* value */ | |
739570bb JFM |
155 | index, gspca_dev->usb_buf, 1, 500); |
156 | } | |
157 | ||
158 | /* write 2 bytes */ | |
ca5e578f JFM |
159 | static void reg_w2(struct gspca_dev *gspca_dev, |
160 | u16 index, u16 value) | |
739570bb | 161 | { |
ca5e578f JFM |
162 | gspca_dev->usb_buf[0] = value; |
163 | gspca_dev->usb_buf[1] = value >> 8; | |
739570bb JFM |
164 | usb_control_msg(gspca_dev->dev, |
165 | usb_sndctrlpipe(gspca_dev->dev, 0), | |
ca5e578f | 166 | 0x02, |
739570bb JFM |
167 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
168 | 0, /* value */ | |
169 | index, gspca_dev->usb_buf, 2, 500); | |
6a7eba24 JFM |
170 | } |
171 | ||
172 | static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev) | |
173 | { | |
ca5e578f JFM |
174 | int i; |
175 | ||
176 | reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Open); | |
177 | for (i = 0; i < ARRAY_SIZE(eeprom_data); i++) { | |
178 | reg_w1(gspca_dev, R03_TABLE_ADDR, i); | |
179 | reg_w1(gspca_dev, R04_WTRAM_DATA_L, eeprom_data[i][2]); | |
180 | reg_w1(gspca_dev, R05_WTRAM_DATA_M, eeprom_data[i][1]); | |
181 | reg_w1(gspca_dev, R06_WTRAM_DATA_H, eeprom_data[i][0]); | |
182 | reg_w1(gspca_dev, R08_RAM_WRITE_ACTION, 0); | |
6a7eba24 | 183 | } |
ca5e578f JFM |
184 | reg_w1(gspca_dev, R07_TABLE_LEN, i); |
185 | reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close); | |
6a7eba24 JFM |
186 | msleep(10); |
187 | } | |
188 | ||
189 | /* this function is called at probe time */ | |
190 | static int sd_config(struct gspca_dev *gspca_dev, | |
191 | const struct usb_device_id *id) | |
192 | { | |
193 | struct sd *sd = (struct sd *) gspca_dev; | |
194 | struct cam *cam; | |
195 | ||
6a7eba24 | 196 | cam = &gspca_dev->cam; |
6a7eba24 | 197 | cam->cam_mode = sif_mode; |
ca5e578f | 198 | cam->nmodes = ARRAY_SIZE(sif_mode); |
6a7eba24 | 199 | |
ca5e578f | 200 | sd->brightness = BRIGHTNESS_DEF; |
6a7eba24 JFM |
201 | return 0; |
202 | } | |
203 | ||
204 | static void tv_8532ReadRegisters(struct gspca_dev *gspca_dev) | |
205 | { | |
ca5e578f JFM |
206 | int i; |
207 | static u8 reg_tb[] = { | |
208 | R0C_AD_WIDTHL, | |
209 | R0D_AD_WIDTHH, | |
210 | R28_QUANT, | |
211 | R29_LINE, | |
212 | R2C_POLARITY, | |
213 | R2D_POINT, | |
214 | R2E_POINTH, | |
215 | R2F_POINTB, | |
216 | R30_POINTBH, | |
217 | R2A_HIGH_BUDGET, | |
218 | R2B_LOW_BUDGET, | |
219 | R34_VID, | |
220 | R35_VIDH, | |
221 | R36_PID, | |
222 | R37_PIDH, | |
223 | R83_AD_IDH, | |
224 | R10_AD_COL_BEGINL, | |
225 | R11_AD_COL_BEGINH, | |
226 | R14_AD_ROW_BEGINL, | |
227 | R15_AD_ROWBEGINH, | |
228 | 0 | |
229 | }; | |
230 | ||
231 | i = 0; | |
232 | do { | |
233 | reg_r(gspca_dev, reg_tb[i]); | |
234 | i++; | |
235 | } while (reg_tb[i] != 0); | |
6a7eba24 JFM |
236 | } |
237 | ||
238 | static void tv_8532_setReg(struct gspca_dev *gspca_dev) | |
239 | { | |
ca5e578f JFM |
240 | reg_w1(gspca_dev, R10_AD_COL_BEGINL, 0x44); |
241 | /* begin active line */ | |
242 | reg_w1(gspca_dev, R11_AD_COL_BEGINH, 0x00); | |
243 | /* mirror and digital gain */ | |
244 | reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE); | |
245 | /* = 0x84 */ | |
246 | ||
247 | reg_w1(gspca_dev, R3B_Test3, 0x0a); /* Test0Sel = 10 */ | |
6a7eba24 | 248 | /******************************************************/ |
ca5e578f JFM |
249 | reg_w1(gspca_dev, R0E_AD_HEIGHTL, 0x90); |
250 | reg_w1(gspca_dev, R0F_AD_HEIGHTH, 0x01); | |
251 | reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, 0x018f); | |
252 | reg_w1(gspca_dev, R10_AD_COL_BEGINL, 0x44); | |
253 | /* begin active line */ | |
254 | reg_w1(gspca_dev, R11_AD_COL_BEGINH, 0x00); | |
255 | /* mirror and digital gain */ | |
256 | reg_w1(gspca_dev, R14_AD_ROW_BEGINL, 0x0a); | |
257 | ||
258 | reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00); | |
259 | reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x02); | |
260 | ||
261 | reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close); | |
262 | ||
263 | reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00); | |
264 | reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE); | |
265 | /* = 0x84 */ | |
6a7eba24 JFM |
266 | } |
267 | ||
268 | static void tv_8532_PollReg(struct gspca_dev *gspca_dev) | |
269 | { | |
6a7eba24 JFM |
270 | int i; |
271 | ||
272 | /* strange polling from tgc */ | |
273 | for (i = 0; i < 10; i++) { | |
ca5e578f JFM |
274 | reg_w1(gspca_dev, R2C_POLARITY, 0x10); |
275 | reg_w1(gspca_dev, R00_PART_CONTROL, | |
276 | LATENT_CHANGE | EXPO_CHANGE); | |
277 | reg_w1(gspca_dev, R31_UPD, 0x01); | |
6a7eba24 JFM |
278 | } |
279 | } | |
280 | ||
012d6b02 JFM |
281 | /* this function is called at probe and resume time */ |
282 | static int sd_init(struct gspca_dev *gspca_dev) | |
6a7eba24 | 283 | { |
ca5e578f JFM |
284 | tv_8532WriteEEprom(gspca_dev); |
285 | ||
286 | reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32); /* slope begin 1,7V, | |
287 | * slope rate 2 */ | |
288 | reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00); | |
6a7eba24 | 289 | tv_8532ReadRegisters(gspca_dev); |
ca5e578f JFM |
290 | reg_w1(gspca_dev, R3B_Test3, 0x0b); |
291 | reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190); | |
292 | reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, 0x018f); | |
293 | reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8); | |
294 | reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03); | |
6a7eba24 JFM |
295 | |
296 | /*******************************************************************/ | |
ca5e578f JFM |
297 | reg_w1(gspca_dev, R28_QUANT, 0x90); |
298 | /* no compress - fixed Q - quant 0 */ | |
299 | reg_w1(gspca_dev, R29_LINE, 0x81); | |
300 | /* 0x84; // CIF | 4 packet 0x29 */ | |
6a7eba24 JFM |
301 | |
302 | /************************************************/ | |
ca5e578f JFM |
303 | reg_w1(gspca_dev, R2C_POLARITY, 0x10); |
304 | /* 0x48; //0x08; 0x2c */ | |
305 | reg_w1(gspca_dev, R2D_POINT, 0x14); | |
306 | /* 0x38; 0x2d */ | |
307 | reg_w1(gspca_dev, R2E_POINTH, 0x01); | |
308 | /* 0x04; 0x2e */ | |
309 | reg_w1(gspca_dev, R2F_POINTB, 0x12); | |
310 | /* 0x04; 0x2f */ | |
311 | reg_w1(gspca_dev, R30_POINTBH, 0x01); | |
312 | /* 0x04; 0x30 */ | |
313 | reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE); | |
314 | /* 0x00<-0x84 */ | |
6a7eba24 | 315 | /*************************************************/ |
ca5e578f | 316 | reg_w1(gspca_dev, R31_UPD, 0x01); /* update registers */ |
6a7eba24 | 317 | msleep(200); |
ca5e578f | 318 | reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */ |
6a7eba24 JFM |
319 | /*************************************************/ |
320 | tv_8532_setReg(gspca_dev); | |
321 | /*************************************************/ | |
ca5e578f | 322 | reg_w1(gspca_dev, R3B_Test3, 0x0b); /* Test0Sel = 11 = GPIO */ |
6a7eba24 JFM |
323 | /*************************************************/ |
324 | tv_8532_setReg(gspca_dev); | |
325 | /*************************************************/ | |
326 | tv_8532_PollReg(gspca_dev); | |
327 | return 0; | |
328 | } | |
329 | ||
330 | static void setbrightness(struct gspca_dev *gspca_dev) | |
331 | { | |
332 | struct sd *sd = (struct sd *) gspca_dev; | |
6a7eba24 | 333 | |
ca5e578f JFM |
334 | reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->brightness); |
335 | reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE); | |
336 | /* 0x84 */ | |
6a7eba24 JFM |
337 | } |
338 | ||
339 | /* -- start the camera -- */ | |
72ab97ce | 340 | static int sd_start(struct gspca_dev *gspca_dev) |
6a7eba24 | 341 | { |
2e0903b0 JFM |
342 | struct sd *sd = (struct sd *) gspca_dev; |
343 | ||
ca5e578f JFM |
344 | reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32); /* slope begin 1,7V, |
345 | * slope rate 2 */ | |
346 | reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00); | |
6a7eba24 | 347 | tv_8532ReadRegisters(gspca_dev); |
ca5e578f JFM |
348 | reg_w1(gspca_dev, R3B_Test3, 0x0b); |
349 | ||
350 | reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190); | |
6a7eba24 JFM |
351 | setbrightness(gspca_dev); |
352 | ||
ca5e578f JFM |
353 | reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8); /* 0x20; 0x0c */ |
354 | reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03); | |
6a7eba24 JFM |
355 | |
356 | /************************************************/ | |
ca5e578f JFM |
357 | reg_w1(gspca_dev, R28_QUANT, 0x90); |
358 | /* 0x72 compressed mode 0x28 */ | |
c2446b3e | 359 | if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { |
6a7eba24 | 360 | /* 176x144 */ |
ca5e578f JFM |
361 | reg_w1(gspca_dev, R29_LINE, 0x41); |
362 | /* CIF - 2 lines/packet */ | |
6a7eba24 JFM |
363 | } else { |
364 | /* 352x288 */ | |
ca5e578f JFM |
365 | reg_w1(gspca_dev, R29_LINE, 0x81); |
366 | /* CIF - 2 lines/packet */ | |
6a7eba24 JFM |
367 | } |
368 | /************************************************/ | |
ca5e578f JFM |
369 | reg_w1(gspca_dev, R2C_POLARITY, 0x10); /* slow clock */ |
370 | reg_w1(gspca_dev, R2D_POINT, 0x14); | |
371 | reg_w1(gspca_dev, R2E_POINTH, 0x01); | |
372 | reg_w1(gspca_dev, R2F_POINTB, 0x12); | |
373 | reg_w1(gspca_dev, R30_POINTBH, 0x01); | |
374 | reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE); | |
6a7eba24 | 375 | /************************************************/ |
ca5e578f | 376 | reg_w1(gspca_dev, R31_UPD, 0x01); /* update registers */ |
6a7eba24 | 377 | msleep(200); |
ca5e578f | 378 | reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */ |
6a7eba24 JFM |
379 | /************************************************/ |
380 | tv_8532_setReg(gspca_dev); | |
381 | /************************************************/ | |
ca5e578f | 382 | reg_w1(gspca_dev, R3B_Test3, 0x0b); /* Test0Sel = 11 = GPIO */ |
6a7eba24 JFM |
383 | /************************************************/ |
384 | tv_8532_setReg(gspca_dev); | |
385 | /************************************************/ | |
386 | tv_8532_PollReg(gspca_dev); | |
ca5e578f | 387 | reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */ |
ba13cca7 JFM |
388 | |
389 | gspca_dev->empty_packet = 0; /* check the empty packets */ | |
2e0903b0 | 390 | sd->packet = 0; /* ignore the first packets */ |
ba13cca7 | 391 | |
72ab97ce | 392 | return 0; |
6a7eba24 JFM |
393 | } |
394 | ||
395 | static void sd_stopN(struct gspca_dev *gspca_dev) | |
396 | { | |
ca5e578f | 397 | reg_w1(gspca_dev, R3B_Test3, 0x0b); /* Test0Sel = 11 = GPIO */ |
6a7eba24 JFM |
398 | } |
399 | ||
6a7eba24 JFM |
400 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, |
401 | struct gspca_frame *frame, /* target */ | |
402 | __u8 *data, /* isoc packet */ | |
403 | int len) /* iso packet length */ | |
404 | { | |
405 | struct sd *sd = (struct sd *) gspca_dev; | |
2e0903b0 | 406 | int packet_type0, packet_type1; |
6a7eba24 | 407 | |
2e0903b0 | 408 | packet_type0 = packet_type1 = INTER_PACKET; |
ba13cca7 | 409 | if (gspca_dev->empty_packet) { |
2e0903b0 JFM |
410 | gspca_dev->empty_packet = 0; |
411 | sd->packet = gspca_dev->height / 2; | |
412 | packet_type0 = FIRST_PACKET; | |
413 | } else if (sd->packet == 0) | |
414 | return; /* 2 more lines in 352x288 ! */ | |
415 | sd->packet--; | |
416 | if (sd->packet == 0) | |
417 | packet_type1 = LAST_PACKET; | |
418 | ||
419 | /* each packet contains: | |
420 | * - header 2 bytes | |
ca5e578f | 421 | * - RGRG line |
2e0903b0 | 422 | * - 4 bytes |
ca5e578f | 423 | * - GBGB line |
2e0903b0 JFM |
424 | * - 4 bytes |
425 | */ | |
426 | gspca_frame_add(gspca_dev, packet_type0, | |
427 | frame, data + 2, gspca_dev->width); | |
428 | gspca_frame_add(gspca_dev, packet_type1, | |
429 | frame, data + gspca_dev->width + 6, gspca_dev->width); | |
6a7eba24 JFM |
430 | } |
431 | ||
6a7eba24 JFM |
432 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) |
433 | { | |
434 | struct sd *sd = (struct sd *) gspca_dev; | |
435 | ||
436 | sd->brightness = val; | |
437 | if (gspca_dev->streaming) | |
438 | setbrightness(gspca_dev); | |
439 | return 0; | |
440 | } | |
441 | ||
442 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) | |
443 | { | |
444 | struct sd *sd = (struct sd *) gspca_dev; | |
445 | ||
446 | *val = sd->brightness; | |
447 | return 0; | |
448 | } | |
449 | ||
6a7eba24 | 450 | /* sub-driver description */ |
a5ae2062 | 451 | static const struct sd_desc sd_desc = { |
6a7eba24 JFM |
452 | .name = MODULE_NAME, |
453 | .ctrls = sd_ctrls, | |
454 | .nctrls = ARRAY_SIZE(sd_ctrls), | |
455 | .config = sd_config, | |
012d6b02 | 456 | .init = sd_init, |
6a7eba24 JFM |
457 | .start = sd_start, |
458 | .stopN = sd_stopN, | |
6a7eba24 JFM |
459 | .pkt_scan = sd_pkt_scan, |
460 | }; | |
461 | ||
462 | /* -- module initialisation -- */ | |
a5ae2062 | 463 | static const __devinitdata struct usb_device_id device_table[] = { |
9d64fdb1 JFM |
464 | {USB_DEVICE(0x046d, 0x0920)}, |
465 | {USB_DEVICE(0x046d, 0x0921)}, | |
466 | {USB_DEVICE(0x0545, 0x808b)}, | |
467 | {USB_DEVICE(0x0545, 0x8333)}, | |
468 | {USB_DEVICE(0x0923, 0x010f)}, | |
6a7eba24 JFM |
469 | {} |
470 | }; | |
471 | ||
472 | MODULE_DEVICE_TABLE(usb, device_table); | |
473 | ||
474 | /* -- device connect -- */ | |
475 | static int sd_probe(struct usb_interface *intf, | |
476 | const struct usb_device_id *id) | |
477 | { | |
478 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | |
479 | THIS_MODULE); | |
480 | } | |
481 | ||
482 | static struct usb_driver sd_driver = { | |
483 | .name = MODULE_NAME, | |
484 | .id_table = device_table, | |
485 | .probe = sd_probe, | |
486 | .disconnect = gspca_disconnect, | |
6a709749 JFM |
487 | #ifdef CONFIG_PM |
488 | .suspend = gspca_suspend, | |
489 | .resume = gspca_resume, | |
490 | #endif | |
6a7eba24 JFM |
491 | }; |
492 | ||
493 | /* -- module insert / remove -- */ | |
494 | static int __init sd_mod_init(void) | |
495 | { | |
f69e9529 AK |
496 | int ret; |
497 | ret = usb_register(&sd_driver); | |
498 | if (ret < 0) | |
e6b14849 | 499 | return ret; |
10b0e96e | 500 | PDEBUG(D_PROBE, "registered"); |
6a7eba24 JFM |
501 | return 0; |
502 | } | |
503 | ||
504 | static void __exit sd_mod_exit(void) | |
505 | { | |
506 | usb_deregister(&sd_driver); | |
507 | PDEBUG(D_PROBE, "deregistered"); | |
508 | } | |
509 | ||
510 | module_init(sd_mod_init); | |
511 | module_exit(sd_mod_exit); |