sn9c102_core.c 69.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/***************************************************************************
 * V4L2 driver for SN9C10x PC Camera Controllers                           *
 *                                                                         *
4
 * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
 *                                                                         *
 * This program is free software; you can redistribute it and/or modify    *
 * it under the terms of the GNU General Public License as published by    *
 * the Free Software Foundation; either version 2 of the License, or       *
 * (at your option) any later version.                                     *
 *                                                                         *
 * This program is distributed in the hope that it will be useful,         *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
 * GNU General Public License for more details.                            *
 *                                                                         *
 * You should have received a copy of the GNU General Public License       *
 * along with this program; if not, write to the Free Software             *
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
 ***************************************************************************/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/compiler.h>
#include <linux/ioctl.h>
#include <linux/poll.h>
#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/page-flags.h>
#include <linux/byteorder/generic.h>
#include <asm/page.h>
#include <asm/uaccess.h>

#include "sn9c102.h"

/*****************************************************************************/

46 47 48 49
#define SN9C102_MODULE_NAME     "V4L2 driver for SN9C10x PC Camera Controllers"
#define SN9C102_MODULE_AUTHOR   "(C) 2004-2006 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE  "GPL"
50 51
#define SN9C102_MODULE_VERSION  "1:1.27"
#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 27)
52 53 54

/*****************************************************************************/

L
Linus Torvalds 已提交
55 56 57 58 59 60 61 62 63 64
MODULE_DEVICE_TABLE(usb, sn9c102_id_table);

MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL);
MODULE_DESCRIPTION(SN9C102_MODULE_NAME);
MODULE_VERSION(SN9C102_MODULE_VERSION);
MODULE_LICENSE(SN9C102_MODULE_LICENSE);

static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
module_param_array(video_nr, short, NULL, 0444);
MODULE_PARM_DESC(video_nr,
65 66 67 68 69 70 71 72 73 74 75 76 77
		 "\n<-1|n[,...]> Specify V4L2 minor mode number."
		 "\n -1 = use next available (default)"
		 "\n  n = use minor number n (integer >= 0)"
		 "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES)
		 " cameras this way."
		 "\nFor example:"
		 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
		 "\nthe second camera and use auto for the first"
		 "\none and for every other camera."
		 "\n");

static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] =
			       SN9C102_FORCE_MUNMAP};
L
Linus Torvalds 已提交
78 79
module_param_array(force_munmap, bool, NULL, 0444);
MODULE_PARM_DESC(force_munmap,
80 81 82 83 84 85 86 87 88
		 "\n<0|1[,...]> Force the application to unmap previously"
		 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
		 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
		 "\nthis feature. This parameter is specific for each"
		 "\ndetected camera."
		 "\n 0 = do not force memory unmapping"
		 "\n 1 = force memory unmapping (save memory)"
		 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
		 "\n");
L
Linus Torvalds 已提交
89

90
static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
91
				       SN9C102_FRAME_TIMEOUT};
92 93
module_param_array(frame_timeout, uint, NULL, 0644);
MODULE_PARM_DESC(frame_timeout,
94 95 96 97
		 "\n<n[,...]> Timeout for a video frame in seconds."
		 "\nThis parameter is specific for each detected camera."
		 "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
		 "\n");
98

L
Linus Torvalds 已提交
99 100 101 102
#ifdef SN9C102_DEBUG
static unsigned short debug = SN9C102_DEBUG_LEVEL;
module_param(debug, ushort, 0644);
MODULE_PARM_DESC(debug,
103 104 105 106 107 108 109 110 111
		 "\n<n> Debugging information level, from 0 to 3:"
		 "\n0 = none (use carefully)"
		 "\n1 = critical errors"
		 "\n2 = significant informations"
		 "\n3 = more verbose messages"
		 "\nLevel 3 is useful for testing only, when only "
		 "one device is used."
		 "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"."
		 "\n");
L
Linus Torvalds 已提交
112 113 114 115 116 117 118 119 120
#endif

/*****************************************************************************/

static sn9c102_sof_header_t sn9c102_sof_header[] = {
	{0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00},
	{0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01},
};

121 122 123
static sn9c103_sof_header_t sn9c103_sof_header[] = {
	{0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x20},
};
L
Linus Torvalds 已提交
124 125 126 127 128 129 130 131 132 133

static sn9c102_eof_header_t sn9c102_eof_header[] = {
	{0x00, 0x00, 0x00, 0x00},
	{0x40, 0x00, 0x00, 0x00},
	{0x80, 0x00, 0x00, 0x00},
	{0xc0, 0x00, 0x00, 0x00},
};

/*****************************************************************************/

134 135 136
static u32
sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
			enum sn9c102_io_method io)
L
Linus Torvalds 已提交
137
{
138 139
	struct v4l2_pix_format* p = &(cam->sensor.pix_format);
	struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
L
Linus Torvalds 已提交
140
	const size_t imagesize = cam->module_param.force_munmap ||
141 142 143
				 io == IO_READ ?
				 (p->width * p->height * p->priv) / 8 :
				 (r->width * r->height * p->priv) / 8;
L
Linus Torvalds 已提交
144 145 146 147 148 149 150 151
	void* buff = NULL;
	u32 i;

	if (count > SN9C102_MAX_FRAMES)
		count = SN9C102_MAX_FRAMES;

	cam->nbuffers = count;
	while (cam->nbuffers > 0) {
152
		if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
L
Linus Torvalds 已提交
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
			break;
		cam->nbuffers--;
	}

	for (i = 0; i < cam->nbuffers; i++) {
		cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
		cam->frame[i].buf.index = i;
		cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
		cam->frame[i].buf.length = imagesize;
		cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		cam->frame[i].buf.sequence = 0;
		cam->frame[i].buf.field = V4L2_FIELD_NONE;
		cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
		cam->frame[i].buf.flags = 0;
	}

	return cam->nbuffers;
}


static void sn9c102_release_buffers(struct sn9c102_device* cam)
{
	if (cam->nbuffers) {
176
		vfree(cam->frame[0].bufmem);
L
Linus Torvalds 已提交
177 178
		cam->nbuffers = 0;
	}
179
	cam->frame_current = NULL;
L
Linus Torvalds 已提交
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
}


static void sn9c102_empty_framequeues(struct sn9c102_device* cam)
{
	u32 i;

	INIT_LIST_HEAD(&cam->inqueue);
	INIT_LIST_HEAD(&cam->outqueue);

	for (i = 0; i < SN9C102_MAX_FRAMES; i++) {
		cam->frame[i].state = F_UNUSED;
		cam->frame[i].buf.bytesused = 0;
	}
}


197 198 199 200 201 202 203 204 205 206 207 208 209
static void sn9c102_requeue_outqueue(struct sn9c102_device* cam)
{
	struct sn9c102_frame_t *i;

	list_for_each_entry(i, &cam->outqueue, frame) {
		i->state = F_QUEUED;
		list_add(&i->frame, &cam->inqueue);
	}

	INIT_LIST_HEAD(&cam->outqueue);
}


L
Linus Torvalds 已提交
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
static void sn9c102_queue_unusedframes(struct sn9c102_device* cam)
{
	unsigned long lock_flags;
	u32 i;

	for (i = 0; i < cam->nbuffers; i++)
		if (cam->frame[i].state == F_UNUSED) {
			cam->frame[i].state = F_QUEUED;
			spin_lock_irqsave(&cam->queue_lock, lock_flags);
			list_add_tail(&cam->frame[i].frame, &cam->inqueue);
			spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
		}
}

/*****************************************************************************/

226 227 228 229 230 231 232 233 234
int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index)
{
	struct usb_device* udev = cam->usbdev;
	int i, res;

	if (index + sizeof(buff) >= ARRAY_SIZE(cam->reg))
		return -1;

	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
235 236
			      index, 0, buff, sizeof(buff),
			      SN9C102_CTRL_TIMEOUT*sizeof(buff));
237 238 239 240 241 242 243 244 245 246 247 248 249
	if (res < 0) {
		DBG(3, "Failed to write registers (index 0x%02X, error %d)",
		    index, res);
		return -1;
	}

	for (i = 0; i < sizeof(buff); i++)
		cam->reg[index+i] = buff[i];

	return 0;
}


L
Linus Torvalds 已提交
250 251 252 253 254 255
int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
{
	struct usb_device* udev = cam->usbdev;
	u8* buff = cam->control_buffer;
	int res;

256 257 258
	if (index >= ARRAY_SIZE(cam->reg))
		return -1;

L
Linus Torvalds 已提交
259 260 261
	*buff = value;

	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
262
			      index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
L
Linus Torvalds 已提交
263 264
	if (res < 0) {
		DBG(3, "Failed to write a register (value 0x%02X, index "
265
		       "0x%02X, error %d)", value, index, res);
L
Linus Torvalds 已提交
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
		return -1;
	}

	cam->reg[index] = value;

	return 0;
}


/* NOTE: reading some registers always returns 0 */
static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
{
	struct usb_device* udev = cam->usbdev;
	u8* buff = cam->control_buffer;
	int res;

	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
283
			      index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
L
Linus Torvalds 已提交
284 285
	if (res < 0)
		DBG(3, "Failed to read a register (index 0x%02X, error %d)",
286
		    index, res);
L
Linus Torvalds 已提交
287 288 289 290 291 292 293

	return (res >= 0) ? (int)(*buff) : -1;
}


int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index)
{
294 295
	if (index >= ARRAY_SIZE(cam->reg))
		return -1;
L
Linus Torvalds 已提交
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321

	return cam->reg[index];
}


static int
sn9c102_i2c_wait(struct sn9c102_device* cam, struct sn9c102_sensor* sensor)
{
	int i, r;

	for (i = 1; i <= 5; i++) {
		r = sn9c102_read_reg(cam, 0x08);
		if (r < 0)
			return -EIO;
		if (r & 0x04)
			return 0;
		if (sensor->frequency & SN9C102_I2C_400KHZ)
			udelay(5*16);
		else
			udelay(16*16);
	}
	return -EBUSY;
}


static int
322 323
sn9c102_i2c_detect_read_error(struct sn9c102_device* cam,
			      struct sn9c102_sensor* sensor)
L
Linus Torvalds 已提交
324 325 326 327 328 329 330 331
{
	int r;
	r = sn9c102_read_reg(cam, 0x08);
	return (r < 0 || (r >= 0 && !(r & 0x08))) ? -EIO : 0;
}


static int
332 333
sn9c102_i2c_detect_write_error(struct sn9c102_device* cam,
			       struct sn9c102_sensor* sensor)
L
Linus Torvalds 已提交
334 335 336 337 338 339 340
{
	int r;
	r = sn9c102_read_reg(cam, 0x08);
	return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0;
}


341
int
L
Linus Torvalds 已提交
342
sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
343 344
			 struct sn9c102_sensor* sensor, u8 data0, u8 data1,
			 u8 n, u8 buffer[])
L
Linus Torvalds 已提交
345 346 347 348 349 350 351
{
	struct usb_device* udev = cam->usbdev;
	u8* data = cam->control_buffer;
	int err = 0, res;

	/* Write cycle */
	data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
352
		  ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10;
L
Linus Torvalds 已提交
353 354 355 356
	data[1] = data0; /* I2C slave id */
	data[2] = data1; /* address */
	data[7] = 0x10;
	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
357
			      0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
L
Linus Torvalds 已提交
358 359 360 361 362 363 364
	if (res < 0)
		err += res;

	err += sn9c102_i2c_wait(cam, sensor);

	/* Read cycle - n bytes */
	data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
365 366
		  ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) |
		  (n << 4) | 0x02;
L
Linus Torvalds 已提交
367 368 369
	data[1] = data0;
	data[7] = 0x10;
	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
370
			      0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
L
Linus Torvalds 已提交
371 372 373 374 375 376 377
	if (res < 0)
		err += res;

	err += sn9c102_i2c_wait(cam, sensor);

	/* The first read byte will be placed in data[4] */
	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
378
			      0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT);
L
Linus Torvalds 已提交
379 380 381 382 383 384
	if (res < 0)
		err += res;

	err += sn9c102_i2c_detect_read_error(cam, sensor);

	PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1,
