Version: v4.11.2

linux/drivers/media/usb/gspca/sq930x.c

     1 
     2 
     3 
     4 
     5 
     6 
     7 
     8 
     9 
    10 
    11 
    12 
    13 
    14 
    15 
    16 
    17 
    18 
    19 
    20 
    21 
    22 
    23 
    24 
    25 
    26 
    27 
    28 
    29 
    30 
    31 
    32 
    33 
    34 
    35 
    36 
    37 
    38 
    39 
    40 
    41 
    42 
    43 
    44 
    45 
    46 
    47 
    48 
    49 
    50 
    51 
    52 
    53 
    54 
    55 
    56 
    57 
    58 
    59 
    60 
    61 
    62 
    63 
    64 
    65 
    66 
    67 
    68 
    69 
    70 
    71 
    72 
    73 
    74 
    75 
    76 
    77 
    78 
    79 
    80 
    81 
    82 
    83 
    84 
    85 
    86 
    87 
    88 
    89 
    90 
    91 
    92 
    93 
    94 
    95 
    96 
    97 
    98 
    99 
   100 
   101 
   102 
   103 
   104 
   105 
   106 
   107 
   108 
   109 
   110 
   111 
   112 
   113 
   114 
   115 
   116 
   117 
   118 
   119 
   120 
   121 
   122 
   123 
   124 
   125 
   126 
   127 
   128 
   129 
   130 
   131 
   132 
   133 
   134 
   135 
   136 
   137 
   138 
   139 
   140 
   141 
   142 
   143 
   144 
   145 
   146 
   147 
   148 
   149 
   150 
   151 
   152 
   153 
   154 
   155 
   156 
   157 
   158 
   159 
   160 
   161 
   162 
   163 
   164 
   165 
   166 
   167 
   168 
   169 
   170 
   171 
   172 
   173 
   174 
   175 
   176 
   177 
   178 
   179 
   180 
   181 
   182 
   183 
   184 
   185 
   186 
   187 
   188 
   189 
   190 
   191 
   192 
   193 
   194 
   195 
   196 
   197 
   198 
   199 
   200 
   201 
   202 
   203 
   204 
   205 
   206 
   207 
   208 
   209 
   210 
   211 
   212 
   213 
   214 
   215 
   216 
   217 
   218 
   219 
   220 
   221 
   222 
   223 
   224 
   225 
   226 
   227 
   228 
   229 
   230 
   231 
   232 
   233 
   234 
   235 
   236 
   237 
   238 
   239 
   240 
   241 
   242 
   243 
   244 
   245 
   246 
   247 
   248 
   249 
   250 
   251 
   252 
   253 
   254 
   255 
   256 
   257 
   258 
   259 
   260 
   261 
   262 
   263 
   264 
   265 
   266 
   267 
   268 
   269 
   270 
   271 
   272 
   273 
   274 
   275 
   276 
   277 
   278 
   279 
   280 
   281 
   282 
   283 
   284 
   285 
   286 
   287 
   288 
   289 
   290 
   291 
   292 
   293 
   294 
   295 
   296 
   297 
   298 
   299 
   300 
   301 
   302 
   303 
   304 
   305 
   306 
   307 
   308 
   309 
   310 
   311 
   312 
   313 
   314 
   315 
   316 
   317 
   318 
   319 
   320 
   321 
   322 
   323 
   324 
   325 
   326 
   327 
   328 
   329 
   330 
   331 
   332 
   333 
   334 
   335 
   336 
   337 
   338 
   339 
   340 
   341 
   342 
   343 
   344 
   345 
   346 
   347 
   348 
   349 
   350 
   351 
   352 
   353 
   354 
   355 
   356 
   357 
   358 
   359 
   360 
   361 
   362 
   363 
   364 
   365 
   366 
   367 
   368 
   369 
   370 
   371 
   372 
   373 
   374 
   375 
   376 
   377 
   378 
   379 
   380 
   381 
   382 
   383 
   384 
   385 
   386 
   387 
   388 
   389 
   390 
   391 
   392 
   393 
   394 
   395 
   396 
   397 
   398 
   399 
   400 
   401 
   402 
   403 
   404 
   405 
   406 
   407 
   408 
   409 
   410 
   411 
   412 
   413 
   414 
   415 
   416 
   417 
   418 
   419 
   420 
   421 
   422 
   423 
   424 
   425 
   426 
   427 
   428 
   429 
   430 
   431 
   432 
   433 
   434 
   435 
   436 
   437 
   438 
   439 
   440 
   441 
   442 
   443 
   444 
   445 
   446 
   447 
   448 
   449 
   450 
   451 
   452 
   453 
   454 
   455 
   456 
   457 
   458 
   459 
   460 
   461 
   462 
   463 
   464 
   465 
   466 
   467 
   468 
   469 
   470 
   471 
   472 
   473 
   474 
   475 
   476 
   477 
   478 
   479 
   480 
   481 
   482 
   483 
   484 
   485 
   486 
   487 
   488 
   489 
   490 
   491 
   492 
   493 
   494 
   495 
   496 
   497 
   498 
   499 
   500 
   501 
   502 
   503 
   504 
   505 
   506 
   507 
   508 
   509 
   510 
   511 
   512 
   513 
   514 
   515 
   516 
   517 
   518 
   519 
   520 
   521 
   522 
   523 
   524 
   525 
   526 
   527 
   528 
   529 
   530 
   531 
   532 
   533 
   534 
   535 
   536 
   537 
   538 
   539 
   540 
   541 
   542 
   543 
   544 
   545 
   546 
   547 
   548 
   549 
   550 
   551 
   552 
   553 
   554 
   555 
   556 
   557 
   558 
   559 
   560 
   561 
   562 
   563 
   564 
   565 
   566 
   567 
   568 
   569 
   570 
   571 
   572 
   573 
   574 
   575 
   576 
   577 
   578 
   579 
   580 
   581 
   582 
   583 
   584 
   585 
   586 
   587 
   588 
   589 
   590 
   591 
   592 
   593 
   594 
   595 
   596 
   597 
   598 
   599 
   600 
   601 
   602 
   603 
   604 
   605 
   606 
   607 
   608 
   609 
   610 
   611 
   612 
   613 
   614 
   615 
   616 
   617 
   618 
   619 
   620 
   621 
   622 
   623 
   624 
   625 
   626 
   627 
   628 
   629 
   630 
   631 
   632 
   633 
   634 
   635 
   636 
   637 
   638 
   639 
   640 
   641 
   642 
   643 
   644 
   645 
   646 
   647 
   648 
   649 
   650 
   651 
   652 
   653 
   654 
   655 
   656 
   657 
   658 
   659 
   660 
   661 
   662 
   663 
   664 
   665 
   666 
   667 
   668 
   669 
   670 
   671 
   672 
   673 
   674 
   675 
   676 
   677 
   678 
   679 
   680 
   681 
   682 
   683 
   684 
   685 
   686 
   687 
   688 
   689 
   690 
   691 
   692 
   693 
   694 
   695 
   696 
   697 
   698 
   699 
   700 
   701 
   702 
   703 
   704 
   705 
   706 
   707 
   708 
   709 
   710 
   711 
   712 
   713 
   714 
   715 
   716 
   717 
   718 
   719 
   720 
   721 
   722 
   723 
   724 
   725 
   726 
   727 
   728 
   729 
   730 
   731 
   732 
   733 
   734 
   735 
   736 
   737 
   738 
   739 
   740 
   741 
   742 
   743 
   744 
   745 
   746 
   747 
   748 
   749 
   750 
   751 
   752 
   753 
   754 
   755 
   756 
   757 
   758 
   759 
   760 
   761 
   762 
   763 
   764 
   765 
   766 
   767 
   768 
   769 
   770 
   771 
   772 
   773 
   774 
   775 
   776 
   777 
   778 
   779 
   780 
   781 
   782 
   783 
   784 
   785 
   786 
   787 
   788 
   789 
   790 
   791 
   792 
   793 
   794 
   795 
   796 
   797 
   798 
   799 
   800 
   801 
   802 
   803 
   804 
   805 
   806 
   807 
   808 
   809 
   810 
   811 
   812 
   813 
   814 
   815 
   816 
   817 
   818 
   819 
   820 
   821 
   822 
   823 
   824 
   825 
   826 
   827 
   828 
   829 
   830 
   831 
   832 
   833 
   834 
   835 
   836 
   837 
   838 
   839 
   840 
   841 
   842 
   843 
   844 
   845 
   846 
   847 
   848 
   849 
   850 
   851 
   852 
   853 
   854 
   855 
   856 
   857 
   858 
   859 
   860 
   861 
   862 
   863 
   864 
   865 
   866 
   867 
   868 
   869 
   870 
   871 
   872 
   873 
   874 
   875 
   876 
   877 
   878 
   879 
   880 
   881 
   882 
   883 
   884 
   885 
   886 
   887 
   888 
   889 
   890 
   891 
   892 
   893 
   894 
   895 
   896 
   897 
   898 
   899 
   900 
   901 
   902 
   903 
   904 
   905 
   906 
   907 
   908 
   909 
   910 
   911 
   912 
   913 
   914 
   915 
   916 
   917 
   918 
   919 
   920 
   921 
   922 
   923 
   924 
   925 
   926 
   927 
   928 
   929 
   930 
   931 
   932 
   933 
   934 
   935 
   936 
   937 
   938 
   939 
   940 
   941 
   942 
   943 
   944 
   945 
   946 
   947 
   948 
   949 
   950 
   951 
   952 
   953 
   954 
   955 
   956 
   957 
   958 
   959 
   960 
   961 
   962 
   963 
   964 
   965 
   966 
   967 
   968 
   969 
   970 
   971 
   972 
   973 
   974 
   975 
   976 
   977 
   978 
   979 
   980 
   981 
   982 
   983 
   984 
   985 
   986 
   987 
   988 
   989 
   990 
   991 
   992 
   993 
   994 
   995 
   996 
   997 
   998 
   999 
  1000 
  1001 
  1002 
  1003 
  1004 
  1005 
  1006 
  1007 
  1008 
  1009 
  1010 
  1011 
  1012 
  1013 
  1014 
  1015 
  1016 
  1017 
  1018 
  1019 
  1020 
  1021 
  1022 
  1023 
  1024 
  1025 
  1026 
  1027 
  1028 
  1029 
  1030 
  1031 
  1032 
  1033 
  1034 
  1035 
  1036 
  1037 
  1038 
  1039 
  1040 
  1041 
  1042 
  1043 
  1044 
  1045 
  1046 
  1047 
  1048 
  1049 
  1050 
  1051 
  1052 
  1053 
  1054 
  1055 
  1056 
  1057 
  1058 
  1059 
  1060 
  1061 
  1062 
  1063 
  1064 
  1065 
  1066 
  1067 
  1068 
  1069 
  1070 
  1071 
  1072 
  1073 
  1074 
  1075 
  1076 
  1077 
  1078 
  1079 
  1080 
  1081 
  1082 
  1083 
  1084 
  1085 
  1086 
  1087 
  1088 
  1089 
  1090 
  1091 
  1092 
  1093 
  1094 
  1095 
  1096 
  1097 
  1098 
  1099 
  1100 
  1101 
  1102 
  1103 
  1104 
  1105 
  1106 
  1107 
  1108 
  1109 
  1110 
  1111 
  1112 
  1113 
  1114 
  1115 
  1116 
  1117 
  1118 
  1119 
  1120 
  1121 
  1122 
  1123 
  1124 
  1125 
  1126 
  1127 
  1128 
  1129 
  1130 
  1131 
  1132 
  1133 
  1134 
  1135 
  1136 
  1137 
  1138 
  1139 
  1140 
  1141 
  1142 
  1143 
  1144 
  1145 
  1146 
  1147 
  1148 
  1149 
  1150 
  1151 
  1152 
  1153 
  1154 
  1155 
  1156 
  1157 
  1158 
  1159 
