Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ab8f12cf authored by Hans de Goede's avatar Hans de Goede Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (8197): gspca: pac207 frames no more decoded in the subdriver.



videodev2: New pixfmt
pac207:   Remove the specific decoding.
main:     get_buff_size operation added for the subdriver.

Signed-off-by: default avatarHans de Goede <j.w.r.degoede@hhs.nl>
Signed-off-by: default avatarJean-Francois Moine <moinejf@free.fr>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 24c530b4
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -321,6 +321,7 @@ static int gspca_is_compressed(__u32 format)
	case V4L2_PIX_FMT_MJPEG:
	case V4L2_PIX_FMT_JPEG:
	case V4L2_PIX_FMT_SPCA561:
	case V4L2_PIX_FMT_PAC207:
		return 1;
	}
	return 0;
@@ -380,7 +381,8 @@ static __u32 get_v4l2_depth(__u32 pixfmt)
	case V4L2_PIX_FMT_JPEG:
	case V4L2_PIX_FMT_SBGGR8:	/* 'BA81' Bayer */
	case V4L2_PIX_FMT_SN9C10X:	/* 'S910' SN9C10x compression */
	case V4L2_PIX_FMT_SPCA561:	/* 'S561' compressed BGGR bayer */
	case V4L2_PIX_FMT_SPCA561:	/* 'S561' compressed GBRG bayer */
	case V4L2_PIX_FMT_PAC207:	/* 'P207' compressed BGGR bayer */
		return 8;
	}
	PDEBUG(D_ERR|D_CONF, "Unknown pixel format %c%c%c%c",
@@ -395,6 +397,9 @@ static int gspca_get_buff_size(struct gspca_dev *gspca_dev, int mode)
{
	unsigned int size;

	if (gspca_dev->sd_desc->get_buff_size)
		return gspca_dev->sd_desc->get_buff_size(gspca_dev, mode);

	size =  gspca_dev->cam.cam_mode[mode].width *
		gspca_dev->cam.cam_mode[mode].height *
		get_v4l2_depth(gspca_dev->cam.cam_mode[mode].pixfmt) / 8;
+2 −0
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
				struct gspca_frame *frame,
				__u8 *data,
				int len);
typedef int (*cam_get_buff_size_op) (struct gspca_dev *gspca_dev, int mode);

struct ctrl {
	struct v4l2_queryctrl qctrl;
@@ -106,6 +107,7 @@ struct sd_desc {
	cam_jpg_op get_jcomp;
	cam_jpg_op set_jcomp;
	cam_qmnu_op querymenu;
	cam_get_buff_size_op get_buff_size; /* optional */
};

/* packet types when moving from iso buf to frame buf */
+43 −310
Original line number Diff line number Diff line
@@ -58,34 +58,10 @@ MODULE_LICENSE("GPL");
   before doing any other adjustments */
#define PAC207_AUTOGAIN_IGNORE_FRAMES	3

enum pac207_line_state {
	LINE_HEADER1,
	LINE_HEADER2,
	LINE_UNCOMPRESSED,
	LINE_COMPRESSED,
};

struct pac207_decoder_state {
	/* generic state */
	u16 line_read;
	u16 line_marker;
	u8 line_state;
	u8 header_read;
	/* compression state */
	u16 processed_bytes;
	u8 remaining_bits;
	s8 no_remaining_bits;
	u8 get_abs;
	u8 discard_byte;
	u8 line_decode_buf[352];
};

/* specific webcam descriptor */
struct sd {
	struct gspca_dev gspca_dev;		/* !! must be the first item */

	struct pac207_decoder_state decoder_state;

	u8 mode;

	u8 brightness;
@@ -94,6 +70,7 @@ struct sd {
	u8 gain;

	u8 sof_read;
	u8 header_read;
	u8 autogain_ignore_frames;

	atomic_t avg_lum;
@@ -173,8 +150,8 @@ static struct ctrl sd_ctrls[] = {
};

static struct cam_mode sif_mode[] = {
	{V4L2_PIX_FMT_SBGGR8, 176, 144, 1},
	{V4L2_PIX_FMT_SBGGR8, 352, 288, 0},
	{V4L2_PIX_FMT_PAC207, 176, 144, 1},
	{V4L2_PIX_FMT_PAC207, 352, 288, 0},
};

static const __u8 pac207_sensor_init[][8] = {
@@ -361,68 +338,17 @@ static void sd_close(struct gspca_dev *gspca_dev)
{
}

/* -- convert pixart frames to Bayer -- */
/* Sonix decompressor struct B.S.(2004) */
static struct {
	u8 is_abs;
	u8 len;
	s8 val;
} table[256];

void init_pixart_decoder(void)
{
	int i, is_abs, val, len;

	for (i = 0; i < 256; i++) {
		is_abs = 0;
		val = 0;
		len = 0;
		if ((i & 0xC0) == 0) {
			/* code 00 */
			val = 0;
			len = 2;
		} else if ((i & 0xC0) == 0x40) {
			/* code 01 */
			val = -5;
			len = 2;
		} else if ((i & 0xC0) == 0x80) {
			/* code 10 */
			val = 5;
			len = 2;
		} else if ((i & 0xF0) == 0xC0) {
			/* code 1100 */
			val = -10;
			len = 4;
		} else if ((i & 0xF0) == 0xD0) {
			/* code 1101 */
			val = 10;
			len = 4;
		} else if ((i & 0xF8) == 0xE0) {
			/* code 11100 */
			val = -15;
			len = 5;
		} else if ((i & 0xF8) == 0xE8) {
			/* code 11101 */
			val = 15;
			len = 5;
		} else if ((i & 0xFC) == 0xF0) {
			/* code 111100 */
			val = -20;
			len = 6;
		} else if ((i & 0xFC) == 0xF4) {
			/* code 111101 */
			val = 20;
			len = 6;
		} else if ((i & 0xF8) == 0xF8) {
			/* code 11111xxxxxx */
			is_abs = 1;
			val = 0;
			len = 5;
		}
		table[i].is_abs = is_abs;
		table[i].val = val;
		table[i].len = len;
static int sd_get_buff_size_op(struct gspca_dev *gspca_dev, int mode)
{
	switch (gspca_dev->cam.cam_mode[mode].width) {
	case 176: /* 176x144 */
		/* uncompressed, add 2 bytes / line for line header */
		return (176 + 2) * 144;
	case 352: /* 352x288 */
		/* compressed */
		return 352 * 288 / 2;
	}
	return -EIO; /* should never happen */
}

/* auto gain and exposure algorithm based on the knee algorithm described here:
@@ -517,245 +443,52 @@ static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
	return NULL;
}

static int pac207_decompress_row(struct gspca_dev *gspca_dev,
				struct gspca_frame *f,
				__u8 *cdata,
				int len)
{
	struct sd *sd = (struct sd *) gspca_dev;
	struct pac207_decoder_state *decoder_state = &sd->decoder_state;
	unsigned char *outp = decoder_state->line_decode_buf +
				decoder_state->line_read;
	int val, bitlen, bitpos = -decoder_state->no_remaining_bits;
	u8 code;

	/* first two pixels are stored as raw 8-bit */
	while (decoder_state->line_read < 2) {
		*outp++ = *cdata++;
		decoder_state->line_read++;
		len--;
		if (len == 0)
			return 0;
	}

	while (decoder_state->line_read < gspca_dev->width) {
		if (bitpos < 0) {
			code = decoder_state->remaining_bits << (8 + bitpos) |
				cdata[0] >> -bitpos;
		} else {
			u8 *addr = cdata + bitpos / 8;
			code = addr[0] << (bitpos & 7) |
				addr[1] >> (8 - (bitpos & 7));
		}

		bitlen = decoder_state->get_abs ?
				6 : table[code].len;

		/* Stop decompressing if we're out of input data */
		if ((bitpos + bitlen) > (len * 8))
			break;

		if (decoder_state->get_abs) {
			*outp++ = code & 0xFC;
			decoder_state->line_read++;
			decoder_state->get_abs = 0;
		} else {
			if (table[code].is_abs) {
				decoder_state->get_abs = 1;
			} else {
				/* relative to left pixel */
				val = outp[-2] +
					table[code].val;
				if (val > 0xff)
					val = 0xff;
				else if (val < 0)
					val = 0;
				*outp++ = val;
				decoder_state->line_read++;
			}
		}
		bitpos += bitlen;
	}

	if (decoder_state->line_read == gspca_dev->width) {
		int compressed_line_len;

		gspca_frame_add(gspca_dev, INTER_PACKET, f,
				decoder_state->line_decode_buf,
				gspca_dev->width);

		/* completely decompressed line, round pos to nearest word */
		compressed_line_len = ((decoder_state->processed_bytes * 8 +
			bitpos + 15) / 16) * 2;

		len -= compressed_line_len - decoder_state->processed_bytes;
		if (len < 0) {
			decoder_state->discard_byte = 1;
			len = 0;
		}
	} else {
		decoder_state->processed_bytes += len;
		decoder_state->remaining_bits = cdata[bitpos/8];
		decoder_state->no_remaining_bits = (8 - bitpos) & 7;
		len = 0;
	}

	return len;
}

static void pac207_decode_line_init(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	struct pac207_decoder_state *decoder_state = &sd->decoder_state;

	decoder_state->line_read = 0;
	decoder_state->line_state = LINE_HEADER1;
	decoder_state->processed_bytes = 0;
	decoder_state->no_remaining_bits = 0;
	decoder_state->get_abs = 0;
}

static void pac207_decode_frame_init(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	struct pac207_decoder_state *decoder_state = &sd->decoder_state;

	decoder_state->header_read = 0;
	decoder_state->discard_byte = 0;

	pac207_decode_line_init(gspca_dev);
}

static int pac207_decode_frame_data(struct gspca_dev *gspca_dev,
	struct gspca_frame *f, unsigned char *data, int len)
{
	struct sd *sd = (struct sd *) gspca_dev;
	struct pac207_decoder_state *decoder_state = &sd->decoder_state;
	int needed = 0;

	/* first 11 bytes after sof marker: frame header */
	if (decoder_state->header_read < 11) {
		/* get average lumination from frame header (byte 5) */
		if (decoder_state->header_read < 5) {
			needed = 5 - decoder_state->header_read;
			if (len >= needed)
				atomic_set(&sd->avg_lum, data[needed-1]);
		}
		/* skip the rest of the header */
		needed = 11 - decoder_state->header_read;
		if (len <= needed) {
			decoder_state->header_read += len;
			return 0;
		}
		data += needed;
		len -= needed;
		decoder_state->header_read = 11;
	}

	while (len) {
		if (decoder_state->discard_byte) {
			data++;
			len--;
			decoder_state->discard_byte = 0;
			continue;
		}

		switch (decoder_state->line_state) {
		case LINE_HEADER1:
			decoder_state->line_marker = data[0] << 8;
			decoder_state->line_state = LINE_HEADER2;
			needed = 1;
			break;
		case LINE_HEADER2:
			decoder_state->line_marker |= data[0];
			switch (decoder_state->line_marker) {
			case 0x0ff0:
				decoder_state->line_state = LINE_UNCOMPRESSED;
				break;
			case 0x1ee1:
				decoder_state->line_state = LINE_COMPRESSED;
				break;
			default:
				PDEBUG(D_STREAM,
					"Error unknown line-header %04X",
					(int) decoder_state->line_marker);
				gspca_dev->last_packet_type = DISCARD_PACKET;
				return 0;
			}
			needed = 1;
			break;
		case LINE_UNCOMPRESSED:
			needed = gspca_dev->width - decoder_state->line_read;
			if (needed > len)
				needed = len;
			gspca_frame_add(gspca_dev, INTER_PACKET, f, data,
				needed);
			decoder_state->line_read += needed;
			break;
		case LINE_COMPRESSED:
			needed = len -
				pac207_decompress_row(gspca_dev, f, data, len);
			break;
		}

		data += needed;
		len -= needed;

		if (decoder_state->line_read == gspca_dev->width) {
			if ((f->data_end - f->data) ==
				(gspca_dev->width * gspca_dev->height)) {
				/* eureka we've got a frame */
				return 1;
			}
			pac207_decode_line_init(gspca_dev);
		}
	}

	return 0;
}

static void sd_pkt_scan(struct gspca_dev *gspca_dev,
			struct gspca_frame *frame,
			__u8 *data,
			int len)
{
	struct sd *sd = (struct sd *) gspca_dev;
	unsigned char *sof;
	int n;

	sof = pac207_find_sof(gspca_dev, data, len);

	if (sof) {
		int n;

		/* finish decoding current frame */
		if (gspca_dev->last_packet_type == INTER_PACKET) {
		n = sof - data;
			if (n > sizeof(pac207_sof_marker))
				n -= sizeof(pac207_sof_marker);
		if (n > sizeof pac207_sof_marker)
			n -= sizeof pac207_sof_marker;
		else
			n = 0;
			n = pac207_decode_frame_data(gspca_dev, frame,
		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
					data, n);
			if (n)
				frame = gspca_frame_add(gspca_dev,
						LAST_PACKET,
						frame,
						NULL,
						0);
			else
				PDEBUG(D_STREAM, "Incomplete frame");
		}
		pac207_decode_frame_init(gspca_dev);
		sd->header_read = 0;
		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
		len -= sof - data;
		data = sof;
	}
	if (sd->header_read < 11) {
		int needed;

	if (gspca_dev->last_packet_type == DISCARD_PACKET)
		/* get average lumination from frame header (byte 5) */
		if (sd->header_read < 5) {
			needed = 5 - sd->header_read;
			if (len >= needed)
				atomic_set(&sd->avg_lum, data[needed - 1]);
		}
		/* skip the rest of the header */
		needed = 11 - sd->header_read;
		if (len <= needed) {
			sd->header_read += len;
			return;
		}
		data += needed;
		len -= needed;
		sd->header_read = 11;
	}

	n = pac207_decode_frame_data(gspca_dev, frame, data, len);
	if (n)
		gspca_frame_add(gspca_dev, LAST_PACKET,
				frame, NULL, 0);
	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}

static void setbrightness(struct gspca_dev *gspca_dev)
@@ -891,6 +624,7 @@ static const struct sd_desc sd_desc = {
	.close = sd_close,
	.dq_callback = pac207_do_auto_gain,
	.pkt_scan = sd_pkt_scan,
	.get_buff_size = sd_get_buff_size_op,
};

/* -- module initialisation -- */
@@ -927,7 +661,6 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
	init_pixart_decoder();
	if (usb_register(&sd_driver) < 0)
		return -1;
	PDEBUG(D_PROBE, "v%s registered", version);
+2 −1
Original line number Diff line number Diff line
@@ -326,7 +326,8 @@ struct v4l2_pix_format
#define V4L2_PIX_FMT_PWC2     v4l2_fourcc('P','W','C','2') /* pwc newer webcam */
#define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E','6','2','5') /* ET61X251 compression */
#define V4L2_PIX_FMT_SPCA501  v4l2_fourcc('S','5','0','1') /* YUYV per line */
#define V4L2_PIX_FMT_SPCA561  v4l2_fourcc('S','5','6','1') /* compressed BGGR bayer */
#define V4L2_PIX_FMT_SPCA561  v4l2_fourcc('S','5','6','1') /* compressed GBRG bayer */
#define V4L2_PIX_FMT_PAC207   v4l2_fourcc('P','2','0','7') /* compressed BGGR bayer */

/*
 *	F O R M A T   E N U M E R A T I O N