385
	      data[4]);
L
Linus Torvalds 已提交
386 387

	if (err) {
388
		DBG(3, "I2C read failed for %s image sensor", sensor->name);
L
Linus Torvalds 已提交
389 390 391 392 393 394 395 396 397 398
		return -1;
	}

	if (buffer)
		memcpy(buffer, data, sizeof(buffer));

	return (int)data[4];
}


399
int
L
Linus Torvalds 已提交
400
sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
401 402
			  struct sn9c102_sensor* sensor, u8 n, u8 data0,
			  u8 data1, u8 data2, u8 data3, u8 data4, u8 data5)
L
Linus Torvalds 已提交
403 404 405 406 407 408 409
{
	struct usb_device* udev = cam->usbdev;
	u8* data = cam->control_buffer;
	int err = 0, res;

	/* Write cycle. It usually is address + value */
	data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
410 411
		  ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0)
		  | ((n - 1) << 4);
L
Linus Torvalds 已提交
412 413 414 415 416 417 418 419
	data[1] = data0;
	data[2] = data1;
	data[3] = data2;
	data[4] = data3;
	data[5] = data4;
	data[6] = data5;
	data[7] = 0x14;
	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
420
			      0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
L
Linus Torvalds 已提交
421 422 423 424 425 426 427
	if (res < 0)
		err += res;

	err += sn9c102_i2c_wait(cam, sensor);
	err += sn9c102_i2c_detect_write_error(cam, sensor);

	if (err)
428
		DBG(3, "I2C write failed for %s image sensor", sensor->name);
L
Linus Torvalds 已提交
429 430 431

	PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, "
	      "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X",
432
	      n, data0, data1, data2, data3, data4, data5);
L
Linus Torvalds 已提交
433 434 435 436 437 438 439

	return err ? -1 : 0;
}


int
sn9c102_i2c_try_read(struct sn9c102_device* cam,
440
		     struct sn9c102_sensor* sensor, u8 address)
L
Linus Torvalds 已提交
441 442
{
	return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id,
443
					address, 1, NULL);
L
Linus Torvalds 已提交
444 445 446
}


447
int
L
Linus Torvalds 已提交
448
sn9c102_i2c_try_write(struct sn9c102_device* cam,
449
		      struct sn9c102_sensor* sensor, u8 address, u8 value)
L
Linus Torvalds 已提交
450
{
451 452 453
	return sn9c102_i2c_try_raw_write(cam, sensor, 3,
					 sensor->i2c_slave_id, address,
					 value, 0, 0, 0);
L
Linus Torvalds 已提交
454 455 456 457 458
}


int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address)
{
459
	return sn9c102_i2c_try_read(cam, &cam->sensor, address);
L
Linus Torvalds 已提交
460 461 462 463 464
}


int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
{
465
	return sn9c102_i2c_try_write(cam, &cam->sensor, address, value);
L
Linus Torvalds 已提交
466 467 468 469 470 471 472
}

/*****************************************************************************/

static void*
sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
{
473 474 475 476 477 478 479 480 481 482 483 484 485
	size_t soflen = 0, i;
	u8 j, n = 0;

	switch (cam->bridge) {
	case BRIDGE_SN9C101:
	case BRIDGE_SN9C102:
		soflen = sizeof(sn9c102_sof_header_t);
		n = sizeof(sn9c102_sof_header) / soflen;
		break;
	case BRIDGE_SN9C103:
		soflen = sizeof(sn9c103_sof_header_t);
		n = sizeof(sn9c103_sof_header) / soflen;
	}
L
Linus Torvalds 已提交
486

487
	for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
L
Linus Torvalds 已提交
488
		for (j = 0; j < n; j++)
489 490 491 492 493
			/* The invariable part of the header is 6 bytes long */
			if ((cam->bridge != BRIDGE_SN9C103 &&
			    !memcmp(mem + i, sn9c102_sof_header[j], 6)) ||
			    (cam->bridge == BRIDGE_SN9C103 &&
			    !memcmp(mem + i, sn9c103_sof_header[j], 6))) {
L
Linus Torvalds 已提交
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
				memcpy(cam->sof_header, mem + i, soflen);
				/* Skip the header */
				return mem + i + soflen;
			}

	return NULL;
}


static void*
sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
{
	size_t eoflen = sizeof(sn9c102_eof_header_t), i;
	unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;

509
	if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
L
Linus Torvalds 已提交
510 511 512 513 514 515 516 517 518 519 520
		return NULL; /* EOF header does not exist in compressed data */

	for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
		for (j = 0; j < n; j++)
			if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen))
				return mem + i;

	return NULL;
}


521
static void sn9c102_urb_complete(struct urb *urb)
L
Linus Torvalds 已提交
522 523 524
{
	struct sn9c102_device* cam = urb->context;
	struct sn9c102_frame_t** f;
525
	size_t imagesize, soflen;
L
Linus Torvalds 已提交
526 527 528 529 530 531 532 533 534 535 536 537
	u8 i;
	int err = 0;

	if (urb->status == -ENOENT)
		return;

	f = &cam->frame_current;

	if (cam->stream == STREAM_INTERRUPT) {
		cam->stream = STREAM_OFF;
		if ((*f))
			(*f)->state = F_QUEUED;
538
		DBG(3, "Stream interrupted");
539
		wake_up(&cam->wait_stream);
L
Linus Torvalds 已提交
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
	}

	if (cam->state & DEV_DISCONNECTED)
		return;

	if (cam->state & DEV_MISCONFIGURED) {
		wake_up_interruptible(&cam->wait_frame);
		return;
	}

	if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
		goto resubmit_urb;

	if (!(*f))
		(*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t,
555
				  frame);
L
Linus Torvalds 已提交
556

557
	imagesize = (cam->sensor.pix_format.width *
558 559
		     cam->sensor.pix_format.height *
		     cam->sensor.pix_format.priv) / 8;
L
Linus Torvalds 已提交
560

561
	soflen = (cam->bridge) == BRIDGE_SN9C103 ?
562 563
				  sizeof(sn9c103_sof_header_t) :
				  sizeof(sn9c102_sof_header_t);
564

L
Linus Torvalds 已提交
565 566 567 568 569 570 571 572 573
	for (i = 0; i < urb->number_of_packets; i++) {
		unsigned int img, len, status;
		void *pos, *sof, *eof;

		len = urb->iso_frame_desc[i].actual_length;
		status = urb->iso_frame_desc[i].status;
		pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;

		if (status) {
574
			DBG(3, "Error in isochronous frame");
L
Linus Torvalds 已提交
575 576 577 578
			(*f)->state = F_ERROR;
			continue;
		}

579
		PDBGG("Isochrnous frame: length %u, #%u i", len, i);
L
Linus Torvalds 已提交
580 581 582

redo:
		sof = sn9c102_find_sof_header(cam, pos, len);
583
		if (likely(!sof)) {
L
Linus Torvalds 已提交
584 585 586 587 588 589 590 591 592
			eof = sn9c102_find_eof_header(cam, pos, len);
			if ((*f)->state == F_GRABBING) {
end_of_frame:
				img = len;

				if (eof)
					img = (eof > pos) ? eof - pos - 1 : 0;

				if ((*f)->buf.bytesused+img > imagesize) {
593 594 595
					u32 b;
					b = (*f)->buf.bytesused + img -
					    imagesize;
L
Linus Torvalds 已提交
596 597
					img = imagesize - (*f)->buf.bytesused;
					DBG(3, "Expected EOF not found: "
598
					       "video frame cut");
L
Linus Torvalds 已提交
599 600
					if (eof)
						DBG(3, "Exceeded limit: +%u "
601
						       "bytes", (unsigned)(b));
L
Linus Torvalds 已提交
602 603 604 605 606 607 608 609 610 611 612
				}

				memcpy((*f)->bufmem + (*f)->buf.bytesused, pos,
				       img);

				if ((*f)->buf.bytesused == 0)
					do_gettimeofday(&(*f)->buf.timestamp);

				(*f)->buf.bytesused += img;

				if ((*f)->buf.bytesused == imagesize ||
613
				    (cam->sensor.pix_format.pixelformat ==
614
						V4L2_PIX_FMT_SN9C10X && eof)) {
615 616
					u32 b;
					b = (*f)->buf.bytesused;
L
Linus Torvalds 已提交
617 618
					(*f)->state = F_DONE;
					(*f)->buf.sequence= ++cam->frame_count;
619
					spin_lock(&cam->queue_lock);
L
Linus Torvalds 已提交
620
					list_move_tail(&(*f)->frame,
621
						       &cam->outqueue);
L
Linus Torvalds 已提交
622 623
					if (!list_empty(&cam->inqueue))
						(*f) = list_entry(
624 625 626
							cam->inqueue.next,
							struct sn9c102_frame_t,
							frame );
L
Linus Torvalds 已提交
627 628
					else
						(*f) = NULL;
629
					spin_unlock(&cam->queue_lock);
L
Linus Torvalds 已提交
630
					memcpy(cam->sysfs.frame_header,
631 632 633
					       cam->sof_header, soflen);
					DBG(3, "Video frame captured: %lu "
					       "bytes", (unsigned long)(b));
L
Linus Torvalds 已提交
634 635 636 637 638 639 640

					if (!(*f))
						goto resubmit_urb;

				} else if (eof) {
					(*f)->state = F_ERROR;
					DBG(3, "Not expected EOF after %lu "
641
					       "bytes of image data",
642 643
					    (unsigned long)
					    ((*f)->buf.bytesused));
L
Linus Torvalds 已提交
644 645 646 647 648 649
				}

				if (sof) /* (1) */
					goto start_of_frame;

			} else if (eof) {
650
				DBG(3, "EOF without SOF");
L
Linus Torvalds 已提交
651 652 653
				continue;

			} else {
654
				PDBGG("Ignoring pointless isochronous frame");
L
Linus Torvalds 已提交
655 656 657 658 659 660 661 662 663
				continue;
			}

		} else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) {
start_of_frame:
			(*f)->state = F_GRABBING;
			(*f)->buf.bytesused = 0;
			len -= (sof - pos);
			pos = sof;
664
			DBG(3, "SOF detected: new video frame");
L
Linus Torvalds 已提交
665 666 667 668 669 670 671 672
			if (len)
				goto redo;

		} else if ((*f)->state == F_GRABBING) {
			eof = sn9c102_find_eof_header(cam, pos, len);
			if (eof && eof < sof)
				goto end_of_frame; /* (1) */
			else {
673
				if (cam->sensor.pix_format.pixelformat ==
L
Linus Torvalds 已提交
674
				    V4L2_PIX_FMT_SN9C10X) {
675
					eof = sof - soflen;
L
Linus Torvalds 已提交
676 677 678
					goto end_of_frame;
				} else {
					DBG(3, "SOF before expected EOF after "
679
					       "%lu bytes of image data",
680 681
					    (unsigned long)
					    ((*f)->buf.bytesused));
L
Linus Torvalds 已提交
682 683 684 685 686 687 688 689 690 691 692
					goto start_of_frame;
				}
			}
		}
	}

resubmit_urb:
	urb->dev = cam->usbdev;
	err = usb_submit_urb(urb, GFP_ATOMIC);
	if (err < 0 && err != -EPERM) {
		cam->state |= DEV_MISCONFIGURED;
693
		DBG(1, "usb_submit_urb() failed");
L
Linus Torvalds 已提交
694 695 696 697 698 699 700 701 702 703
	}

	wake_up_interruptible(&cam->wait_frame);
}


static int sn9c102_start_transfer(struct sn9c102_device* cam)
{
	struct usb_device *udev = cam->usbdev;
	struct urb* urb;
704
	const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512,
705
						       680, 800, 900, 1023};
706
	const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512,
707
						       680, 800, 900, 1003};
708
	const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ?
709 710
			    sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] :
			    sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