/*
 * SQ930x subdriver
 *
 * Copyright (C) 2010 Jean-Fran├žois Moine <http://moinejf.free.fr>
 * Copyright (C) 2006 -2008 Gerard Klaver <gerard at gkall dot hobby dot nl>
 * Copyright (C) 2007 Sam Revitch <samr7@cs.washington.edu>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#define MODULE_NAME "sq930x"

#include "gspca.h"

MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>\n"
		"Gerard Klaver <gerard at gkall dot hobby dot nl\n"
		"Sam Revitch <samr7@cs.washington.edu>");
MODULE_DESCRIPTION("GSPCA/SQ930x USB Camera Driver");
MODULE_LICENSE("GPL");

/* Structure to hold all of our device specific stuff */
struct sd {
	struct gspca_dev gspca_dev;	/* !! must be the first item */

	struct { /* exposure/gain control cluster */
		struct v4l2_ctrl *exposure;
		struct v4l2_ctrl *gain;
	};

	u8 do_ctrl;
	u8 gpio[2];
	u8 sensor;
	u8 type;
#define Generic 0
#define Creative_live_motion 1
};
enum sensors {
	SENSOR_ICX098BQ,
	SENSOR_LZ24BP,
	SENSOR_MI0360,
	SENSOR_MT9V111,		/* = MI360SOC */
	SENSOR_OV7660,
	SENSOR_OV9630,
};

