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 70MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); 71MODULE_DESCRIPTION("Pixart PAC7302"); 72MODULE_LICENSE("GPL"); 73 74/* specific webcam descriptor for pac7302 */ 75struct 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 */ 100static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); 101static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); 102static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); 103static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); 104static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); 105static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); 106static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val); 107static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val); 108static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val); 109static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val); 110static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val); 111static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val); 112static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); 113static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); 114static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); 115static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); 116static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); 117static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); 118static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); 119static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); 120static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); 121static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); 122 123static 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 286static 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 */ 298static 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}; 305static 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() */ 371static 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 394static 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 PDEBUG(D_ERR, "reg_w_buf(): " 412 "Failed to write registers to index 0x%x, error %i", 413 index, ret); 414 gspca_dev->usb_err = ret; 415 } 416} 417 418 419static void reg_w(struct gspca_dev *gspca_dev, 420 __u8 index, 421 __u8 value) 422{ 423 int ret; 424 425 if (gspca_dev->usb_err < 0) 426 return; 427 gspca_dev->usb_buf[0] = value; 428 ret = usb_control_msg(gspca_dev->dev, 429 usb_sndctrlpipe(gspca_dev->dev, 0), 430 0, /* request */ 431 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 432 0, index, gspca_dev->usb_buf, 1, 433 500); 434 if (ret < 0) { 435 PDEBUG(D_ERR, "reg_w(): " 436 "Failed to write register to index 0x%x, value 0x%x, error %i", 437 index, value, ret); 438 gspca_dev->usb_err = ret; 439 } 440} 441 442static void reg_w_seq(struct gspca_dev *gspca_dev, 443 const __u8 *seq, int len) 444{ 445 while (--len >= 0) { 446 reg_w(gspca_dev, seq[0], seq[1]); 447 seq += 2; 448 } 449} 450 451/* load the beginning of a page */ 452static void reg_w_page(struct gspca_dev *gspca_dev, 453 const __u8 *page, int len) 454{ 455 int index; 456 int ret = 0; 457 458 if (gspca_dev->usb_err < 0) 459 return; 460 for (index = 0; index < len; index++) { 461 if (page[index] == SKIP) /* skip this index */ 462 continue; 463 gspca_dev->usb_buf[0] = page[index]; 464 ret = usb_control_msg(gspca_dev->dev, 465 usb_sndctrlpipe(gspca_dev->dev, 0), 466 0, /* request */ 467 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 468 0, index, gspca_dev->usb_buf, 1, 469 500); 470 if (ret < 0) { 471 PDEBUG(D_ERR, "reg_w_page(): " 472 "Failed to write register to index 0x%x, " 473 "value 0x%x, error %i", 474 index, page[index], ret); 475 gspca_dev->usb_err = ret; 476 break; 477 } 478 } 479} 480 481/* output a variable sequence */ 482static void reg_w_var(struct gspca_dev *gspca_dev, 483 const __u8 *seq, 484 const __u8 *page3, unsigned int page3_len) 485{ 486 int index, len; 487 488 for (;;) { 489 index = *seq++; 490 len = *seq++; 491 switch (len) { 492 case END_OF_SEQUENCE: 493 return; 494 case LOAD_PAGE3: 495 reg_w_page(gspca_dev, page3, page3_len); 496 break; 497 default: 498 if (len > USB_BUF_SZ) { 499 PDEBUG(D_ERR|D_STREAM, 500 "Incorrect variable sequence"); 501 return; 502 } 503 while (len > 0) { 504 if (len < 8) { 505 reg_w_buf(gspca_dev, 506 index, seq, len); 507 seq += len; 508 break; 509 } 510 reg_w_buf(gspca_dev, index, seq, 8); 511 seq += 8; 512 index += 8; 513 len -= 8; 514 } 515 } 516 } 517 /* not reached */ 518} 519 520/* this function is called at probe time for pac7302 */ 521static int sd_config(struct gspca_dev *gspca_dev, 522 const struct usb_device_id *id) 523{ 524 struct sd *sd = (struct sd *) gspca_dev; 525 struct cam *cam; 526 527 cam = &gspca_dev->cam; 528 529 PDEBUG(D_CONF, "Find Sensor PAC7302"); 530 cam->cam_mode = vga_mode; /* only 640x480 */ 531 cam->nmodes = ARRAY_SIZE(vga_mode); 532 533 sd->brightness = BRIGHTNESS_DEF; 534 sd->contrast = CONTRAST_DEF; 535 sd->colors = COLOR_DEF; 536 sd->white_balance = WHITEBALANCE_DEF; 537 sd->red_balance = REDBALANCE_DEF; 538 sd->blue_balance = BLUEBALANCE_DEF; 539 sd->gain = GAIN_DEF; 540 sd->exposure = EXPOSURE_DEF; 541 sd->autogain = AUTOGAIN_DEF; 542 sd->hflip = HFLIP_DEF; 543 sd->vflip = VFLIP_DEF; 544 sd->flags = id->driver_info; 545 return 0; 546} 547 548/* This function is used by pac7302 only */ 549static void setbrightcont(struct gspca_dev *gspca_dev) 550{ 551 struct sd *sd = (struct sd *) gspca_dev; 552 int i, v; 553 static const __u8 max[10] = 554 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb, 555 0xd4, 0xec}; 556 static const __u8 delta[10] = 557 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17, 558 0x11, 0x0b}; 559 560 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ 561 for (i = 0; i < 10; i++) { 562 v = max[i]; 563 v += (sd->brightness - BRIGHTNESS_MAX) 564 * 150 / BRIGHTNESS_MAX; /* 200 ? */ 565 v -= delta[i] * sd->contrast / CONTRAST_MAX; 566 if (v < 0) 567 v = 0; 568 else if (v > 0xff) 569 v = 0xff; 570 reg_w(gspca_dev, 0xa2 + i, v); 571 } 572 reg_w(gspca_dev, 0xdc, 0x01); 573} 574 575/* This function is used by pac7302 only */ 576static void setcolors(struct gspca_dev *gspca_dev) 577{ 578 struct sd *sd = (struct sd *) gspca_dev; 579 int i, v; 580 static const int a[9] = 581 {217, -212, 0, -101, 170, -67, -38, -315, 355}; 582 static const int b[9] = 583 {19, 106, 0, 19, 106, 1, 19, 106, 1}; 584 585 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ 586 reg_w(gspca_dev, 0x11, 0x01); 587 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ 588 for (i = 0; i < 9; i++) { 589 v = a[i] * sd->colors / COLOR_MAX + b[i]; 590 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); 591 reg_w(gspca_dev, 0x0f + 2 * i + 1, v); 592 } 593 reg_w(gspca_dev, 0xdc, 0x01); 594 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); 595} 596 597static void setwhitebalance(struct gspca_dev *gspca_dev) 598{ 599 struct sd *sd = (struct sd *) gspca_dev; 600 601 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ 602 reg_w(gspca_dev, 0xc6, sd->white_balance); 603 604 reg_w(gspca_dev, 0xdc, 0x01); 605 PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance); 606} 607 608static void setredbalance(struct gspca_dev *gspca_dev) 609{ 610 struct sd *sd = (struct sd *) gspca_dev; 611 612 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ 613 reg_w(gspca_dev, 0xc5, sd->red_balance); 614 615 reg_w(gspca_dev, 0xdc, 0x01); 616 PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance); 617} 618 619static void setbluebalance(struct gspca_dev *gspca_dev) 620{ 621 struct sd *sd = (struct sd *) gspca_dev; 622 623 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ 624 reg_w(gspca_dev, 0xc7, sd->blue_balance); 625 626 reg_w(gspca_dev, 0xdc, 0x01); 627 PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance); 628} 629 630static void setgain(struct gspca_dev *gspca_dev) 631{ 632 struct sd *sd = (struct sd *) gspca_dev; 633 634 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ 635 reg_w(gspca_dev, 0x10, sd->gain >> 3); 636 637 /* load registers to sensor (Bit 0, auto clear) */ 638 reg_w(gspca_dev, 0x11, 0x01); 639} 640 641static void setexposure(struct gspca_dev *gspca_dev) 642{ 643 struct sd *sd = (struct sd *) gspca_dev; 644 __u8 clockdiv; 645 __u16 exposure; 646 647 /* register 2 of frame 3 contains the clock divider configuring the 648 no fps according to the formula: 90 / reg. sd->exposure is the 649 desired exposure time in 0.5 ms. */ 650 clockdiv = (90 * sd->exposure + 1999) / 2000; 651 652 /* Note clockdiv = 3 also works, but when running at 30 fps, depending 653 on the scene being recorded, the camera switches to another 654 quantization table for certain JPEG blocks, and we don't know how 655 to decompress these blocks. So we cap the framerate at 15 fps */ 656 if (clockdiv < 6) 657 clockdiv = 6; 658 else if (clockdiv > 63) 659 clockdiv = 63; 660 661 /* reg2 MUST be a multiple of 3, except when between 6 and 12? 662 Always round up, otherwise we cannot get the desired frametime 663 using the partial frame time exposure control */ 664 if (clockdiv < 6 || clockdiv > 12) 665 clockdiv = ((clockdiv + 2) / 3) * 3; 666 667 /* frame exposure time in ms = 1000 * clockdiv / 90 -> 668 exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */ 669 exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv); 670 /* 0 = use full frametime, 448 = no exposure, reverse it */ 671 exposure = 448 - exposure; 672 673 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ 674 reg_w(gspca_dev, 0x02, clockdiv); 675 reg_w(gspca_dev, 0x0e, exposure & 0xff); 676 reg_w(gspca_dev, 0x0f, exposure >> 8); 677 678 /* load registers to sensor (Bit 0, auto clear) */ 679 reg_w(gspca_dev, 0x11, 0x01); 680} 681 682static void sethvflip(struct gspca_dev *gspca_dev) 683{ 684 struct sd *sd = (struct sd *) gspca_dev; 685 u8 data, hflip, vflip; 686 687 hflip = sd->hflip; 688 if (sd->flags & FL_HFLIP) 689 hflip = !hflip; 690 vflip = sd->vflip; 691 if (sd->flags & FL_VFLIP) 692 vflip = !vflip; 693 694 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ 695 data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00); 696 reg_w(gspca_dev, 0x21, data); 697 698 /* load registers to sensor (Bit 0, auto clear) */ 699 reg_w(gspca_dev, 0x11, 0x01); 700} 701 702/* this function is called at probe and resume time for pac7302 */ 703static int sd_init(struct gspca_dev *gspca_dev) 704{ 705 reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2); 706 return gspca_dev->usb_err; 707} 708 709static int sd_start(struct gspca_dev *gspca_dev) 710{ 711 struct sd *sd = (struct sd *) gspca_dev; 712 713 sd->sof_read = 0; 714 715 reg_w_var(gspca_dev, start_7302, 716 page3_7302, sizeof(page3_7302)); 717 setbrightcont(gspca_dev); 718 setcolors(gspca_dev); 719 setwhitebalance(gspca_dev); 720 setredbalance(gspca_dev); 721 setbluebalance(gspca_dev); 722 setgain(gspca_dev); 723 setexposure(gspca_dev); 724 sethvflip(gspca_dev); 725 726 /* only resolution 640x480 is supported for pac7302 */ 727 728 sd->sof_read = 0; 729 sd->autogain_ignore_frames = 0; 730 atomic_set(&sd->avg_lum, -1); 731 732 /* start stream */ 733 reg_w(gspca_dev, 0xff, 0x01); 734 reg_w(gspca_dev, 0x78, 0x01); 735 736 return gspca_dev->usb_err; 737} 738 739static void sd_stopN(struct gspca_dev *gspca_dev) 740{ 741 742 /* stop stream */ 743 reg_w(gspca_dev, 0xff, 0x01); 744 reg_w(gspca_dev, 0x78, 0x00); 745} 746 747/* called on streamoff with alt 0 and on disconnect for pac7302 */ 748static void sd_stop0(struct gspca_dev *gspca_dev) 749{ 750 if (!gspca_dev->present) 751 return; 752 reg_w(gspca_dev, 0xff, 0x01); 753 reg_w(gspca_dev, 0x78, 0x40); 754} 755 756/* Include pac common sof detection functions */ 757#include "pac_common.h" 758 759static void do_autogain(struct gspca_dev *gspca_dev) 760{ 761 struct sd *sd = (struct sd *) gspca_dev; 762 int avg_lum = atomic_read(&sd->avg_lum); 763 int desired_lum; 764 const int deadzone = 30; 765 766 if (avg_lum == -1) 767 return; 768 769 desired_lum = 270 + sd->brightness; 770 771 if (sd->autogain_ignore_frames > 0) 772 sd->autogain_ignore_frames--; 773 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum, 774 deadzone, GAIN_KNEE, EXPOSURE_KNEE)) 775 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; 776} 777 778/* JPEG header, part 1 */ 779static const unsigned char pac_jpeg_header1[] = { 780 0xff, 0xd8, /* SOI: Start of Image */ 781 782 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */ 783 0x00, 0x11, /* length = 17 bytes (including this length field) */ 784 0x08 /* Precision: 8 */ 785 /* 2 bytes is placed here: number of image lines */ 786 /* 2 bytes is placed here: samples per line */ 787}; 788 789/* JPEG header, continued */ 790static const unsigned char pac_jpeg_header2[] = { 791 0x03, /* Number of image components: 3 */ 792 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */ 793 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */ 794 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */ 795 796 0xff, 0xda, /* SOS: Start Of Scan */ 797 0x00, 0x0c, /* length = 12 bytes (including this length field) */ 798 0x03, /* number of components: 3 */ 799 0x01, 0x00, /* selector 1, table 0x00 */ 800 0x02, 0x11, /* selector 2, table 0x11 */ 801 0x03, 0x11, /* selector 3, table 0x11 */ 802 0x00, 0x3f, /* Spectral selection: 0 .. 63 */ 803 0x00 /* Successive approximation: 0 */ 804}; 805 806static void pac_start_frame(struct gspca_dev *gspca_dev, 807 __u16 lines, __u16 samples_per_line) 808{ 809 unsigned char tmpbuf[4]; 810 811 gspca_frame_add(gspca_dev, FIRST_PACKET, 812 pac_jpeg_header1, sizeof(pac_jpeg_header1)); 813 814 tmpbuf[0] = lines >> 8; 815 tmpbuf[1] = lines & 0xff; 816 tmpbuf[2] = samples_per_line >> 8; 817 tmpbuf[3] = samples_per_line & 0xff; 818 819 gspca_frame_add(gspca_dev, INTER_PACKET, 820 tmpbuf, sizeof(tmpbuf)); 821 gspca_frame_add(gspca_dev, INTER_PACKET, 822 pac_jpeg_header2, sizeof(pac_jpeg_header2)); 823} 824 825/* this function is run at interrupt level */ 826static void sd_pkt_scan(struct gspca_dev *gspca_dev, 827 u8 *data, /* isoc packet */ 828 int len) /* iso packet length */ 829{ 830 struct sd *sd = (struct sd *) gspca_dev; 831 u8 *image; 832 unsigned char *sof; 833 834 sof = pac_find_sof(&sd->sof_read, data, len); 835 if (sof) { 836 int n, lum_offset, footer_length; 837 838 /* 6 bytes after the FF D9 EOF marker a number of lumination 839 bytes are send corresponding to different parts of the 840 image, the 14th and 15th byte after the EOF seem to 841 correspond to the center of the image */ 842 lum_offset = 61 + sizeof pac_sof_marker; 843 footer_length = 74; 844 845 /* Finish decoding current frame */ 846 n = (sof - data) - (footer_length + sizeof pac_sof_marker); 847 if (n < 0) { 848 gspca_dev->image_len += n; 849 n = 0; 850 } else { 851 gspca_frame_add(gspca_dev, INTER_PACKET, data, n); 852 } 853 854 image = gspca_dev->image; 855 if (image != NULL 856 && image[gspca_dev->image_len - 2] == 0xff 857 && image[gspca_dev->image_len - 1] == 0xd9) 858 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); 859 860 n = sof - data; 861 len -= n; 862 data = sof; 863 864 /* Get average lumination */ 865 if (gspca_dev->last_packet_type == LAST_PACKET && 866 n >= lum_offset) 867 atomic_set(&sd->avg_lum, data[-lum_offset] + 868 data[-lum_offset + 1]); 869 else 870 atomic_set(&sd->avg_lum, -1); 871 872 /* Start the new frame with the jpeg header */ 873 /* The PAC7302 has the image rotated 90 degrees */ 874 pac_start_frame(gspca_dev, 875 gspca_dev->width, gspca_dev->height); 876 } 877 gspca_frame_add(gspca_dev, INTER_PACKET, data, len); 878} 879 880static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) 881{ 882 struct sd *sd = (struct sd *) gspca_dev; 883 884 sd->brightness = val; 885 if (gspca_dev->streaming) 886 setbrightcont(gspca_dev); 887 return gspca_dev->usb_err; 888} 889 890static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) 891{ 892 struct sd *sd = (struct sd *) gspca_dev; 893 894 *val = sd->brightness; 895 return 0; 896} 897 898static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) 899{ 900 struct sd *sd = (struct sd *) gspca_dev; 901 902 sd->contrast = val; 903 if (gspca_dev->streaming) { 904 setbrightcont(gspca_dev); 905 } 906 return gspca_dev->usb_err; 907} 908 909static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) 910{ 911 struct sd *sd = (struct sd *) gspca_dev; 912 913 *val = sd->contrast; 914 return 0; 915} 916 917static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) 918{ 919 struct sd *sd = (struct sd *) gspca_dev; 920 921 sd->colors = val; 922 if (gspca_dev->streaming) 923 setcolors(gspca_dev); 924 return gspca_dev->usb_err; 925} 926 927static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) 928{ 929 struct sd *sd = (struct sd *) gspca_dev; 930 931 *val = sd->colors; 932 return 0; 933} 934 935static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val) 936{ 937 struct sd *sd = (struct sd *) gspca_dev; 938 939 sd->white_balance = val; 940 if (gspca_dev->streaming) 941 setwhitebalance(gspca_dev); 942 return gspca_dev->usb_err; 943} 944 945static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val) 946{ 947 struct sd *sd = (struct sd *) gspca_dev; 948 949 *val = sd->white_balance; 950 return 0; 951} 952 953static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val) 954{ 955 struct sd *sd = (struct sd *) gspca_dev; 956 957 sd->red_balance = val; 958 if (gspca_dev->streaming) 959 setredbalance(gspca_dev); 960 return gspca_dev->usb_err; 961} 962 963static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val) 964{ 965 struct sd *sd = (struct sd *) gspca_dev; 966 967 *val = sd->red_balance; 968 return 0; 969} 970 971static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val) 972{ 973 struct sd *sd = (struct sd *) gspca_dev; 974 975 sd->blue_balance = val; 976 if (gspca_dev->streaming) 977 setbluebalance(gspca_dev); 978 return gspca_dev->usb_err; 979} 980 981static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val) 982{ 983 struct sd *sd = (struct sd *) gspca_dev; 984 985 *val = sd->blue_balance; 986 return 0; 987} 988 989static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) 990{ 991 struct sd *sd = (struct sd *) gspca_dev; 992 993 sd->gain = val; 994 if (gspca_dev->streaming) 995 setgain(gspca_dev); 996 return gspca_dev->usb_err; 997} 998 999static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) 1000{ 1001 struct sd *sd = (struct sd *) gspca_dev; 1002 1003 *val = sd->gain; 1004 return 0; 1005} 1006 1007static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) 1008{ 1009 struct sd *sd = (struct sd *) gspca_dev; 1010 1011 sd->exposure = val; 1012 if (gspca_dev->streaming) 1013 setexposure(gspca_dev); 1014 return gspca_dev->usb_err; 1015} 1016 1017static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) 1018{ 1019 struct sd *sd = (struct sd *) gspca_dev; 1020 1021 *val = sd->exposure; 1022 return 0; 1023} 1024 1025static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) 1026{ 1027 struct sd *sd = (struct sd *) gspca_dev; 1028 1029 sd->autogain = val; 1030 /* when switching to autogain set defaults to make sure 1031 we are on a valid point of the autogain gain / 1032 exposure knee graph, and give this change time to 1033 take effect before doing autogain. */ 1034 if (sd->autogain) { 1035 sd->exposure = EXPOSURE_DEF; 1036 sd->gain = GAIN_DEF; 1037 if (gspca_dev->streaming) { 1038 sd->autogain_ignore_frames = 1039 PAC_AUTOGAIN_IGNORE_FRAMES; 1040 setexposure(gspca_dev); 1041 setgain(gspca_dev); 1042 } 1043 } 1044 1045 return gspca_dev->usb_err; 1046} 1047 1048static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) 1049{ 1050 struct sd *sd = (struct sd *) gspca_dev; 1051 1052 *val = sd->autogain; 1053 return 0; 1054} 1055 1056static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) 1057{ 1058 struct sd *sd = (struct sd *) gspca_dev; 1059 1060 sd->hflip = val; 1061 if (gspca_dev->streaming) 1062 sethvflip(gspca_dev); 1063 return gspca_dev->usb_err; 1064} 1065 1066static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) 1067{ 1068 struct sd *sd = (struct sd *) gspca_dev; 1069 1070 *val = sd->hflip; 1071 return 0; 1072} 1073 1074static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) 1075{ 1076 struct sd *sd = (struct sd *) gspca_dev; 1077 1078 sd->vflip = val; 1079 if (gspca_dev->streaming) 1080 sethvflip(gspca_dev); 1081 return gspca_dev->usb_err; 1082} 1083 1084static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) 1085{ 1086 struct sd *sd = (struct sd *) gspca_dev; 1087 1088 *val = sd->vflip; 1089 return 0; 1090} 1091 1092#ifdef CONFIG_VIDEO_ADV_DEBUG 1093static int sd_dbg_s_register(struct gspca_dev *gspca_dev, 1094 struct v4l2_dbg_register *reg) 1095{ 1096 __u8 index; 1097 __u8 value; 1098 1099 /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit 1100 long on the USB bus) 1101 */ 1102 if (reg->match.type == V4L2_CHIP_MATCH_HOST && 1103 reg->match.addr == 0 && 1104 (reg->reg < 0x000000ff) && 1105 (reg->val <= 0x000000ff) 1106 ) { 1107 /* Currently writing to page 0 is only supported. */ 1108 /* reg_w() only supports 8bit index */ 1109 index = reg->reg & 0x000000ff; 1110 value = reg->val & 0x000000ff; 1111 1112 /* Note that there shall be no access to other page 1113 by any other function between the page swith and 1114 the actual register write */ 1115 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ 1116 reg_w(gspca_dev, index, value); 1117 1118 reg_w(gspca_dev, 0xdc, 0x01); 1119 } 1120 return gspca_dev->usb_err; 1121} 1122 1123static int sd_chip_ident(struct gspca_dev *gspca_dev, 1124 struct v4l2_dbg_chip_ident *chip) 1125{ 1126 int ret = -EINVAL; 1127 1128 if (chip->match.type == V4L2_CHIP_MATCH_HOST && 1129 chip->match.addr == 0) { 1130 chip->revision = 0; 1131 chip->ident = V4L2_IDENT_UNKNOWN; 1132 ret = 0; 1133 } 1134 return ret; 1135} 1136#endif 1137 1138#ifdef CONFIG_INPUT 1139static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, 1140 u8 *data, /* interrupt packet data */ 1141 int len) /* interrput packet length */ 1142{ 1143 int ret = -EINVAL; 1144 u8 data0, data1; 1145 1146 if (len == 2) { 1147 data0 = data[0]; 1148 data1 = data[1]; 1149 if ((data0 == 0x00 && data1 == 0x11) || 1150 (data0 == 0x22 && data1 == 0x33) || 1151 (data0 == 0x44 && data1 == 0x55) || 1152 (data0 == 0x66 && data1 == 0x77) || 1153 (data0 == 0x88 && data1 == 0x99) || 1154 (data0 == 0xaa && data1 == 0xbb) || 1155 (data0 == 0xcc && data1 == 0xdd) || 1156 (data0 == 0xee && data1 == 0xff)) { 1157 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); 1158 input_sync(gspca_dev->input_dev); 1159 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); 1160 input_sync(gspca_dev->input_dev); 1161 ret = 0; 1162 } 1163 } 1164 1165 return ret; 1166} 1167#endif 1168 1169/* sub-driver description for pac7302 */ 1170static const struct sd_desc sd_desc = { 1171 .name = MODULE_NAME, 1172 .ctrls = sd_ctrls, 1173 .nctrls = ARRAY_SIZE(sd_ctrls), 1174 .config = sd_config, 1175 .init = sd_init, 1176 .start = sd_start, 1177 .stopN = sd_stopN, 1178 .stop0 = sd_stop0, 1179 .pkt_scan = sd_pkt_scan, 1180 .dq_callback = do_autogain, 1181#ifdef CONFIG_VIDEO_ADV_DEBUG 1182 .set_register = sd_dbg_s_register, 1183 .get_chip_ident = sd_chip_ident, 1184#endif 1185#ifdef CONFIG_INPUT 1186 .int_pkt_scan = sd_int_pkt_scan, 1187#endif 1188}; 1189 1190/* -- module initialisation -- */ 1191static const struct usb_device_id device_table[] __devinitconst = { 1192 {USB_DEVICE(0x06f8, 0x3009)}, 1193 {USB_DEVICE(0x093a, 0x2620)}, 1194 {USB_DEVICE(0x093a, 0x2621)}, 1195 {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP}, 1196 {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP}, 1197 {USB_DEVICE(0x093a, 0x2625)}, 1198 {USB_DEVICE(0x093a, 0x2626)}, 1199 {USB_DEVICE(0x093a, 0x2628)}, 1200 {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP}, 1201 {USB_DEVICE(0x093a, 0x262a)}, 1202 {USB_DEVICE(0x093a, 0x262c)}, 1203 {} 1204}; 1205MODULE_DEVICE_TABLE(usb, device_table); 1206 1207/* -- device connect -- */ 1208static int __devinit sd_probe(struct usb_interface *intf, 1209 const struct usb_device_id *id) 1210{ 1211 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), 1212 THIS_MODULE); 1213} 1214 1215static struct usb_driver sd_driver = { 1216 .name = MODULE_NAME, 1217 .id_table = device_table, 1218 .probe = sd_probe, 1219 .disconnect = gspca_disconnect, 1220#ifdef CONFIG_PM 1221 .suspend = gspca_suspend, 1222 .resume = gspca_resume, 1223#endif 1224}; 1225 1226/* -- module insert / remove -- */ 1227static int __init sd_mod_init(void) 1228{ 1229 int ret; 1230 ret = usb_register(&sd_driver); 1231 if (ret < 0) 1232 return ret; 1233 PDEBUG(D_PROBE, "registered"); 1234 return 0; 1235} 1236static void __exit sd_mod_exit(void) 1237{ 1238 usb_deregister(&sd_driver); 1239 PDEBUG(D_PROBE, "deregistered"); 1240} 1241 1242module_init(sd_mod_init); 1243module_exit(sd_mod_exit); 1244