L
Linus Torvalds 已提交
711 712 713 714
	s8 i, j;
	int err = 0;

	for (i = 0; i < SN9C102_URBS; i++) {
715
		cam->transfer_buffer[i] = kzalloc(SN9C102_ISO_PACKETS * psz,
716
						  GFP_KERNEL);
L
Linus Torvalds 已提交
717 718
		if (!cam->transfer_buffer[i]) {
			err = -ENOMEM;
719
			DBG(1, "Not enough memory");
L
Linus Torvalds 已提交
720 721 722 723 724 725 726 727 728
			goto free_buffers;
		}
	}

	for (i = 0; i < SN9C102_URBS; i++) {
		urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL);
		cam->urb[i] = urb;
		if (!urb) {
			err = -ENOMEM;
729
			DBG(1, "usb_alloc_urb() failed");
L
Linus Torvalds 已提交
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751
			goto free_urbs;
		}
		urb->dev = udev;
		urb->context = cam;
		urb->pipe = usb_rcvisocpipe(udev, 1);
		urb->transfer_flags = URB_ISO_ASAP;
		urb->number_of_packets = SN9C102_ISO_PACKETS;
		urb->complete = sn9c102_urb_complete;
		urb->transfer_buffer = cam->transfer_buffer[i];
		urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS;
		urb->interval = 1;
		for (j = 0; j < SN9C102_ISO_PACKETS; j++) {
			urb->iso_frame_desc[j].offset = psz * j;
			urb->iso_frame_desc[j].length = psz;
		}
	}

	/* Enable video */
	if (!(cam->reg[0x01] & 0x04)) {
		err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01);
		if (err) {
			err = -EIO;
752
			DBG(1, "I/O hardware error");
L
Linus Torvalds 已提交
753 754 755 756 757 758
			goto free_urbs;
		}
	}

	err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING);
	if (err) {
759
		DBG(1, "usb_set_interface() failed");
L
Linus Torvalds 已提交
760 761 762 763 764 765 766 767 768 769
		goto free_urbs;
	}

	cam->frame_current = NULL;

	for (i = 0; i < SN9C102_URBS; i++) {
		err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
		if (err) {
			for (j = i-1; j >= 0; j--)
				usb_kill_urb(cam->urb[j]);
770
			DBG(1, "usb_submit_urb() failed, error %d", err);
L
Linus Torvalds 已提交
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
			goto free_urbs;
		}
	}

	return 0;

free_urbs:
	for (i = 0; (i < SN9C102_URBS) &&  cam->urb[i]; i++)
		usb_free_urb(cam->urb[i]);

free_buffers:
	for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++)
		kfree(cam->transfer_buffer[i]);

	return err;
}


static int sn9c102_stop_transfer(struct sn9c102_device* cam)
{
	struct usb_device *udev = cam->usbdev;
	s8 i;
	int err = 0;

	if (cam->state & DEV_DISCONNECTED)
		return 0;

	for (i = SN9C102_URBS-1; i >= 0; i--) {
		usb_kill_urb(cam->urb[i]);
		usb_free_urb(cam->urb[i]);
		kfree(cam->transfer_buffer[i]);
	}

	err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
	if (err)
806
		DBG(3, "usb_set_interface() failed");
L
Linus Torvalds 已提交
807 808 809 810 811

	return err;
}


812
static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
L
Linus Torvalds 已提交
813
{
814
	long timeout;
L
Linus Torvalds 已提交
815 816

	cam->stream = STREAM_INTERRUPT;
817
	timeout = wait_event_timeout(cam->wait_stream,
818 819 820
				     (cam->stream == STREAM_OFF) ||
				     (cam->state & DEV_DISCONNECTED),
				     SN9C102_URB_TIMEOUT);
L
Linus Torvalds 已提交
821 822
	if (cam->state & DEV_DISCONNECTED)
		return -ENODEV;
823
	else if (cam->stream != STREAM_OFF) {
L
Linus Torvalds 已提交
824
		cam->state |= DEV_MISCONFIGURED;
825 826 827 828
		DBG(1, "URB timeout reached. The camera is misconfigured. "
		       "To use it, close and open /dev/video%d again.",
		    cam->v4ldev->minor);
		return -EIO;
L
Linus Torvalds 已提交
829 830 831 832 833 834 835
	}

	return 0;
}

/*****************************************************************************/

836
#ifdef CONFIG_VIDEO_ADV_DEBUG
L
Linus Torvalds 已提交
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count)
{
	char str[5];
	char* endp;
	unsigned long val;

	if (len < 4) {
		strncpy(str, buff, len);
		str[len+1] = '\0';
	} else {
		strncpy(str, buff, 4);
		str[4] = '\0';
	}

	val = simple_strtoul(str, &endp, 0);

	*count = 0;
	if (val <= 0xff)
		*count = (ssize_t)(endp - str);
	if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
		*count += 1;

	return (u8)val;
}

/*
   NOTE 1: being inside one of the following methods implies that the v4l
864
	   device exists for sure (see kobjects and reference counters)
L
Linus Torvalds 已提交
865 866 867 868 869 870 871 872
   NOTE 2: buffers are PAGE_SIZE long
*/

static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
{
	struct sn9c102_device* cam;
	ssize_t count;

873
	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
L
Linus Torvalds 已提交
874 875 876 877
		return -ERESTARTSYS;

	cam = video_get_drvdata(to_video_device(cd));
	if (!cam) {
878
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
879 880 881 882 883
		return -ENODEV;
	}

	count = sprintf(buf, "%u\n", cam->sysfs.reg);

884
	mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
885 886

	return count;
887
}
L
Linus Torvalds 已提交
888 889


890
static ssize_t
L
Linus Torvalds 已提交
891 892 893 894 895 896
sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
{
	struct sn9c102_device* cam;
	u8 index;
	ssize_t count;

897
	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
L
Linus Torvalds 已提交
898 899 900 901
		return -ERESTARTSYS;

	cam = video_get_drvdata(to_video_device(cd));
	if (!cam) {
902
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
903 904 905 906 907
		return -ENODEV;
	}

	index = sn9c102_strtou8(buf, len, &count);
	if (index > 0x1f || !count) {
908
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
909 910 911 912 913
		return -EINVAL;
	}

	cam->sysfs.reg = index;

914 915
	DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg);
	DBG(3, "Written bytes: %zd", count);
L
Linus Torvalds 已提交
916

917
	mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
918 919 920 921 922 923 924 925 926 927 928

	return count;
}


static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
{
	struct sn9c102_device* cam;
	ssize_t count;
	int val;

929
	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
L
Linus Torvalds 已提交
930 931 932 933
		return -ERESTARTSYS;

	cam = video_get_drvdata(to_video_device(cd));
	if (!cam) {
934
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
935 936 937 938
		return -ENODEV;
	}

	if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) {
939
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
940 941 942 943 944
		return -EIO;
	}

	count = sprintf(buf, "%d\n", val);

945
	DBG(3, "Read bytes: %zd", count);
L
Linus Torvalds 已提交
946

947
	mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
948 949

	return count;
950
}
L
Linus Torvalds 已提交
951 952 953 954 955 956 957 958 959 960


static ssize_t
sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
{
	struct sn9c102_device* cam;
	u8 value;
	ssize_t count;
	int err;

961
	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
L
Linus Torvalds 已提交
962 963 964 965
		return -ERESTARTSYS;

	cam = video_get_drvdata(to_video_device(cd));
	if (!cam) {
966
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
967 968 969 970 971
		return -ENODEV;
	}

	value = sn9c102_strtou8(buf, len, &count);
	if (!count) {
972
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
973 974 975 976 977
		return -EINVAL;
	}

	err = sn9c102_write_reg(cam, value, cam->sysfs.reg);
	if (err) {
978
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
979 980 981 982
		return -EIO;
	}

	DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X",
983 984
	    cam->sysfs.reg, value);
	DBG(3, "Written bytes: %zd", count);
L
Linus Torvalds 已提交
985

986
	mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
987 988 989 990 991 992 993 994 995 996

	return count;
}


static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
{
	struct sn9c102_device* cam;
	ssize_t count;

997
	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
L
Linus Torvalds 已提交
998 999 1000 1001
		return -ERESTARTSYS;

	cam = video_get_drvdata(to_video_device(cd));
	if (!cam) {
1002
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1003 1004 1005 1006 1007
		return -ENODEV;
	}

	count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);

1008
	DBG(3, "Read bytes: %zd", count);
L
Linus Torvalds 已提交
1009

1010
	mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1011 1012 1013 1014 1015

	return count;
}


1016
static ssize_t
L
Linus Torvalds 已提交
1017 1018 1019 1020 1021 1022
sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
{
	struct sn9c102_device* cam;
	u8 index;
	ssize_t count;

1023
	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
L
Linus Torvalds 已提交
1024 1025 1026 1027
		return -ERESTARTSYS;

	cam = video_get_drvdata(to_video_device(cd));
	if (!cam) {
1028
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1029 1030 1031 1032 1033
		return -ENODEV;
	}

	index = sn9c102_strtou8(buf, len, &count);
	if (!count) {
1034
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1035 1036 1037 1038 1039
		return -EINVAL;
	}

	cam->sysfs.i2c_reg = index;

1040 1041
	DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
	DBG(3, "Written bytes: %zd", count);
L
Linus Torvalds 已提交
1042

1043
	mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054

	return count;
}


static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
{
	struct sn9c102_device* cam;
	ssize_t count;
	int val;

1055
	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
L
Linus Torvalds 已提交
1056 1057 1058 1059
		return -ERESTARTSYS;

	cam = video_get_drvdata(to_video_device(cd));
	if (!cam) {
1060
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1061 1062 1063
		return -ENODEV;
	}

1064
	if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) {
1065
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1066 1067 1068 1069
		return -ENOSYS;
	}

	if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
1070
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1071 1072 1073 1074 1075
		return -EIO;
	}

	count = sprintf(buf, "%d\n", val);

1076
	DBG(3, "Read bytes: %zd", count);
L
Linus Torvalds 已提交
1077

1078
	mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1079 1080

	return count;
1081
}
L
Linus Torvalds 已提交
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091


static ssize_t
sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
{
	struct sn9c102_device* cam;
	u8 value;
	ssize_t count;
	int err;

1092
	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
L
Linus Torvalds 已提交
1093 1094 1095 1096
		return -ERESTARTSYS;

	cam = video_get_drvdata(to_video_device(cd));
	if (!cam) {
1097
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1098 1099 1100
		return -ENODEV;
	}

1101
	if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) {
1102
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1103 1104 1105 1106 1107
		return -ENOSYS;
	}

	value = sn9c102_strtou8(buf, len, &count);
	if (!count) {
1108
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1109 1110 1111 1112 1113
		return -EINVAL;
	}

	err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value);
	if (err) {
1114
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1115 1116 1117 1118
		return -EIO;
	}

	DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
1119 1120
	    cam->sysfs.i2c_reg, value);
	DBG(3, "Written bytes: %zd", count);
L
Linus Torvalds 已提交
1121

1122
	mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136

	return count;
}


static ssize_t
sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
{
	struct sn9c102_device* cam;
	enum sn9c102_bridge bridge;
	ssize_t res = 0;
	u8 value;
	ssize_t count;

1137
	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
L
Linus Torvalds 已提交
1138 1139 1140 1141
		return -ERESTARTSYS;

	cam = video_get_drvdata(to_video_device(cd));
	if (!cam) {
1142
		mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1143 1144 1145 1146 1147
		return -ENODEV;
	}

	bridge = cam->bridge;

1148
	mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221

	value = sn9c102_strtou8(buf, len, &count);
	if (!count)
		return -EINVAL;

	switch (bridge) {
	case BRIDGE_SN9C101:
	case BRIDGE_SN9C102:
		if (value > 0x0f)
			return -EINVAL;
		if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0)
			res = sn9c102_store_val(cd, buf, len);
		break;
	case BRIDGE_SN9C103:
		if (value > 0x7f)
			return -EINVAL;
		if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0)
			res = sn9c102_store_val(cd, buf, len);
		break;
	}

	return res;
}


static ssize_t
sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
{
	ssize_t res = 0;
	u8 value;
	ssize_t count;

	value = sn9c102_strtou8(buf, len, &count);
	if (!count || value > 0x7f)
		return -EINVAL;

	if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0)
		res = sn9c102_store_val(cd, buf, len);

	return res;
}