static struct v4l2_pix_format vga_mode[] = {
	{320, 240, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE,
		.bytesperline = 320,
		.sizeimage = 320 * 240,
		.colorspace = V4L2_COLORSPACE_SRGB,
		.priv = 0},
	{640, 480, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE,
		.bytesperline = 640,
		.sizeimage = 640 * 480,
		.colorspace = V4L2_COLORSPACE_SRGB,
		.priv = 1},
};

/* sq930x registers */
#define SQ930_CTRL_UCBUS_IO	0x0001
#define SQ930_CTRL_I2C_IO	0x0002
#define SQ930_CTRL_GPIO		0x0005
#define SQ930_CTRL_CAP_START	0x0010
#define SQ930_CTRL_CAP_STOP	0x0011
#define SQ930_CTRL_SET_EXPOSURE 0x001d
#define SQ930_CTRL_RESET	0x001e
#define SQ930_CTRL_GET_DEV_INFO 0x001f

/* gpio 1 (8..15) */
#define SQ930_GPIO_DFL_I2C_SDA	0x0001
#define SQ930_GPIO_DFL_I2C_SCL	0x0002
#define SQ930_GPIO_RSTBAR	0x0004
#define SQ930_GPIO_EXTRA1	0x0040
#define SQ930_GPIO_EXTRA2	0x0080
/* gpio 3 (24..31) */
#define SQ930_GPIO_POWER	0x0200
#define SQ930_GPIO_DFL_LED	0x1000

struct ucbus_write_cmd {
	u16	bw_addr;
	u8	bw_data;
};
struct i2c_write_cmd {
	u8	reg;
	u16	val;
};

static const struct ucbus_write_cmd icx098bq_start_0[] = {
	{0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xce},
	{0xf802, 0xc1}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x0e},
	{0xf80a, 0x01}, {0xf80b, 0xee}, {0xf807, 0x60}, {0xf80c, 0x02},
	{0xf80d, 0xf0}, {0xf80e, 0x03}, {0xf80f, 0x0a}, {0xf81c, 0x02},
	{0xf81d, 0xf0}, {0xf81e, 0x03}, {0xf81f, 0x0a}, {0xf83a, 0x00},
	{0xf83b, 0x10}, {0xf83c, 0x00}, {0xf83d, 0x4e}, {0xf810, 0x04},
	{0xf811, 0x00}, {0xf812, 0x02}, {0xf813, 0x10}, {0xf803, 0x00},
	{0xf814, 0x01}, {0xf815, 0x18}, {0xf816, 0x00}, {0xf817, 0x48},
	{0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c},
	{0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff},
	{0xf823, 0x07}, {0xf824, 0xff}, {0xf825, 0x03}, {0xf826, 0xff},
	{0xf827, 0x06}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff},
	{0xf82b, 0x0c}, {0xf82c, 0xfd}, {0xf82d, 0x01}, {0xf82e, 0x00},
	{0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00},
	{0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24},
	{0xf854, 0x00}, {0xf855, 0x18}, {0xf856, 0x00}, {0xf857, 0x3c},
	{0xf858, 0x00}, {0xf859, 0x0c}, {0xf85a, 0x00}, {0xf85b, 0x30},
	{0xf85c, 0x00}, {0xf85d, 0x0c}, {0xf85e, 0x00}, {0xf85f, 0x30},
	{0xf860, 0x00}, {0xf861, 0x48}, {0xf862, 0x01}, {0xf863, 0xdc},
	{0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0},
	{0xf868, 0xff}, {0xf869, 0x70}, {0xf86c, 0xff}, {0xf86d, 0x00},
	{0xf86a, 0xff}, {0xf86b, 0x48}, {0xf86e, 0xff}, {0xf86f, 0x00},
	{0xf870, 0x01}, {0xf871, 0xdb}, {0xf872, 0x01}, {0xf873, 0xfa},
	{0xf874, 0x01}, {0xf875, 0xdb}, {0xf876, 0x01}, {0xf877, 0xfa},
	{0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff},
	{0xf800, 0x03}
};
static const struct ucbus_write_cmd icx098bq_start_1[] = {
	{0xf5f0, 0x00}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
	{0xf5f4, 0xc0},
	{0xf5f0, 0x49}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
	{0xf5f4, 0xc0},
	{0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
	{0xf5f9, 0x00}
};

static const struct ucbus_write_cmd icx098bq_start_2[] = {
	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x82}, {0xf806, 0x00},
	{0xf807, 0x7f}, {0xf800, 0x03},
	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x40}, {0xf806, 0x00},
	{0xf807, 0x7f}, {0xf800, 0x03},
	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xcf}, {0xf806, 0xd0},
	{0xf807, 0x7f}, {0xf800, 0x03},
	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00},
	{0xf807, 0x7f}, {0xf800, 0x03}
};

