]>
Commit | Line | Data |
---|---|---|
b517af72 HG |
1 | /* |
2 | * Driver for USB webcams based on Konica chipset. This | |
3 | * chipset is used in Intel YC76 camera. | |
4 | * | |
5 | * Copyright (C) 2010 Hans de Goede <hdegoede@redhat.com> | |
6 | * | |
7 | * Based on the usbvideo v4l1 konicawc driver which is: | |
8 | * | |
9 | * Copyright (C) 2002 Simon Evans <spse@secret.org.uk> | |
10 | * | |
11 | * The code for making gspca work with a webcam with 2 isoc endpoints was | |
12 | * taken from the benq gspca subdriver which is: | |
13 | * | |
14 | * Copyright (C) 2009 Jean-Francois Moine (http://moinejf.free.fr) | |
15 | * | |
16 | * This program is free software; you can redistribute it and/or modify | |
17 | * it under the terms of the GNU General Public License as published by | |
18 | * the Free Software Foundation; either version 2 of the License, or | |
19 | * any later version. | |
20 | * | |
21 | * This program is distributed in the hope that it will be useful, | |
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | * GNU General Public License for more details. | |
25 | * | |
26 | * You should have received a copy of the GNU General Public License | |
27 | * along with this program; if not, write to the Free Software | |
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
29 | */ | |
30 | ||
133a9fe9 JP |
31 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
32 | ||
b517af72 HG |
33 | #define MODULE_NAME "konica" |
34 | ||
35 | #include <linux/input.h> | |
36 | #include "gspca.h" | |
37 | ||
38 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); | |
39 | MODULE_DESCRIPTION("Konica chipset USB Camera Driver"); | |
40 | MODULE_LICENSE("GPL"); | |
41 | ||
42 | #define WHITEBAL_REG 0x01 | |
43 | #define BRIGHTNESS_REG 0x02 | |
44 | #define SHARPNESS_REG 0x03 | |
45 | #define CONTRAST_REG 0x04 | |
46 | #define SATURATION_REG 0x05 | |
47 | ||
48 | /* specific webcam descriptor */ | |
49 | struct sd { | |
50 | struct gspca_dev gspca_dev; /* !! must be the first item */ | |
51 | struct urb *last_data_urb; | |
52 | u8 snapshot_pressed; | |
53 | u8 brightness; | |
54 | u8 contrast; | |
55 | u8 saturation; | |
56 | u8 whitebal; | |
57 | u8 sharpness; | |
58 | }; | |
59 | ||
60 | /* V4L2 controls supported by the driver */ | |
61 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); | |
62 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); | |
63 | static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); | |
64 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); | |
65 | static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val); | |
66 | static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val); | |
67 | static int sd_setwhitebal(struct gspca_dev *gspca_dev, __s32 val); | |
68 | static int sd_getwhitebal(struct gspca_dev *gspca_dev, __s32 *val); | |
69 | static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); | |
70 | static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); | |
71 | ||
72 | static const struct ctrl sd_ctrls[] = { | |
73 | #define SD_BRIGHTNESS 0 | |
74 | { | |
75 | { | |
76 | .id = V4L2_CID_BRIGHTNESS, | |
77 | .type = V4L2_CTRL_TYPE_INTEGER, | |
78 | .name = "Brightness", | |
79 | .minimum = 0, | |
80 | .maximum = 9, | |
81 | .step = 1, | |
82 | #define BRIGHTNESS_DEFAULT 4 | |
83 | .default_value = BRIGHTNESS_DEFAULT, | |
84 | .flags = 0, | |
85 | }, | |
86 | .set = sd_setbrightness, | |
87 | .get = sd_getbrightness, | |
88 | }, | |
89 | #define SD_CONTRAST 1 | |
90 | { | |
91 | { | |
92 | .id = V4L2_CID_CONTRAST, | |
93 | .type = V4L2_CTRL_TYPE_INTEGER, | |
780e3121 | 94 | .name = "Contrast", |
b517af72 HG |
95 | .minimum = 0, |
96 | .maximum = 9, | |
97 | .step = 4, | |
98 | #define CONTRAST_DEFAULT 10 | |
99 | .default_value = CONTRAST_DEFAULT, | |
100 | .flags = 0, | |
101 | }, | |
102 | .set = sd_setcontrast, | |
103 | .get = sd_getcontrast, | |
104 | }, | |
105 | #define SD_SATURATION 2 | |
106 | { | |
107 | { | |
108 | .id = V4L2_CID_SATURATION, | |
109 | .type = V4L2_CTRL_TYPE_INTEGER, | |
110 | .name = "Saturation", | |
111 | .minimum = 0, | |
112 | .maximum = 9, | |
113 | .step = 1, | |
114 | #define SATURATION_DEFAULT 4 | |
115 | .default_value = SATURATION_DEFAULT, | |
116 | .flags = 0, | |
117 | }, | |
118 | .set = sd_setsaturation, | |
119 | .get = sd_getsaturation, | |
120 | }, | |
121 | #define SD_WHITEBAL 3 | |
122 | { | |
123 | { | |
124 | .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, | |
125 | .type = V4L2_CTRL_TYPE_INTEGER, | |
780e3121 | 126 | .name = "White Balance", |
b517af72 HG |
127 | .minimum = 0, |
128 | .maximum = 33, | |
129 | .step = 1, | |
130 | #define WHITEBAL_DEFAULT 25 | |
131 | .default_value = WHITEBAL_DEFAULT, | |
132 | .flags = 0, | |
133 | }, | |
134 | .set = sd_setwhitebal, | |
135 | .get = sd_getwhitebal, | |
136 | }, | |
137 | #define SD_SHARPNESS 4 | |
138 | { | |
139 | { | |
140 | .id = V4L2_CID_SHARPNESS, | |
141 | .type = V4L2_CTRL_TYPE_INTEGER, | |
142 | .name = "Sharpness", | |
143 | .minimum = 0, | |
144 | .maximum = 9, | |
145 | .step = 1, | |
146 | #define SHARPNESS_DEFAULT 4 | |
147 | .default_value = SHARPNESS_DEFAULT, | |
148 | .flags = 0, | |
149 | }, | |
150 | .set = sd_setsharpness, | |
151 | .get = sd_getsharpness, | |
152 | }, | |
153 | }; | |
154 | ||
155 | /* .priv is what goes to register 8 for this mode, known working values: | |
156 | 0x00 -> 176x144, cropped | |
157 | 0x01 -> 176x144, cropped | |
158 | 0x02 -> 176x144, cropped | |
159 | 0x03 -> 176x144, cropped | |
160 | 0x04 -> 176x144, binned | |
161 | 0x05 -> 320x240 | |
162 | 0x06 -> 320x240 | |
163 | 0x07 -> 160x120, cropped | |
164 | 0x08 -> 160x120, cropped | |
165 | 0x09 -> 160x120, binned (note has 136 lines) | |
166 | 0x0a -> 160x120, binned (note has 136 lines) | |
167 | 0x0b -> 160x120, cropped | |
168 | */ | |
169 | static const struct v4l2_pix_format vga_mode[] = { | |
170 | {160, 120, V4L2_PIX_FMT_KONICA420, V4L2_FIELD_NONE, | |
171 | .bytesperline = 160, | |
172 | .sizeimage = 160 * 136 * 3 / 2 + 960, | |
173 | .colorspace = V4L2_COLORSPACE_SRGB, | |
174 | .priv = 0x0a}, | |
175 | {176, 144, V4L2_PIX_FMT_KONICA420, V4L2_FIELD_NONE, | |
176 | .bytesperline = 176, | |
177 | .sizeimage = 176 * 144 * 3 / 2 + 960, | |
178 | .colorspace = V4L2_COLORSPACE_SRGB, | |
179 | .priv = 0x04}, | |
180 | {320, 240, V4L2_PIX_FMT_KONICA420, V4L2_FIELD_NONE, | |
181 | .bytesperline = 320, | |
182 | .sizeimage = 320 * 240 * 3 / 2 + 960, | |
183 | .colorspace = V4L2_COLORSPACE_SRGB, | |
184 | .priv = 0x05}, | |
185 | }; | |
186 | ||
187 | static void sd_isoc_irq(struct urb *urb); | |
188 | ||
189 | static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) | |
190 | { | |
191 | struct usb_device *dev = gspca_dev->dev; | |
192 | int ret; | |
193 | ||
194 | if (gspca_dev->usb_err < 0) | |
195 | return; | |
196 | ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | |
197 | 0x02, | |
198 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
199 | value, | |
200 | index, | |
201 | NULL, | |
202 | 0, | |
203 | 1000); | |
204 | if (ret < 0) { | |
133a9fe9 | 205 | pr_err("reg_w err %d\n", ret); |
b517af72 HG |
206 | gspca_dev->usb_err = ret; |
207 | } | |
208 | } | |
209 | ||
210 | static void reg_r(struct gspca_dev *gspca_dev, u16 value, u16 index) | |
211 | { | |
212 | struct usb_device *dev = gspca_dev->dev; | |
213 | int ret; | |
214 | ||
215 | if (gspca_dev->usb_err < 0) | |
216 | return; | |
217 | ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), | |
218 | 0x03, | |
219 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
220 | value, | |
221 | index, | |
222 | gspca_dev->usb_buf, | |
223 | 2, | |
224 | 1000); | |
225 | if (ret < 0) { | |
133a9fe9 | 226 | pr_err("reg_w err %d\n", ret); |
b517af72 HG |
227 | gspca_dev->usb_err = ret; |
228 | } | |
229 | } | |
230 | ||
231 | static void konica_stream_on(struct gspca_dev *gspca_dev) | |
232 | { | |
233 | reg_w(gspca_dev, 1, 0x0b); | |
234 | } | |
235 | ||
236 | static void konica_stream_off(struct gspca_dev *gspca_dev) | |
237 | { | |
238 | reg_w(gspca_dev, 0, 0x0b); | |
239 | } | |
240 | ||
241 | /* this function is called at probe time */ | |
242 | static int sd_config(struct gspca_dev *gspca_dev, | |
243 | const struct usb_device_id *id) | |
244 | { | |
245 | struct sd *sd = (struct sd *) gspca_dev; | |
246 | ||
247 | gspca_dev->cam.cam_mode = vga_mode; | |
248 | gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); | |
249 | gspca_dev->cam.no_urb_create = 1; | |
b517af72 HG |
250 | |
251 | sd->brightness = BRIGHTNESS_DEFAULT; | |
252 | sd->contrast = CONTRAST_DEFAULT; | |
253 | sd->saturation = SATURATION_DEFAULT; | |
254 | sd->whitebal = WHITEBAL_DEFAULT; | |
255 | sd->sharpness = SHARPNESS_DEFAULT; | |
256 | ||
257 | return 0; | |
258 | } | |
259 | ||
260 | /* this function is called at probe and resume time */ | |
261 | static int sd_init(struct gspca_dev *gspca_dev) | |
262 | { | |
263 | /* HDG not sure if these 2 reads are needed */ | |
264 | reg_r(gspca_dev, 0, 0x10); | |
265 | PDEBUG(D_PROBE, "Reg 0x10 reads: %02x %02x", | |
266 | gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); | |
267 | reg_r(gspca_dev, 0, 0x10); | |
268 | PDEBUG(D_PROBE, "Reg 0x10 reads: %02x %02x", | |
269 | gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); | |
270 | reg_w(gspca_dev, 0, 0x0d); | |
271 | ||
272 | return 0; | |
273 | } | |
274 | ||
275 | static int sd_start(struct gspca_dev *gspca_dev) | |
276 | { | |
277 | struct sd *sd = (struct sd *) gspca_dev; | |
278 | struct urb *urb; | |
279 | int i, n, packet_size; | |
280 | struct usb_host_interface *alt; | |
281 | struct usb_interface *intf; | |
282 | ||
283 | intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); | |
284 | alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); | |
285 | if (!alt) { | |
133a9fe9 | 286 | pr_err("Couldn't get altsetting\n"); |
b517af72 HG |
287 | return -EIO; |
288 | } | |
289 | ||
290 | packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); | |
291 | ||
292 | reg_w(gspca_dev, sd->brightness, BRIGHTNESS_REG); | |
293 | reg_w(gspca_dev, sd->whitebal, WHITEBAL_REG); | |
294 | reg_w(gspca_dev, sd->contrast, CONTRAST_REG); | |
295 | reg_w(gspca_dev, sd->saturation, SATURATION_REG); | |
296 | reg_w(gspca_dev, sd->sharpness, SHARPNESS_REG); | |
297 | ||
298 | n = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; | |
299 | reg_w(gspca_dev, n, 0x08); | |
300 | ||
301 | konica_stream_on(gspca_dev); | |
302 | ||
303 | if (gspca_dev->usb_err) | |
304 | return gspca_dev->usb_err; | |
305 | ||
306 | /* create 4 URBs - 2 on endpoint 0x83 and 2 on 0x082 */ | |
307 | #if MAX_NURBS < 4 | |
308 | #error "Not enough URBs in the gspca table" | |
309 | #endif | |
310 | #define SD_NPKT 32 | |
311 | for (n = 0; n < 4; n++) { | |
312 | i = n & 1 ? 0 : 1; | |
313 | packet_size = | |
314 | le16_to_cpu(alt->endpoint[i].desc.wMaxPacketSize); | |
315 | urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL); | |
316 | if (!urb) { | |
133a9fe9 | 317 | pr_err("usb_alloc_urb failed\n"); |
b517af72 HG |
318 | return -ENOMEM; |
319 | } | |
320 | gspca_dev->urb[n] = urb; | |
76e241d4 | 321 | urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev, |
b517af72 HG |
322 | packet_size * SD_NPKT, |
323 | GFP_KERNEL, | |
324 | &urb->transfer_dma); | |
325 | if (urb->transfer_buffer == NULL) { | |
133a9fe9 | 326 | pr_err("usb_buffer_alloc failed\n"); |
b517af72 HG |
327 | return -ENOMEM; |
328 | } | |
329 | ||
330 | urb->dev = gspca_dev->dev; | |
331 | urb->context = gspca_dev; | |
332 | urb->transfer_buffer_length = packet_size * SD_NPKT; | |
333 | urb->pipe = usb_rcvisocpipe(gspca_dev->dev, | |
334 | n & 1 ? 0x81 : 0x82); | |
335 | urb->transfer_flags = URB_ISO_ASAP | |
336 | | URB_NO_TRANSFER_DMA_MAP; | |
337 | urb->interval = 1; | |
338 | urb->complete = sd_isoc_irq; | |
339 | urb->number_of_packets = SD_NPKT; | |
340 | for (i = 0; i < SD_NPKT; i++) { | |
341 | urb->iso_frame_desc[i].length = packet_size; | |
342 | urb->iso_frame_desc[i].offset = packet_size * i; | |
343 | } | |
344 | } | |
345 | ||
346 | return 0; | |
347 | } | |
348 | ||
349 | static void sd_stopN(struct gspca_dev *gspca_dev) | |
350 | { | |
351 | struct sd *sd = (struct sd *) gspca_dev; | |
352 | ||
353 | konica_stream_off(gspca_dev); | |
2856643e | 354 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) |
b517af72 HG |
355 | /* Don't keep the button in the pressed state "forever" if it was |
356 | pressed when streaming is stopped */ | |
357 | if (sd->snapshot_pressed) { | |
358 | input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); | |
359 | input_sync(gspca_dev->input_dev); | |
360 | sd->snapshot_pressed = 0; | |
361 | } | |
362 | #endif | |
363 | } | |
364 | ||
365 | /* reception of an URB */ | |
366 | static void sd_isoc_irq(struct urb *urb) | |
367 | { | |
368 | struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; | |
369 | struct sd *sd = (struct sd *) gspca_dev; | |
370 | struct urb *data_urb, *status_urb; | |
371 | u8 *data; | |
372 | int i, st; | |
373 | ||
374 | PDEBUG(D_PACK, "sd isoc irq"); | |
375 | if (!gspca_dev->streaming) | |
376 | return; | |
377 | ||
378 | if (urb->status != 0) { | |
379 | if (urb->status == -ESHUTDOWN) | |
380 | return; /* disconnection */ | |
381 | #ifdef CONFIG_PM | |
382 | if (gspca_dev->frozen) | |
383 | return; | |
384 | #endif | |
385 | PDEBUG(D_ERR, "urb status: %d", urb->status); | |
386 | st = usb_submit_urb(urb, GFP_ATOMIC); | |
387 | if (st < 0) | |
133a9fe9 | 388 | pr_err("resubmit urb error %d\n", st); |
b517af72 HG |
389 | return; |
390 | } | |
391 | ||
392 | /* if this is a data URB (ep 0x82), wait */ | |
393 | if (urb->transfer_buffer_length > 32) { | |
394 | sd->last_data_urb = urb; | |
395 | return; | |
396 | } | |
397 | ||
398 | status_urb = urb; | |
399 | data_urb = sd->last_data_urb; | |
400 | sd->last_data_urb = NULL; | |
401 | ||
402 | if (!data_urb || data_urb->start_frame != status_urb->start_frame) { | |
403 | PDEBUG(D_ERR|D_PACK, "lost sync on frames"); | |
404 | goto resubmit; | |
405 | } | |
406 | ||
407 | if (data_urb->number_of_packets != status_urb->number_of_packets) { | |
408 | PDEBUG(D_ERR|D_PACK, | |
409 | "no packets does not match, data: %d, status: %d", | |
410 | data_urb->number_of_packets, | |
411 | status_urb->number_of_packets); | |
412 | goto resubmit; | |
413 | } | |
414 | ||
415 | for (i = 0; i < status_urb->number_of_packets; i++) { | |
416 | if (data_urb->iso_frame_desc[i].status || | |
417 | status_urb->iso_frame_desc[i].status) { | |
418 | PDEBUG(D_ERR|D_PACK, | |
419 | "pkt %d data-status %d, status-status %d", i, | |
420 | data_urb->iso_frame_desc[i].status, | |
421 | status_urb->iso_frame_desc[i].status); | |
422 | gspca_dev->last_packet_type = DISCARD_PACKET; | |
423 | continue; | |
424 | } | |
425 | ||
426 | if (status_urb->iso_frame_desc[i].actual_length != 1) { | |
427 | PDEBUG(D_ERR|D_PACK, | |
428 | "bad status packet length %d", | |
429 | status_urb->iso_frame_desc[i].actual_length); | |
430 | gspca_dev->last_packet_type = DISCARD_PACKET; | |
431 | continue; | |
432 | } | |
433 | ||
434 | st = *((u8 *)status_urb->transfer_buffer | |
435 | + status_urb->iso_frame_desc[i].offset); | |
436 | ||
437 | data = (u8 *)data_urb->transfer_buffer | |
438 | + data_urb->iso_frame_desc[i].offset; | |
439 | ||
440 | /* st: 0x80-0xff: frame start with frame number (ie 0-7f) | |
441 | * otherwise: | |
442 | * bit 0 0: keep packet | |
443 | * 1: drop packet (padding data) | |
444 | * | |
445 | * bit 4 0 button not clicked | |
446 | * 1 button clicked | |
447 | * button is used to `take a picture' (in software) | |
448 | */ | |
449 | if (st & 0x80) { | |
450 | gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); | |
451 | gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); | |
452 | } else { | |
2856643e | 453 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) |
b517af72 HG |
454 | u8 button_state = st & 0x40 ? 1 : 0; |
455 | if (sd->snapshot_pressed != button_state) { | |
456 | input_report_key(gspca_dev->input_dev, | |
457 | KEY_CAMERA, | |
458 | button_state); | |
459 | input_sync(gspca_dev->input_dev); | |
460 | sd->snapshot_pressed = button_state; | |
461 | } | |
462 | #endif | |
463 | if (st & 0x01) | |
464 | continue; | |
465 | } | |
466 | gspca_frame_add(gspca_dev, INTER_PACKET, data, | |
467 | data_urb->iso_frame_desc[i].actual_length); | |
468 | } | |
469 | ||
470 | resubmit: | |
471 | if (data_urb) { | |
472 | st = usb_submit_urb(data_urb, GFP_ATOMIC); | |
473 | if (st < 0) | |
474 | PDEBUG(D_ERR|D_PACK, | |
475 | "usb_submit_urb(data_urb) ret %d", st); | |
476 | } | |
477 | st = usb_submit_urb(status_urb, GFP_ATOMIC); | |
478 | if (st < 0) | |
133a9fe9 | 479 | pr_err("usb_submit_urb(status_urb) ret %d\n", st); |
b517af72 HG |
480 | } |
481 | ||
482 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) | |
483 | { | |
484 | struct sd *sd = (struct sd *) gspca_dev; | |
485 | ||
486 | sd->brightness = val; | |
487 | if (gspca_dev->streaming) { | |
488 | konica_stream_off(gspca_dev); | |
489 | reg_w(gspca_dev, sd->brightness, BRIGHTNESS_REG); | |
490 | konica_stream_on(gspca_dev); | |
491 | } | |
492 | ||
493 | return 0; | |
494 | } | |
495 | ||
496 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) | |
497 | { | |
498 | struct sd *sd = (struct sd *) gspca_dev; | |
499 | ||
500 | *val = sd->brightness; | |
501 | ||
502 | return 0; | |
503 | } | |
504 | ||
505 | static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) | |
506 | { | |
507 | struct sd *sd = (struct sd *) gspca_dev; | |
508 | ||
509 | sd->contrast = val; | |
510 | if (gspca_dev->streaming) { | |
511 | konica_stream_off(gspca_dev); | |
512 | reg_w(gspca_dev, sd->contrast, CONTRAST_REG); | |
513 | konica_stream_on(gspca_dev); | |
514 | } | |
515 | ||
516 | return 0; | |
517 | } | |
518 | ||
519 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) | |
520 | { | |
521 | struct sd *sd = (struct sd *) gspca_dev; | |
522 | ||
523 | *val = sd->contrast; | |
524 | ||
525 | return 0; | |
526 | } | |
527 | ||
528 | static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val) | |
529 | { | |
530 | struct sd *sd = (struct sd *) gspca_dev; | |
531 | ||
532 | sd->saturation = val; | |
533 | if (gspca_dev->streaming) { | |
534 | konica_stream_off(gspca_dev); | |
535 | reg_w(gspca_dev, sd->saturation, SATURATION_REG); | |
536 | konica_stream_on(gspca_dev); | |
537 | } | |
538 | return 0; | |
539 | } | |
540 | ||
541 | static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val) | |
542 | { | |
543 | struct sd *sd = (struct sd *) gspca_dev; | |
544 | ||
545 | *val = sd->saturation; | |
546 | ||
547 | return 0; | |
548 | } | |
549 | ||
550 | static int sd_setwhitebal(struct gspca_dev *gspca_dev, __s32 val) | |
551 | { | |
552 | struct sd *sd = (struct sd *) gspca_dev; | |
553 | ||
554 | sd->whitebal = val; | |
555 | if (gspca_dev->streaming) { | |
556 | konica_stream_off(gspca_dev); | |
557 | reg_w(gspca_dev, sd->whitebal, WHITEBAL_REG); | |
558 | konica_stream_on(gspca_dev); | |
559 | } | |
560 | return 0; | |
561 | } | |
562 | ||
563 | static int sd_getwhitebal(struct gspca_dev *gspca_dev, __s32 *val) | |
564 | { | |
565 | struct sd *sd = (struct sd *) gspca_dev; | |
566 | ||
567 | *val = sd->whitebal; | |
568 | ||
569 | return 0; | |
570 | } | |
571 | ||
572 | static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) | |
573 | { | |
574 | struct sd *sd = (struct sd *) gspca_dev; | |
575 | ||
576 | sd->sharpness = val; | |
577 | if (gspca_dev->streaming) { | |
578 | konica_stream_off(gspca_dev); | |
579 | reg_w(gspca_dev, sd->sharpness, SHARPNESS_REG); | |
580 | konica_stream_on(gspca_dev); | |
581 | } | |
582 | return 0; | |
583 | } | |
584 | ||
585 | static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) | |
586 | { | |
587 | struct sd *sd = (struct sd *) gspca_dev; | |
588 | ||
589 | *val = sd->sharpness; | |
590 | ||
591 | return 0; | |
592 | } | |
593 | ||
594 | /* sub-driver description */ | |
595 | static const struct sd_desc sd_desc = { | |
596 | .name = MODULE_NAME, | |
597 | .ctrls = sd_ctrls, | |
598 | .nctrls = ARRAY_SIZE(sd_ctrls), | |
599 | .config = sd_config, | |
600 | .init = sd_init, | |
601 | .start = sd_start, | |
602 | .stopN = sd_stopN, | |
2856643e | 603 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) |
b517af72 HG |
604 | .other_input = 1, |
605 | #endif | |
606 | }; | |
607 | ||
608 | /* -- module initialisation -- */ | |
95c967c1 | 609 | static const struct usb_device_id device_table[] = { |
b517af72 HG |
610 | {USB_DEVICE(0x04c8, 0x0720)}, /* Intel YC 76 */ |
611 | {} | |
612 | }; | |
613 | MODULE_DEVICE_TABLE(usb, device_table); | |
614 | ||
615 | /* -- device connect -- */ | |
616 | static int sd_probe(struct usb_interface *intf, | |
617 | const struct usb_device_id *id) | |
618 | { | |
619 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | |
620 | THIS_MODULE); | |
621 | } | |
622 | ||
623 | static struct usb_driver sd_driver = { | |
624 | .name = MODULE_NAME, | |
625 | .id_table = device_table, | |
626 | .probe = sd_probe, | |
627 | .disconnect = gspca_disconnect, | |
628 | #ifdef CONFIG_PM | |
629 | .suspend = gspca_suspend, | |
630 | .resume = gspca_resume, | |
631 | #endif | |
632 | }; | |
633 | ||
634 | /* -- module insert / remove -- */ | |
635 | static int __init sd_mod_init(void) | |
636 | { | |
54826437 | 637 | return usb_register(&sd_driver); |
b517af72 HG |
638 | } |
639 | static void __exit sd_mod_exit(void) | |
640 | { | |
641 | usb_deregister(&sd_driver); | |
b517af72 HG |
642 | } |
643 | ||
644 | module_init(sd_mod_init); | |
645 | module_exit(sd_mod_exit); |