static ssize_t
sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
{
	ssize_t res = 0;
	u8 value;
	ssize_t count;

	value = sn9c102_strtou8(buf, len, &count);
	if (!count || value > 0x7f)
		return -EINVAL;

	if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0)
		res = sn9c102_store_val(cd, buf, len);

	return res;
}


static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
{
	struct sn9c102_device* cam;
	ssize_t count;

	cam = video_get_drvdata(to_video_device(cd));
	if (!cam)
		return -ENODEV;

	count = sizeof(cam->sysfs.frame_header);
	memcpy(buf, cam->sysfs.frame_header, count);

1222
	DBG(3, "Frame header, read bytes: %zd", count);
L
Linus Torvalds 已提交
1223 1224

	return count;
1225
}
L
Linus Torvalds 已提交
1226 1227 1228


static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
1229
			 sn9c102_show_reg, sn9c102_store_reg);
L
Linus Torvalds 已提交
1230
static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
1231
			 sn9c102_show_val, sn9c102_store_val);
L
Linus Torvalds 已提交
1232
static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
1233
			 sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
L
Linus Torvalds 已提交
1234
static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
1235
			 sn9c102_show_i2c_val, sn9c102_store_i2c_val);
L
Linus Torvalds 已提交
1236 1237 1238 1239
static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue);
static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red);
static CLASS_DEVICE_ATTR(frame_header, S_IRUGO,
1240
			 sn9c102_show_frame_header, NULL);
L
Linus Torvalds 已提交
1241 1242


1243
static int sn9c102_create_sysfs(struct sn9c102_device* cam)
L
Linus Torvalds 已提交
1244 1245
{
	struct video_device *v4ldev = cam->v4ldev;
1246 1247 1248 1249 1250 1251 1252 1253
	int rc;

	rc = video_device_create_file(v4ldev, &class_device_attr_reg);
	if (rc) goto err;
	rc = video_device_create_file(v4ldev, &class_device_attr_val);
	if (rc) goto err_reg;
	rc = video_device_create_file(v4ldev, &class_device_attr_frame_header);
	if (rc) goto err_val;
L
Linus Torvalds 已提交
1254

1255
	if (cam->sensor.sysfs_ops) {
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269
		rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
		if (rc) goto err_frhead;
		rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val);
		if (rc) goto err_i2c_reg;
	}

	if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
		rc = video_device_create_file(v4ldev, &class_device_attr_green);
		if (rc) goto err_i2c_val;
	} else if (cam->bridge == BRIDGE_SN9C103) {
		rc = video_device_create_file(v4ldev, &class_device_attr_blue);
		if (rc) goto err_i2c_val;
		rc = video_device_create_file(v4ldev, &class_device_attr_red);
		if (rc) goto err_blue;
L
Linus Torvalds 已提交
1270
	}
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289

	return 0;

err_blue:
	video_device_remove_file(v4ldev, &class_device_attr_blue);
err_i2c_val:
	if (cam->sensor.sysfs_ops)
		video_device_remove_file(v4ldev, &class_device_attr_i2c_val);
err_i2c_reg:
	if (cam->sensor.sysfs_ops)
		video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
err_frhead:
	video_device_remove_file(v4ldev, &class_device_attr_frame_header);
err_val:
	video_device_remove_file(v4ldev, &class_device_attr_val);
err_reg:
	video_device_remove_file(v4ldev, &class_device_attr_reg);
err:
	return rc;
L
Linus Torvalds 已提交
1290
}
1291
#endif /* CONFIG_VIDEO_ADV_DEBUG */
L
Linus Torvalds 已提交
1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310

/*****************************************************************************/

static int
sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix)
{
	int err = 0;

	if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
		err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18);
	else
		err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18);

	return err ? -EIO : 0;
}


static int
sn9c102_set_compression(struct sn9c102_device* cam,
1311
			struct v4l2_jpegcompression* compression)
L
Linus Torvalds 已提交
1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
{
	int err = 0;

	if (compression->quality == 0)
		err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17);
	else if (compression->quality == 1)
		err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17);

	return err ? -EIO : 0;
}


static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
{
	u8 r = 0;
	int err = 0;

	if (scale == 1)
		r = cam->reg[0x18] & 0xcf;
	else if (scale == 2) {
		r = cam->reg[0x18] & 0xcf;
		r |= 0x10;
	} else if (scale == 4)
		r = cam->reg[0x18] | 0x20;

	err += sn9c102_write_reg(cam, r, 0x18);
	if (err)
		return -EIO;

1341
	PDBGG("Scaling factor: %u", scale);
L
Linus Torvalds 已提交
1342 1343 1344 1345 1346 1347 1348

	return 0;
}


static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
{
1349
	struct sn9c102_sensor* s = &cam->sensor;
L
Linus Torvalds 已提交
1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363
	u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
	   v_start = (u8)(rect->top - s->cropcap.bounds.top),
	   h_size = (u8)(rect->width / 16),
	   v_size = (u8)(rect->height / 16);
	int err = 0;

	err += sn9c102_write_reg(cam, h_start, 0x12);
	err += sn9c102_write_reg(cam, v_start, 0x13);
	err += sn9c102_write_reg(cam, h_size, 0x15);
	err += sn9c102_write_reg(cam, v_size, 0x16);
	if (err)
		return -EIO;

	PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size "
1364
	      "%u %u %u %u", h_start, v_start, h_size, v_size);
L
Linus Torvalds 已提交
1365 1366 1367 1368 1369 1370 1371

	return 0;
}


static int sn9c102_init(struct sn9c102_device* cam)
{
1372
	struct sn9c102_sensor* s = &cam->sensor;
L
Linus Torvalds 已提交
1373 1374 1375
	struct v4l2_control ctrl;
	struct v4l2_queryctrl *qctrl;
	struct v4l2_rect* rect;
1376
	u8 i = 0;
L
Linus Torvalds 已提交
1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395
	int err = 0;

	if (!(cam->state & DEV_INITIALIZED)) {
		init_waitqueue_head(&cam->open);
		qctrl = s->qctrl;
		rect = &(s->cropcap.defrect);
	} else { /* use current values */
		qctrl = s->_qctrl;
		rect = &(s->_rect);
	}

	err += sn9c102_set_scale(cam, rect->width / s->pix_format.width);
	err += sn9c102_set_crop(cam, rect);
	if (err)
		return err;

	if (s->init) {
		err = s->init(cam);
		if (err) {
1396
			DBG(3, "Sensor initialization failed");
L
Linus Torvalds 已提交
1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411
			return err;
		}
	}

	if (!(cam->state & DEV_INITIALIZED))
		cam->compression.quality =  cam->reg[0x17] & 0x01 ? 0 : 1;
	else
		err += sn9c102_set_compression(cam, &cam->compression);
	err += sn9c102_set_pix_format(cam, &s->pix_format);
	if (s->set_pix_format)
		err += s->set_pix_format(cam, &s->pix_format);
	if (err)
		return err;

	if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
1412
		DBG(3, "Compressed video format is active, quality %d",
1413
		    cam->compression.quality);
L
Linus Torvalds 已提交
1414
	else
1415
		DBG(3, "Uncompressed video format is active");
L
Linus Torvalds 已提交
1416 1417 1418

	if (s->set_crop)
		if ((err = s->set_crop(cam, rect))) {
1419
			DBG(3, "set_crop() failed");
L
Linus Torvalds 已提交
1420 1421 1422 1423
			return err;
		}

	if (s->set_ctrl) {
1424 1425
		for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
			if (s->qctrl[i].id != 0 &&
L
Linus Torvalds 已提交
1426 1427 1428 1429 1430 1431
			    !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
				ctrl.id = s->qctrl[i].id;
				ctrl.value = qctrl[i].default_value;
				err = s->set_ctrl(cam, &ctrl);
				if (err) {
					DBG(3, "Set %s control failed",
1432
					    s->qctrl[i].name);
L
Linus Torvalds 已提交
1433 1434 1435
					return err;
				}
				DBG(3, "Image sensor supports '%s' control",
1436
				    s->qctrl[i].name);
L
Linus Torvalds 已提交
1437 1438 1439 1440
			}
	}

	if (!(cam->state & DEV_INITIALIZED)) {
1441
		mutex_init(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1442 1443 1444 1445 1446
		spin_lock_init(&cam->queue_lock);
		init_waitqueue_head(&cam->wait_frame);
		init_waitqueue_head(&cam->wait_stream);
		cam->nreadbuffers = 2;
		memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
1447
		memcpy(&(s->_rect), &(s->cropcap.defrect),
L
Linus Torvalds 已提交
1448 1449 1450 1451
		       sizeof(struct v4l2_rect));
		cam->state |= DEV_INITIALIZED;
	}

1452
	DBG(2, "Initialization succeeded");
L
Linus Torvalds 已提交
1453 1454 1455 1456 1457 1458
	return 0;
}


static void sn9c102_release_resources(struct sn9c102_device* cam)
{
1459
	mutex_lock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1460

1461
	DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
L
Linus Torvalds 已提交
1462 1463 1464
	video_set_drvdata(cam->v4ldev, NULL);
	video_unregister_device(cam->v4ldev);

1465 1466
	usb_put_dev(cam->usbdev);

1467
	mutex_unlock(&sn9c102_sysfs_lock);
L
Linus Torvalds 已提交
1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487

	kfree(cam->control_buffer);
}

/*****************************************************************************/

static int sn9c102_open(struct inode* inode, struct file* filp)
{
	struct sn9c102_device* cam;
	int err = 0;

	/*
	   This is the only safe way to prevent race conditions with
	   disconnect
	*/
	if (!down_read_trylock(&sn9c102_disconnect))
		return -ERESTARTSYS;

	cam = video_get_drvdata(video_devdata(filp));

1488
	if (mutex_lock_interruptible(&cam->dev_mutex)) {
L
Linus Torvalds 已提交
1489 1490 1491 1492 1493
		up_read(&sn9c102_disconnect);
		return -ERESTARTSYS;
	}

	if (cam->users) {
1494
		DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
L
Linus Torvalds 已提交
1495 1496 1497 1498 1499
		if ((filp->f_flags & O_NONBLOCK) ||
		    (filp->f_flags & O_NDELAY)) {
			err = -EWOULDBLOCK;
			goto out;
		}
1500
		mutex_unlock(&cam->dev_mutex);
L
Linus Torvalds 已提交
1501
		err = wait_event_interruptible_exclusive(cam->open,
1502 1503
						  cam->state & DEV_DISCONNECTED
							 || !cam->users);
L
Linus Torvalds 已提交
1504 1505 1506 1507 1508 1509 1510 1511
		if (err) {
			up_read(&sn9c102_disconnect);
			return err;
		}
		if (cam->state & DEV_DISCONNECTED) {
			up_read(&sn9c102_disconnect);
			return -ENODEV;
		}
1512
		mutex_lock(&cam->dev_mutex);
L
Linus Torvalds 已提交
1513 1514 1515 1516 1517 1518 1519
	}


	if (cam->state & DEV_MISCONFIGURED) {
		err = sn9c102_init(cam);
		if (err) {
			DBG(1, "Initialization failed again. "
1520
			       "I will retry on next open().");
L
Linus Torvalds 已提交
1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536
			goto out;
		}
		cam->state &= ~DEV_MISCONFIGURED;
	}

	if ((err = sn9c102_start_transfer(cam)))
		goto out;

	filp->private_data = cam;
	cam->users++;
	cam->io = IO_NONE;
	cam->stream = STREAM_OFF;
	cam->nbuffers = 0;
	cam->frame_count = 0;
	sn9c102_empty_framequeues(cam);

1537
	DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
L
Linus Torvalds 已提交
1538 1539

out:
1540
	mutex_unlock(&cam->dev_mutex);
L
Linus Torvalds 已提交
1541 1542 1543 1544 1545 1546 1547 1548 1549
	up_read(&sn9c102_disconnect);
	return err;
}


static int sn9c102_release(struct inode* inode, struct file* filp)
{
	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));

1550
	mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
