Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net) |
| 3 | * |
| 4 | * Thanks to STMicroelectronics for information on the usb commands, and |
| 5 | * to Steve Miller at STM for his help and encouragement while I was |
| 6 | * writing this driver. |
| 7 | * |
| 8 | * This driver is based heavily on the |
| 9 | * Endpoints (formerly known as AOX) se401 USB Camera Driver |
| 10 | * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org) |
| 11 | * |
| 12 | * Still somewhat based on the Linux ov511 driver. |
| 13 | * |
| 14 | * This program is free software; you can redistribute it and/or modify it |
| 15 | * under the terms of the GNU General Public License as published by the |
| 16 | * Free Software Foundation; either version 2 of the License, or (at your |
| 17 | * option) any later version. |
| 18 | * |
| 19 | * This program is distributed in the hope that it will be useful, but |
| 20 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| 21 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 22 | * for more details. |
| 23 | * |
| 24 | * You should have received a copy of the GNU General Public License |
| 25 | * along with this program; if not, write to the Free Software Foundation, |
| 26 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 27 | * |
| 28 | * History: |
| 29 | * ver 0.1 October, 2001. Initial attempt. |
| 30 | * |
| 31 | * ver 0.2 November, 2001. Fixed asbility to resize, added brightness |
| 32 | * function, made more stable (?) |
| 33 | * |
| 34 | * ver 0.21 Nov, 2001. Added gamma correction and white balance, |
| 35 | * due to Alexander Schwartz. Still trying to |
| 36 | * improve stablility. Moved stuff into stv680.h |
| 37 | * |
| 38 | * ver 0.22 Nov, 2001. Added sharpen function (by Michael Sweet, |
| 39 | * mike@easysw.com) from GIMP, also used in pencam. |
| 40 | * Simple, fast, good integer math routine. |
| 41 | * |
| 42 | * ver 0.23 Dec, 2001 (gkh) |
| 43 | * Took out sharpen function, ran code through |
| 44 | * Lindent, and did other minor tweaks to get |
| 45 | * things to work properly with 2.5.1 |
| 46 | * |
| 47 | * ver 0.24 Jan, 2002 (kjs) |
| 48 | * Fixed the problem with webcam crashing after |
| 49 | * two pictures. Changed the way pic is halved to |
| 50 | * improve quality. Got rid of green line around |
| 51 | * frame. Fix brightness reset when changing size |
| 52 | * bug. Adjusted gamma filters slightly. |
| 53 | * |
| 54 | * ver 0.25 Jan, 2002 (kjs) |
| 55 | * Fixed a bug in which the driver sometimes attempted |
| 56 | * to set to a non-supported size. This allowed |
| 57 | * gnomemeeting to work. |
| 58 | * Fixed proc entry removal bug. |
| 59 | */ |
| 60 | |
| 61 | #include <linux/config.h> |
| 62 | #include <linux/module.h> |
| 63 | #include <linux/init.h> |
| 64 | #include <linux/vmalloc.h> |
| 65 | #include <linux/slab.h> |
| 66 | #include <linux/pagemap.h> |
| 67 | #include <linux/errno.h> |
| 68 | #include <linux/videodev.h> |
| 69 | #include <linux/usb.h> |
| 70 | |
| 71 | #include "stv680.h" |
| 72 | |
| 73 | static int video_nr = -1; |
| 74 | static int swapRGB = 0; /* default for auto sleect */ |
| 75 | static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */ |
| 76 | |
| 77 | static unsigned int debug = 0; |
| 78 | |
| 79 | #define PDEBUG(level, fmt, args...) \ |
| 80 | do { \ |
| 81 | if (debug >= level) \ |
| 82 | info("[%s:%d] " fmt, __FUNCTION__, __LINE__ , ## args); \ |
| 83 | } while (0) |
| 84 | |
| 85 | |
| 86 | /* |
| 87 | * Version Information |
| 88 | */ |
| 89 | #define DRIVER_VERSION "v0.25" |
| 90 | #define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>" |
| 91 | #define DRIVER_DESC "STV0680 USB Camera Driver" |
| 92 | |
| 93 | MODULE_AUTHOR (DRIVER_AUTHOR); |
| 94 | MODULE_DESCRIPTION (DRIVER_DESC); |
| 95 | MODULE_LICENSE ("GPL"); |
| 96 | module_param(debug, int, S_IRUGO | S_IWUSR); |
| 97 | MODULE_PARM_DESC (debug, "Debug enabled or not"); |
| 98 | module_param(swapRGB_on, int, 0); |
| 99 | MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never"); |
| 100 | module_param(video_nr, int, 0); |
| 101 | |
| 102 | /******************************************************************** |
| 103 | * |
| 104 | * Memory management |
| 105 | * |
| 106 | * This is a shameless copy from the USB-cpia driver (linux kernel |
| 107 | * version 2.3.29 or so, I have no idea what this code actually does ;). |
| 108 | * Actually it seems to be a copy of a shameless copy of the bttv-driver. |
| 109 | * Or that is a copy of a shameless copy of ... (To the powers: is there |
| 110 | * no generic kernel-function to do this sort of stuff?) |
| 111 | * |
| 112 | * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says |
| 113 | * there will be one, but apparentely not yet -jerdfelt |
| 114 | * |
| 115 | * So I copied it again for the ov511 driver -claudio |
| 116 | * |
| 117 | * Same for the se401 driver -Jeroen |
| 118 | * |
| 119 | * And the STV0680 driver - Kevin |
| 120 | ********************************************************************/ |
| 121 | static void *rvmalloc (unsigned long size) |
| 122 | { |
| 123 | void *mem; |
| 124 | unsigned long adr; |
| 125 | |
| 126 | size = PAGE_ALIGN(size); |
| 127 | mem = vmalloc_32 (size); |
| 128 | if (!mem) |
| 129 | return NULL; |
| 130 | |
| 131 | memset (mem, 0, size); /* Clear the ram out, no junk to the user */ |
| 132 | adr = (unsigned long) mem; |
| 133 | while (size > 0) { |
| 134 | SetPageReserved(vmalloc_to_page((void *)adr)); |
| 135 | adr += PAGE_SIZE; |
| 136 | size -= PAGE_SIZE; |
| 137 | } |
| 138 | return mem; |
| 139 | } |
| 140 | |
| 141 | static void rvfree (void *mem, unsigned long size) |
| 142 | { |
| 143 | unsigned long adr; |
| 144 | |
| 145 | if (!mem) |
| 146 | return; |
| 147 | |
| 148 | adr = (unsigned long) mem; |
| 149 | while ((long) size > 0) { |
| 150 | ClearPageReserved(vmalloc_to_page((void *)adr)); |
| 151 | adr += PAGE_SIZE; |
| 152 | size -= PAGE_SIZE; |
| 153 | } |
| 154 | vfree (mem); |
| 155 | } |
| 156 | |
| 157 | |
| 158 | /********************************************************************* |
| 159 | * pencam read/write functions |
| 160 | ********************************************************************/ |
| 161 | |
| 162 | static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size) |
| 163 | { |
| 164 | int ret = -1; |
| 165 | |
| 166 | switch (set) { |
| 167 | case 0: /* 0xc1 */ |
| 168 | ret = usb_control_msg (stv680->udev, |
| 169 | usb_rcvctrlpipe (stv680->udev, 0), |
| 170 | req, |
| 171 | (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT), |
| 172 | value, 0, buffer, size, PENCAM_TIMEOUT); |
| 173 | break; |
| 174 | |
| 175 | case 1: /* 0x41 */ |
| 176 | ret = usb_control_msg (stv680->udev, |
| 177 | usb_sndctrlpipe (stv680->udev, 0), |
| 178 | req, |
| 179 | (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT), |
| 180 | value, 0, buffer, size, PENCAM_TIMEOUT); |
| 181 | break; |
| 182 | |
| 183 | case 2: /* 0x80 */ |
| 184 | ret = usb_control_msg (stv680->udev, |
| 185 | usb_rcvctrlpipe (stv680->udev, 0), |
| 186 | req, |
| 187 | (USB_DIR_IN | USB_RECIP_DEVICE), |
| 188 | value, 0, buffer, size, PENCAM_TIMEOUT); |
| 189 | break; |
| 190 | |
| 191 | case 3: /* 0x40 */ |
| 192 | ret = usb_control_msg (stv680->udev, |
| 193 | usb_sndctrlpipe (stv680->udev, 0), |
| 194 | req, |
| 195 | (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE), |
| 196 | value, 0, buffer, size, PENCAM_TIMEOUT); |
| 197 | break; |
| 198 | |
| 199 | } |
| 200 | if ((ret < 0) && (req != 0x0a)) { |
| 201 | PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret); |
| 202 | } |
| 203 | return ret; |
| 204 | } |
| 205 | |
| 206 | static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate) |
| 207 | { |
| 208 | |
| 209 | if (configuration != dev->udev->actconfig->desc.bConfigurationValue |
| 210 | || usb_reset_configuration (dev->udev) < 0) { |
| 211 | PDEBUG (1, "STV(e): FAILED to reset configuration %i", configuration); |
| 212 | return -1; |
| 213 | } |
| 214 | if (usb_set_interface (dev->udev, interface, alternate) < 0) { |
| 215 | PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate); |
| 216 | return -1; |
| 217 | } |
| 218 | return 0; |
| 219 | } |
| 220 | |
| 221 | static int stv_stop_video (struct usb_stv *dev) |
| 222 | { |
| 223 | int i; |
| 224 | unsigned char *buf; |
| 225 | |
| 226 | buf = kmalloc (40, GFP_KERNEL); |
| 227 | if (buf == NULL) { |
| 228 | PDEBUG (0, "STV(e): Out of (small buf) memory"); |
| 229 | return -1; |
| 230 | } |
| 231 | |
| 232 | /* this is a high priority command; it stops all lower order commands */ |
| 233 | if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) { |
| 234 | i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02); /* Get Last Error; 2 = busy */ |
| 235 | PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buf[0], buf[1]); |
| 236 | } else { |
| 237 | PDEBUG (1, "STV(i): Camera reset to idle mode."); |
| 238 | } |
| 239 | |
| 240 | if ((i = stv_set_config (dev, 1, 0, 0)) < 0) |
| 241 | PDEBUG (1, "STV(e): Reset config during exit failed"); |
| 242 | |
| 243 | /* get current mode */ |
| 244 | buf[0] = 0xf0; |
| 245 | if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08) /* get mode */ |
| 246 | PDEBUG (0, "STV(e): Stop_video: problem setting original mode"); |
| 247 | if (dev->origMode != buf[0]) { |
| 248 | memset (buf, 0, 8); |
| 249 | buf[0] = (unsigned char) dev->origMode; |
| 250 | if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) { |
| 251 | PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed"); |
| 252 | i = -1; |
| 253 | } |
| 254 | buf[0] = 0xf0; |
| 255 | i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08); |
| 256 | if ((i != 0x08) || (buf[0] != dev->origMode)) { |
| 257 | PDEBUG (0, "STV(e): camera NOT set to original resolution."); |
| 258 | i = -1; |
| 259 | } else |
| 260 | PDEBUG (0, "STV(i): Camera set to original resolution"); |
| 261 | } |
| 262 | /* origMode */ |
Jesper Juhl | f9101210 | 2005-09-10 00:26:54 -0700 | [diff] [blame^] | 263 | kfree(buf); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 264 | return i; |
| 265 | } |
| 266 | |
| 267 | static int stv_set_video_mode (struct usb_stv *dev) |
| 268 | { |
| 269 | int i, stop_video = 1; |
| 270 | unsigned char *buf; |
| 271 | |
| 272 | buf = kmalloc (40, GFP_KERNEL); |
| 273 | if (buf == NULL) { |
| 274 | PDEBUG (0, "STV(e): Out of (small buf) memory"); |
| 275 | return -1; |
| 276 | } |
| 277 | |
| 278 | if ((i = stv_set_config (dev, 1, 0, 0)) < 0) { |
Jesper Juhl | f9101210 | 2005-09-10 00:26:54 -0700 | [diff] [blame^] | 279 | kfree(buf); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 280 | return i; |
| 281 | } |
| 282 | |
| 283 | i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12); |
| 284 | if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) { |
| 285 | PDEBUG (1, "STV(e): Could not get descriptor 0100."); |
| 286 | goto error; |
| 287 | } |
| 288 | |
| 289 | /* set alternate interface 1 */ |
| 290 | if ((i = stv_set_config (dev, 1, 0, 1)) < 0) |
| 291 | goto error; |
| 292 | |
| 293 | if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10) |
| 294 | goto error; |
| 295 | PDEBUG (1, "STV(i): Setting video mode."); |
| 296 | /* Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240) */ |
| 297 | if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) { |
| 298 | stop_video = 0; |
| 299 | goto error; |
| 300 | } |
| 301 | goto exit; |
| 302 | |
| 303 | error: |
Jesper Juhl | f9101210 | 2005-09-10 00:26:54 -0700 | [diff] [blame^] | 304 | kfree(buf); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 305 | if (stop_video == 1) |
| 306 | stv_stop_video (dev); |
| 307 | return -1; |
| 308 | |
| 309 | exit: |
Jesper Juhl | f9101210 | 2005-09-10 00:26:54 -0700 | [diff] [blame^] | 310 | kfree(buf); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 311 | return 0; |
| 312 | } |
| 313 | |
| 314 | static int stv_init (struct usb_stv *stv680) |
| 315 | { |
| 316 | int i = 0; |
| 317 | unsigned char *buffer; |
| 318 | unsigned long int bufsize; |
| 319 | |
| 320 | buffer = kmalloc (40, GFP_KERNEL); |
| 321 | if (buffer == NULL) { |
| 322 | PDEBUG (0, "STV(e): Out of (small buf) memory"); |
| 323 | return -1; |
| 324 | } |
| 325 | memset (buffer, 0, 40); |
| 326 | udelay (100); |
| 327 | |
| 328 | /* set config 1, interface 0, alternate 0 */ |
| 329 | if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) { |
Jesper Juhl | f9101210 | 2005-09-10 00:26:54 -0700 | [diff] [blame^] | 330 | kfree(buffer); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 331 | PDEBUG (0, "STV(e): set config 1,0,0 failed"); |
| 332 | return -1; |
| 333 | } |
| 334 | /* ping camera to be sure STV0680 is present */ |
| 335 | if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02) |
| 336 | goto error; |
| 337 | if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) { |
| 338 | PDEBUG (1, "STV(e): camera ping failed!!"); |
| 339 | goto error; |
| 340 | } |
| 341 | |
| 342 | /* get camera descriptor */ |
| 343 | if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09) |
| 344 | goto error; |
| 345 | i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22); |
| 346 | if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) { |
| 347 | PDEBUG (1, "STV(e): Could not get descriptor 0200."); |
| 348 | goto error; |
| 349 | } |
| 350 | if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02) |
| 351 | goto error; |
| 352 | if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24) |
| 353 | goto error; |
| 354 | if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10) |
| 355 | goto error; |
| 356 | |
| 357 | stv680->SupportedModes = buffer[7]; |
| 358 | i = stv680->SupportedModes; |
| 359 | stv680->CIF = 0; |
| 360 | stv680->VGA = 0; |
| 361 | stv680->QVGA = 0; |
| 362 | if (i & 1) |
| 363 | stv680->CIF = 1; |
| 364 | if (i & 2) |
| 365 | stv680->VGA = 1; |
| 366 | if (i & 8) |
| 367 | stv680->QVGA = 1; |
| 368 | if (stv680->SupportedModes == 0) { |
| 369 | PDEBUG (0, "STV(e): There are NO supported STV680 modes!!"); |
| 370 | i = -1; |
| 371 | goto error; |
| 372 | } else { |
| 373 | if (stv680->CIF) |
| 374 | PDEBUG (0, "STV(i): CIF is supported"); |
| 375 | if (stv680->QVGA) |
| 376 | PDEBUG (0, "STV(i): QVGA is supported"); |
| 377 | } |
| 378 | /* FW rev, ASIC rev, sensor ID */ |
| 379 | PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]); |
| 380 | PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]); |
| 381 | PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4)); |
| 382 | |
| 383 | /* set alternate interface 1 */ |
| 384 | if ((i = stv_set_config (stv680, 1, 0, 1)) < 0) |
| 385 | goto error; |
| 386 | |
| 387 | if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10) |
| 388 | goto error; |
| 389 | if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08) |
| 390 | goto error; |
| 391 | i = buffer[3]; |
| 392 | PDEBUG (0, "STV(i): Camera has %i pictures.", i); |
| 393 | |
| 394 | /* get current mode */ |
| 395 | if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08) |
| 396 | goto error; |
| 397 | stv680->origMode = buffer[0]; /* 01 = VGA, 03 = QVGA, 00 = CIF */ |
| 398 | |
| 399 | /* This will attemp CIF mode, if supported. If not, set to QVGA */ |
| 400 | memset (buffer, 0, 8); |
| 401 | if (stv680->CIF) |
| 402 | buffer[0] = 0x00; |
| 403 | else if (stv680->QVGA) |
| 404 | buffer[0] = 0x03; |
| 405 | if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) { |
| 406 | PDEBUG (0, "STV(i): Set_Camera_Mode failed"); |
| 407 | i = -1; |
| 408 | goto error; |
| 409 | } |
| 410 | buffer[0] = 0xf0; |
| 411 | stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08); |
| 412 | if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) { |
| 413 | PDEBUG (0, "STV(e): Error setting camera video mode!"); |
| 414 | i = -1; |
| 415 | goto error; |
| 416 | } else { |
| 417 | if (buffer[0] == 0) { |
| 418 | stv680->VideoMode = 0x0000; |
| 419 | PDEBUG (0, "STV(i): Video Mode set to CIF"); |
| 420 | } |
| 421 | if (buffer[0] == 0x03) { |
| 422 | stv680->VideoMode = 0x0300; |
| 423 | PDEBUG (0, "STV(i): Video Mode set to QVGA"); |
| 424 | } |
| 425 | } |
| 426 | if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10) |
| 427 | goto error; |
| 428 | bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]); |
| 429 | stv680->cwidth = (buffer[4] << 8) | (buffer[5]); /* ->camera = 322, 356, 644 */ |
| 430 | stv680->cheight = (buffer[6] << 8) | (buffer[7]); /* ->camera = 242, 292, 484 */ |
| 431 | stv680->origGain = buffer[12]; |
| 432 | |
| 433 | goto exit; |
| 434 | |
| 435 | error: |
| 436 | i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02); /* Get Last Error */ |
| 437 | PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buffer[0], buffer[1]); |
Jesper Juhl | f9101210 | 2005-09-10 00:26:54 -0700 | [diff] [blame^] | 438 | kfree(buffer); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 439 | return -1; |
| 440 | |
| 441 | exit: |
Jesper Juhl | f9101210 | 2005-09-10 00:26:54 -0700 | [diff] [blame^] | 442 | kfree(buffer); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 443 | |
| 444 | /* video = 320x240, 352x288 */ |
| 445 | if (stv680->CIF == 1) { |
| 446 | stv680->maxwidth = 352; |
| 447 | stv680->maxheight = 288; |
| 448 | stv680->vwidth = 352; |
| 449 | stv680->vheight = 288; |
| 450 | } |
| 451 | if (stv680->QVGA == 1) { |
| 452 | stv680->maxwidth = 320; |
| 453 | stv680->maxheight = 240; |
| 454 | stv680->vwidth = 320; |
| 455 | stv680->vheight = 240; |
| 456 | } |
| 457 | |
| 458 | stv680->rawbufsize = bufsize; /* must be ./. by 8 */ |
| 459 | stv680->maxframesize = bufsize * 3; /* RGB size */ |
| 460 | PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight); |
| 461 | PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize); |
| 462 | |
| 463 | /* some default values */ |
| 464 | stv680->bulk_in_endpointAddr = 0x82; |
| 465 | stv680->dropped = 0; |
| 466 | stv680->error = 0; |
| 467 | stv680->framecount = 0; |
| 468 | stv680->readcount = 0; |
| 469 | stv680->streaming = 0; |
| 470 | /* bright, white, colour, hue, contrast are set by software, not in stv0680 */ |
| 471 | stv680->brightness = 32767; |
| 472 | stv680->chgbright = 0; |
| 473 | stv680->whiteness = 0; /* only for greyscale */ |
| 474 | stv680->colour = 32767; |
| 475 | stv680->contrast = 32767; |
| 476 | stv680->hue = 32767; |
| 477 | stv680->palette = STV_VIDEO_PALETTE; |
| 478 | stv680->depth = 24; /* rgb24 bits */ |
| 479 | if ((swapRGB_on == 0) && (swapRGB == 0)) |
| 480 | PDEBUG (1, "STV(i): swapRGB is (auto) OFF"); |
| 481 | else if ((swapRGB_on == 0) && (swapRGB == 1)) |
| 482 | PDEBUG (1, "STV(i): swapRGB is (auto) ON"); |
| 483 | else if (swapRGB_on == 1) |
| 484 | PDEBUG (1, "STV(i): swapRGB is (forced) ON"); |
| 485 | else if (swapRGB_on == -1) |
| 486 | PDEBUG (1, "STV(i): swapRGB is (forced) OFF"); |
| 487 | |
| 488 | if (stv_set_video_mode (stv680) < 0) { |
| 489 | PDEBUG (0, "STV(e): Could not set video mode in stv_init"); |
| 490 | return -1; |
| 491 | } |
| 492 | |
| 493 | return 0; |
| 494 | } |
| 495 | |
| 496 | /***************** last of pencam routines *******************/ |
| 497 | |
| 498 | /**************************************************************************** |
| 499 | * sysfs |
| 500 | ***************************************************************************/ |
| 501 | #define stv680_file(name, variable, field) \ |
| 502 | static ssize_t show_##name(struct class_device *class_dev, char *buf) \ |
| 503 | { \ |
| 504 | struct video_device *vdev = to_video_device(class_dev); \ |
| 505 | struct usb_stv *stv = video_get_drvdata(vdev); \ |
| 506 | return sprintf(buf, field, stv->variable); \ |
| 507 | } \ |
| 508 | static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); |
| 509 | |
| 510 | stv680_file(model, camera_name, "%s\n"); |
| 511 | stv680_file(in_use, user, "%d\n"); |
| 512 | stv680_file(streaming, streaming, "%d\n"); |
| 513 | stv680_file(palette, palette, "%i\n"); |
| 514 | stv680_file(frames_total, readcount, "%d\n"); |
| 515 | stv680_file(frames_read, framecount, "%d\n"); |
| 516 | stv680_file(packets_dropped, dropped, "%d\n"); |
| 517 | stv680_file(decoding_errors, error, "%d\n"); |
| 518 | |
| 519 | static void stv680_create_sysfs_files(struct video_device *vdev) |
| 520 | { |
| 521 | video_device_create_file(vdev, &class_device_attr_model); |
| 522 | video_device_create_file(vdev, &class_device_attr_in_use); |
| 523 | video_device_create_file(vdev, &class_device_attr_streaming); |
| 524 | video_device_create_file(vdev, &class_device_attr_palette); |
| 525 | video_device_create_file(vdev, &class_device_attr_frames_total); |
| 526 | video_device_create_file(vdev, &class_device_attr_frames_read); |
| 527 | video_device_create_file(vdev, &class_device_attr_packets_dropped); |
| 528 | video_device_create_file(vdev, &class_device_attr_decoding_errors); |
| 529 | } |
| 530 | |
| 531 | static void stv680_remove_sysfs_files(struct video_device *vdev) |
| 532 | { |
| 533 | video_device_remove_file(vdev, &class_device_attr_model); |
| 534 | video_device_remove_file(vdev, &class_device_attr_in_use); |
| 535 | video_device_remove_file(vdev, &class_device_attr_streaming); |
| 536 | video_device_remove_file(vdev, &class_device_attr_palette); |
| 537 | video_device_remove_file(vdev, &class_device_attr_frames_total); |
| 538 | video_device_remove_file(vdev, &class_device_attr_frames_read); |
| 539 | video_device_remove_file(vdev, &class_device_attr_packets_dropped); |
| 540 | video_device_remove_file(vdev, &class_device_attr_decoding_errors); |
| 541 | } |
| 542 | |
| 543 | /******************************************************************** |
| 544 | * Camera control |
| 545 | *******************************************************************/ |
| 546 | |
| 547 | static int stv680_get_pict (struct usb_stv *stv680, struct video_picture *p) |
| 548 | { |
| 549 | /* This sets values for v4l interface. max/min = 65535/0 */ |
| 550 | |
| 551 | p->brightness = stv680->brightness; |
| 552 | p->whiteness = stv680->whiteness; /* greyscale */ |
| 553 | p->colour = stv680->colour; |
| 554 | p->contrast = stv680->contrast; |
| 555 | p->hue = stv680->hue; |
| 556 | p->palette = stv680->palette; |
| 557 | p->depth = stv680->depth; |
| 558 | return 0; |
| 559 | } |
| 560 | |
| 561 | static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p) |
| 562 | { |
| 563 | /* See above stv680_get_pict */ |
| 564 | |
| 565 | if (p->palette != STV_VIDEO_PALETTE) { |
| 566 | PDEBUG (2, "STV(e): Palette set error in _set_pic"); |
| 567 | return 1; |
| 568 | } |
| 569 | |
| 570 | if (stv680->brightness != p->brightness) { |
| 571 | stv680->chgbright = 1; |
| 572 | stv680->brightness = p->brightness; |
| 573 | } |
| 574 | |
| 575 | stv680->whiteness = p->whiteness; /* greyscale */ |
| 576 | stv680->colour = p->colour; |
| 577 | stv680->contrast = p->contrast; |
| 578 | stv680->hue = p->hue; |
| 579 | stv680->palette = p->palette; |
| 580 | stv680->depth = p->depth; |
| 581 | |
| 582 | return 0; |
| 583 | } |
| 584 | |
| 585 | static void stv680_video_irq (struct urb *urb, struct pt_regs *regs) |
| 586 | { |
| 587 | struct usb_stv *stv680 = urb->context; |
| 588 | int length = urb->actual_length; |
| 589 | |
| 590 | if (length < stv680->rawbufsize) |
| 591 | PDEBUG (2, "STV(i): Lost data in transfer: exp %li, got %i", stv680->rawbufsize, length); |
| 592 | |
| 593 | /* ohoh... */ |
| 594 | if (!stv680->streaming) |
| 595 | return; |
| 596 | |
| 597 | if (!stv680->udev) { |
| 598 | PDEBUG (0, "STV(e): device vapourished in video_irq"); |
| 599 | return; |
| 600 | } |
| 601 | |
| 602 | /* 0 sized packets happen if we are to fast, but sometimes the camera |
| 603 | keeps sending them forever... |
| 604 | */ |
| 605 | if (length && !urb->status) { |
| 606 | stv680->nullpackets = 0; |
| 607 | switch (stv680->scratch[stv680->scratch_next].state) { |
| 608 | case BUFFER_READY: |
| 609 | case BUFFER_BUSY: |
| 610 | stv680->dropped++; |
| 611 | break; |
| 612 | |
| 613 | case BUFFER_UNUSED: |
| 614 | memcpy (stv680->scratch[stv680->scratch_next].data, |
| 615 | (unsigned char *) urb->transfer_buffer, length); |
| 616 | stv680->scratch[stv680->scratch_next].state = BUFFER_READY; |
| 617 | stv680->scratch[stv680->scratch_next].length = length; |
| 618 | if (waitqueue_active (&stv680->wq)) { |
| 619 | wake_up_interruptible (&stv680->wq); |
| 620 | } |
| 621 | stv680->scratch_overflow = 0; |
| 622 | stv680->scratch_next++; |
| 623 | if (stv680->scratch_next >= STV680_NUMSCRATCH) |
| 624 | stv680->scratch_next = 0; |
| 625 | break; |
| 626 | } /* switch */ |
| 627 | } else { |
| 628 | stv680->nullpackets++; |
| 629 | if (stv680->nullpackets > STV680_MAX_NULLPACKETS) { |
| 630 | if (waitqueue_active (&stv680->wq)) { |
| 631 | wake_up_interruptible (&stv680->wq); |
| 632 | } |
| 633 | } |
| 634 | } /* if - else */ |
| 635 | |
| 636 | /* Resubmit urb for new data */ |
| 637 | urb->status = 0; |
| 638 | urb->dev = stv680->udev; |
| 639 | if (usb_submit_urb (urb, GFP_ATOMIC)) |
| 640 | PDEBUG (0, "STV(e): urb burned down in video irq"); |
| 641 | return; |
| 642 | } /* _video_irq */ |
| 643 | |
| 644 | static int stv680_start_stream (struct usb_stv *stv680) |
| 645 | { |
| 646 | struct urb *urb; |
| 647 | int err = 0, i; |
| 648 | |
| 649 | stv680->streaming = 1; |
| 650 | |
| 651 | /* Do some memory allocation */ |
| 652 | for (i = 0; i < STV680_NUMFRAMES; i++) { |
| 653 | stv680->frame[i].data = stv680->fbuf + i * stv680->maxframesize; |
| 654 | stv680->frame[i].curpix = 0; |
| 655 | } |
| 656 | /* packet size = 4096 */ |
| 657 | for (i = 0; i < STV680_NUMSBUF; i++) { |
| 658 | stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL); |
| 659 | if (stv680->sbuf[i].data == NULL) { |
| 660 | PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i); |
| 661 | return -1; |
| 662 | } |
| 663 | } |
| 664 | |
| 665 | stv680->scratch_next = 0; |
| 666 | stv680->scratch_use = 0; |
| 667 | stv680->scratch_overflow = 0; |
| 668 | for (i = 0; i < STV680_NUMSCRATCH; i++) { |
| 669 | stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL); |
| 670 | if (stv680->scratch[i].data == NULL) { |
| 671 | PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i); |
| 672 | return -1; |
| 673 | } |
| 674 | stv680->scratch[i].state = BUFFER_UNUSED; |
| 675 | } |
| 676 | |
| 677 | for (i = 0; i < STV680_NUMSBUF; i++) { |
| 678 | urb = usb_alloc_urb (0, GFP_KERNEL); |
| 679 | if (!urb) |
| 680 | return -ENOMEM; |
| 681 | |
| 682 | /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */ |
| 683 | usb_fill_bulk_urb (urb, stv680->udev, |
| 684 | usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr), |
| 685 | stv680->sbuf[i].data, stv680->rawbufsize, |
| 686 | stv680_video_irq, stv680); |
| 687 | stv680->urb[i] = urb; |
| 688 | err = usb_submit_urb (stv680->urb[i], GFP_KERNEL); |
| 689 | if (err) |
| 690 | PDEBUG (0, "STV(e): urb burned down in start stream"); |
| 691 | } /* i STV680_NUMSBUF */ |
| 692 | |
| 693 | stv680->framecount = 0; |
| 694 | return 0; |
| 695 | } |
| 696 | |
| 697 | static int stv680_stop_stream (struct usb_stv *stv680) |
| 698 | { |
| 699 | int i; |
| 700 | |
| 701 | if (!stv680->streaming || !stv680->udev) |
| 702 | return 1; |
| 703 | |
| 704 | stv680->streaming = 0; |
| 705 | |
| 706 | for (i = 0; i < STV680_NUMSBUF; i++) |
| 707 | if (stv680->urb[i]) { |
| 708 | usb_kill_urb (stv680->urb[i]); |
| 709 | usb_free_urb (stv680->urb[i]); |
| 710 | stv680->urb[i] = NULL; |
Jesper Juhl | f9101210 | 2005-09-10 00:26:54 -0700 | [diff] [blame^] | 711 | kfree(stv680->sbuf[i].data); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 712 | } |
| 713 | for (i = 0; i < STV680_NUMSCRATCH; i++) { |
Jesper Juhl | f9101210 | 2005-09-10 00:26:54 -0700 | [diff] [blame^] | 714 | kfree(stv680->scratch[i].data); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 715 | stv680->scratch[i].data = NULL; |
| 716 | } |
| 717 | |
| 718 | return 0; |
| 719 | } |
| 720 | |
| 721 | static int stv680_set_size (struct usb_stv *stv680, int width, int height) |
| 722 | { |
| 723 | int wasstreaming = stv680->streaming; |
| 724 | |
| 725 | /* Check to see if we need to change */ |
| 726 | if ((stv680->vwidth == width) && (stv680->vheight == height)) |
| 727 | return 0; |
| 728 | |
| 729 | PDEBUG (1, "STV(i): size request for %i x %i", width, height); |
| 730 | /* Check for a valid mode */ |
| 731 | if ((!width || !height) || ((width & 1) || (height & 1))) { |
| 732 | PDEBUG (1, "STV(e): set_size error: request: v.width = %i, v.height = %i actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight); |
| 733 | return 1; |
| 734 | } |
| 735 | |
| 736 | if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) { |
| 737 | width = stv680->maxwidth / 2; |
| 738 | height = stv680->maxheight / 2; |
| 739 | } else if ((width >= 158) && (width <= 166) && (stv680->QVGA == 1)) { |
| 740 | width = 160; |
| 741 | height = 120; |
| 742 | } else if ((width >= 172) && (width <= 180) && (stv680->CIF == 1)) { |
| 743 | width = 176; |
| 744 | height = 144; |
| 745 | } else if ((width >= 318) && (width <= 350) && (stv680->QVGA == 1)) { |
| 746 | width = 320; |
| 747 | height = 240; |
| 748 | } else if ((width >= 350) && (width <= 358) && (stv680->CIF == 1)) { |
| 749 | width = 352; |
| 750 | height = 288; |
| 751 | } else { |
| 752 | PDEBUG (1, "STV(e): request for non-supported size: request: v.width = %i, v.height = %i actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight); |
| 753 | return 1; |
| 754 | } |
| 755 | |
| 756 | /* Stop a current stream and start it again at the new size */ |
| 757 | if (wasstreaming) |
| 758 | stv680_stop_stream (stv680); |
| 759 | stv680->vwidth = width; |
| 760 | stv680->vheight = height; |
| 761 | PDEBUG (1, "STV(i): size set to %i x %i", stv680->vwidth, stv680->vheight); |
| 762 | if (wasstreaming) |
| 763 | stv680_start_stream (stv680); |
| 764 | |
| 765 | return 0; |
| 766 | } |
| 767 | |
| 768 | /********************************************************************** |
| 769 | * Video Decoding |
| 770 | **********************************************************************/ |
| 771 | |
| 772 | /******* routines from the pencam program; hey, they work! ********/ |
| 773 | |
| 774 | /* |
| 775 | * STV0680 Vision Camera Chipset Driver |
| 776 | * Copyright (C) 2000 Adam Harrison <adam@antispin.org> |
| 777 | */ |
| 778 | |
| 779 | #define RED 0 |
| 780 | #define GREEN 1 |
| 781 | #define BLUE 2 |
| 782 | #define AD(x, y, w) (((y)*(w)+(x))*3) |
| 783 | |
| 784 | static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buffer) |
| 785 | { |
| 786 | int x, y, i; |
| 787 | int w = stv680->cwidth; |
| 788 | int vw = stv680->cwidth, vh = stv680->cheight; |
| 789 | unsigned int p = 0; |
| 790 | int colour = 0, bayer = 0; |
| 791 | unsigned char *raw = buffer->data; |
| 792 | struct stv680_frame *frame = &stv680->frame[stv680->curframe]; |
| 793 | unsigned char *output = frame->data; |
| 794 | unsigned char *temp = frame->data; |
| 795 | int offset = buffer->offset; |
| 796 | |
| 797 | if (frame->curpix == 0) { |
| 798 | if (frame->grabstate == FRAME_READY) { |
| 799 | frame->grabstate = FRAME_GRABBING; |
| 800 | } |
| 801 | } |
| 802 | if (offset != frame->curpix) { /* Regard frame as lost :( */ |
| 803 | frame->curpix = 0; |
| 804 | stv680->error++; |
| 805 | return; |
| 806 | } |
| 807 | |
| 808 | if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) { |
| 809 | vw = 320; |
| 810 | vh = 240; |
| 811 | } |
| 812 | if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) { |
| 813 | vw = 352; |
| 814 | vh = 288; |
| 815 | } |
| 816 | |
| 817 | memset (output, 0, 3 * vw * vh); /* clear output matrix. */ |
| 818 | |
| 819 | for (y = 0; y < vh; y++) { |
| 820 | for (x = 0; x < vw; x++) { |
| 821 | if (x & 1) |
| 822 | p = *(raw + y * w + (x >> 1)); |
| 823 | else |
| 824 | p = *(raw + y * w + (x >> 1) + (w >> 1)); |
| 825 | |
| 826 | if (y & 1) |
| 827 | bayer = 2; |
| 828 | else |
| 829 | bayer = 0; |
| 830 | if (x & 1) |
| 831 | bayer++; |
| 832 | |
| 833 | switch (bayer) { |
| 834 | case 0: |
| 835 | case 3: |
| 836 | colour = 1; |
| 837 | break; |
| 838 | case 1: |
| 839 | colour = 0; |
| 840 | break; |
| 841 | case 2: |
| 842 | colour = 2; |
| 843 | break; |
| 844 | } |
| 845 | i = (y * vw + x) * 3; |
| 846 | *(output + i + colour) = (unsigned char) p; |
| 847 | } /* for x */ |
| 848 | |
| 849 | } /* for y */ |
| 850 | |
| 851 | /****** gamma correction plus hardcoded white balance */ |
| 852 | /* Thanks to Alexander Schwartx <alexander.schwartx@gmx.net> for this code. |
| 853 | Correction values red[], green[], blue[], are generated by |
| 854 | (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. |
| 855 | White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and |
| 856 | converted to unsigned char. Values are in stv680.h */ |
| 857 | |
| 858 | for (y = 0; y < vh; y++) { |
| 859 | for (x = 0; x < vw; x++) { |
| 860 | i = (y * vw + x) * 3; |
| 861 | *(output + i) = red[*(output + i)]; |
| 862 | *(output + i + 1) = green[*(output + i + 1)]; |
| 863 | *(output + i + 2) = blue[*(output + i + 2)]; |
| 864 | } |
| 865 | } |
| 866 | |
| 867 | /****** bayer demosaic ******/ |
| 868 | for (y = 1; y < (vh - 1); y++) { |
| 869 | for (x = 1; x < (vw - 1); x++) { /* work out pixel type */ |
| 870 | if (y & 1) |
| 871 | bayer = 0; |
| 872 | else |
| 873 | bayer = 2; |
| 874 | if (!(x & 1)) |
| 875 | bayer++; |
| 876 | |
| 877 | switch (bayer) { |
| 878 | case 0: /* green. blue lr, red tb */ |
| 879 | *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y, vw) + BLUE) + (int) *(output + AD (x + 1, y, vw) + BLUE)) >> 1; |
| 880 | *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1; |
| 881 | break; |
| 882 | |
| 883 | case 1: /* blue. green lrtb, red diagonals */ |
| 884 | *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2; |
| 885 | *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2; |
| 886 | break; |
| 887 | |
| 888 | case 2: /* red. green lrtb, blue diagonals */ |
| 889 | *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2; |
| 890 | *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2; |
| 891 | break; |
| 892 | |
| 893 | case 3: /* green. red lr, blue tb */ |
| 894 | *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1; |
| 895 | *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1; |
| 896 | break; |
| 897 | } /* switch */ |
| 898 | } /* for x */ |
| 899 | } /* for y - end demosaic */ |
| 900 | |
| 901 | /* fix top and bottom row, left and right side */ |
| 902 | i = vw * 3; |
| 903 | memcpy (output, (output + i), i); |
| 904 | memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i); |
| 905 | for (y = 0; y < vh; y++) { |
| 906 | i = y * vw * 3; |
| 907 | memcpy ((output + i), (output + i + 3), 3); |
| 908 | memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3); |
| 909 | } |
| 910 | |
| 911 | /* process all raw data, then trim to size if necessary */ |
| 912 | if ((stv680->vwidth == 160) || (stv680->vwidth == 176)) { |
| 913 | i = 0; |
| 914 | for (y = 0; y < vh; y++) { |
| 915 | if (!(y & 1)) { |
| 916 | for (x = 0; x < vw; x++) { |
| 917 | p = (y * vw + x) * 3; |
| 918 | if (!(x & 1)) { |
| 919 | *(output + i) = *(output + p); |
| 920 | *(output + i + 1) = *(output + p + 1); |
| 921 | *(output + i + 2) = *(output + p + 2); |
| 922 | i += 3; |
| 923 | } |
| 924 | } /* for x */ |
| 925 | } |
| 926 | } /* for y */ |
| 927 | } |
| 928 | /* reset to proper width */ |
| 929 | if ((stv680->vwidth == 160)) { |
| 930 | vw = 160; |
| 931 | vh = 120; |
| 932 | } |
| 933 | if ((stv680->vwidth == 176)) { |
| 934 | vw = 176; |
| 935 | vh = 144; |
| 936 | } |
| 937 | |
| 938 | /* output is RGB; some programs want BGR */ |
| 939 | /* swapRGB_on=0 -> program decides; swapRGB_on=1, always swap */ |
| 940 | /* swapRGB_on=-1, never swap */ |
| 941 | if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) { |
| 942 | for (y = 0; y < vh; y++) { |
| 943 | for (x = 0; x < vw; x++) { |
| 944 | i = (y * vw + x) * 3; |
| 945 | *(temp) = *(output + i); |
| 946 | *(output + i) = *(output + i + 2); |
| 947 | *(output + i + 2) = *(temp); |
| 948 | } |
| 949 | } |
| 950 | } |
| 951 | /* brightness */ |
| 952 | if (stv680->chgbright == 1) { |
| 953 | if (stv680->brightness >= 32767) { |
| 954 | p = (stv680->brightness - 32767) / 256; |
| 955 | for (x = 0; x < (vw * vh * 3); x++) { |
| 956 | if ((*(output + x) + (unsigned char) p) > 255) |
| 957 | *(output + x) = 255; |
| 958 | else |
| 959 | *(output + x) += (unsigned char) p; |
| 960 | } /* for */ |
| 961 | } else { |
| 962 | p = (32767 - stv680->brightness) / 256; |
| 963 | for (x = 0; x < (vw * vh * 3); x++) { |
| 964 | if ((unsigned char) p > *(output + x)) |
| 965 | *(output + x) = 0; |
| 966 | else |
| 967 | *(output + x) -= (unsigned char) p; |
| 968 | } /* for */ |
| 969 | } /* else */ |
| 970 | } |
| 971 | /* if */ |
| 972 | frame->curpix = 0; |
| 973 | frame->curlinepix = 0; |
| 974 | frame->grabstate = FRAME_DONE; |
| 975 | stv680->framecount++; |
| 976 | stv680->readcount++; |
| 977 | if (stv680->frame[(stv680->curframe + 1) & (STV680_NUMFRAMES - 1)].grabstate == FRAME_READY) { |
| 978 | stv680->curframe = (stv680->curframe + 1) & (STV680_NUMFRAMES - 1); |
| 979 | } |
| 980 | |
| 981 | } /* bayer_unshuffle */ |
| 982 | |
| 983 | /******* end routines from the pencam program *********/ |
| 984 | |
| 985 | static int stv680_newframe (struct usb_stv *stv680, int framenr) |
| 986 | { |
| 987 | int errors = 0; |
| 988 | |
| 989 | while (stv680->streaming && (stv680->frame[framenr].grabstate == FRAME_READY || stv680->frame[framenr].grabstate == FRAME_GRABBING)) { |
| 990 | if (!stv680->frame[framenr].curpix) { |
| 991 | errors++; |
| 992 | } |
| 993 | wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY)); |
| 994 | |
| 995 | if (stv680->nullpackets > STV680_MAX_NULLPACKETS) { |
| 996 | stv680->nullpackets = 0; |
| 997 | PDEBUG (2, "STV(i): too many null length packets, restarting capture"); |
| 998 | stv680_stop_stream (stv680); |
| 999 | stv680_start_stream (stv680); |
| 1000 | } else { |
| 1001 | if (stv680->scratch[stv680->scratch_use].state != BUFFER_READY) { |
| 1002 | stv680->frame[framenr].grabstate = FRAME_ERROR; |
| 1003 | PDEBUG (2, "STV(e): FRAME_ERROR in _newframe"); |
| 1004 | return -EIO; |
| 1005 | } |
| 1006 | stv680->scratch[stv680->scratch_use].state = BUFFER_BUSY; |
| 1007 | |
| 1008 | bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]); |
| 1009 | |
| 1010 | stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED; |
| 1011 | stv680->scratch_use++; |
| 1012 | if (stv680->scratch_use >= STV680_NUMSCRATCH) |
| 1013 | stv680->scratch_use = 0; |
| 1014 | if (errors > STV680_MAX_ERRORS) { |
| 1015 | errors = 0; |
| 1016 | PDEBUG (2, "STV(i): too many errors, restarting capture"); |
| 1017 | stv680_stop_stream (stv680); |
| 1018 | stv680_start_stream (stv680); |
| 1019 | } |
| 1020 | } /* else */ |
| 1021 | } /* while */ |
| 1022 | return 0; |
| 1023 | } |
| 1024 | |
| 1025 | /********************************************************************* |
| 1026 | * Video4Linux |
| 1027 | *********************************************************************/ |
| 1028 | |
| 1029 | static int stv_open (struct inode *inode, struct file *file) |
| 1030 | { |
| 1031 | struct video_device *dev = video_devdata(file); |
| 1032 | struct usb_stv *stv680 = video_get_drvdata(dev); |
| 1033 | int err = 0; |
| 1034 | |
| 1035 | /* we are called with the BKL held */ |
| 1036 | stv680->user = 1; |
| 1037 | err = stv_init (stv680); /* main initialization routine for camera */ |
| 1038 | |
| 1039 | if (err >= 0) { |
| 1040 | stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES); |
| 1041 | if (!stv680->fbuf) { |
| 1042 | PDEBUG (0, "STV(e): Could not rvmalloc frame bufer"); |
| 1043 | err = -ENOMEM; |
| 1044 | } |
| 1045 | file->private_data = dev; |
| 1046 | } |
| 1047 | if (err) |
| 1048 | stv680->user = 0; |
| 1049 | |
| 1050 | return err; |
| 1051 | } |
| 1052 | |
| 1053 | static int stv_close (struct inode *inode, struct file *file) |
| 1054 | { |
| 1055 | struct video_device *dev = file->private_data; |
| 1056 | struct usb_stv *stv680 = video_get_drvdata(dev); |
| 1057 | int i; |
| 1058 | |
| 1059 | for (i = 0; i < STV680_NUMFRAMES; i++) |
| 1060 | stv680->frame[i].grabstate = FRAME_UNUSED; |
| 1061 | if (stv680->streaming) |
| 1062 | stv680_stop_stream (stv680); |
| 1063 | |
| 1064 | if ((i = stv_stop_video (stv680)) < 0) |
| 1065 | PDEBUG (1, "STV(e): stop_video failed in stv_close"); |
| 1066 | |
| 1067 | rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES); |
| 1068 | stv680->user = 0; |
| 1069 | |
| 1070 | if (stv680->removed) { |
Jesper Juhl | f9101210 | 2005-09-10 00:26:54 -0700 | [diff] [blame^] | 1071 | kfree(stv680); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1072 | stv680 = NULL; |
| 1073 | PDEBUG (0, "STV(i): device unregistered"); |
| 1074 | } |
| 1075 | file->private_data = NULL; |
| 1076 | return 0; |
| 1077 | } |
| 1078 | |
| 1079 | static int stv680_do_ioctl (struct inode *inode, struct file *file, |
| 1080 | unsigned int cmd, void *arg) |
| 1081 | { |
| 1082 | struct video_device *vdev = file->private_data; |
| 1083 | struct usb_stv *stv680 = video_get_drvdata(vdev); |
| 1084 | |
| 1085 | if (!stv680->udev) |
| 1086 | return -EIO; |
| 1087 | |
| 1088 | switch (cmd) { |
| 1089 | case VIDIOCGCAP:{ |
| 1090 | struct video_capability *b = arg; |
| 1091 | |
| 1092 | strcpy (b->name, stv680->camera_name); |
| 1093 | b->type = VID_TYPE_CAPTURE; |
| 1094 | b->channels = 1; |
| 1095 | b->audios = 0; |
| 1096 | b->maxwidth = stv680->maxwidth; |
| 1097 | b->maxheight = stv680->maxheight; |
| 1098 | b->minwidth = stv680->maxwidth / 2; |
| 1099 | b->minheight = stv680->maxheight / 2; |
| 1100 | return 0; |
| 1101 | } |
| 1102 | case VIDIOCGCHAN:{ |
| 1103 | struct video_channel *v = arg; |
| 1104 | |
| 1105 | if (v->channel != 0) |
| 1106 | return -EINVAL; |
| 1107 | v->flags = 0; |
| 1108 | v->tuners = 0; |
| 1109 | v->type = VIDEO_TYPE_CAMERA; |
| 1110 | strcpy (v->name, "STV Camera"); |
| 1111 | return 0; |
| 1112 | } |
| 1113 | case VIDIOCSCHAN:{ |
| 1114 | struct video_channel *v = arg; |
| 1115 | if (v->channel != 0) |
| 1116 | return -EINVAL; |
| 1117 | return 0; |
| 1118 | } |
| 1119 | case VIDIOCGPICT:{ |
| 1120 | struct video_picture *p = arg; |
| 1121 | |
| 1122 | stv680_get_pict (stv680, p); |
| 1123 | return 0; |
| 1124 | } |
| 1125 | case VIDIOCSPICT:{ |
| 1126 | struct video_picture *p = arg; |
| 1127 | |
| 1128 | if (stv680_set_pict (stv680, p)) |
| 1129 | return -EINVAL; |
| 1130 | return 0; |
| 1131 | } |
| 1132 | case VIDIOCSWIN:{ |
| 1133 | struct video_window *vw = arg; |
| 1134 | |
| 1135 | if (vw->flags) |
| 1136 | return -EINVAL; |
| 1137 | if (vw->clipcount) |
| 1138 | return -EINVAL; |
| 1139 | if (vw->width != stv680->vwidth) { |
| 1140 | if (stv680_set_size (stv680, vw->width, vw->height)) { |
| 1141 | PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN"); |
| 1142 | return -EINVAL; |
| 1143 | } |
| 1144 | } |
| 1145 | return 0; |
| 1146 | } |
| 1147 | case VIDIOCGWIN:{ |
| 1148 | struct video_window *vw = arg; |
| 1149 | |
| 1150 | vw->x = 0; /* FIXME */ |
| 1151 | vw->y = 0; |
| 1152 | vw->chromakey = 0; |
| 1153 | vw->flags = 0; |
| 1154 | vw->clipcount = 0; |
| 1155 | vw->width = stv680->vwidth; |
| 1156 | vw->height = stv680->vheight; |
| 1157 | return 0; |
| 1158 | } |
| 1159 | case VIDIOCGMBUF:{ |
| 1160 | struct video_mbuf *vm = arg; |
| 1161 | int i; |
| 1162 | |
| 1163 | memset (vm, 0, sizeof (*vm)); |
| 1164 | vm->size = STV680_NUMFRAMES * stv680->maxframesize; |
| 1165 | vm->frames = STV680_NUMFRAMES; |
| 1166 | for (i = 0; i < STV680_NUMFRAMES; i++) |
| 1167 | vm->offsets[i] = stv680->maxframesize * i; |
| 1168 | return 0; |
| 1169 | } |
| 1170 | case VIDIOCMCAPTURE:{ |
| 1171 | struct video_mmap *vm = arg; |
| 1172 | |
| 1173 | if (vm->format != STV_VIDEO_PALETTE) { |
| 1174 | PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)", |
| 1175 | vm->format, STV_VIDEO_PALETTE); |
| 1176 | if ((vm->format == 3) && (swapRGB_on == 0)) { |
| 1177 | PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON"); |
| 1178 | /* this may fix those apps (e.g., xawtv) that want BGR */ |
| 1179 | swapRGB = 1; |
| 1180 | } |
| 1181 | return -EINVAL; |
| 1182 | } |
| 1183 | if (vm->frame >= STV680_NUMFRAMES) { |
| 1184 | PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES"); |
| 1185 | return -EINVAL; |
| 1186 | } |
| 1187 | if ((stv680->frame[vm->frame].grabstate == FRAME_ERROR) |
| 1188 | || (stv680->frame[vm->frame].grabstate == FRAME_GRABBING)) { |
| 1189 | PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error", |
| 1190 | stv680->frame[vm->frame].grabstate); |
| 1191 | return -EBUSY; |
| 1192 | } |
| 1193 | /* Is this according to the v4l spec??? */ |
| 1194 | if (stv680->vwidth != vm->width) { |
| 1195 | if (stv680_set_size (stv680, vm->width, vm->height)) { |
| 1196 | PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed"); |
| 1197 | return -EINVAL; |
| 1198 | } |
| 1199 | } |
| 1200 | stv680->frame[vm->frame].grabstate = FRAME_READY; |
| 1201 | |
| 1202 | if (!stv680->streaming) |
| 1203 | stv680_start_stream (stv680); |
| 1204 | |
| 1205 | return 0; |
| 1206 | } |
| 1207 | case VIDIOCSYNC:{ |
| 1208 | int *frame = arg; |
| 1209 | int ret = 0; |
| 1210 | |
| 1211 | if (*frame < 0 || *frame >= STV680_NUMFRAMES) { |
| 1212 | PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC"); |
| 1213 | return -EINVAL; |
| 1214 | } |
| 1215 | ret = stv680_newframe (stv680, *frame); |
| 1216 | stv680->frame[*frame].grabstate = FRAME_UNUSED; |
| 1217 | return ret; |
| 1218 | } |
| 1219 | case VIDIOCGFBUF:{ |
| 1220 | struct video_buffer *vb = arg; |
| 1221 | |
| 1222 | memset (vb, 0, sizeof (*vb)); |
| 1223 | return 0; |
| 1224 | } |
| 1225 | case VIDIOCKEY: |
| 1226 | return 0; |
| 1227 | case VIDIOCCAPTURE: |
| 1228 | { |
| 1229 | PDEBUG (2, "STV(e): VIDIOCCAPTURE failed"); |
| 1230 | return -EINVAL; |
| 1231 | } |
| 1232 | case VIDIOCSFBUF: |
| 1233 | case VIDIOCGTUNER: |
| 1234 | case VIDIOCSTUNER: |
| 1235 | case VIDIOCGFREQ: |
| 1236 | case VIDIOCSFREQ: |
| 1237 | case VIDIOCGAUDIO: |
| 1238 | case VIDIOCSAUDIO: |
| 1239 | return -EINVAL; |
| 1240 | default: |
| 1241 | return -ENOIOCTLCMD; |
| 1242 | } /* end switch */ |
| 1243 | |
| 1244 | return 0; |
| 1245 | } |
| 1246 | |
| 1247 | static int stv680_ioctl(struct inode *inode, struct file *file, |
| 1248 | unsigned int cmd, unsigned long arg) |
| 1249 | { |
| 1250 | return video_usercopy(inode, file, cmd, arg, stv680_do_ioctl); |
| 1251 | } |
| 1252 | |
| 1253 | static int stv680_mmap (struct file *file, struct vm_area_struct *vma) |
| 1254 | { |
| 1255 | struct video_device *dev = file->private_data; |
| 1256 | struct usb_stv *stv680 = video_get_drvdata(dev); |
| 1257 | unsigned long start = vma->vm_start; |
| 1258 | unsigned long size = vma->vm_end-vma->vm_start; |
| 1259 | unsigned long page, pos; |
| 1260 | |
| 1261 | down (&stv680->lock); |
| 1262 | |
| 1263 | if (stv680->udev == NULL) { |
| 1264 | up (&stv680->lock); |
| 1265 | return -EIO; |
| 1266 | } |
| 1267 | if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1) |
| 1268 | & ~(PAGE_SIZE - 1))) { |
| 1269 | up (&stv680->lock); |
| 1270 | return -EINVAL; |
| 1271 | } |
| 1272 | pos = (unsigned long) stv680->fbuf; |
| 1273 | while (size > 0) { |
| 1274 | page = vmalloc_to_pfn((void *)pos); |
| 1275 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { |
| 1276 | up (&stv680->lock); |
| 1277 | return -EAGAIN; |
| 1278 | } |
| 1279 | start += PAGE_SIZE; |
| 1280 | pos += PAGE_SIZE; |
| 1281 | if (size > PAGE_SIZE) |
| 1282 | size -= PAGE_SIZE; |
| 1283 | else |
| 1284 | size = 0; |
| 1285 | } |
| 1286 | up (&stv680->lock); |
| 1287 | |
| 1288 | return 0; |
| 1289 | } |
| 1290 | |
| 1291 | static ssize_t stv680_read (struct file *file, char __user *buf, |
| 1292 | size_t count, loff_t *ppos) |
| 1293 | { |
| 1294 | struct video_device *dev = file->private_data; |
| 1295 | unsigned long int realcount = count; |
| 1296 | int ret = 0; |
| 1297 | struct usb_stv *stv680 = video_get_drvdata(dev); |
| 1298 | unsigned long int i; |
| 1299 | |
| 1300 | if (STV680_NUMFRAMES != 2) { |
| 1301 | PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!"); |
| 1302 | return -1; |
| 1303 | } |
| 1304 | if (stv680->udev == NULL) |
| 1305 | return -EIO; |
| 1306 | if (realcount > (stv680->vwidth * stv680->vheight * 3)) |
| 1307 | realcount = stv680->vwidth * stv680->vheight * 3; |
| 1308 | |
| 1309 | /* Shouldn't happen: */ |
| 1310 | if (stv680->frame[0].grabstate == FRAME_GRABBING) { |
| 1311 | PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read"); |
| 1312 | return -EBUSY; |
| 1313 | } |
| 1314 | stv680->frame[0].grabstate = FRAME_READY; |
| 1315 | stv680->frame[1].grabstate = FRAME_UNUSED; |
| 1316 | stv680->curframe = 0; |
| 1317 | |
| 1318 | if (!stv680->streaming) |
| 1319 | stv680_start_stream (stv680); |
| 1320 | |
| 1321 | if (!stv680->streaming) { |
| 1322 | ret = stv680_newframe (stv680, 0); /* ret should = 0 */ |
| 1323 | } |
| 1324 | |
| 1325 | ret = stv680_newframe (stv680, 0); |
| 1326 | |
| 1327 | if (!ret) { |
| 1328 | if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) { |
| 1329 | PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i); |
| 1330 | return -EFAULT; |
| 1331 | } |
| 1332 | } else { |
| 1333 | realcount = ret; |
| 1334 | } |
| 1335 | stv680->frame[0].grabstate = FRAME_UNUSED; |
| 1336 | return realcount; |
| 1337 | } /* stv680_read */ |
| 1338 | |
| 1339 | static struct file_operations stv680_fops = { |
| 1340 | .owner = THIS_MODULE, |
| 1341 | .open = stv_open, |
| 1342 | .release = stv_close, |
| 1343 | .read = stv680_read, |
| 1344 | .mmap = stv680_mmap, |
| 1345 | .ioctl = stv680_ioctl, |
| 1346 | .llseek = no_llseek, |
| 1347 | }; |
| 1348 | static struct video_device stv680_template = { |
| 1349 | .owner = THIS_MODULE, |
| 1350 | .name = "STV0680 USB camera", |
| 1351 | .type = VID_TYPE_CAPTURE, |
| 1352 | .hardware = VID_HARDWARE_SE401, |
| 1353 | .fops = &stv680_fops, |
| 1354 | .release = video_device_release, |
| 1355 | .minor = -1, |
| 1356 | }; |
| 1357 | |
| 1358 | static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id) |
| 1359 | { |
| 1360 | struct usb_device *dev = interface_to_usbdev(intf); |
| 1361 | struct usb_host_interface *interface; |
| 1362 | struct usb_stv *stv680 = NULL; |
| 1363 | char *camera_name = NULL; |
| 1364 | int retval = 0; |
| 1365 | |
| 1366 | /* We don't handle multi-config cameras */ |
| 1367 | if (dev->descriptor.bNumConfigurations != 1) { |
| 1368 | PDEBUG (0, "STV(e): Number of Configurations != 1"); |
| 1369 | return -ENODEV; |
| 1370 | } |
| 1371 | |
| 1372 | interface = &intf->altsetting[0]; |
| 1373 | /* Is it a STV680? */ |
| 1374 | if ((le16_to_cpu(dev->descriptor.idVendor) == USB_PENCAM_VENDOR_ID) && |
| 1375 | (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) { |
| 1376 | camera_name = "STV0680"; |
| 1377 | PDEBUG (0, "STV(i): STV0680 camera found."); |
Kiril Jovchev | 1636787 | 2005-06-05 01:52:33 +0300 | [diff] [blame] | 1378 | } else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) && |
| 1379 | (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) { |
| 1380 | camera_name = "Creative WebCam Go Mini"; |
| 1381 | PDEBUG (0, "STV(i): Creative WebCam Go Mini found."); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1382 | } else { |
Kiril Jovchev | 1636787 | 2005-06-05 01:52:33 +0300 | [diff] [blame] | 1383 | PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values."); |
| 1384 | PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer."); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1385 | retval = -ENODEV; |
| 1386 | goto error; |
| 1387 | } |
| 1388 | /* We found one */ |
| 1389 | if ((stv680 = kmalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) { |
| 1390 | PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct."); |
| 1391 | retval = -ENOMEM; |
| 1392 | goto error; |
| 1393 | } |
| 1394 | |
| 1395 | memset (stv680, 0, sizeof (*stv680)); |
| 1396 | |
| 1397 | stv680->udev = dev; |
| 1398 | stv680->camera_name = camera_name; |
| 1399 | |
| 1400 | stv680->vdev = video_device_alloc(); |
| 1401 | if (!stv680->vdev) { |
| 1402 | retval = -ENOMEM; |
| 1403 | goto error; |
| 1404 | } |
| 1405 | memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template)); |
| 1406 | stv680->vdev->dev = &intf->dev; |
| 1407 | video_set_drvdata(stv680->vdev, stv680); |
| 1408 | |
| 1409 | memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name)); |
| 1410 | init_waitqueue_head (&stv680->wq); |
| 1411 | init_MUTEX (&stv680->lock); |
| 1412 | wmb (); |
| 1413 | |
| 1414 | if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { |
| 1415 | PDEBUG (0, "STV(e): video_register_device failed"); |
| 1416 | retval = -EIO; |
| 1417 | goto error_vdev; |
| 1418 | } |
| 1419 | PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor); |
| 1420 | |
| 1421 | usb_set_intfdata (intf, stv680); |
| 1422 | stv680_create_sysfs_files(stv680->vdev); |
| 1423 | return 0; |
| 1424 | |
| 1425 | error_vdev: |
| 1426 | video_device_release(stv680->vdev); |
| 1427 | error: |
| 1428 | kfree(stv680); |
| 1429 | return retval; |
| 1430 | } |
| 1431 | |
| 1432 | static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680) |
| 1433 | { |
| 1434 | int i; |
| 1435 | |
| 1436 | stv680->udev = NULL; |
| 1437 | stv680->frame[0].grabstate = FRAME_ERROR; |
| 1438 | stv680->frame[1].grabstate = FRAME_ERROR; |
| 1439 | stv680->streaming = 0; |
| 1440 | |
| 1441 | wake_up_interruptible (&stv680->wq); |
| 1442 | |
| 1443 | for (i = 0; i < STV680_NUMSBUF; i++) |
| 1444 | if (stv680->urb[i]) { |
| 1445 | usb_kill_urb (stv680->urb[i]); |
| 1446 | usb_free_urb (stv680->urb[i]); |
| 1447 | stv680->urb[i] = NULL; |
Jesper Juhl | f9101210 | 2005-09-10 00:26:54 -0700 | [diff] [blame^] | 1448 | kfree(stv680->sbuf[i].data); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1449 | } |
| 1450 | for (i = 0; i < STV680_NUMSCRATCH; i++) |
Jesper Juhl | f9101210 | 2005-09-10 00:26:54 -0700 | [diff] [blame^] | 1451 | kfree(stv680->scratch[i].data); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1452 | PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name); |
| 1453 | |
| 1454 | /* Free the memory */ |
Jesper Juhl | f9101210 | 2005-09-10 00:26:54 -0700 | [diff] [blame^] | 1455 | kfree(stv680); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1456 | } |
| 1457 | |
| 1458 | static void stv680_disconnect (struct usb_interface *intf) |
| 1459 | { |
| 1460 | struct usb_stv *stv680 = usb_get_intfdata (intf); |
| 1461 | |
| 1462 | usb_set_intfdata (intf, NULL); |
| 1463 | |
| 1464 | if (stv680) { |
| 1465 | /* We don't want people trying to open up the device */ |
| 1466 | if (stv680->vdev) { |
| 1467 | stv680_remove_sysfs_files(stv680->vdev); |
| 1468 | video_unregister_device(stv680->vdev); |
| 1469 | stv680->vdev = NULL; |
| 1470 | } |
| 1471 | if (!stv680->user) { |
| 1472 | usb_stv680_remove_disconnected (stv680); |
| 1473 | } else { |
| 1474 | stv680->removed = 1; |
| 1475 | } |
| 1476 | } |
| 1477 | } |
| 1478 | |
| 1479 | static struct usb_driver stv680_driver = { |
| 1480 | .owner = THIS_MODULE, |
| 1481 | .name = "stv680", |
| 1482 | .probe = stv680_probe, |
| 1483 | .disconnect = stv680_disconnect, |
| 1484 | .id_table = device_table |
| 1485 | }; |
| 1486 | |
| 1487 | /******************************************************************** |
| 1488 | * Module routines |
| 1489 | ********************************************************************/ |
| 1490 | |
| 1491 | static int __init usb_stv680_init (void) |
| 1492 | { |
| 1493 | if (usb_register (&stv680_driver) < 0) { |
| 1494 | PDEBUG (0, "STV(e): Could not setup STV0680 driver"); |
| 1495 | return -1; |
| 1496 | } |
| 1497 | PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION); |
| 1498 | |
| 1499 | info(DRIVER_DESC " " DRIVER_VERSION); |
| 1500 | return 0; |
| 1501 | } |
| 1502 | |
| 1503 | static void __exit usb_stv680_exit (void) |
| 1504 | { |
| 1505 | usb_deregister (&stv680_driver); |
| 1506 | PDEBUG (0, "STV(i): driver deregistered"); |
| 1507 | } |
| 1508 | |
| 1509 | module_init (usb_stv680_init); |
| 1510 | module_exit (usb_stv680_exit); |