static const struct ucbus_write_cmd lz24bp_start_0[] = {
	{0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xbe},
	{0xf802, 0xc6}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x06},
	{0xf80a, 0x01}, {0xf80b, 0xfe}, {0xf807, 0x84}, {0xf80c, 0x02},
	{0xf80d, 0xf7}, {0xf80e, 0x03}, {0xf80f, 0x0b}, {0xf81c, 0x00},
	{0xf81d, 0x49}, {0xf81e, 0x03}, {0xf81f, 0x0b}, {0xf83a, 0x00},
	{0xf83b, 0x01}, {0xf83c, 0x00}, {0xf83d, 0x6b}, {0xf810, 0x03},
	{0xf811, 0x10}, {0xf812, 0x02}, {0xf813, 0x6f}, {0xf803, 0x00},
	{0xf814, 0x00}, {0xf815, 0x44}, {0xf816, 0x00}, {0xf817, 0x48},
	{0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c},
	{0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff},
	{0xf823, 0x07}, {0xf824, 0xfd}, {0xf825, 0x07}, {0xf826, 0xf0},
	{0xf827, 0x0c}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff},
	{0xf82b, 0x0c}, {0xf82c, 0xfc}, {0xf82d, 0x01}, {0xf82e, 0x00},
	{0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00},
	{0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24},
	{0xf854, 0x00}, {0xf855, 0x0c}, {0xf856, 0x00}, {0xf857, 0x30},
	{0xf858, 0x00}, {0xf859, 0x18}, {0xf85a, 0x00}, {0xf85b, 0x3c},
	{0xf85c, 0x00}, {0xf85d, 0x18}, {0xf85e, 0x00}, {0xf85f, 0x3c},
	{0xf860, 0xff}, {0xf861, 0x37}, {0xf862, 0xff}, {0xf863, 0x1d},
	{0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0},
	{0xf868, 0x00}, {0xf869, 0x37}, {0xf86c, 0x02}, {0xf86d, 0x1d},
	{0xf86a, 0x00}, {0xf86b, 0x37}, {0xf86e, 0x02}, {0xf86f, 0x1d},
	{0xf870, 0x01}, {0xf871, 0xc6}, {0xf872, 0x02}, {0xf873, 0x04},
	{0xf874, 0x01}, {0xf875, 0xc6}, {0xf876, 0x02}, {0xf877, 0x04},
	{0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff},
	{0xf800, 0x03}
};
static const struct ucbus_write_cmd lz24bp_start_1_gen[] = {
	{0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
	{0xf5f4, 0xb3},
	{0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
	{0xf5f4, 0xb3},
	{0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
	{0xf5f9, 0x00}
};

static const struct ucbus_write_cmd lz24bp_start_1_clm[] = {
	{0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88},
	{0xf5f4, 0xc0},
	{0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88},
	{0xf5f4, 0xc0},
	{0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
	{0xf5f9, 0x00}
};

static const struct ucbus_write_cmd lz24bp_start_2[] = {
	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x80}, {0xf806, 0x00},
	{0xf807, 0x7f}, {0xf800, 0x03},
	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x4e}, {0xf806, 0x00},
	{0xf807, 0x7f}, {0xf800, 0x03},
	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xc0}, {0xf806, 0x48},
	{0xf807, 0x7f}, {0xf800, 0x03},
	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00},
	{0xf807, 0x7f}, {0xf800, 0x03}
};