L
Linus Torvalds 已提交
1551 1552 1553 1554 1555 1556 1557

	sn9c102_stop_transfer(cam);

	sn9c102_release_buffers(cam);

	if (cam->state & DEV_DISCONNECTED) {
		sn9c102_release_resources(cam);
1558
		mutex_unlock(&cam->dev_mutex);
L
Linus Torvalds 已提交
1559 1560 1561 1562 1563 1564 1565
		kfree(cam);
		return 0;
	}

	cam->users--;
	wake_up_interruptible_nr(&cam->open, 1);

1566
	DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
L
Linus Torvalds 已提交
1567

1568
	mutex_unlock(&cam->dev_mutex);
L
Linus Torvalds 已提交
1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579

	return 0;
}


static ssize_t
sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
{
	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
	struct sn9c102_frame_t* f, * i;
	unsigned long lock_flags;
1580
	long timeout;
L
Linus Torvalds 已提交
1581 1582
	int err = 0;

1583
	if (mutex_lock_interruptible(&cam->fileop_mutex))
L
Linus Torvalds 已提交
1584 1585 1586
		return -ERESTARTSYS;

	if (cam->state & DEV_DISCONNECTED) {
1587
		DBG(1, "Device not present");
1588
		mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1589 1590 1591 1592
		return -ENODEV;
	}

	if (cam->state & DEV_MISCONFIGURED) {
1593 1594
		DBG(1, "The camera is misconfigured. Close and open it "
		       "again.");
1595
		mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1596 1597 1598 1599 1600
		return -EIO;
	}

	if (cam->io == IO_MMAP) {
		DBG(3, "Close and open the device again to choose "
1601
		       "the read method");
1602
		mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1603 1604 1605 1606 1607
		return -EINVAL;
	}

	if (cam->io == IO_NONE) {
		if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) {
1608
			DBG(1, "read() failed, not enough memory");
1609
			mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1610 1611 1612 1613
			return -ENOMEM;
		}
		cam->io = IO_READ;
		cam->stream = STREAM_ON;
1614 1615 1616 1617 1618
	}

	if (list_empty(&cam->inqueue)) {
		if (!list_empty(&cam->outqueue))
			sn9c102_empty_framequeues(cam);
L
Linus Torvalds 已提交
1619 1620 1621 1622
		sn9c102_queue_unusedframes(cam);
	}

	if (!count) {
1623
		mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1624 1625 1626 1627 1628
		return 0;
	}

	if (list_empty(&cam->outqueue)) {
		if (filp->f_flags & O_NONBLOCK) {
1629
			mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1630 1631
			return -EAGAIN;
		}
1632
		timeout = wait_event_interruptible_timeout
1633 1634 1635 1636 1637 1638
			  ( cam->wait_frame,
			    (!list_empty(&cam->outqueue)) ||
			    (cam->state & DEV_DISCONNECTED) ||
			    (cam->state & DEV_MISCONFIGURED),
			    cam->module_param.frame_timeout *
			    1000 * msecs_to_jiffies(1) );
1639
		if (timeout < 0) {
1640
			mutex_unlock(&cam->fileop_mutex);
1641
			return timeout;
L
Linus Torvalds 已提交
1642 1643
		}
		if (cam->state & DEV_DISCONNECTED) {
1644
			mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1645 1646
			return -ENODEV;
		}
1647
		if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
1648
			mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1649 1650 1651 1652 1653 1654
			return -EIO;
		}
	}

	f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame);

1655 1656 1657 1658 1659 1660 1661 1662 1663 1664
	if (count > f->buf.bytesused)
		count = f->buf.bytesused;

	if (copy_to_user(buf, f->bufmem, count)) {
		err = -EFAULT;
		goto exit;
	}
	*f_pos += count;

exit:
L
Linus Torvalds 已提交
1665 1666 1667 1668 1669 1670 1671 1672
	spin_lock_irqsave(&cam->queue_lock, lock_flags);
	list_for_each_entry(i, &cam->outqueue, frame)
		i->state = F_UNUSED;
	INIT_LIST_HEAD(&cam->outqueue);
	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);

	sn9c102_queue_unusedframes(cam);

1673 1674
	PDBGG("Frame #%lu, bytes read: %zu",
	      (unsigned long)f->buf.index, count);
L
Linus Torvalds 已提交
1675

1676
	mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1677 1678 1679 1680 1681 1682 1683 1684

	return count;
}


static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
{
	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
1685 1686
	struct sn9c102_frame_t* f;
	unsigned long lock_flags;
L
Linus Torvalds 已提交
1687 1688
	unsigned int mask = 0;

1689
	if (mutex_lock_interruptible(&cam->fileop_mutex))
L
Linus Torvalds 已提交
1690 1691 1692
		return POLLERR;

	if (cam->state & DEV_DISCONNECTED) {
1693
		DBG(1, "Device not present");
L
Linus Torvalds 已提交
1694 1695 1696 1697
		goto error;
	}

	if (cam->state & DEV_MISCONFIGURED) {
1698 1699
		DBG(1, "The camera is misconfigured. Close and open it "
		       "again.");
L
Linus Torvalds 已提交
1700 1701 1702 1703 1704
		goto error;
	}

	if (cam->io == IO_NONE) {
		if (!sn9c102_request_buffers(cam, cam->nreadbuffers,
1705
					     IO_READ)) {
1706
			DBG(1, "poll() failed, not enough memory");
L
Linus Torvalds 已提交
1707 1708 1709 1710 1711 1712
			goto error;
		}
		cam->io = IO_READ;
		cam->stream = STREAM_ON;
	}

1713 1714 1715 1716 1717 1718
	if (cam->io == IO_READ) {
		spin_lock_irqsave(&cam->queue_lock, lock_flags);
		list_for_each_entry(f, &cam->outqueue, frame)
			f->state = F_UNUSED;
		INIT_LIST_HEAD(&cam->outqueue);
		spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
L
Linus Torvalds 已提交
1719
		sn9c102_queue_unusedframes(cam);
1720
	}
L
Linus Torvalds 已提交
1721 1722 1723 1724 1725 1726

	poll_wait(filp, &cam->wait_frame, wait);

	if (!list_empty(&cam->outqueue))
		mask |= POLLIN | POLLRDNORM;

1727
	mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1728 1729 1730 1731

	return mask;

error:
1732
	mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761
	return POLLERR;
}


static void sn9c102_vm_open(struct vm_area_struct* vma)
{
	struct sn9c102_frame_t* f = vma->vm_private_data;
	f->vma_use_count++;
}


static void sn9c102_vm_close(struct vm_area_struct* vma)
{
	/* NOTE: buffers are not freed here */
	struct sn9c102_frame_t* f = vma->vm_private_data;
	f->vma_use_count--;
}


static struct vm_operations_struct sn9c102_vm_ops = {
	.open = sn9c102_vm_open,
	.close = sn9c102_vm_close,
};


static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
{
	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
	unsigned long size = vma->vm_end - vma->vm_start,
1762
		      start = vma->vm_start;
1763
	void *pos;
L
Linus Torvalds 已提交
1764 1765
	u32 i;

1766
	if (mutex_lock_interruptible(&cam->fileop_mutex))
L
Linus Torvalds 已提交
1767 1768 1769
		return -ERESTARTSYS;

	if (cam->state & DEV_DISCONNECTED) {
1770
		DBG(1, "Device not present");
1771
		mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1772 1773 1774 1775
		return -ENODEV;
	}

	if (cam->state & DEV_MISCONFIGURED) {
1776 1777
		DBG(1, "The camera is misconfigured. Close and open it "
		       "again.");
1778
		mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1779 1780 1781 1782 1783
		return -EIO;
	}

	if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
	    size != PAGE_ALIGN(cam->frame[0].buf.length)) {
1784
		mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1785 1786 1787 1788 1789 1790 1791 1792
		return -EINVAL;
	}

	for (i = 0; i < cam->nbuffers; i++) {
		if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
			break;
	}
	if (i == cam->nbuffers) {
1793
		mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1794 1795 1796 1797
		return -EINVAL;
	}

	vma->vm_flags |= VM_IO;
1798
	vma->vm_flags |= VM_RESERVED;
L
Linus Torvalds 已提交
1799

1800
	pos = cam->frame[i].bufmem;
L
Linus Torvalds 已提交
1801
	while (size > 0) { /* size is page-aligned */
1802
		if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
1803
			mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815
			return -EAGAIN;
		}
		start += PAGE_SIZE;
		pos += PAGE_SIZE;
		size -= PAGE_SIZE;
	}

	vma->vm_ops = &sn9c102_vm_ops;
	vma->vm_private_data = &cam->frame[i];

	sn9c102_vm_open(vma);

1816
	mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
1817 1818 1819 1820

	return 0;
}

1821
/*****************************************************************************/
L
Linus Torvalds 已提交
1822

1823 1824
static int
sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
L
Linus Torvalds 已提交
1825
{
1826 1827 1828 1829
	struct v4l2_capability cap = {
		.driver = "sn9c102",
		.version = SN9C102_MODULE_VERSION_CODE,
		.capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
1830
				V4L2_CAP_STREAMING,
1831 1832 1833 1834
	};

	strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
	if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
1835
		strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
1836
			sizeof(cap.bus_info));
1837 1838 1839

	if (copy_to_user(arg, &cap, sizeof(cap)))
		return -EFAULT;
L
Linus Torvalds 已提交
1840

1841 1842
	return 0;
}
L
Linus Torvalds 已提交
1843 1844


1845 1846 1847 1848
static int
sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
{
	struct v4l2_input i;
L
Linus Torvalds 已提交
1849

1850 1851
	if (copy_from_user(&i, arg, sizeof(i)))
		return -EFAULT;
L
Linus Torvalds 已提交
1852

1853 1854
	if (i.index)
		return -EINVAL;
L
Linus Torvalds 已提交
1855

1856
	memset(&i, 0, sizeof(i));
1857
	strcpy(i.name, "Camera");
1858
	i.type = V4L2_INPUT_TYPE_CAMERA;
L
Linus Torvalds 已提交
1859

1860 1861
	if (copy_to_user(arg, &i, sizeof(i)))
		return -EFAULT;
L
Linus Torvalds 已提交
1862

1863 1864
	return 0;
}
L
Linus Torvalds 已提交
1865 1866


1867
static int
1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880
sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg)
{
	int index = 0;

	if (copy_to_user(arg, &index, sizeof(index)))
		return -EFAULT;

	return 0;
}


static int
sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg)
1881 1882
{
	int index;
L
Linus Torvalds 已提交
1883

1884 1885
	if (copy_from_user(&index, arg, sizeof(index)))
		return -EFAULT;
L
Linus Torvalds 已提交
1886

1887
	if (index != 0)
L
Linus Torvalds 已提交
1888 1889
		return -EINVAL;

1890 1891
	return 0;
}
L
Linus Torvalds 已提交
1892 1893


1894 1895 1896
static int
sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
{
1897
	struct sn9c102_sensor* s = &cam->sensor;
1898 1899
	struct v4l2_queryctrl qc;
	u8 i;
L
Linus Torvalds 已提交
1900

1901 1902
	if (copy_from_user(&qc, arg, sizeof(qc)))
		return -EFAULT;
L
Linus Torvalds 已提交
1903

1904 1905 1906 1907 1908 1909 1910
	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
		if (qc.id && qc.id == s->qctrl[i].id) {
			memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
			if (copy_to_user(arg, &qc, sizeof(qc)))
				return -EFAULT;
			return 0;
		}
L
Linus Torvalds 已提交
1911

1912 1913
	return -EINVAL;
}
L
Linus Torvalds 已提交
1914 1915


