1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Quickcam cameras initialization data
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun #define MODULE_NAME "tv8532"
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include "gspca.h"
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
12*4882a593Smuzhiyun MODULE_DESCRIPTION("TV8532 USB Camera Driver");
13*4882a593Smuzhiyun MODULE_LICENSE("GPL");
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun /* specific webcam descriptor */
16*4882a593Smuzhiyun struct sd {
17*4882a593Smuzhiyun struct gspca_dev gspca_dev; /* !! must be the first item */
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun __u8 packet;
20*4882a593Smuzhiyun };
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun static const struct v4l2_pix_format sif_mode[] = {
23*4882a593Smuzhiyun {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
24*4882a593Smuzhiyun .bytesperline = 176,
25*4882a593Smuzhiyun .sizeimage = 176 * 144,
26*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
27*4882a593Smuzhiyun .priv = 1},
28*4882a593Smuzhiyun {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
29*4882a593Smuzhiyun .bytesperline = 352,
30*4882a593Smuzhiyun .sizeimage = 352 * 288,
31*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
32*4882a593Smuzhiyun .priv = 0},
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /* TV-8532A (ICM532A) registers (LE) */
36*4882a593Smuzhiyun #define R00_PART_CONTROL 0x00
37*4882a593Smuzhiyun #define LATENT_CHANGE 0x80
38*4882a593Smuzhiyun #define EXPO_CHANGE 0x04
39*4882a593Smuzhiyun #define R01_TIMING_CONTROL_LOW 0x01
40*4882a593Smuzhiyun #define CMD_EEprom_Open 0x30
41*4882a593Smuzhiyun #define CMD_EEprom_Close 0x29
42*4882a593Smuzhiyun #define R03_TABLE_ADDR 0x03
43*4882a593Smuzhiyun #define R04_WTRAM_DATA_L 0x04
44*4882a593Smuzhiyun #define R05_WTRAM_DATA_M 0x05
45*4882a593Smuzhiyun #define R06_WTRAM_DATA_H 0x06
46*4882a593Smuzhiyun #define R07_TABLE_LEN 0x07
47*4882a593Smuzhiyun #define R08_RAM_WRITE_ACTION 0x08
48*4882a593Smuzhiyun #define R0C_AD_WIDTHL 0x0c
49*4882a593Smuzhiyun #define R0D_AD_WIDTHH 0x0d
50*4882a593Smuzhiyun #define R0E_AD_HEIGHTL 0x0e
51*4882a593Smuzhiyun #define R0F_AD_HEIGHTH 0x0f
52*4882a593Smuzhiyun #define R10_AD_COL_BEGINL 0x10
53*4882a593Smuzhiyun #define R11_AD_COL_BEGINH 0x11
54*4882a593Smuzhiyun #define MIRROR 0x04 /* [10] */
55*4882a593Smuzhiyun #define R14_AD_ROW_BEGINL 0x14
56*4882a593Smuzhiyun #define R15_AD_ROWBEGINH 0x15
57*4882a593Smuzhiyun #define R1C_AD_EXPOSE_TIMEL 0x1c
58*4882a593Smuzhiyun #define R20_GAIN_G1L 0x20
59*4882a593Smuzhiyun #define R21_GAIN_G1H 0x21
60*4882a593Smuzhiyun #define R22_GAIN_RL 0x22
61*4882a593Smuzhiyun #define R23_GAIN_RH 0x23
62*4882a593Smuzhiyun #define R24_GAIN_BL 0x24
63*4882a593Smuzhiyun #define R25_GAIN_BH 0x25
64*4882a593Smuzhiyun #define R26_GAIN_G2L 0x26
65*4882a593Smuzhiyun #define R27_GAIN_G2H 0x27
66*4882a593Smuzhiyun #define R28_QUANT 0x28
67*4882a593Smuzhiyun #define R29_LINE 0x29
68*4882a593Smuzhiyun #define R2C_POLARITY 0x2c
69*4882a593Smuzhiyun #define R2D_POINT 0x2d
70*4882a593Smuzhiyun #define R2E_POINTH 0x2e
71*4882a593Smuzhiyun #define R2F_POINTB 0x2f
72*4882a593Smuzhiyun #define R30_POINTBH 0x30
73*4882a593Smuzhiyun #define R31_UPD 0x31
74*4882a593Smuzhiyun #define R2A_HIGH_BUDGET 0x2a
75*4882a593Smuzhiyun #define R2B_LOW_BUDGET 0x2b
76*4882a593Smuzhiyun #define R34_VID 0x34
77*4882a593Smuzhiyun #define R35_VIDH 0x35
78*4882a593Smuzhiyun #define R36_PID 0x36
79*4882a593Smuzhiyun #define R37_PIDH 0x37
80*4882a593Smuzhiyun #define R39_Test1 0x39 /* GPIO */
81*4882a593Smuzhiyun #define R3B_Test3 0x3b /* GPIO */
82*4882a593Smuzhiyun #define R83_AD_IDH 0x83
83*4882a593Smuzhiyun #define R91_AD_SLOPEREG 0x91
84*4882a593Smuzhiyun #define R94_AD_BITCONTROL 0x94
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun static const u8 eeprom_data[][3] = {
87*4882a593Smuzhiyun /* dataH dataM dataL */
88*4882a593Smuzhiyun {0x01, 0x00, 0x01},
89*4882a593Smuzhiyun {0x01, 0x80, 0x11},
90*4882a593Smuzhiyun {0x05, 0x00, 0x14},
91*4882a593Smuzhiyun {0x05, 0x00, 0x1c},
92*4882a593Smuzhiyun {0x0d, 0x00, 0x1e},
93*4882a593Smuzhiyun {0x05, 0x00, 0x1f},
94*4882a593Smuzhiyun {0x05, 0x05, 0x19},
95*4882a593Smuzhiyun {0x05, 0x01, 0x1b},
96*4882a593Smuzhiyun {0x05, 0x09, 0x1e},
97*4882a593Smuzhiyun {0x0d, 0x89, 0x2e},
98*4882a593Smuzhiyun {0x05, 0x89, 0x2f},
99*4882a593Smuzhiyun {0x05, 0x0d, 0xd9},
100*4882a593Smuzhiyun {0x05, 0x09, 0xf1},
101*4882a593Smuzhiyun };
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun /* write 1 byte */
reg_w1(struct gspca_dev * gspca_dev,__u16 index,__u8 value)105*4882a593Smuzhiyun static void reg_w1(struct gspca_dev *gspca_dev,
106*4882a593Smuzhiyun __u16 index, __u8 value)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun gspca_dev->usb_buf[0] = value;
109*4882a593Smuzhiyun usb_control_msg(gspca_dev->dev,
110*4882a593Smuzhiyun usb_sndctrlpipe(gspca_dev->dev, 0),
111*4882a593Smuzhiyun 0x02,
112*4882a593Smuzhiyun USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
113*4882a593Smuzhiyun 0, /* value */
114*4882a593Smuzhiyun index, gspca_dev->usb_buf, 1, 500);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun /* write 2 bytes */
reg_w2(struct gspca_dev * gspca_dev,u16 index,u16 value)118*4882a593Smuzhiyun static void reg_w2(struct gspca_dev *gspca_dev,
119*4882a593Smuzhiyun u16 index, u16 value)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun gspca_dev->usb_buf[0] = value;
122*4882a593Smuzhiyun gspca_dev->usb_buf[1] = value >> 8;
123*4882a593Smuzhiyun usb_control_msg(gspca_dev->dev,
124*4882a593Smuzhiyun usb_sndctrlpipe(gspca_dev->dev, 0),
125*4882a593Smuzhiyun 0x02,
126*4882a593Smuzhiyun USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
127*4882a593Smuzhiyun 0, /* value */
128*4882a593Smuzhiyun index, gspca_dev->usb_buf, 2, 500);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
tv_8532WriteEEprom(struct gspca_dev * gspca_dev)131*4882a593Smuzhiyun static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun int i;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Open);
136*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(eeprom_data); i++) {
137*4882a593Smuzhiyun reg_w1(gspca_dev, R03_TABLE_ADDR, i);
138*4882a593Smuzhiyun reg_w1(gspca_dev, R04_WTRAM_DATA_L, eeprom_data[i][2]);
139*4882a593Smuzhiyun reg_w1(gspca_dev, R05_WTRAM_DATA_M, eeprom_data[i][1]);
140*4882a593Smuzhiyun reg_w1(gspca_dev, R06_WTRAM_DATA_H, eeprom_data[i][0]);
141*4882a593Smuzhiyun reg_w1(gspca_dev, R08_RAM_WRITE_ACTION, 0);
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun reg_w1(gspca_dev, R07_TABLE_LEN, i);
144*4882a593Smuzhiyun reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun /* this function is called at probe time */
sd_config(struct gspca_dev * gspca_dev,const struct usb_device_id * id)148*4882a593Smuzhiyun static int sd_config(struct gspca_dev *gspca_dev,
149*4882a593Smuzhiyun const struct usb_device_id *id)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun struct cam *cam;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun cam = &gspca_dev->cam;
154*4882a593Smuzhiyun cam->cam_mode = sif_mode;
155*4882a593Smuzhiyun cam->nmodes = ARRAY_SIZE(sif_mode);
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun return 0;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
tv_8532_setReg(struct gspca_dev * gspca_dev)160*4882a593Smuzhiyun static void tv_8532_setReg(struct gspca_dev *gspca_dev)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun reg_w1(gspca_dev, R3B_Test3, 0x0a); /* Test0Sel = 10 */
163*4882a593Smuzhiyun /******************************************************/
164*4882a593Smuzhiyun reg_w1(gspca_dev, R0E_AD_HEIGHTL, 0x90);
165*4882a593Smuzhiyun reg_w1(gspca_dev, R0F_AD_HEIGHTH, 0x01);
166*4882a593Smuzhiyun reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, 0x018f);
167*4882a593Smuzhiyun reg_w1(gspca_dev, R10_AD_COL_BEGINL, 0x44);
168*4882a593Smuzhiyun /* begin active line */
169*4882a593Smuzhiyun reg_w1(gspca_dev, R11_AD_COL_BEGINH, 0x00);
170*4882a593Smuzhiyun /* mirror and digital gain */
171*4882a593Smuzhiyun reg_w1(gspca_dev, R14_AD_ROW_BEGINL, 0x0a);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x02);
174*4882a593Smuzhiyun reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00);
175*4882a593Smuzhiyun reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
176*4882a593Smuzhiyun /* = 0x84 */
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /* this function is called at probe and resume time */
sd_init(struct gspca_dev * gspca_dev)180*4882a593Smuzhiyun static int sd_init(struct gspca_dev *gspca_dev)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun tv_8532WriteEEprom(gspca_dev);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun return 0;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
setexposure(struct gspca_dev * gspca_dev,s32 val)187*4882a593Smuzhiyun static void setexposure(struct gspca_dev *gspca_dev, s32 val)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, val);
190*4882a593Smuzhiyun reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
191*4882a593Smuzhiyun /* 0x84 */
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
setgain(struct gspca_dev * gspca_dev,s32 val)194*4882a593Smuzhiyun static void setgain(struct gspca_dev *gspca_dev, s32 val)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun reg_w2(gspca_dev, R20_GAIN_G1L, val);
197*4882a593Smuzhiyun reg_w2(gspca_dev, R22_GAIN_RL, val);
198*4882a593Smuzhiyun reg_w2(gspca_dev, R24_GAIN_BL, val);
199*4882a593Smuzhiyun reg_w2(gspca_dev, R26_GAIN_G2L, val);
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun /* -- start the camera -- */
sd_start(struct gspca_dev * gspca_dev)203*4882a593Smuzhiyun static int sd_start(struct gspca_dev *gspca_dev)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8); /* 0x20; 0x0c */
208*4882a593Smuzhiyun reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03);
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun /************************************************/
211*4882a593Smuzhiyun reg_w1(gspca_dev, R28_QUANT, 0x90);
212*4882a593Smuzhiyun /* 0x72 compressed mode 0x28 */
213*4882a593Smuzhiyun if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
214*4882a593Smuzhiyun /* 176x144 */
215*4882a593Smuzhiyun reg_w1(gspca_dev, R29_LINE, 0x41);
216*4882a593Smuzhiyun /* CIF - 2 lines/packet */
217*4882a593Smuzhiyun } else {
218*4882a593Smuzhiyun /* 352x288 */
219*4882a593Smuzhiyun reg_w1(gspca_dev, R29_LINE, 0x81);
220*4882a593Smuzhiyun /* CIF - 2 lines/packet */
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun /************************************************/
223*4882a593Smuzhiyun reg_w1(gspca_dev, R2C_POLARITY, 0x10); /* slow clock */
224*4882a593Smuzhiyun reg_w1(gspca_dev, R2D_POINT, 0x14);
225*4882a593Smuzhiyun reg_w1(gspca_dev, R2E_POINTH, 0x01);
226*4882a593Smuzhiyun reg_w1(gspca_dev, R2F_POINTB, 0x12);
227*4882a593Smuzhiyun reg_w1(gspca_dev, R30_POINTBH, 0x01);
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun tv_8532_setReg(gspca_dev);
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun /************************************************/
232*4882a593Smuzhiyun reg_w1(gspca_dev, R31_UPD, 0x01); /* update registers */
233*4882a593Smuzhiyun msleep(200);
234*4882a593Smuzhiyun reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun gspca_dev->empty_packet = 0; /* check the empty packets */
237*4882a593Smuzhiyun sd->packet = 0; /* ignore the first packets */
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun return 0;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
sd_stopN(struct gspca_dev * gspca_dev)242*4882a593Smuzhiyun static void sd_stopN(struct gspca_dev *gspca_dev)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun reg_w1(gspca_dev, R3B_Test3, 0x0b); /* Test0Sel = 11 = GPIO */
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
sd_pkt_scan(struct gspca_dev * gspca_dev,u8 * data,int len)247*4882a593Smuzhiyun static void sd_pkt_scan(struct gspca_dev *gspca_dev,
248*4882a593Smuzhiyun u8 *data, /* isoc packet */
249*4882a593Smuzhiyun int len) /* iso packet length */
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
252*4882a593Smuzhiyun int packet_type0, packet_type1;
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun packet_type0 = packet_type1 = INTER_PACKET;
255*4882a593Smuzhiyun if (gspca_dev->empty_packet) {
256*4882a593Smuzhiyun gspca_dev->empty_packet = 0;
257*4882a593Smuzhiyun sd->packet = gspca_dev->pixfmt.height / 2;
258*4882a593Smuzhiyun packet_type0 = FIRST_PACKET;
259*4882a593Smuzhiyun } else if (sd->packet == 0)
260*4882a593Smuzhiyun return; /* 2 more lines in 352x288 ! */
261*4882a593Smuzhiyun sd->packet--;
262*4882a593Smuzhiyun if (sd->packet == 0)
263*4882a593Smuzhiyun packet_type1 = LAST_PACKET;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun /* each packet contains:
266*4882a593Smuzhiyun * - header 2 bytes
267*4882a593Smuzhiyun * - RGRG line
268*4882a593Smuzhiyun * - 4 bytes
269*4882a593Smuzhiyun * - GBGB line
270*4882a593Smuzhiyun * - 4 bytes
271*4882a593Smuzhiyun */
272*4882a593Smuzhiyun gspca_frame_add(gspca_dev, packet_type0,
273*4882a593Smuzhiyun data + 2, gspca_dev->pixfmt.width);
274*4882a593Smuzhiyun gspca_frame_add(gspca_dev, packet_type1,
275*4882a593Smuzhiyun data + gspca_dev->pixfmt.width + 5,
276*4882a593Smuzhiyun gspca_dev->pixfmt.width);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
sd_s_ctrl(struct v4l2_ctrl * ctrl)279*4882a593Smuzhiyun static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun struct gspca_dev *gspca_dev =
282*4882a593Smuzhiyun container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun gspca_dev->usb_err = 0;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun if (!gspca_dev->streaming)
287*4882a593Smuzhiyun return 0;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun switch (ctrl->id) {
290*4882a593Smuzhiyun case V4L2_CID_EXPOSURE:
291*4882a593Smuzhiyun setexposure(gspca_dev, ctrl->val);
292*4882a593Smuzhiyun break;
293*4882a593Smuzhiyun case V4L2_CID_GAIN:
294*4882a593Smuzhiyun setgain(gspca_dev, ctrl->val);
295*4882a593Smuzhiyun break;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun return gspca_dev->usb_err;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun static const struct v4l2_ctrl_ops sd_ctrl_ops = {
301*4882a593Smuzhiyun .s_ctrl = sd_s_ctrl,
302*4882a593Smuzhiyun };
303*4882a593Smuzhiyun
sd_init_controls(struct gspca_dev * gspca_dev)304*4882a593Smuzhiyun static int sd_init_controls(struct gspca_dev *gspca_dev)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun gspca_dev->vdev.ctrl_handler = hdl;
309*4882a593Smuzhiyun v4l2_ctrl_handler_init(hdl, 2);
310*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
311*4882a593Smuzhiyun V4L2_CID_EXPOSURE, 0, 0x18f, 1, 0x18f);
312*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
313*4882a593Smuzhiyun V4L2_CID_GAIN, 0, 0x7ff, 1, 0x100);
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun if (hdl->error) {
316*4882a593Smuzhiyun pr_err("Could not initialize controls\n");
317*4882a593Smuzhiyun return hdl->error;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun return 0;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun /* sub-driver description */
323*4882a593Smuzhiyun static const struct sd_desc sd_desc = {
324*4882a593Smuzhiyun .name = MODULE_NAME,
325*4882a593Smuzhiyun .config = sd_config,
326*4882a593Smuzhiyun .init = sd_init,
327*4882a593Smuzhiyun .init_controls = sd_init_controls,
328*4882a593Smuzhiyun .start = sd_start,
329*4882a593Smuzhiyun .stopN = sd_stopN,
330*4882a593Smuzhiyun .pkt_scan = sd_pkt_scan,
331*4882a593Smuzhiyun };
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun /* -- module initialisation -- */
334*4882a593Smuzhiyun static const struct usb_device_id device_table[] = {
335*4882a593Smuzhiyun {USB_DEVICE(0x046d, 0x0920)},
336*4882a593Smuzhiyun {USB_DEVICE(0x046d, 0x0921)},
337*4882a593Smuzhiyun {USB_DEVICE(0x0545, 0x808b)},
338*4882a593Smuzhiyun {USB_DEVICE(0x0545, 0x8333)},
339*4882a593Smuzhiyun {USB_DEVICE(0x0923, 0x010f)},
340*4882a593Smuzhiyun {}
341*4882a593Smuzhiyun };
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, device_table);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun /* -- device connect -- */
sd_probe(struct usb_interface * intf,const struct usb_device_id * id)346*4882a593Smuzhiyun static int sd_probe(struct usb_interface *intf,
347*4882a593Smuzhiyun const struct usb_device_id *id)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
350*4882a593Smuzhiyun THIS_MODULE);
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun static struct usb_driver sd_driver = {
354*4882a593Smuzhiyun .name = MODULE_NAME,
355*4882a593Smuzhiyun .id_table = device_table,
356*4882a593Smuzhiyun .probe = sd_probe,
357*4882a593Smuzhiyun .disconnect = gspca_disconnect,
358*4882a593Smuzhiyun #ifdef CONFIG_PM
359*4882a593Smuzhiyun .suspend = gspca_suspend,
360*4882a593Smuzhiyun .resume = gspca_resume,
361*4882a593Smuzhiyun .reset_resume = gspca_resume,
362*4882a593Smuzhiyun #endif
363*4882a593Smuzhiyun };
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun module_usb_driver(sd_driver);
366