static const struct ucbus_write_cmd mi0360_start_0[] = {
	{0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0xcc}, {0xf333, 0xcc},
	{0xf334, 0xcc}, {0xf335, 0xcc}, {0xf33f, 0x00}
};
static const struct i2c_write_cmd mi0360_init_23[] = {
	{0x30, 0x0040},		/* reserved - def 0x0005 */
	{0x31, 0x0000},		/* reserved - def 0x002a */
	{0x34, 0x0100},		/* reserved - def 0x0100 */
	{0x3d, 0x068f},		/* reserved - def 0x068f */
};
static const struct i2c_write_cmd mi0360_init_24[] = {
	{0x03, 0x01e5},		/* window height */
	{0x04, 0x0285},		/* window width */
};
static const struct i2c_write_cmd mi0360_init_25[] = {
	{0x35, 0x0020},		/* global gain */
	{0x2b, 0x0020},		/* green1 gain */
	{0x2c, 0x002a},		/* blue gain */
	{0x2d, 0x0028},		/* red gain */
	{0x2e, 0x0020},		/* green2 gain */
};
static const struct ucbus_write_cmd mi0360_start_1[] = {
	{0xf5f0, 0x11}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
	{0xf5f4, 0xa6},
	{0xf5f0, 0x51}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
	{0xf5f4, 0xa6},
	{0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
	{0xf5f9, 0x00}
};
static const struct i2c_write_cmd mi0360_start_2[] = {
	{0x62, 0x041d},		/* reserved - def 0x0418 */
};
static const struct i2c_write_cmd mi0360_start_3[] = {
	{0x05, 0x007b},		/* horiz blanking */
};
static const struct i2c_write_cmd mi0360_start_4[] = {
	{0x05, 0x03f5},		/* horiz blanking */
};

static const struct i2c_write_cmd mt9v111_init_0[] = {
	{0x01, 0x0001},		/* select IFP/SOC registers */
	{0x06, 0x300c},		/* operating mode control */
	{0x08, 0xcc00},		/* output format control (RGB) */
	{0x01, 0x0004},		/* select sensor core registers */
};
static const struct i2c_write_cmd mt9v111_init_1[] = {
	{0x03, 0x01e5},		/* window height */
	{0x04, 0x0285},		/* window width */
};
static const struct i2c_write_cmd mt9v111_init_2[] = {
	{0x30, 0x7800},
	{0x31, 0x0000},
	{0x07, 0x3002},		/* output control */
	{0x35, 0x0020},		/* global gain */
	{0x2b, 0x0020},		/* green1 gain */
	{0x2c, 0x0020},		/* blue gain */
	{0x2d, 0x0020},		/* red gain */
	{0x2e, 0x0020},		/* green2 gain */
};
static const struct ucbus_write_cmd mt9v111_start_1[] = {
	{0xf5f0, 0x11}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
	{0xf5f4, 0xaa},
	{0xf5f0, 0x51}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
	{0xf5f4, 0xaa},
	{0xf5fa, 0x00}, {0xf5f6, 0x0a}, {0xf5f7, 0x0a}, {0xf5f8, 0x0a},
	{0xf5f9, 0x0a}
};
static const struct i2c_write_cmd mt9v111_init_3[] = {
	{0x62, 0x0405},
};
static const struct i2c_write_cmd mt9v111_init_4[] = {
/*	{0x05, 0x00ce}, */
	{0x05, 0x005d},		/* horizontal blanking */
};

static const struct ucbus_write_cmd ov7660_start_0[] = {
	{0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0xc0},
	{0xf334, 0x39}, {0xf335, 0xe7}, {0xf33f, 0x03}
};

static const struct ucbus_write_cmd ov9630_start_0[] = {
	{0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0x00},
	{0xf334, 0x3e}, {0xf335, 0xf8}, {0xf33f, 0x03}
};

/* start parameters indexed by [sensor][mode] */
static const struct cap_s {
	u8	cc_sizeid;
	u8	cc_bytes[32];
} capconfig[4][2] = {
	[SENSOR_ICX098BQ] = {
		{2,				/* Bayer 320x240 */
		  {0x05, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
		   0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
		{4,				/* Bayer 640x480 */
		  {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
		   0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
	},
	[SENSOR_LZ24BP] = {
		{2,				/* Bayer 320x240 */
		  {0x05, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee,
		   0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
		{4,				/* Bayer 640x480 */
		  {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee,
		   0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
	},
	[SENSOR_MI0360] = {
		{2,				/* Bayer 320x240 */
		  {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
		   0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
		{4,				/* Bayer 640x480 */
		  {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
		   0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
	},
	[SENSOR_MT9V111] = {
		{2,				/* Bayer 320x240 */
		  {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
		   0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
		{4,				/* Bayer 640x480 */
		  {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
		   0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
	},
};

struct sensor_s {
	const char *name;
	u8 i2c_addr;
	u8 i2c_dum;
	u8 gpio[5];
	u8 cmd_len;
	const struct ucbus_write_cmd *cmd;
};

static const struct sensor_s sensor_tb[] = {
	[SENSOR_ICX098BQ] = {
		"icx098bp",
		0x00, 0x00,
		{0,
		 SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
		 SQ930_GPIO_DFL_I2C_SDA,
		 0,
		 SQ930_GPIO_RSTBAR
		},
		8, icx098bq_start_0
	    },
	[SENSOR_LZ24BP] = {
		"lz24bp",
		0x00, 0x00,
		{0,
		 SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
		 SQ930_GPIO_DFL_I2C_SDA,
		 0,
		 SQ930_GPIO_RSTBAR
		},
		8, lz24bp_start_0
	    },
	[SENSOR_MI0360] = {
		"mi0360",
		0x5d, 0x80,
		{SQ930_GPIO_RSTBAR,
		 SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
		 SQ930_GPIO_DFL_I2C_SDA,
		 0,
		 0
		},
		7, mi0360_start_0
	    },
	[SENSOR_MT9V111] = {
		"mt9v111",
		0x5c, 0x7f,
		{SQ930_GPIO_RSTBAR,
		 SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
		 SQ930_GPIO_DFL_I2C_SDA,
		 0,
		 0
		},
		7, mi0360_start_0
	    },
	[SENSOR_OV7660] = {
		"ov7660",
		0x21, 0x00,
		{0,
		 SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
		 SQ930_GPIO_DFL_I2C_SDA,
		 0,
		 SQ930_GPIO_RSTBAR
		},
		7, ov7660_start_0
	    },
	[SENSOR_OV9630] = {
		"ov9630",
		0x30, 0x00,
		{0,
		 SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
		 SQ930_GPIO_DFL_I2C_SDA,
		 0,
		 SQ930_GPIO_RSTBAR
		},
		7, ov9630_start_0
	    },
};

static void reg_r(struct gspca_dev *gspca_dev,
		u16 value, int len)
{
	int ret;

	if (gspca_dev->usb_err < 0)
		return;
	ret = usb_control_msg(gspca_dev->dev,
			usb_rcvctrlpipe(gspca_dev->dev, 0),
			0x0c,
			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			value, 0, gspca_dev->usb_buf, len,
			500);
	if (ret < 0) {
		pr_err("reg_r %04x failed %d\n", value, ret);
		gspca_dev->usb_err = ret;
	}
}

static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
{
	int ret;

	if (gspca_dev->usb_err < 0)
		return;
	PDEBUG(D_USBO, "reg_w v: %04x i: %04x", value, index);
	ret = usb_control_msg(gspca_dev->dev,
			usb_sndctrlpipe(gspca_dev->dev, 0),
			0x0c,			/* request */
			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			value, index, NULL, 0,
			500);
	msleep(30);
	if (ret < 0) {
		pr_err("reg_w %04x %04x failed %d\n", value, index, ret);
		gspca_dev->usb_err = ret;
	}
}

static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index,
		const u8 *data, int len)
{
	int ret;

	if (gspca_dev->usb_err < 0)
		return;
	PDEBUG(D_USBO, "reg_wb v: %04x i: %04x %02x...%02x",
			value, index, *data, data[len - 1]);
	memcpy(gspca_dev->usb_buf, data, len);
	ret = usb_control_msg(gspca_dev->dev,
			usb_sndctrlpipe(gspca_dev->dev, 0),
			0x0c,			/* request */
			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			value, index, gspca_dev->usb_buf, len,
			1000);
	msleep(30);
	if (ret < 0) {
		pr_err("reg_wb %04x %04x failed %d\n", value, index, ret);
		gspca_dev->usb_err = ret;
	}
}

static void i2c_write(struct sd *sd,
			const struct i2c_write_cmd *cmd,
			int ncmds)
{
	struct gspca_dev *gspca_dev = &sd->gspca_dev;
	const struct sensor_s *sensor;
	u16 val, idx;
	u8 *buf;
	int ret;

	if (gspca_dev->usb_err < 0)
		return;

	sensor = &sensor_tb[sd->sensor];

	val = (sensor->i2c_addr << 8) | SQ930_CTRL_I2C_IO;
	idx = (cmd->val & 0xff00) | cmd->reg;

	buf = gspca_dev->usb_buf;
	*buf++ = sensor->i2c_dum;
	*buf++ = cmd->val;

	while (--ncmds > 0) {
		cmd++;
		*buf++ = cmd->reg;
		*buf++ = cmd->val >> 8;
		*buf++ = sensor->i2c_dum;
		*buf++ = cmd->val;
	}

	PDEBUG(D_USBO, "i2c_w v: %04x i: %04x %02x...%02x",
			val, idx, gspca_dev->usb_buf[0], buf[-1]);
	ret = usb_control_msg(gspca_dev->dev,
			usb_sndctrlpipe(gspca_dev->dev, 0),
			0x0c,			/* request */
			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			val, idx,
			gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
			500);
	if (ret < 0) {
		pr_err("i2c_write failed %d\n", ret);
		gspca_dev->usb_err = ret;
	}
}

static void ucbus_write(struct gspca_dev *gspca_dev,
			const struct ucbus_write_cmd *cmd,
			int ncmds,
			int batchsize)
{
	u8 *buf;
	u16 val, idx;
	int len, ret;

	if (gspca_dev->usb_err < 0)
		return;

	if ((batchsize - 1) * 3 > USB_BUF_SZ) {
		PERR("Bug: usb_buf overflow\n");
		gspca_dev->usb_err = -ENOMEM;
		return;
	}

	for (;;) {
		len = ncmds;
		if (len > batchsize)
			len = batchsize;
		ncmds -= len;

		val = (cmd->bw_addr << 8) | SQ930_CTRL_UCBUS_IO;
		idx = (cmd->bw_data << 8) | (cmd->bw_addr >> 8);

		buf = gspca_dev->usb_buf;
		while (--len > 0) {
			cmd++;
			*buf++ = cmd->bw_addr;
			*buf++ = cmd->bw_addr >> 8;
			*buf++ = cmd->bw_data;
		}
		if (buf != gspca_dev->usb_buf)
			PDEBUG(D_USBO, "ucbus v: %04x i: %04x %02x...%02x",
					val, idx,
					gspca_dev->usb_buf[0], buf[-1]);
		else
			PDEBUG(D_USBO, "ucbus v: %04x i: %04x",
					val, idx);
		ret = usb_control_msg(gspca_dev->dev,
				usb_sndctrlpipe(gspca_dev->dev, 0),
				0x0c,			/* request */
			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
				val, idx,
				gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
				500);
		if (ret < 0) {
			pr_err("ucbus_write failed %d\n", ret);
			gspca_dev->usb_err = ret;
			return;
		}
		msleep(30);
		if (ncmds <= 0)
			break;
		cmd++;
	}
}

static void gpio_set(struct sd *sd, u16 val, u16 mask)
{
	struct gspca_dev *gspca_dev = &sd->gspca_dev;

	if (mask & 0x00ff) {
		sd->gpio[0] &= ~mask;
		sd->gpio[0] |= val;
		reg_w(gspca_dev, 0x0100 | SQ930_CTRL_GPIO,
			~sd->gpio[0] << 8);
	}
	mask >>= 8;
	val >>= 8;
	if (mask) {
		sd->gpio[1] &= ~mask;
		sd->gpio[1] |= val;
		reg_w(gspca_dev, 0x0300 | SQ930_CTRL_GPIO,
			~sd->gpio[1] << 8);
	}
}

static void gpio_init(struct sd *sd,
			const u8 *gpio)
{
	gpio_set(sd, *gpio++, 0x000f);
	gpio_set(sd, *gpio++, 0x000f);
	gpio_set(sd, *gpio++, 0x000f);
	gpio_set(sd, *gpio++, 0x000f);
	gpio_set(sd, *gpio, 0x000f);
}

static void bridge_init(struct sd *sd)
{
	static const struct ucbus_write_cmd clkfreq_cmd = {
				0xf031, 0	/* SQ930_CLKFREQ_60MHZ */
	};

	ucbus_write(&sd->gspca_dev, &clkfreq_cmd, 1, 1);

	gpio_set(sd, SQ930_GPIO_POWER, 0xff00);
}

static void cmos_probe(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	int i;
	const struct sensor_s *sensor;
	static const u8 probe_order[] = {
/*		SENSOR_LZ24BP,		(tested as ccd) */
		SENSOR_OV9630,
		SENSOR_MI0360,
		SENSOR_OV7660,
		SENSOR_MT9V111,
	};

	for (i = 0; i < ARRAY_SIZE(probe_order); i++) {
		sensor = &sensor_tb[probe_order[i]];
		ucbus_write(&sd->gspca_dev, sensor->cmd, sensor->cmd_len, 8);
		gpio_init(sd, sensor->gpio);
		msleep(100);
		reg_r(gspca_dev, (sensor->i2c_addr << 8) | 0x001c, 1);
		msleep(100);
		if (gspca_dev->usb_buf[0] != 0)
			break;
	}
	if (i >= ARRAY_SIZE(probe_order)) {
		pr_err("Unknown sensor\n");
		gspca_dev->usb_err = -EINVAL;
		return;
	}
	sd->sensor = probe_order[i];
	switch (sd->sensor) {
	case SENSOR_OV7660:
	case SENSOR_OV9630:
		pr_err("Sensor %s not yet treated\n",
		       sensor_tb[sd->sensor].name);
		gspca_dev->usb_err = -EINVAL;
		break;
	}
}

static void mt9v111_init(struct gspca_dev *gspca_dev)
{
	int i, nwait;
	static const u8 cmd_001b[] = {
		0x00, 0x3b, 0xf6, 0x01, 0x03, 0x02, 0x00, 0x00,
		0x00, 0x00, 0x00
	};
	static const u8 cmd_011b[][7] = {
		{0x10, 0x01, 0x66, 0x08, 0x00, 0x00, 0x00},
		{0x01, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x00},
		{0x20, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00},
		{0x02, 0x01, 0xae, 0x01, 0x00, 0x00, 0x00},
	};

	reg_wb(gspca_dev, 0x001b, 0x0000, cmd_001b, sizeof cmd_001b);
	for (i = 0; i < ARRAY_SIZE(cmd_011b); i++) {
		reg_wb(gspca_dev, 0x001b, 0x0000, cmd_011b[i],
				ARRAY_SIZE(cmd_011b[0]));
		msleep(400);
		nwait = 20;
		for (;;) {
			reg_r(gspca_dev, 0x031b, 1);
			if (gspca_dev->usb_buf[0] == 0
			 || gspca_dev->usb_err != 0)
				break;
			if (--nwait < 0) {
				PDEBUG(D_PROBE, "mt9v111_init timeout");
				gspca_dev->usb_err = -ETIME;
				return;
			}
			msleep(50);
		}
	}
}

static void global_init(struct sd *sd, int first_time)
{
	switch (sd->sensor) {
	case SENSOR_ICX098BQ:
		if (first_time)
			ucbus_write(&sd->gspca_dev,
					icx098bq_start_0,
					8, 8);
		gpio_init(sd, sensor_tb[sd->sensor].gpio);
		break;
	case SENSOR_LZ24BP:
		if (sd->type != Creative_live_motion)
			gpio_set(sd, SQ930_GPIO_EXTRA1, 0x00ff);
		else
			gpio_set(sd, 0, 0x00ff);
		msleep(50);
		if (first_time)
			ucbus_write(&sd->gspca_dev,
					lz24bp_start_0,
					8, 8);
		gpio_init(sd, sensor_tb[sd->sensor].gpio);
		break;
	case SENSOR_MI0360:
		if (first_time)
			ucbus_write(&sd->gspca_dev,
					mi0360_start_0,
					ARRAY_SIZE(mi0360_start_0),
					8);
		gpio_init(sd, sensor_tb[sd->sensor].gpio);
		gpio_set(sd, SQ930_GPIO_EXTRA2, SQ930_GPIO_EXTRA2);
		break;
	default:
/*	case SENSOR_MT9V111: */
		if (first_time)
			mt9v111_init(&sd->gspca_dev);
		else
			gpio_init(sd, sensor_tb[sd->sensor].gpio);
		break;
	}
}

static void lz24bp_ppl(struct sd *sd, u16 ppl)
{
	struct ucbus_write_cmd cmds[2] = {
		{0xf810, ppl >> 8},
		{0xf811, ppl}
	};

	ucbus_write(&sd->gspca_dev, cmds, ARRAY_SIZE(cmds), 2);
}

static void setexposure(struct gspca_dev *gspca_dev, s32 expo, s32 gain)
{
	struct sd *sd = (struct sd *) gspca_dev;
	int i, integclks, intstartclk, frameclks, min_frclk;
	const struct sensor_s *sensor;
	u16 cmd;
	u8 buf[15];

	integclks = expo;
	i = 0;
	cmd = SQ930_CTRL_SET_EXPOSURE;

	switch (sd->sensor) {
	case SENSOR_ICX098BQ:			/* ccd */
	case SENSOR_LZ24BP:
		min_frclk = sd->sensor == SENSOR_ICX098BQ ? 0x210 : 0x26f;
		if (integclks >= min_frclk) {
			intstartclk = 0;
			frameclks = integclks;
		} else {
			intstartclk = min_frclk - integclks;
			frameclks = min_frclk;
		}
		buf[i++] = intstartclk >> 8;
		buf[i++] = intstartclk;
		buf[i++] = frameclks >> 8;
		buf[i++] = frameclks;
		buf[i++] = gain;
		break;
	default:				/* cmos */
/*	case SENSOR_MI0360: */
/*	case SENSOR_MT9V111: */
		cmd |= 0x0100;
		sensor = &sensor_tb[sd->sensor];
		buf[i++] = sensor->i2c_addr;	/* i2c_slave_addr */
		buf[i++] = 0x08;	/* 2 * ni2c */
		buf[i++] = 0x09;	/* reg = shutter width */
		buf[i++] = integclks >> 8; /* val H */
		buf[i++] = sensor->i2c_dum;
		buf[i++] = integclks;	/* val L */
		buf[i++] = 0x35;	/* reg = global gain */
		buf[i++] = 0x00;	/* val H */
		buf[i++] = sensor->i2c_dum;
		buf[i++] = 0x80 + gain / 2; /* val L */
		buf[i++] = 0x00;
		buf[i++] = 0x00;
		buf[i++] = 0x00;
		buf[i++] = 0x00;
		buf[i++] = 0x83;
		break;
	}
	reg_wb(gspca_dev, cmd, 0, buf, i);
}

/* This function is called at probe time just before sd_init */
static int sd_config(struct gspca_dev *gspca_dev,
		const struct usb_device_id *id)
{
	struct sd *sd = (struct sd *) gspca_dev;
	struct cam *cam = &gspca_dev->cam;

	sd->sensor = id->driver_info >> 8;
	sd->type = id->driver_info;

	cam->cam_mode = vga_mode;
	cam->nmodes = ARRAY_SIZE(vga_mode);

	cam->bulk = 1;

	return 0;
}

/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;

	sd->gpio[0] = sd->gpio[1] = 0xff;	/* force gpio rewrite */

/*fixme: is this needed for icx098bp and mi0360?
	if (sd->sensor != SENSOR_LZ24BP)
		reg_w(gspca_dev, SQ930_CTRL_RESET, 0x0000);
 */

	reg_r(gspca_dev, SQ930_CTRL_GET_DEV_INFO, 8);
	if (gspca_dev->usb_err < 0)
		return gspca_dev->usb_err;

/* it returns:
 * 03 00 12 93 0b f6 c9 00	live! ultra
 * 03 00 07 93 0b f6 ca 00	live! ultra for notebook
 * 03 00 12 93 0b fe c8 00	Trust WB-3500T
 * 02 00 06 93 0b fe c8 00	Joy-IT 318S
 * 03 00 12 93 0b f6 cf 00	icam tracer - sensor icx098bq
 * 02 00 12 93 0b fe cf 00	ProQ Motion Webcam
 *
 * byte
 * 0: 02 = usb 1.0 (12Mbit) / 03 = usb2.0 (480Mbit)
 * 1: 00
 * 2: 06 / 07 / 12 = mode webcam? firmware??
 * 3: 93 chip = 930b (930b or 930c)
 * 4: 0b
 * 5: f6 = cdd (icx098bq, lz24bp) / fe or de = cmos (i2c) (other sensors)
 * 6: c8 / c9 / ca / cf = mode webcam?, sensor? webcam?
 * 7: 00
 */
	PDEBUG(D_PROBE, "info: %*ph", 8, gspca_dev->usb_buf);

	bridge_init(sd);

	if (sd->sensor == SENSOR_MI0360) {

		/* no sensor probe for icam tracer */
		if (gspca_dev->usb_buf[5] == 0xf6)	/* if ccd */
			sd->sensor = SENSOR_ICX098BQ;
		else
			cmos_probe(gspca_dev);
	}
	if (gspca_dev->usb_err >= 0) {
		PDEBUG(D_PROBE, "Sensor %s", sensor_tb[sd->sensor].name);
		global_init(sd, 1);
	}
	return gspca_dev->usb_err;
}

/* send the start/stop commands to the webcam */
static void send_start(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	const struct cap_s *cap;
	int mode;

	mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
	cap = &capconfig[sd->sensor][mode];
	reg_wb(gspca_dev, 0x0900 | SQ930_CTRL_CAP_START,
			0x0a00 | cap->cc_sizeid,
			cap->cc_bytes, 32);
}

static void send_stop(struct gspca_dev *gspca_dev)
{
	reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0);
}

/* function called at start time before URB creation */
static int sd_isoc_init(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;

	gspca_dev->cam.bulk_nurbs = 1;	/* there must be one URB only */
	sd->do_ctrl = 0;
	gspca_dev->cam.bulk_size = gspca_dev->pixfmt.width *
			gspca_dev->pixfmt.height + 8;
	return 0;
}

/* start the capture */
static int sd_start(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	int mode;

	bridge_init(sd);
	global_init(sd, 0);
	msleep(100);

	switch (sd->sensor) {
	case SENSOR_ICX098BQ:
		ucbus_write(gspca_dev, icx098bq_start_0,
				ARRAY_SIZE(icx098bq_start_0),
				8);
		ucbus_write(gspca_dev, icx098bq_start_1,
				ARRAY_SIZE(icx098bq_start_1),
				5);
		ucbus_write(gspca_dev, icx098bq_start_2,
				ARRAY_SIZE(icx098bq_start_2),
				6);
		msleep(50);

		/* 1st start */
		send_start(gspca_dev);
		gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff);
		msleep(70);
		reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000);
		gpio_set(sd, 0x7f, 0x00ff);

		/* 2nd start */
		send_start(gspca_dev);
		gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff);
		goto out;
	case SENSOR_LZ24BP:
		ucbus_write(gspca_dev, lz24bp_start_0,
				ARRAY_SIZE(lz24bp_start_0),
				8);
		if (sd->type != Creative_live_motion)
			ucbus_write(gspca_dev, lz24bp_start_1_gen,
					ARRAY_SIZE(lz24bp_start_1_gen),
					5);
		else
			ucbus_write(gspca_dev, lz24bp_start_1_clm,
					ARRAY_SIZE(lz24bp_start_1_clm),
					5);
		ucbus_write(gspca_dev, lz24bp_start_2,
				ARRAY_SIZE(lz24bp_start_2),
				6);
		mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
		lz24bp_ppl(sd, mode == 1 ? 0x0564 : 0x0310);
		msleep(10);
		break;
	case SENSOR_MI0360:
		ucbus_write(gspca_dev, mi0360_start_0,
				ARRAY_SIZE(mi0360_start_0),
				8);
		i2c_write(sd, mi0360_init_23,
				ARRAY_SIZE(mi0360_init_23));
		i2c_write(sd, mi0360_init_24,
				ARRAY_SIZE(mi0360_init_24));
		i2c_write(sd, mi0360_init_25,
				ARRAY_SIZE(mi0360_init_25));
		ucbus_write(gspca_dev, mi0360_start_1,
				ARRAY_SIZE(mi0360_start_1),
				5);
		i2c_write(sd, mi0360_start_2,
				ARRAY_SIZE(mi0360_start_2));
		i2c_write(sd, mi0360_start_3,
				ARRAY_SIZE(mi0360_start_3));

		/* 1st start */
		send_start(gspca_dev);
		msleep(60);
		send_stop(gspca_dev);

		i2c_write(sd,
			mi0360_start_4, ARRAY_SIZE(mi0360_start_4));
		break;
	default:
/*	case SENSOR_MT9V111: */
		ucbus_write(gspca_dev, mi0360_start_0,
				ARRAY_SIZE(mi0360_start_0),
				8);
		i2c_write(sd, mt9v111_init_0,
				ARRAY_SIZE(mt9v111_init_0));
		i2c_write(sd, mt9v111_init_1,
				ARRAY_SIZE(mt9v111_init_1));
		i2c_write(sd, mt9v111_init_2,
				ARRAY_SIZE(mt9v111_init_2));
		ucbus_write(gspca_dev, mt9v111_start_1,
				ARRAY_SIZE(mt9v111_start_1),
				5);
		i2c_write(sd, mt9v111_init_3,
				ARRAY_SIZE(mt9v111_init_3));
		i2c_write(sd, mt9v111_init_4,
				ARRAY_SIZE(mt9v111_init_4));
		break;
	}

	send_start(gspca_dev);
out:
	msleep(1000);

	if (sd->sensor == SENSOR_MT9V111)
		gpio_set(sd, SQ930_GPIO_DFL_LED, SQ930_GPIO_DFL_LED);

	sd->do_ctrl = 1;	/* set the exposure */

	return gspca_dev->usb_err;
}

static void sd_stopN(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;

	if (sd->sensor == SENSOR_MT9V111)
		gpio_set(sd, 0, SQ930_GPIO_DFL_LED);
	send_stop(gspca_dev);
}

/* function called when the application gets a new frame */
/* It sets the exposure if required and restart the bulk transfer. */
static void sd_dq_callback(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	int ret;

	if (!sd->do_ctrl || gspca_dev->cam.bulk_nurbs != 0)
		return;
	sd->do_ctrl = 0;

	setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure),
			v4l2_ctrl_g_ctrl(sd->gain));

	gspca_dev->cam.bulk_nurbs = 1;
	ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC);
	if (ret < 0)
		pr_err("sd_dq_callback() err %d\n", ret);

	/* wait a little time, otherwise the webcam crashes */
	msleep(100);
}

static void sd_pkt_scan(struct gspca_dev *gspca_dev,
			u8 *data,		/* isoc packet */
			int len)		/* iso packet length */
{
	struct sd *sd = (struct sd *) gspca_dev;

	if (sd->do_ctrl)
		gspca_dev->cam.bulk_nurbs = 0;
	gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
	gspca_frame_add(gspca_dev, INTER_PACKET, data, len - 8);
	gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
}

static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct gspca_dev *gspca_dev =
		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
	struct sd *sd = (struct sd *) gspca_dev;

	gspca_dev->usb_err = 0;

	if (!gspca_dev->streaming)
		return 0;

	switch (ctrl->id) {
	case V4L2_CID_EXPOSURE:
		setexposure(gspca_dev, ctrl->val, sd->gain->val);
		break;
	}
	return gspca_dev->usb_err;
}

static const struct v4l2_ctrl_ops sd_ctrl_ops = {
	.s_ctrl = sd_s_ctrl,
};

static int sd_init_controls(struct gspca_dev *gspca_dev)
{
	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
	struct sd *sd = (struct sd *) gspca_dev;

	gspca_dev->vdev.ctrl_handler = hdl;
	v4l2_ctrl_handler_init(hdl, 2);
	sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
			V4L2_CID_EXPOSURE, 1, 0xfff, 1, 0x356);
	sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
			V4L2_CID_GAIN, 1, 255, 1, 0x8d);

	if (hdl->error) {
		pr_err("Could not initialize controls\n");
		return hdl->error;
	}
	v4l2_ctrl_cluster(2, &sd->exposure);
	return 0;
}

/* sub-driver description */
static const struct sd_desc sd_desc = {
	.name   = MODULE_NAME,
	.config = sd_config,
	.init   = sd_init,
	.init_controls = sd_init_controls,
	.isoc_init = sd_isoc_init,
	.start  = sd_start,
	.stopN  = sd_stopN,
	.pkt_scan = sd_pkt_scan,
	.dq_callback = sd_dq_callback,
};

/* Table of supported USB devices */
#define ST(sensor, type) \
	.driver_info = (SENSOR_ ## sensor << 8) \
			| (type)
static const struct usb_device_id device_table[] = {
	{USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)},
	{USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)},
	{USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)},
	{USB_DEVICE(0x041e, 0x4041), ST(LZ24BP, Creative_live_motion)},
	{USB_DEVICE(0x2770, 0x930b), ST(MI0360, 0)},
	{USB_DEVICE(0x2770, 0x930c), ST(MI0360, 0)},
	{}
};
MODULE_DEVICE_TABLE(usb, device_table);


/* -- device connect -- */
static int sd_probe(struct usb_interface *intf,
		const struct usb_device_id *id)
{
	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
			THIS_MODULE);
}

static struct usb_driver sd_driver = {
	.name	    = MODULE_NAME,
	.id_table   = device_table,
	.probe	    = sd_probe,
	.disconnect = gspca_disconnect,
#ifdef CONFIG_PM
	.suspend    = gspca_suspend,
	.resume     = gspca_resume,
	.reset_resume = gspca_resume,
#endif
};

module_usb_driver(sd_driver);

This page was automatically generated by Elixir 0.1.2 (source)  •  Please report bugs by mail or directly through the issue tracker.