1916 1917 1918
static int
sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
{
1919
	struct sn9c102_sensor* s = &cam->sensor;
1920 1921 1922
	struct v4l2_control ctrl;
	int err = 0;
	u8 i;
L
Linus Torvalds 已提交
1923

1924 1925
	if (!s->get_ctrl && !s->set_ctrl)
		return -EINVAL;
L
Linus Torvalds 已提交
1926

1927 1928 1929 1930
	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
		return -EFAULT;

	if (!s->get_ctrl) {
1931
		for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
1932 1933 1934
			if (ctrl.id && ctrl.id == s->qctrl[i].id) {
				ctrl.value = s->_qctrl[i].default_value;
				goto exit;
L
Linus Torvalds 已提交
1935
			}
1936 1937 1938
		return -EINVAL;
	} else
		err = s->get_ctrl(cam, &ctrl);
L
Linus Torvalds 已提交
1939

1940 1941 1942
exit:
	if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
		return -EFAULT;
L
Linus Torvalds 已提交
1943

1944 1945
	return err;
}
L
Linus Torvalds 已提交
1946 1947


1948 1949 1950
static int
sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
{
1951
	struct sn9c102_sensor* s = &cam->sensor;
1952 1953 1954
	struct v4l2_control ctrl;
	u8 i;
	int err = 0;
L
Linus Torvalds 已提交
1955

1956 1957
	if (!s->set_ctrl)
		return -EINVAL;
L
Linus Torvalds 已提交
1958

1959 1960
	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
		return -EFAULT;
L
Linus Torvalds 已提交
1961

1962 1963
	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
		if (ctrl.id == s->qctrl[i].id) {
1964 1965
			if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
				return -EINVAL;
1966 1967 1968 1969 1970 1971
			if (ctrl.value < s->qctrl[i].minimum ||
			    ctrl.value > s->qctrl[i].maximum)
				return -ERANGE;
			ctrl.value -= ctrl.value % s->qctrl[i].step;
			break;
		}
L
Linus Torvalds 已提交
1972

1973 1974
	if ((err = s->set_ctrl(cam, &ctrl)))
		return err;
L
Linus Torvalds 已提交
1975

1976
	s->_qctrl[i].default_value = ctrl.value;
L
Linus Torvalds 已提交
1977

1978 1979
	PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
	      (unsigned long)ctrl.id, (unsigned long)ctrl.value);
L
Linus Torvalds 已提交
1980

1981 1982
	return 0;
}
L
Linus Torvalds 已提交
1983 1984


1985 1986 1987
static int
sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
{
1988
	struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
L
Linus Torvalds 已提交
1989

1990 1991 1992
	cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	cc->pixelaspect.numerator = 1;
	cc->pixelaspect.denominator = 1;
L
Linus Torvalds 已提交
1993

1994 1995
	if (copy_to_user(arg, cc, sizeof(*cc)))
		return -EFAULT;
L
Linus Torvalds 已提交
1996

1997 1998
	return 0;
}
L
Linus Torvalds 已提交
1999 2000


2001 2002 2003
static int
sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
{
2004
	struct sn9c102_sensor* s = &cam->sensor;
2005 2006 2007
	struct v4l2_crop crop = {
		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
	};
L
Linus Torvalds 已提交
2008

2009
	memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
L
Linus Torvalds 已提交
2010

2011 2012
	if (copy_to_user(arg, &crop, sizeof(crop)))
		return -EFAULT;
L
Linus Torvalds 已提交
2013

2014 2015
	return 0;
}
L
Linus Torvalds 已提交
2016 2017


2018 2019 2020
static int
sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
{
2021
	struct sn9c102_sensor* s = &cam->sensor;
2022 2023 2024 2025 2026 2027 2028 2029 2030
	struct v4l2_crop crop;
	struct v4l2_rect* rect;
	struct v4l2_rect* bounds = &(s->cropcap.bounds);
	struct v4l2_pix_format* pix_format = &(s->pix_format);
	u8 scale;
	const enum sn9c102_stream_state stream = cam->stream;
	const u32 nbuffers = cam->nbuffers;
	u32 i;
	int err = 0;
L
Linus Torvalds 已提交
2031

2032 2033
	if (copy_from_user(&crop, arg, sizeof(crop)))
		return -EFAULT;
L
Linus Torvalds 已提交
2034

2035
	rect = &(crop.c);
L
Linus Torvalds 已提交
2036

2037 2038
	if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;
L
Linus Torvalds 已提交
2039

2040 2041 2042 2043 2044 2045 2046
	if (cam->module_param.force_munmap)
		for (i = 0; i < cam->nbuffers; i++)
			if (cam->frame[i].vma_use_count) {
				DBG(3, "VIDIOC_S_CROP failed. "
				       "Unmap the buffers first.");
				return -EINVAL;
			}
L
Linus Torvalds 已提交
2047

2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083
	/* Preserve R,G or B origin */
	rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
	rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;

	if (rect->width < 16)
		rect->width = 16;
	if (rect->height < 16)
		rect->height = 16;
	if (rect->width > bounds->width)
		rect->width = bounds->width;
	if (rect->height > bounds->height)
		rect->height = bounds->height;
	if (rect->left < bounds->left)
		rect->left = bounds->left;
	if (rect->top < bounds->top)
		rect->top = bounds->top;
	if (rect->left + rect->width > bounds->left + bounds->width)
		rect->left = bounds->left+bounds->width - rect->width;
	if (rect->top + rect->height > bounds->top + bounds->height)
		rect->top = bounds->top+bounds->height - rect->height;

	rect->width &= ~15L;
	rect->height &= ~15L;

	if (SN9C102_PRESERVE_IMGSCALE) {
		/* Calculate the actual scaling factor */
		u32 a, b;
		a = rect->width * rect->height;
		b = pix_format->width * pix_format->height;
		scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
	} else
		scale = 1;

	if (cam->stream == STREAM_ON)
		if ((err = sn9c102_stream_interrupt(cam)))
			return err;
L
Linus Torvalds 已提交
2084

2085 2086 2087
	if (copy_to_user(arg, &crop, sizeof(crop))) {
		cam->stream = stream;
		return -EFAULT;
L
Linus Torvalds 已提交
2088 2089
	}

2090 2091
	if (cam->module_param.force_munmap || cam->io == IO_READ)
		sn9c102_release_buffers(cam);
L
Linus Torvalds 已提交
2092

2093 2094 2095 2096
	err = sn9c102_set_crop(cam, rect);
	if (s->set_crop)
		err += s->set_crop(cam, rect);
	err += sn9c102_set_scale(cam, scale);
L
Linus Torvalds 已提交
2097

2098 2099 2100 2101 2102 2103 2104
	if (err) { /* atomic, no rollback in ioctl() */
		cam->state |= DEV_MISCONFIGURED;
		DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
		       "use the camera, close and open /dev/video%d again.",
		    cam->v4ldev->minor);
		return -EIO;
	}
L
Linus Torvalds 已提交
2105

2106 2107 2108
	s->pix_format.width = rect->width/scale;
	s->pix_format.height = rect->height/scale;
	memcpy(&(s->_rect), rect, sizeof(*rect));
L
Linus Torvalds 已提交
2109

2110 2111 2112 2113 2114 2115 2116
	if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
	    nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
		cam->state |= DEV_MISCONFIGURED;
		DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
		       "use the camera, close and open /dev/video%d again.",
		    cam->v4ldev->minor);
		return -ENOMEM;
L
Linus Torvalds 已提交
2117 2118
	}

2119 2120 2121 2122
	if (cam->io == IO_READ)
		sn9c102_empty_framequeues(cam);
	else if (cam->module_param.force_munmap)
		sn9c102_requeue_outqueue(cam);
L
Linus Torvalds 已提交
2123

2124
	cam->stream = stream;
L
Linus Torvalds 已提交
2125

2126 2127
	return 0;
}
L
Linus Torvalds 已提交
2128 2129


2130 2131 2132 2133
static int
sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
{
	struct v4l2_fmtdesc fmtd;
L
Linus Torvalds 已提交
2134

2135 2136
	if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
		return -EFAULT;
L
Linus Torvalds 已提交
2137

2138 2139 2140 2141 2142 2143 2144 2145 2146
	if (fmtd.index == 0) {
		strcpy(fmtd.description, "bayer rgb");
		fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
	} else if (fmtd.index == 1) {
		strcpy(fmtd.description, "compressed");
		fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
		fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
	} else
		return -EINVAL;
L
Linus Torvalds 已提交
2147

2148 2149
	fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
L
Linus Torvalds 已提交
2150

2151 2152
	if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
		return -EFAULT;
L
Linus Torvalds 已提交
2153

2154 2155
	return 0;
}
L
Linus Torvalds 已提交
2156 2157


2158 2159 2160 2161
static int
sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
{
	struct v4l2_format format;
2162
	struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
L
Linus Torvalds 已提交
2163

2164 2165
	if (copy_from_user(&format, arg, sizeof(format)))
		return -EFAULT;
L
Linus Torvalds 已提交
2166

2167 2168
	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;
L
Linus Torvalds 已提交
2169

2170
	pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
2171
			     ? 0 : (pfmt->width * pfmt->priv) / 8;
2172 2173 2174
	pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
	pfmt->field = V4L2_FIELD_NONE;
	memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
L
Linus Torvalds 已提交
2175

2176 2177
	if (copy_to_user(arg, &format, sizeof(format)))
		return -EFAULT;
L
Linus Torvalds 已提交
2178

2179 2180
	return 0;
}
L
Linus Torvalds 已提交
2181 2182


2183 2184
static int
sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
2185
			 void __user * arg)
2186
{
2187
	struct sn9c102_sensor* s = &cam->sensor;
2188 2189 2190 2191 2192 2193 2194 2195 2196 2197
	struct v4l2_format format;
	struct v4l2_pix_format* pix;
	struct v4l2_pix_format* pfmt = &(s->pix_format);
	struct v4l2_rect* bounds = &(s->cropcap.bounds);
	struct v4l2_rect rect;
	u8 scale;
	const enum sn9c102_stream_state stream = cam->stream;
	const u32 nbuffers = cam->nbuffers;
	u32 i;
	int err = 0;
L
Linus Torvalds 已提交
2198

2199 2200
	if (copy_from_user(&format, arg, sizeof(format)))
		return -EFAULT;
L
Linus Torvalds 已提交
2201

2202
	pix = &(format.fmt.pix);
L
Linus Torvalds 已提交
2203

2204 2205
	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;
L
Linus Torvalds 已提交
2206

2207
	memcpy(&rect, &(s->_rect), sizeof(rect));
L
Linus Torvalds 已提交
2208

2209 2210 2211 2212 2213
	{ /* calculate the actual scaling factor */
		u32 a, b;
		a = rect.width * rect.height;
		b = pix->width * pix->height;
		scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
L
Linus Torvalds 已提交
2214 2215
	}

2216 2217
	rect.width = scale * pix->width;
	rect.height = scale * pix->height;
L
Linus Torvalds 已提交
2218

2219 2220 2221 2222 2223 2224 2225 2226
	if (rect.width < 16)
		rect.width = 16;
	if (rect.height < 16)
		rect.height = 16;
	if (rect.width > bounds->left + bounds->width - rect.left)
		rect.width = bounds->left + bounds->width - rect.left;
	if (rect.height > bounds->top + bounds->height - rect.top)
		rect.height = bounds->top + bounds->height - rect.top;
L
Linus Torvalds 已提交
2227

2228 2229
	rect.width &= ~15L;
	rect.height &= ~15L;
L
Linus Torvalds 已提交
2230

2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246
	{ /* adjust the scaling factor */
		u32 a, b;
		a = rect.width * rect.height;
		b = pix->width * pix->height;
		scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
	}

	pix->width = rect.width / scale;
	pix->height = rect.height / scale;

	if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
	    pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
		pix->pixelformat = pfmt->pixelformat;
	pix->priv = pfmt->priv; /* bpp */
	pix->colorspace = pfmt->colorspace;
	pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
2247
			    ? 0 : (pix->width * pix->priv) / 8;
2248 2249 2250 2251 2252 2253 2254 2255
	pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
	pix->field = V4L2_FIELD_NONE;

	if (cmd == VIDIOC_TRY_FMT) {
		if (copy_to_user(arg, &format, sizeof(format)))
			return -EFAULT;
		return 0;
	}
L
Linus Torvalds 已提交
2256

2257
	if (cam->module_param.force_munmap)
L
Linus Torvalds 已提交
2258 2259
		for (i = 0; i < cam->nbuffers; i++)
			if (cam->frame[i].vma_use_count) {
2260 2261
				DBG(3, "VIDIOC_S_FMT failed. Unmap the "
				       "buffers first.");
L
Linus Torvalds 已提交
2262 2263 2264
				return -EINVAL;
			}

2265 2266 2267
	if (cam->stream == STREAM_ON)
		if ((err = sn9c102_stream_interrupt(cam)))
			return err;
L
Linus Torvalds 已提交
2268

2269 2270 2271 2272
	if (copy_to_user(arg, &format, sizeof(format))) {
		cam->stream = stream;
		return -EFAULT;
	}
L
Linus Torvalds 已提交
2273

2274
	if (cam->module_param.force_munmap  || cam->io == IO_READ)
L
Linus Torvalds 已提交
2275 2276
		sn9c102_release_buffers(cam);

2277 2278 2279 2280 2281 2282 2283
	err += sn9c102_set_pix_format(cam, pix);
	err += sn9c102_set_crop(cam, &rect);
	if (s->set_pix_format)
		err += s->set_pix_format(cam, pix);
	if (s->set_crop)
		err += s->set_crop(cam, &rect);
	err += sn9c102_set_scale(cam, scale);
L
Linus Torvalds 已提交
2284

2285 2286 2287 2288 2289 2290 2291
	if (err) { /* atomic, no rollback in ioctl() */
		cam->state |= DEV_MISCONFIGURED;
		DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
		       "use the camera, close and open /dev/video%d again.",
		    cam->v4ldev->minor);
		return -EIO;
	}
