[media] gspca: Fix coding style issues
[deliverable/linux.git] / drivers / media / video / gspca / pac7302.c
1 /*
2 * Pixart PAC7302 library
3 * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
4 *
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6 *
7 * Separated from Pixart PAC7311 library by Márton Németh
8 * Camera button input handling by Márton Németh <nm127@freemail.hu>
9 * Copyright (C) 2009-2010 Márton Németh <nm127@freemail.hu>
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 * 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 /* Some documentation about various registers as determined by trial and error.
27
28 Register page 1:
29
30 Address Description
31 0x78 Global control, bit 6 controls the LED (inverted)
32
33 Register page 3:
34
35 Address Description
36 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on
37 the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
38 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps
39 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps,
40 63 -> ~27 fps, the 2 msb's must always be 1 !!
41 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0:
42 1 -> ~30 fps, 2 -> ~20 fps
43 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time
44 0x0f Exposure bit 8, 0-448, 448 = no exposure at all
45 0x10 Master gain 0-31
46 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
47
48 The registers are accessed in the following functions:
49
50 Page | Register | Function
51 -----+------------+---------------------------------------------------
52 0 | 0x0f..0x20 | setcolors()
53 0 | 0xa2..0xab | setbrightcont()
54 0 | 0xc5 | setredbalance()
55 0 | 0xc6 | setwhitebalance()
56 0 | 0xc7 | setbluebalance()
57 0 | 0xdc | setbrightcont(), setcolors()
58 3 | 0x02 | setexposure()
59 3 | 0x10 | setgain()
60 3 | 0x11 | setcolors(), setgain(), setexposure(), sethvflip()
61 3 | 0x21 | sethvflip()
62 */
63
64 #define MODULE_NAME "pac7302"
65
66 #include <linux/input.h>
67 #include <media/v4l2-chip-ident.h>
68 #include "gspca.h"
69
70 MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
71 MODULE_DESCRIPTION("Pixart PAC7302");
72 MODULE_LICENSE("GPL");
73
74 /* specific webcam descriptor for pac7302 */
75 struct sd {
76 struct gspca_dev gspca_dev; /* !! must be the first item */
77
78 unsigned char brightness;
79 unsigned char contrast;
80 unsigned char colors;
81 unsigned char white_balance;
82 unsigned char red_balance;
83 unsigned char blue_balance;
84 unsigned char gain;
85 unsigned char autogain;
86 unsigned short exposure;
87 __u8 hflip;
88 __u8 vflip;
89 u8 flags;
90 #define FL_HFLIP 0x01 /* mirrored by default */
91 #define FL_VFLIP 0x02 /* vertical flipped by default */
92
93 u8 sof_read;
94 u8 autogain_ignore_frames;
95
96 atomic_t avg_lum;
97 };
98
99 /* V4L2 controls supported by the driver */
100 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
101 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
102 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
103 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
104 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
105 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
106 static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
107 static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
108 static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val);
109 static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val);
110 static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val);
111 static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val);
112 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
113 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
114 static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
115 static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
116 static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
117 static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
118 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
119 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
120 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
121 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
122
123 static const struct ctrl sd_ctrls[] = {
124 {
125 {
126 .id = V4L2_CID_BRIGHTNESS,
127 .type = V4L2_CTRL_TYPE_INTEGER,
128 .name = "Brightness",
129 .minimum = 0,
130 #define BRIGHTNESS_MAX 0x20
131 .maximum = BRIGHTNESS_MAX,
132 .step = 1,
133 #define BRIGHTNESS_DEF 0x10
134 .default_value = BRIGHTNESS_DEF,
135 },
136 .set = sd_setbrightness,
137 .get = sd_getbrightness,
138 },
139 {
140 {
141 .id = V4L2_CID_CONTRAST,
142 .type = V4L2_CTRL_TYPE_INTEGER,
143 .name = "Contrast",
144 .minimum = 0,
145 #define CONTRAST_MAX 255
146 .maximum = CONTRAST_MAX,
147 .step = 1,
148 #define CONTRAST_DEF 127
149 .default_value = CONTRAST_DEF,
150 },
151 .set = sd_setcontrast,
152 .get = sd_getcontrast,
153 },
154 {
155 {
156 .id = V4L2_CID_SATURATION,
157 .type = V4L2_CTRL_TYPE_INTEGER,
158 .name = "Saturation",
159 .minimum = 0,
160 #define COLOR_MAX 255
161 .maximum = COLOR_MAX,
162 .step = 1,
163 #define COLOR_DEF 127
164 .default_value = COLOR_DEF,
165 },
166 .set = sd_setcolors,
167 .get = sd_getcolors,
168 },
169 {
170 {
171 .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
172 .type = V4L2_CTRL_TYPE_INTEGER,
173 .name = "White Balance",
174 .minimum = 0,
175 .maximum = 255,
176 .step = 1,
177 #define WHITEBALANCE_DEF 4
178 .default_value = WHITEBALANCE_DEF,
179 },
180 .set = sd_setwhitebalance,
181 .get = sd_getwhitebalance,
182 },
183 {
184 {
185 .id = V4L2_CID_RED_BALANCE,
186 .type = V4L2_CTRL_TYPE_INTEGER,
187 .name = "Red",
188 .minimum = 0,
189 .maximum = 3,
190 .step = 1,
191 #define REDBALANCE_DEF 1
192 .default_value = REDBALANCE_DEF,
193 },
194 .set = sd_setredbalance,
195 .get = sd_getredbalance,
196 },
197 {
198 {
199 .id = V4L2_CID_BLUE_BALANCE,
200 .type = V4L2_CTRL_TYPE_INTEGER,
201 .name = "Blue",
202 .minimum = 0,
203 .maximum = 3,
204 .step = 1,
205 #define BLUEBALANCE_DEF 1
206 .default_value = BLUEBALANCE_DEF,
207 },
208 .set = sd_setbluebalance,
209 .get = sd_getbluebalance,
210 },
211 {
212 {
213 .id = V4L2_CID_GAIN,
214 .type = V4L2_CTRL_TYPE_INTEGER,
215 .name = "Gain",
216 .minimum = 0,
217 #define GAIN_MAX 255
218 .maximum = GAIN_MAX,
219 .step = 1,
220 #define GAIN_DEF 127
221 #define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
222 .default_value = GAIN_DEF,
223 },
224 .set = sd_setgain,
225 .get = sd_getgain,
226 },
227 {
228 {
229 .id = V4L2_CID_EXPOSURE,
230 .type = V4L2_CTRL_TYPE_INTEGER,
231 .name = "Exposure",
232 .minimum = 0,
233 .maximum = 1023,
234 .step = 1,
235 #define EXPOSURE_DEF 66 /* 33 ms / 30 fps */
236 #define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */
237 .default_value = EXPOSURE_DEF,
238 },
239 .set = sd_setexposure,
240 .get = sd_getexposure,
241 },
242 {
243 {
244 .id = V4L2_CID_AUTOGAIN,
245 .type = V4L2_CTRL_TYPE_BOOLEAN,
246 .name = "Auto Gain",
247 .minimum = 0,
248 .maximum = 1,
249 .step = 1,
250 #define AUTOGAIN_DEF 1
251 .default_value = AUTOGAIN_DEF,
252 },
253 .set = sd_setautogain,
254 .get = sd_getautogain,
255 },
256 {
257 {
258 .id = V4L2_CID_HFLIP,
259 .type = V4L2_CTRL_TYPE_BOOLEAN,
260 .name = "Mirror",
261 .minimum = 0,
262 .maximum = 1,
263 .step = 1,
264 #define HFLIP_DEF 0
265 .default_value = HFLIP_DEF,
266 },
267 .set = sd_sethflip,
268 .get = sd_gethflip,
269 },
270 {
271 {
272 .id = V4L2_CID_VFLIP,
273 .type = V4L2_CTRL_TYPE_BOOLEAN,
274 .name = "Vflip",
275 .minimum = 0,
276 .maximum = 1,
277 .step = 1,
278 #define VFLIP_DEF 0
279 .default_value = VFLIP_DEF,
280 },
281 .set = sd_setvflip,
282 .get = sd_getvflip,
283 },
284 };
285
286 static const struct v4l2_pix_format vga_mode[] = {
287 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
288 .bytesperline = 640,
289 .sizeimage = 640 * 480 * 3 / 8 + 590,
290 .colorspace = V4L2_COLORSPACE_JPEG,
291 .priv = 0},
292 };
293
294 #define LOAD_PAGE3 255
295 #define END_OF_SEQUENCE 0
296
297 /* pac 7302 */
298 static const __u8 init_7302[] = {
299 /* index,value */
300 0xff, 0x01, /* page 1 */
301 0x78, 0x00, /* deactivate */
302 0xff, 0x01,
303 0x78, 0x40, /* led off */
304 };
305 static const __u8 start_7302[] = {
306 /* index, len, [value]* */
307 0xff, 1, 0x00, /* page 0 */
308 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
309 0x00, 0x00, 0x00, 0x00,
310 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
311 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
312 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
313 0x26, 2, 0xaa, 0xaa,
314 0x2e, 1, 0x31,
315 0x38, 1, 0x01,
316 0x3a, 3, 0x14, 0xff, 0x5a,
317 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
318 0x00, 0x54, 0x11,
319 0x55, 1, 0x00,
320 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
321 0x6b, 1, 0x00,
322 0x6e, 3, 0x08, 0x06, 0x00,
323 0x72, 3, 0x00, 0xff, 0x00,
324 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
325 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
326 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
327 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
328 0xd2, 0xeb,
329 0xaf, 1, 0x02,
330 0xb5, 2, 0x08, 0x08,
331 0xb8, 2, 0x08, 0x88,
332 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
333 0xcc, 1, 0x00,
334 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
335 0xc1, 0xd7, 0xec,
336 0xdc, 1, 0x01,
337 0xff, 1, 0x01, /* page 1 */
338 0x12, 3, 0x02, 0x00, 0x01,
339 0x3e, 2, 0x00, 0x00,
340 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
341 0x7c, 1, 0x00,
342 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
343 0x02, 0x00,
344 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
345 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
346 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
347 0xd8, 1, 0x01,
348 0xdb, 2, 0x00, 0x01,
349 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
350 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
351 0xeb, 1, 0x00,
352 0xff, 1, 0x02, /* page 2 */
353 0x22, 1, 0x00,
354 0xff, 1, 0x03, /* page 3 */
355 0, LOAD_PAGE3, /* load the page 3 */
356 0x11, 1, 0x01,
357 0xff, 1, 0x02, /* page 2 */
358 0x13, 1, 0x00,
359 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
360 0x27, 2, 0x14, 0x0c,
361 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
362 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
363 0x6e, 1, 0x08,
364 0xff, 1, 0x01, /* page 1 */
365 0x78, 1, 0x00,
366 0, END_OF_SEQUENCE /* end of sequence */
367 };
368
369 #define SKIP 0xaa
370 /* page 3 - the value SKIP says skip the index - see reg_w_page() */
371 static const __u8 page3_7302[] = {
372 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
373 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
374 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
375 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
376 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
377 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
378 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
379 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
380 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
381 SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
382 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
383 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
384 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
386 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
387 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
388 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
389 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
390 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
391 0x00
392 };
393
394 static void reg_w_buf(struct gspca_dev *gspca_dev,
395 __u8 index,
396 const char *buffer, int len)
397 {
398 int ret;
399
400 if (gspca_dev->usb_err < 0)
401 return;
402 memcpy(gspca_dev->usb_buf, buffer, len);
403 ret = usb_control_msg(gspca_dev->dev,
404 usb_sndctrlpipe(gspca_dev->dev, 0),
405 0, /* request */
406 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
407 0, /* value */
408 index, gspca_dev->usb_buf, len,
409 500);
410 if (ret < 0) {
411 err("reg_w_buf failed index 0x%02x, error %d",
412 index, ret);
413 gspca_dev->usb_err = ret;
414 }
415 }
416
417
418 static void reg_w(struct gspca_dev *gspca_dev,
419 __u8 index,
420 __u8 value)
421 {
422 int ret;
423
424 if (gspca_dev->usb_err < 0)
425 return;
426 gspca_dev->usb_buf[0] = value;
427 ret = usb_control_msg(gspca_dev->dev,
428 usb_sndctrlpipe(gspca_dev->dev, 0),
429 0, /* request */
430 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
431 0, index, gspca_dev->usb_buf, 1,
432 500);
433 if (ret < 0) {
434 err("reg_w() failed index 0x%02x, value 0x%02x, error %d",
435 index, value, ret);
436 gspca_dev->usb_err = ret;
437 }
438 }
439
440 static void reg_w_seq(struct gspca_dev *gspca_dev,
441 const __u8 *seq, int len)
442 {
443 while (--len >= 0) {
444 reg_w(gspca_dev, seq[0], seq[1]);
445 seq += 2;
446 }
447 }
448
449 /* load the beginning of a page */
450 static void reg_w_page(struct gspca_dev *gspca_dev,
451 const __u8 *page, int len)
452 {
453 int index;
454 int ret = 0;
455
456 if (gspca_dev->usb_err < 0)
457 return;
458 for (index = 0; index < len; index++) {
459 if (page[index] == SKIP) /* skip this index */
460 continue;
461 gspca_dev->usb_buf[0] = page[index];
462 ret = usb_control_msg(gspca_dev->dev,
463 usb_sndctrlpipe(gspca_dev->dev, 0),
464 0, /* request */
465 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
466 0, index, gspca_dev->usb_buf, 1,
467 500);
468 if (ret < 0) {
469 err("reg_w_page() failed index 0x%02x, "
470 "value 0x%02x, error %d",
471 index, page[index], ret);
472 gspca_dev->usb_err = ret;
473 break;
474 }
475 }
476 }
477
478 /* output a variable sequence */
479 static void reg_w_var(struct gspca_dev *gspca_dev,
480 const __u8 *seq,
481 const __u8 *page3, unsigned int page3_len)
482 {
483 int index, len;
484
485 for (;;) {
486 index = *seq++;
487 len = *seq++;
488 switch (len) {
489 case END_OF_SEQUENCE:
490 return;
491 case LOAD_PAGE3:
492 reg_w_page(gspca_dev, page3, page3_len);
493 break;
494 default:
495 if (len > USB_BUF_SZ) {
496 PDEBUG(D_ERR|D_STREAM,
497 "Incorrect variable sequence");
498 return;
499 }
500 while (len > 0) {
501 if (len < 8) {
502 reg_w_buf(gspca_dev,
503 index, seq, len);
504 seq += len;
505 break;
506 }
507 reg_w_buf(gspca_dev, index, seq, 8);
508 seq += 8;
509 index += 8;
510 len -= 8;
511 }
512 }
513 }
514 /* not reached */
515 }
516
517 /* this function is called at probe time for pac7302 */
518 static int sd_config(struct gspca_dev *gspca_dev,
519 const struct usb_device_id *id)
520 {
521 struct sd *sd = (struct sd *) gspca_dev;
522 struct cam *cam;
523
524 cam = &gspca_dev->cam;
525
526 PDEBUG(D_CONF, "Find Sensor PAC7302");
527 cam->cam_mode = vga_mode; /* only 640x480 */
528 cam->nmodes = ARRAY_SIZE(vga_mode);
529
530 sd->brightness = BRIGHTNESS_DEF;
531 sd->contrast = CONTRAST_DEF;
532 sd->colors = COLOR_DEF;
533 sd->white_balance = WHITEBALANCE_DEF;
534 sd->red_balance = REDBALANCE_DEF;
535 sd->blue_balance = BLUEBALANCE_DEF;
536 sd->gain = GAIN_DEF;
537 sd->exposure = EXPOSURE_DEF;
538 sd->autogain = AUTOGAIN_DEF;
539 sd->hflip = HFLIP_DEF;
540 sd->vflip = VFLIP_DEF;
541 sd->flags = id->driver_info;
542 return 0;
543 }
544
545 /* This function is used by pac7302 only */
546 static void setbrightcont(struct gspca_dev *gspca_dev)
547 {
548 struct sd *sd = (struct sd *) gspca_dev;
549 int i, v;
550 static const __u8 max[10] =
551 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
552 0xd4, 0xec};
553 static const __u8 delta[10] =
554 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
555 0x11, 0x0b};
556
557 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
558 for (i = 0; i < 10; i++) {
559 v = max[i];
560 v += (sd->brightness - BRIGHTNESS_MAX)
561 * 150 / BRIGHTNESS_MAX; /* 200 ? */
562 v -= delta[i] * sd->contrast / CONTRAST_MAX;
563 if (v < 0)
564 v = 0;
565 else if (v > 0xff)
566 v = 0xff;
567 reg_w(gspca_dev, 0xa2 + i, v);
568 }
569 reg_w(gspca_dev, 0xdc, 0x01);
570 }
571
572 /* This function is used by pac7302 only */
573 static void setcolors(struct gspca_dev *gspca_dev)
574 {
575 struct sd *sd = (struct sd *) gspca_dev;
576 int i, v;
577 static const int a[9] =
578 {217, -212, 0, -101, 170, -67, -38, -315, 355};
579 static const int b[9] =
580 {19, 106, 0, 19, 106, 1, 19, 106, 1};
581
582 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
583 reg_w(gspca_dev, 0x11, 0x01);
584 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
585 for (i = 0; i < 9; i++) {
586 v = a[i] * sd->colors / COLOR_MAX + b[i];
587 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
588 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
589 }
590 reg_w(gspca_dev, 0xdc, 0x01);
591 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
592 }
593
594 static void setwhitebalance(struct gspca_dev *gspca_dev)
595 {
596 struct sd *sd = (struct sd *) gspca_dev;
597
598 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
599 reg_w(gspca_dev, 0xc6, sd->white_balance);
600
601 reg_w(gspca_dev, 0xdc, 0x01);
602 PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance);
603 }
604
605 static void setredbalance(struct gspca_dev *gspca_dev)
606 {
607 struct sd *sd = (struct sd *) gspca_dev;
608
609 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
610 reg_w(gspca_dev, 0xc5, sd->red_balance);
611
612 reg_w(gspca_dev, 0xdc, 0x01);
613 PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance);
614 }
615
616 static void setbluebalance(struct gspca_dev *gspca_dev)
617 {
618 struct sd *sd = (struct sd *) gspca_dev;
619
620 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
621 reg_w(gspca_dev, 0xc7, sd->blue_balance);
622
623 reg_w(gspca_dev, 0xdc, 0x01);
624 PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance);
625 }
626
627 static void setgain(struct gspca_dev *gspca_dev)
628 {
629 struct sd *sd = (struct sd *) gspca_dev;
630
631 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
632 reg_w(gspca_dev, 0x10, sd->gain >> 3);
633
634 /* load registers to sensor (Bit 0, auto clear) */
635 reg_w(gspca_dev, 0x11, 0x01);
636 }
637
638 static void setexposure(struct gspca_dev *gspca_dev)
639 {
640 struct sd *sd = (struct sd *) gspca_dev;
641 __u8 clockdiv;
642 __u16 exposure;
643
644 /* register 2 of frame 3 contains the clock divider configuring the
645 no fps according to the formula: 90 / reg. sd->exposure is the
646 desired exposure time in 0.5 ms. */
647 clockdiv = (90 * sd->exposure + 1999) / 2000;
648
649 /* Note clockdiv = 3 also works, but when running at 30 fps, depending
650 on the scene being recorded, the camera switches to another
651 quantization table for certain JPEG blocks, and we don't know how
652 to decompress these blocks. So we cap the framerate at 15 fps */
653 if (clockdiv < 6)
654 clockdiv = 6;
655 else if (clockdiv > 63)
656 clockdiv = 63;
657
658 /* reg2 MUST be a multiple of 3, except when between 6 and 12?
659 Always round up, otherwise we cannot get the desired frametime
660 using the partial frame time exposure control */
661 if (clockdiv < 6 || clockdiv > 12)
662 clockdiv = ((clockdiv + 2) / 3) * 3;
663
664 /* frame exposure time in ms = 1000 * clockdiv / 90 ->
665 exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */
666 exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv);
667 /* 0 = use full frametime, 448 = no exposure, reverse it */
668 exposure = 448 - exposure;
669
670 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
671 reg_w(gspca_dev, 0x02, clockdiv);
672 reg_w(gspca_dev, 0x0e, exposure & 0xff);
673 reg_w(gspca_dev, 0x0f, exposure >> 8);
674
675 /* load registers to sensor (Bit 0, auto clear) */
676 reg_w(gspca_dev, 0x11, 0x01);
677 }
678
679 static void sethvflip(struct gspca_dev *gspca_dev)
680 {
681 struct sd *sd = (struct sd *) gspca_dev;
682 u8 data, hflip, vflip;
683
684 hflip = sd->hflip;
685 if (sd->flags & FL_HFLIP)
686 hflip = !hflip;
687 vflip = sd->vflip;
688 if (sd->flags & FL_VFLIP)
689 vflip = !vflip;
690
691 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
692 data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
693 reg_w(gspca_dev, 0x21, data);
694
695 /* load registers to sensor (Bit 0, auto clear) */
696 reg_w(gspca_dev, 0x11, 0x01);
697 }
698
699 /* this function is called at probe and resume time for pac7302 */
700 static int sd_init(struct gspca_dev *gspca_dev)
701 {
702 reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
703 return gspca_dev->usb_err;
704 }
705
706 static int sd_start(struct gspca_dev *gspca_dev)
707 {
708 struct sd *sd = (struct sd *) gspca_dev;
709
710 sd->sof_read = 0;
711
712 reg_w_var(gspca_dev, start_7302,
713 page3_7302, sizeof(page3_7302));
714 setbrightcont(gspca_dev);
715 setcolors(gspca_dev);
716 setwhitebalance(gspca_dev);
717 setredbalance(gspca_dev);
718 setbluebalance(gspca_dev);
719 setgain(gspca_dev);
720 setexposure(gspca_dev);
721 sethvflip(gspca_dev);
722
723 /* only resolution 640x480 is supported for pac7302 */
724
725 sd->sof_read = 0;
726 sd->autogain_ignore_frames = 0;
727 atomic_set(&sd->avg_lum, -1);
728
729 /* start stream */
730 reg_w(gspca_dev, 0xff, 0x01);
731 reg_w(gspca_dev, 0x78, 0x01);
732
733 return gspca_dev->usb_err;
734 }
735
736 static void sd_stopN(struct gspca_dev *gspca_dev)
737 {
738
739 /* stop stream */
740 reg_w(gspca_dev, 0xff, 0x01);
741 reg_w(gspca_dev, 0x78, 0x00);
742 }
743
744 /* called on streamoff with alt 0 and on disconnect for pac7302 */
745 static void sd_stop0(struct gspca_dev *gspca_dev)
746 {
747 if (!gspca_dev->present)
748 return;
749 reg_w(gspca_dev, 0xff, 0x01);
750 reg_w(gspca_dev, 0x78, 0x40);
751 }
752
753 /* Include pac common sof detection functions */
754 #include "pac_common.h"
755
756 static void do_autogain(struct gspca_dev *gspca_dev)
757 {
758 struct sd *sd = (struct sd *) gspca_dev;
759 int avg_lum = atomic_read(&sd->avg_lum);
760 int desired_lum;
761 const int deadzone = 30;
762
763 if (avg_lum == -1)
764 return;
765
766 desired_lum = 270 + sd->brightness;
767
768 if (sd->autogain_ignore_frames > 0)
769 sd->autogain_ignore_frames--;
770 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
771 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
772 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
773 }
774
775 /* JPEG header, part 1 */
776 static const unsigned char pac_jpeg_header1[] = {
777 0xff, 0xd8, /* SOI: Start of Image */
778
779 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
780 0x00, 0x11, /* length = 17 bytes (including this length field) */
781 0x08 /* Precision: 8 */
782 /* 2 bytes is placed here: number of image lines */
783 /* 2 bytes is placed here: samples per line */
784 };
785
786 /* JPEG header, continued */
787 static const unsigned char pac_jpeg_header2[] = {
788 0x03, /* Number of image components: 3 */
789 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
790 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
791 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
792
793 0xff, 0xda, /* SOS: Start Of Scan */
794 0x00, 0x0c, /* length = 12 bytes (including this length field) */
795 0x03, /* number of components: 3 */
796 0x01, 0x00, /* selector 1, table 0x00 */
797 0x02, 0x11, /* selector 2, table 0x11 */
798 0x03, 0x11, /* selector 3, table 0x11 */
799 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
800 0x00 /* Successive approximation: 0 */
801 };
802
803 static void pac_start_frame(struct gspca_dev *gspca_dev,
804 __u16 lines, __u16 samples_per_line)
805 {
806 unsigned char tmpbuf[4];
807
808 gspca_frame_add(gspca_dev, FIRST_PACKET,
809 pac_jpeg_header1, sizeof(pac_jpeg_header1));
810
811 tmpbuf[0] = lines >> 8;
812 tmpbuf[1] = lines & 0xff;
813 tmpbuf[2] = samples_per_line >> 8;
814 tmpbuf[3] = samples_per_line & 0xff;
815
816 gspca_frame_add(gspca_dev, INTER_PACKET,
817 tmpbuf, sizeof(tmpbuf));
818 gspca_frame_add(gspca_dev, INTER_PACKET,
819 pac_jpeg_header2, sizeof(pac_jpeg_header2));
820 }
821
822 /* this function is run at interrupt level */
823 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
824 u8 *data, /* isoc packet */
825 int len) /* iso packet length */
826 {
827 struct sd *sd = (struct sd *) gspca_dev;
828 u8 *image;
829 unsigned char *sof;
830
831 sof = pac_find_sof(&sd->sof_read, data, len);
832 if (sof) {
833 int n, lum_offset, footer_length;
834
835 /* 6 bytes after the FF D9 EOF marker a number of lumination
836 bytes are send corresponding to different parts of the
837 image, the 14th and 15th byte after the EOF seem to
838 correspond to the center of the image */
839 lum_offset = 61 + sizeof pac_sof_marker;
840 footer_length = 74;
841
842 /* Finish decoding current frame */
843 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
844 if (n < 0) {
845 gspca_dev->image_len += n;
846 n = 0;
847 } else {
848 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
849 }
850
851 image = gspca_dev->image;
852 if (image != NULL
853 && image[gspca_dev->image_len - 2] == 0xff
854 && image[gspca_dev->image_len - 1] == 0xd9)
855 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
856
857 n = sof - data;
858 len -= n;
859 data = sof;
860
861 /* Get average lumination */
862 if (gspca_dev->last_packet_type == LAST_PACKET &&
863 n >= lum_offset)
864 atomic_set(&sd->avg_lum, data[-lum_offset] +
865 data[-lum_offset + 1]);
866 else
867 atomic_set(&sd->avg_lum, -1);
868
869 /* Start the new frame with the jpeg header */
870 /* The PAC7302 has the image rotated 90 degrees */
871 pac_start_frame(gspca_dev,
872 gspca_dev->width, gspca_dev->height);
873 }
874 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
875 }
876
877 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
878 {
879 struct sd *sd = (struct sd *) gspca_dev;
880
881 sd->brightness = val;
882 if (gspca_dev->streaming)
883 setbrightcont(gspca_dev);
884 return gspca_dev->usb_err;
885 }
886
887 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
888 {
889 struct sd *sd = (struct sd *) gspca_dev;
890
891 *val = sd->brightness;
892 return 0;
893 }
894
895 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
896 {
897 struct sd *sd = (struct sd *) gspca_dev;
898
899 sd->contrast = val;
900 if (gspca_dev->streaming)
901 setbrightcont(gspca_dev);
902 return gspca_dev->usb_err;
903 }
904
905 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
906 {
907 struct sd *sd = (struct sd *) gspca_dev;
908
909 *val = sd->contrast;
910 return 0;
911 }
912
913 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
914 {
915 struct sd *sd = (struct sd *) gspca_dev;
916
917 sd->colors = val;
918 if (gspca_dev->streaming)
919 setcolors(gspca_dev);
920 return gspca_dev->usb_err;
921 }
922
923 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
924 {
925 struct sd *sd = (struct sd *) gspca_dev;
926
927 *val = sd->colors;
928 return 0;
929 }
930
931 static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
932 {
933 struct sd *sd = (struct sd *) gspca_dev;
934
935 sd->white_balance = val;
936 if (gspca_dev->streaming)
937 setwhitebalance(gspca_dev);
938 return gspca_dev->usb_err;
939 }
940
941 static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
942 {
943 struct sd *sd = (struct sd *) gspca_dev;
944
945 *val = sd->white_balance;
946 return 0;
947 }
948
949 static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val)
950 {
951 struct sd *sd = (struct sd *) gspca_dev;
952
953 sd->red_balance = val;
954 if (gspca_dev->streaming)
955 setredbalance(gspca_dev);
956 return gspca_dev->usb_err;
957 }
958
959 static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val)
960 {
961 struct sd *sd = (struct sd *) gspca_dev;
962
963 *val = sd->red_balance;
964 return 0;
965 }
966
967 static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val)
968 {
969 struct sd *sd = (struct sd *) gspca_dev;
970
971 sd->blue_balance = val;
972 if (gspca_dev->streaming)
973 setbluebalance(gspca_dev);
974 return gspca_dev->usb_err;
975 }
976
977 static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val)
978 {
979 struct sd *sd = (struct sd *) gspca_dev;
980
981 *val = sd->blue_balance;
982 return 0;
983 }
984
985 static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
986 {
987 struct sd *sd = (struct sd *) gspca_dev;
988
989 sd->gain = val;
990 if (gspca_dev->streaming)
991 setgain(gspca_dev);
992 return gspca_dev->usb_err;
993 }
994
995 static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
996 {
997 struct sd *sd = (struct sd *) gspca_dev;
998
999 *val = sd->gain;
1000 return 0;
1001 }
1002
1003 static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1004 {
1005 struct sd *sd = (struct sd *) gspca_dev;
1006
1007 sd->exposure = val;
1008 if (gspca_dev->streaming)
1009 setexposure(gspca_dev);
1010 return gspca_dev->usb_err;
1011 }
1012
1013 static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1014 {
1015 struct sd *sd = (struct sd *) gspca_dev;
1016
1017 *val = sd->exposure;
1018 return 0;
1019 }
1020
1021 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1022 {
1023 struct sd *sd = (struct sd *) gspca_dev;
1024
1025 sd->autogain = val;
1026 /* when switching to autogain set defaults to make sure
1027 we are on a valid point of the autogain gain /
1028 exposure knee graph, and give this change time to
1029 take effect before doing autogain. */
1030 if (sd->autogain) {
1031 sd->exposure = EXPOSURE_DEF;
1032 sd->gain = GAIN_DEF;
1033 if (gspca_dev->streaming) {
1034 sd->autogain_ignore_frames =
1035 PAC_AUTOGAIN_IGNORE_FRAMES;
1036 setexposure(gspca_dev);
1037 setgain(gspca_dev);
1038 }
1039 }
1040
1041 return gspca_dev->usb_err;
1042 }
1043
1044 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1045 {
1046 struct sd *sd = (struct sd *) gspca_dev;
1047
1048 *val = sd->autogain;
1049 return 0;
1050 }
1051
1052 static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
1053 {
1054 struct sd *sd = (struct sd *) gspca_dev;
1055
1056 sd->hflip = val;
1057 if (gspca_dev->streaming)
1058 sethvflip(gspca_dev);
1059 return gspca_dev->usb_err;
1060 }
1061
1062 static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
1063 {
1064 struct sd *sd = (struct sd *) gspca_dev;
1065
1066 *val = sd->hflip;
1067 return 0;
1068 }
1069
1070 static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
1071 {
1072 struct sd *sd = (struct sd *) gspca_dev;
1073
1074 sd->vflip = val;
1075 if (gspca_dev->streaming)
1076 sethvflip(gspca_dev);
1077 return gspca_dev->usb_err;
1078 }
1079
1080 static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
1081 {
1082 struct sd *sd = (struct sd *) gspca_dev;
1083
1084 *val = sd->vflip;
1085 return 0;
1086 }
1087
1088 #ifdef CONFIG_VIDEO_ADV_DEBUG
1089 static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
1090 struct v4l2_dbg_register *reg)
1091 {
1092 __u8 index;
1093 __u8 value;
1094
1095 /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit
1096 long on the USB bus)
1097 */
1098 if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
1099 reg->match.addr == 0 &&
1100 (reg->reg < 0x000000ff) &&
1101 (reg->val <= 0x000000ff)
1102 ) {
1103 /* Currently writing to page 0 is only supported. */
1104 /* reg_w() only supports 8bit index */
1105 index = reg->reg & 0x000000ff;
1106 value = reg->val & 0x000000ff;
1107
1108 /* Note that there shall be no access to other page
1109 by any other function between the page swith and
1110 the actual register write */
1111 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
1112 reg_w(gspca_dev, index, value);
1113
1114 reg_w(gspca_dev, 0xdc, 0x01);
1115 }
1116 return gspca_dev->usb_err;
1117 }
1118
1119 static int sd_chip_ident(struct gspca_dev *gspca_dev,
1120 struct v4l2_dbg_chip_ident *chip)
1121 {
1122 int ret = -EINVAL;
1123
1124 if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
1125 chip->match.addr == 0) {
1126 chip->revision = 0;
1127 chip->ident = V4L2_IDENT_UNKNOWN;
1128 ret = 0;
1129 }
1130 return ret;
1131 }
1132 #endif
1133
1134 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
1135 static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
1136 u8 *data, /* interrupt packet data */
1137 int len) /* interrput packet length */
1138 {
1139 int ret = -EINVAL;
1140 u8 data0, data1;
1141
1142 if (len == 2) {
1143 data0 = data[0];
1144 data1 = data[1];
1145 if ((data0 == 0x00 && data1 == 0x11) ||
1146 (data0 == 0x22 && data1 == 0x33) ||
1147 (data0 == 0x44 && data1 == 0x55) ||
1148 (data0 == 0x66 && data1 == 0x77) ||
1149 (data0 == 0x88 && data1 == 0x99) ||
1150 (data0 == 0xaa && data1 == 0xbb) ||
1151 (data0 == 0xcc && data1 == 0xdd) ||
1152 (data0 == 0xee && data1 == 0xff)) {
1153 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
1154 input_sync(gspca_dev->input_dev);
1155 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
1156 input_sync(gspca_dev->input_dev);
1157 ret = 0;
1158 }
1159 }
1160
1161 return ret;
1162 }
1163 #endif
1164
1165 /* sub-driver description for pac7302 */
1166 static const struct sd_desc sd_desc = {
1167 .name = MODULE_NAME,
1168 .ctrls = sd_ctrls,
1169 .nctrls = ARRAY_SIZE(sd_ctrls),
1170 .config = sd_config,
1171 .init = sd_init,
1172 .start = sd_start,
1173 .stopN = sd_stopN,
1174 .stop0 = sd_stop0,
1175 .pkt_scan = sd_pkt_scan,
1176 .dq_callback = do_autogain,
1177 #ifdef CONFIG_VIDEO_ADV_DEBUG
1178 .set_register = sd_dbg_s_register,
1179 .get_chip_ident = sd_chip_ident,
1180 #endif
1181 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
1182 .int_pkt_scan = sd_int_pkt_scan,
1183 #endif
1184 };
1185
1186 /* -- module initialisation -- */
1187 static const struct usb_device_id device_table[] __devinitconst = {
1188 {USB_DEVICE(0x06f8, 0x3009)},
1189 {USB_DEVICE(0x093a, 0x2620)},
1190 {USB_DEVICE(0x093a, 0x2621)},
1191 {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
1192 {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
1193 {USB_DEVICE(0x093a, 0x2625)},
1194 {USB_DEVICE(0x093a, 0x2626)},
1195 {USB_DEVICE(0x093a, 0x2628)},
1196 {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
1197 {USB_DEVICE(0x093a, 0x262a)},
1198 {USB_DEVICE(0x093a, 0x262c)},
1199 {}
1200 };
1201 MODULE_DEVICE_TABLE(usb, device_table);
1202
1203 /* -- device connect -- */
1204 static int __devinit sd_probe(struct usb_interface *intf,
1205 const struct usb_device_id *id)
1206 {
1207 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1208 THIS_MODULE);
1209 }
1210
1211 static struct usb_driver sd_driver = {
1212 .name = MODULE_NAME,
1213 .id_table = device_table,
1214 .probe = sd_probe,
1215 .disconnect = gspca_disconnect,
1216 #ifdef CONFIG_PM
1217 .suspend = gspca_suspend,
1218 .resume = gspca_resume,
1219 #endif
1220 };
1221
1222 /* -- module insert / remove -- */
1223 static int __init sd_mod_init(void)
1224 {
1225 return usb_register(&sd_driver);
1226 }
1227 static void __exit sd_mod_exit(void)
1228 {
1229 usb_deregister(&sd_driver);
1230 }
1231
1232 module_init(sd_mod_init);
1233 module_exit(sd_mod_exit);
This page took 0.059143 seconds and 5 git commands to generate.