L
Linus Torvalds 已提交
2292

2293 2294 2295 2296 2297 2298 2299 2300 2301 2302
	memcpy(pfmt, pix, sizeof(*pix));
	memcpy(&(s->_rect), &rect, sizeof(rect));

	if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
	    nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
		cam->state |= DEV_MISCONFIGURED;
		DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
		       "use the camera, close and open /dev/video%d again.",
		    cam->v4ldev->minor);
		return -ENOMEM;
L
Linus Torvalds 已提交
2303 2304
	}

2305 2306 2307 2308
	if (cam->io == IO_READ)
		sn9c102_empty_framequeues(cam);
	else if (cam->module_param.force_munmap)
		sn9c102_requeue_outqueue(cam);
L
Linus Torvalds 已提交
2309

2310
	cam->stream = stream;
L
Linus Torvalds 已提交
2311

2312 2313 2314 2315 2316 2317 2318 2319
	return 0;
}


static int
sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
{
	if (copy_to_user(arg, &cam->compression,
2320
			 sizeof(cam->compression)))
2321
		return -EFAULT;
L
Linus Torvalds 已提交
2322

2323 2324
	return 0;
}
L
Linus Torvalds 已提交
2325 2326


2327 2328 2329 2330 2331 2332
static int
sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg)
{
	struct v4l2_jpegcompression jc;
	const enum sn9c102_stream_state stream = cam->stream;
	int err = 0;
L
Linus Torvalds 已提交
2333

2334 2335
	if (copy_from_user(&jc, arg, sizeof(jc)))
		return -EFAULT;
L
Linus Torvalds 已提交
2336

2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350
	if (jc.quality != 0 && jc.quality != 1)
		return -EINVAL;

	if (cam->stream == STREAM_ON)
		if ((err = sn9c102_stream_interrupt(cam)))
			return err;

	err += sn9c102_set_compression(cam, &jc);
	if (err) { /* atomic, no rollback in ioctl() */
		cam->state |= DEV_MISCONFIGURED;
		DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
		       "problems. To use the camera, close and open "
		       "/dev/video%d again.", cam->v4ldev->minor);
		return -EIO;
L
Linus Torvalds 已提交
2351 2352
	}

2353
	cam->compression.quality = jc.quality;
L
Linus Torvalds 已提交
2354

2355
	cam->stream = stream;
L
Linus Torvalds 已提交
2356

2357 2358
	return 0;
}
L
Linus Torvalds 已提交
2359

2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384

static int
sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg)
{
	struct v4l2_requestbuffers rb;
	u32 i;
	int err;

	if (copy_from_user(&rb, arg, sizeof(rb)))
		return -EFAULT;

	if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
	    rb.memory != V4L2_MEMORY_MMAP)
		return -EINVAL;

	if (cam->io == IO_READ) {
		DBG(3, "Close and open the device again to choose the mmap "
		       "I/O method");
		return -EINVAL;
	}

	for (i = 0; i < cam->nbuffers; i++)
		if (cam->frame[i].vma_use_count) {
			DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are "
			       "still mapped.");
L
Linus Torvalds 已提交
2385
			return -EINVAL;
2386
		}
L
Linus Torvalds 已提交
2387

2388 2389 2390
	if (cam->stream == STREAM_ON)
		if ((err = sn9c102_stream_interrupt(cam)))
			return err;
L
Linus Torvalds 已提交
2391

2392
	sn9c102_empty_framequeues(cam);
L
Linus Torvalds 已提交
2393

2394 2395 2396
	sn9c102_release_buffers(cam);
	if (rb.count)
		rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP);
L
Linus Torvalds 已提交
2397

2398 2399 2400 2401
	if (copy_to_user(arg, &rb, sizeof(rb))) {
		sn9c102_release_buffers(cam);
		cam->io = IO_NONE;
		return -EFAULT;
L
Linus Torvalds 已提交
2402 2403
	}

2404
	cam->io = rb.count ? IO_MMAP : IO_NONE;
L
Linus Torvalds 已提交
2405

2406 2407
	return 0;
}
L
Linus Torvalds 已提交
2408 2409


2410 2411 2412 2413
static int
sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg)
{
	struct v4l2_buffer b;
L
Linus Torvalds 已提交
2414

2415 2416
	if (copy_from_user(&b, arg, sizeof(b)))
		return -EFAULT;
L
Linus Torvalds 已提交
2417

2418 2419 2420
	if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
	    b.index >= cam->nbuffers || cam->io != IO_MMAP)
		return -EINVAL;
L
Linus Torvalds 已提交
2421

2422
	memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
L
Linus Torvalds 已提交
2423

2424 2425
	if (cam->frame[b.index].vma_use_count)
		b.flags |= V4L2_BUF_FLAG_MAPPED;
L
Linus Torvalds 已提交
2426

2427 2428 2429 2430
	if (cam->frame[b.index].state == F_DONE)
		b.flags |= V4L2_BUF_FLAG_DONE;
	else if (cam->frame[b.index].state != F_UNUSED)
		b.flags |= V4L2_BUF_FLAG_QUEUED;
L
Linus Torvalds 已提交
2431

2432 2433
	if (copy_to_user(arg, &b, sizeof(b)))
		return -EFAULT;
L
Linus Torvalds 已提交
2434

2435 2436
	return 0;
}
L
Linus Torvalds 已提交
2437 2438


2439 2440 2441 2442 2443
static int
sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg)
{
	struct v4l2_buffer b;
	unsigned long lock_flags;
L
Linus Torvalds 已提交
2444

2445 2446
	if (copy_from_user(&b, arg, sizeof(b)))
		return -EFAULT;
L
Linus Torvalds 已提交
2447

2448 2449 2450
	if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
	    b.index >= cam->nbuffers || cam->io != IO_MMAP)
		return -EINVAL;
L
Linus Torvalds 已提交
2451

2452 2453
	if (cam->frame[b.index].state != F_UNUSED)
		return -EINVAL;
L
Linus Torvalds 已提交
2454

2455
	cam->frame[b.index].state = F_QUEUED;
L
Linus Torvalds 已提交
2456

2457 2458 2459
	spin_lock_irqsave(&cam->queue_lock, lock_flags);
	list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
L
Linus Torvalds 已提交
2460

2461
	PDBGG("Frame #%lu queued", (unsigned long)b.index);
L
Linus Torvalds 已提交
2462

2463 2464
	return 0;
}
L
Linus Torvalds 已提交
2465 2466


2467 2468
static int
sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
2469
		     void __user * arg)
2470 2471 2472 2473
{
	struct v4l2_buffer b;
	struct sn9c102_frame_t *f;
	unsigned long lock_flags;
2474
	long timeout;
L
Linus Torvalds 已提交
2475

2476 2477
	if (copy_from_user(&b, arg, sizeof(b)))
		return -EFAULT;
L
Linus Torvalds 已提交
2478

2479 2480 2481 2482 2483 2484 2485 2486
	if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
		return -EINVAL;

	if (list_empty(&cam->outqueue)) {
		if (cam->stream == STREAM_OFF)
			return -EINVAL;
		if (filp->f_flags & O_NONBLOCK)
			return -EAGAIN;
2487
		timeout = wait_event_interruptible_timeout
2488 2489 2490 2491 2492 2493
			  ( cam->wait_frame,
			    (!list_empty(&cam->outqueue)) ||
			    (cam->state & DEV_DISCONNECTED) ||
			    (cam->state & DEV_MISCONFIGURED),
			    cam->module_param.frame_timeout *
			    1000 * msecs_to_jiffies(1) );
2494 2495
		if (timeout < 0)
			return timeout;
2496 2497
		if (cam->state & DEV_DISCONNECTED)
			return -ENODEV;
2498
		if (!timeout || (cam->state & DEV_MISCONFIGURED))
2499
			return -EIO;
L
Linus Torvalds 已提交
2500 2501
	}

2502 2503 2504 2505
	spin_lock_irqsave(&cam->queue_lock, lock_flags);
	f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame);
	list_del(cam->outqueue.next);
	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
L
Linus Torvalds 已提交
2506

2507
	f->state = F_UNUSED;
L
Linus Torvalds 已提交
2508

2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599
	memcpy(&b, &f->buf, sizeof(b));
	if (f->vma_use_count)
		b.flags |= V4L2_BUF_FLAG_MAPPED;

	if (copy_to_user(arg, &b, sizeof(b)))
		return -EFAULT;

	PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);

	return 0;
}


static int
sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg)
{
	int type;

	if (copy_from_user(&type, arg, sizeof(type)))
		return -EFAULT;

	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
		return -EINVAL;

	if (list_empty(&cam->inqueue))
		return -EINVAL;

	cam->stream = STREAM_ON;

	DBG(3, "Stream on");

	return 0;
}


static int
sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg)
{
	int type, err;

	if (copy_from_user(&type, arg, sizeof(type)))
		return -EFAULT;

	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
		return -EINVAL;

	if (cam->stream == STREAM_ON)
		if ((err = sn9c102_stream_interrupt(cam)))
			return err;

	sn9c102_empty_framequeues(cam);

	DBG(3, "Stream off");

	return 0;
}


static int
sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg)
{
	struct v4l2_streamparm sp;

	if (copy_from_user(&sp, arg, sizeof(sp)))
		return -EFAULT;

	if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;

	sp.parm.capture.extendedmode = 0;
	sp.parm.capture.readbuffers = cam->nreadbuffers;

	if (copy_to_user(arg, &sp, sizeof(sp)))
		return -EFAULT;

	return 0;
}


static int
sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
{
	struct v4l2_streamparm sp;

	if (copy_from_user(&sp, arg, sizeof(sp)))
		return -EFAULT;

	if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;

	sp.parm.capture.extendedmode = 0;
L
Linus Torvalds 已提交
2600

2601
	if (sp.parm.capture.readbuffers == 0)
L
Linus Torvalds 已提交
2602 2603
		sp.parm.capture.readbuffers = cam->nreadbuffers;

2604 2605
	if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
		sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
L
Linus Torvalds 已提交
2606

2607 2608
	if (copy_to_user(arg, &sp, sizeof(sp)))
		return -EFAULT;
L
Linus Torvalds 已提交
2609

2610
	cam->nreadbuffers = sp.parm.capture.readbuffers;
L
Linus Torvalds 已提交
2611

2612 2613
	return 0;
}
L
Linus Torvalds 已提交
2614 2615


2616
static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
2617
			      unsigned int cmd, void __user * arg)
2618 2619
{
	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
L
Linus Torvalds 已提交
2620

2621
	switch (cmd) {
L
Linus Torvalds 已提交
2622

2623 2624
	case VIDIOC_QUERYCAP:
		return sn9c102_vidioc_querycap(cam, arg);
L
Linus Torvalds 已提交
2625

2626 2627
	case VIDIOC_ENUMINPUT:
		return sn9c102_vidioc_enuminput(cam, arg);
L
Linus Torvalds 已提交
2628

2629
	case VIDIOC_G_INPUT:
2630 2631
		return sn9c102_vidioc_g_input(cam, arg);

2632
	case VIDIOC_S_INPUT:
2633
		return sn9c102_vidioc_s_input(cam, arg);
L
Linus Torvalds 已提交
2634

2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691
	case VIDIOC_QUERYCTRL:
		return sn9c102_vidioc_query_ctrl(cam, arg);

	case VIDIOC_G_CTRL:
		return sn9c102_vidioc_g_ctrl(cam, arg);

	case VIDIOC_S_CTRL:
		return sn9c102_vidioc_s_ctrl(cam, arg);

	case VIDIOC_CROPCAP:
		return sn9c102_vidioc_cropcap(cam, arg);

	case VIDIOC_G_CROP:
		return sn9c102_vidioc_g_crop(cam, arg);

	case VIDIOC_S_CROP:
		return sn9c102_vidioc_s_crop(cam, arg);

	case VIDIOC_ENUM_FMT:
		return sn9c102_vidioc_enum_fmt(cam, arg);

	case VIDIOC_G_FMT:
		return sn9c102_vidioc_g_fmt(cam, arg);

	case VIDIOC_TRY_FMT:
	case VIDIOC_S_FMT:
		return sn9c102_vidioc_try_s_fmt(cam, cmd, arg);

	case VIDIOC_G_JPEGCOMP:
		return sn9c102_vidioc_g_jpegcomp(cam, arg);

	case VIDIOC_S_JPEGCOMP:
		return sn9c102_vidioc_s_jpegcomp(cam, arg);

	case VIDIOC_REQBUFS:
		return sn9c102_vidioc_reqbufs(cam, arg);

	case VIDIOC_QUERYBUF:
		return sn9c102_vidioc_querybuf(cam, arg);

	case VIDIOC_QBUF:
		return sn9c102_vidioc_qbuf(cam, arg);

	case VIDIOC_DQBUF:
		return sn9c102_vidioc_dqbuf(cam, filp, arg);

	case VIDIOC_STREAMON:
		return sn9c102_vidioc_streamon(cam, arg);

	case VIDIOC_STREAMOFF:
		return sn9c102_vidioc_streamoff(cam, arg);

	case VIDIOC_G_PARM:
		return sn9c102_vidioc_g_parm(cam, arg);

	case VIDIOC_S_PARM:
		return sn9c102_vidioc_s_parm(cam, arg);
L
Linus Torvalds 已提交
2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707

	case VIDIOC_G_STD:
	case VIDIOC_S_STD:
	case VIDIOC_QUERYSTD:
	case VIDIOC_ENUMSTD:
	case VIDIOC_QUERYMENU:
		return -EINVAL;

	default:
		return -EINVAL;

	}
}


static int sn9c102_ioctl(struct inode* inode, struct file* filp,
2708
			 unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
2709 2710 2711 2712
{
	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
	int err = 0;

2713
	if (mutex_lock_interruptible(&cam->fileop_mutex))
L
Linus Torvalds 已提交
2714 2715 2716
		return -ERESTARTSYS;

	if (cam->state & DEV_DISCONNECTED) {
2717
		DBG(1, "Device not present");
2718
		mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
2719 2720 2721 2722
		return -ENODEV;
	}

	if (cam->state & DEV_MISCONFIGURED) {
2723 2724
		DBG(1, "The camera is misconfigured. Close and open it "
		       "again.");
2725
		mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
2726 2727 2728
		return -EIO;
	}

2729 2730
	V4LDBG(3, "sn9c102", cmd);

L
Linus Torvalds 已提交
2731 2732
	err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);

2733
	mutex_unlock(&cam->fileop_mutex);
L
Linus Torvalds 已提交
2734 2735 2736 2737

	return err;
}

2738
/*****************************************************************************/
L
Linus Torvalds 已提交
2739 2740

static struct file_operations sn9c102_fops = {
2741
	.owner = THIS_MODULE,
L
Linus Torvalds 已提交
2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759
	.open =    sn9c102_open,
	.release = sn9c102_release,
	.ioctl =   sn9c102_ioctl,
	.read =    sn9c102_read,
	.poll =    sn9c102_poll,
	.mmap =    sn9c102_mmap,
	.llseek =  no_llseek,
};

/*****************************************************************************/

/* It exists a single interface only. We do not need to validate anything. */
static int
sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
{
	struct usb_device *udev = interface_to_usbdev(intf);
	struct sn9c102_device* cam;
	static unsigned int dev_nr = 0;
2760
	unsigned int i;
L
Linus Torvalds 已提交
2761 2762
	int err = 0, r;

2763
	if (!(cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL)))
L
Linus Torvalds 已提交
2764 2765 2766 2767
		return -ENOMEM;

	cam->usbdev = udev;

2768
	if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
2769
		DBG(1, "kmalloc() failed");
L
Linus Torvalds 已提交
2770 2771 2772 2773 2774
		err = -ENOMEM;
		goto fail;
	}

	if (!(cam->v4ldev = video_device_alloc())) {
2775
		DBG(1, "video_device_alloc() failed");
L
Linus Torvalds 已提交
2776 2777 2778 2779
		err = -ENOMEM;
		goto fail;
	}

2780
	mutex_init(&cam->dev_mutex);
L
Linus Torvalds 已提交
2781 2782 2783 2784

	r = sn9c102_read_reg(cam, 0x00);
	if (r < 0 || r != 0x10) {
		DBG(1, "Sorry, this is not a SN9C10x based camera "
2785
		       "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
L
Linus Torvalds 已提交
2786 2787 2788 2789
		err = -ENODEV;
		goto fail;
	}

2790
	cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ?
2791
		      BRIDGE_SN9C103 : BRIDGE_SN9C102;
L
Linus Torvalds 已提交
2792 2793 2794 2795
	switch (cam->bridge) {
	case BRIDGE_SN9C101:
	case BRIDGE_SN9C102:
		DBG(2, "SN9C10[12] PC Camera Controller detected "
2796
		       "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
L
Linus Torvalds 已提交
2797 2798 2799
		break;
	case BRIDGE_SN9C103:
		DBG(2, "SN9C103 PC Camera Controller detected "
2800
		       "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
L
Linus Torvalds 已提交
2801 2802 2803 2804 2805 2806 2807 2808 2809
		break;
	}

	for  (i = 0; sn9c102_sensor_table[i]; i++) {
		err = sn9c102_sensor_table[i](cam);
		if (!err)
			break;
	}

2810 2811
	if (!err) {
		DBG(2, "%s image sensor detected", cam->sensor.name);
L
Linus Torvalds 已提交
2812
		DBG(3, "Support for %s maintained by %s",
2813
		    cam->sensor.name, cam->sensor.maintainer);
L
Linus Torvalds 已提交
2814
	} else {
2815
		DBG(1, "No supported image sensor detected");
L
Linus Torvalds 已提交
2816 2817 2818 2819 2820
		err = -ENODEV;
		goto fail;
	}

	if (sn9c102_init(cam)) {
2821
		DBG(1, "Initialization failed. I will retry on open().");
L
Linus Torvalds 已提交
2822 2823 2824 2825 2826 2827
		cam->state |= DEV_MISCONFIGURED;
	}

	strcpy(cam->v4ldev->name, "SN9C10x PC Camera");
	cam->v4ldev->owner = THIS_MODULE;
	cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
2828
	cam->v4ldev->hardware = 0;
L
Linus Torvalds 已提交
2829 2830 2831 2832 2833
	cam->v4ldev->fops = &sn9c102_fops;
	cam->v4ldev->minor = video_nr[dev_nr];
	cam->v4ldev->release = video_device_release;
	video_set_drvdata(cam->v4ldev, cam);

2834
	mutex_lock(&cam->dev_mutex);
L
Linus Torvalds 已提交
2835 2836

	err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
2837
				    video_nr[dev_nr]);
L
Linus Torvalds 已提交
2838
	if (err) {
2839
		DBG(1, "V4L2 device registration failed");
L
Linus Torvalds 已提交
2840
		if (err == -ENFILE && video_nr[dev_nr] == -1)
2841
			DBG(1, "Free /dev/videoX node not found");
2842
		goto fail2;
L
Linus Torvalds 已提交
2843 2844
	}

2845
	DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
L
Linus Torvalds 已提交
2846 2847

	cam->module_param.force_munmap = force_munmap[dev_nr];
2848
	cam->module_param.frame_timeout = frame_timeout[dev_nr];
L
Linus Torvalds 已提交
2849 2850 2851

	dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;

2852
#ifdef CONFIG_VIDEO_ADV_DEBUG
2853 2854 2855
	err = sn9c102_create_sysfs(cam);
	if (err)
		goto fail3;
2856
	DBG(2, "Optional device control through 'sysfs' interface ready");
2857
#endif
L
Linus Torvalds 已提交
2858 2859 2860

	usb_set_intfdata(intf, cam);

2861
	mutex_unlock(&cam->dev_mutex);
L
Linus Torvalds 已提交
2862 2863 2864

	return 0;

2865 2866 2867 2868 2869 2870 2871 2872
#ifdef CONFIG_VIDEO_ADV_DEBUG
fail3:
	video_unregister_device(cam->v4ldev);
#endif
fail2:
	video_nr[dev_nr] = -1;
	dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
	mutex_unlock(&cam->dev_mutex);
L
Linus Torvalds 已提交
2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892
fail:
	if (cam) {
		kfree(cam->control_buffer);
		if (cam->v4ldev)
			video_device_release(cam->v4ldev);
		kfree(cam);
	}
	return err;
}


static void sn9c102_usb_disconnect(struct usb_interface* intf)
{
	struct sn9c102_device* cam = usb_get_intfdata(intf);

	if (!cam)
		return;

	down_write(&sn9c102_disconnect);

2893
	mutex_lock(&cam->dev_mutex);
L
Linus Torvalds 已提交
2894

2895
	DBG(2, "Disconnecting %s...", cam->v4ldev->name);
L
Linus Torvalds 已提交
2896 2897 2898 2899 2900 2901

	wake_up_interruptible_all(&cam->open);

	if (cam->users) {
		DBG(2, "Device /dev/video%d is open! Deregistration and "
		       "memory deallocation are deferred on close.",
2902
		    cam->v4ldev->minor);
L
Linus Torvalds 已提交
2903 2904 2905 2906
		cam->state |= DEV_MISCONFIGURED;
		sn9c102_stop_transfer(cam);
		cam->state |= DEV_DISCONNECTED;
		wake_up_interruptible(&cam->wait_frame);
2907 2908
		wake_up(&cam->wait_stream);
		usb_get_dev(cam->usbdev);
L
Linus Torvalds 已提交
2909 2910 2911 2912 2913
	} else {
		cam->state |= DEV_DISCONNECTED;
		sn9c102_release_resources(cam);
	}

2914
	mutex_unlock(&cam->dev_mutex);
L
Linus Torvalds 已提交
2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935

	if (!cam->users)
		kfree(cam);

	up_write(&sn9c102_disconnect);
}


static struct usb_driver sn9c102_usb_driver = {
	.name =       "sn9c102",
	.id_table =   sn9c102_id_table,
	.probe =      sn9c102_usb_probe,
	.disconnect = sn9c102_usb_disconnect,
};

/*****************************************************************************/

static int __init sn9c102_module_init(void)
{
	int err = 0;

2936 2937
	KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION);
	KDBG(3, SN9C102_MODULE_AUTHOR);
L
Linus Torvalds 已提交
2938 2939

	if ((err = usb_register(&sn9c102_usb_driver)))
2940
		KDBG(1, "usb_register() failed");
L
Linus Torvalds 已提交
2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953

	return err;
}


static void __exit sn9c102_module_exit(void)
{
	usb_deregister(&sn9c102_usb_driver);
}


module_init(sn9c102_module_init);
module_exit(sn9c102_module_exit);