brintos

brintos / linux-shallow public Read only

0
0
Text · 10.1 KiB · ccc4779 Raw
439 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * spca1528 subdriver4 *5 * Copyright (C) 2010-2011 Jean-Francois Moine (http://moinejf.free.fr)6 */7 8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt9 10#define MODULE_NAME "spca1528"11 12#include "gspca.h"13#include "jpeg.h"14 15MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");16MODULE_DESCRIPTION("SPCA1528 USB Camera Driver");17MODULE_LICENSE("GPL");18 19/* specific webcam descriptor */20struct sd {21	struct gspca_dev gspca_dev;	/* !! must be the first item */22 23	u8 pkt_seq;24 25	u8 jpeg_hdr[JPEG_HDR_SZ];26};27 28static const struct v4l2_pix_format vga_mode[] = {29/*		(does not work correctly)30	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,31		.bytesperline = 176,32		.sizeimage = 176 * 144 * 5 / 8 + 590,33		.colorspace = V4L2_COLORSPACE_JPEG,34		.priv = 3},35*/36	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,37		.bytesperline = 320,38		.sizeimage = 320 * 240 * 4 / 8 + 590,39		.colorspace = V4L2_COLORSPACE_JPEG,40		.priv = 2},41	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,42		.bytesperline = 640,43		.sizeimage = 640 * 480 * 3 / 8 + 590,44		.colorspace = V4L2_COLORSPACE_JPEG,45		.priv = 1},46};47 48/* read <len> bytes to gspca usb_buf */49static void reg_r(struct gspca_dev *gspca_dev,50			u8 req,51			u16 index,52			int len)53{54#if USB_BUF_SZ < 6455#error "USB buffer too small"56#endif57	struct usb_device *dev = gspca_dev->dev;58	int ret;59 60	if (gspca_dev->usb_err < 0)61		return;62	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),63			req,64			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,65			0x0000,			/* value */66			index,67			gspca_dev->usb_buf, len,68			500);69	gspca_dbg(gspca_dev, D_USBI, "GET %02x 0000 %04x %02x\n", req, index,70		  gspca_dev->usb_buf[0]);71	if (ret < 0) {72		pr_err("reg_r err %d\n", ret);73		gspca_dev->usb_err = ret;74		/*75		 * Make sure the buffer is zeroed to avoid uninitialized76		 * values.77		 */78		memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);79	}80}81 82static void reg_w(struct gspca_dev *gspca_dev,83			u8 req,84			u16 value,85			u16 index)86{87	struct usb_device *dev = gspca_dev->dev;88	int ret;89 90	if (gspca_dev->usb_err < 0)91		return;92	gspca_dbg(gspca_dev, D_USBO, "SET %02x %04x %04x\n", req, value, index);93	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),94			req,95			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,96			value, index,97			NULL, 0, 500);98	if (ret < 0) {99		pr_err("reg_w err %d\n", ret);100		gspca_dev->usb_err = ret;101	}102}103 104static void reg_wb(struct gspca_dev *gspca_dev,105			u8 req,106			u16 value,107			u16 index,108			u8 byte)109{110	struct usb_device *dev = gspca_dev->dev;111	int ret;112 113	if (gspca_dev->usb_err < 0)114		return;115	gspca_dbg(gspca_dev, D_USBO, "SET %02x %04x %04x %02x\n",116		  req, value, index, byte);117	gspca_dev->usb_buf[0] = byte;118	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),119			req,120			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,121			value, index,122			gspca_dev->usb_buf, 1, 500);123	if (ret < 0) {124		pr_err("reg_w err %d\n", ret);125		gspca_dev->usb_err = ret;126	}127}128 129static void wait_status_0(struct gspca_dev *gspca_dev)130{131	int i, w;132 133	i = 16;134	w = 0;135	do {136		reg_r(gspca_dev, 0x21, 0x0000, 1);137		if (gspca_dev->usb_buf[0] == 0)138			return;139		w += 15;140		msleep(w);141	} while (--i > 0);142	gspca_err(gspca_dev, "wait_status_0 timeout\n");143	gspca_dev->usb_err = -ETIME;144}145 146static void wait_status_1(struct gspca_dev *gspca_dev)147{148	int i;149 150	i = 10;151	do {152		reg_r(gspca_dev, 0x21, 0x0001, 1);153		msleep(10);154		if (gspca_dev->usb_buf[0] == 1) {155			reg_wb(gspca_dev, 0x21, 0x0000, 0x0001, 0x00);156			reg_r(gspca_dev, 0x21, 0x0001, 1);157			return;158		}159	} while (--i > 0);160	gspca_err(gspca_dev, "wait_status_1 timeout\n");161	gspca_dev->usb_err = -ETIME;162}163 164static void setbrightness(struct gspca_dev *gspca_dev, s32 val)165{166	reg_wb(gspca_dev, 0xc0, 0x0000, 0x00c0, val);167}168 169static void setcontrast(struct gspca_dev *gspca_dev, s32 val)170{171	reg_wb(gspca_dev, 0xc1, 0x0000, 0x00c1, val);172}173 174static void sethue(struct gspca_dev *gspca_dev, s32 val)175{176	reg_wb(gspca_dev, 0xc2, 0x0000, 0x0000, val);177}178 179static void setcolor(struct gspca_dev *gspca_dev, s32 val)180{181	reg_wb(gspca_dev, 0xc3, 0x0000, 0x00c3, val);182}183 184static void setsharpness(struct gspca_dev *gspca_dev, s32 val)185{186	reg_wb(gspca_dev, 0xc4, 0x0000, 0x00c4, val);187}188 189/* this function is called at probe time */190static int sd_config(struct gspca_dev *gspca_dev,191			const struct usb_device_id *id)192{193	gspca_dev->cam.cam_mode = vga_mode;194	gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);195	gspca_dev->cam.npkt = 128; /* number of packets per ISOC message */196			/*fixme: 256 in ms-win traces*/197 198	return 0;199}200 201/* this function is called at probe and resume time */202static int sd_init(struct gspca_dev *gspca_dev)203{204	reg_w(gspca_dev, 0x00, 0x0001, 0x2067);205	reg_w(gspca_dev, 0x00, 0x00d0, 0x206b);206	reg_w(gspca_dev, 0x00, 0x0000, 0x206c);207	reg_w(gspca_dev, 0x00, 0x0001, 0x2069);208	msleep(8);209	reg_w(gspca_dev, 0x00, 0x00c0, 0x206b);210	reg_w(gspca_dev, 0x00, 0x0000, 0x206c);211	reg_w(gspca_dev, 0x00, 0x0001, 0x2069);212 213	reg_r(gspca_dev, 0x20, 0x0000, 1);214	reg_r(gspca_dev, 0x20, 0x0000, 5);215	reg_r(gspca_dev, 0x23, 0x0000, 64);216	gspca_dbg(gspca_dev, D_PROBE, "%s%s\n", &gspca_dev->usb_buf[0x1c],217		  &gspca_dev->usb_buf[0x30]);218	reg_r(gspca_dev, 0x23, 0x0001, 64);219	return gspca_dev->usb_err;220}221 222/* function called at start time before URB creation */223static int sd_isoc_init(struct gspca_dev *gspca_dev)224{225	u8 mode;226 227	reg_r(gspca_dev, 0x00, 0x2520, 1);228	wait_status_0(gspca_dev);229	reg_w(gspca_dev, 0xc5, 0x0003, 0x0000);230	wait_status_1(gspca_dev);231 232	wait_status_0(gspca_dev);233	mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;234	reg_wb(gspca_dev, 0x25, 0x0000, 0x0004, mode);235	reg_r(gspca_dev, 0x25, 0x0004, 1);236	reg_wb(gspca_dev, 0x27, 0x0000, 0x0000, 0x06);	/* 420 */237	reg_r(gspca_dev, 0x27, 0x0000, 1);238 239/* not useful..240	gspca_dev->alt = 4;		* use alternate setting 3 */241 242	return gspca_dev->usb_err;243}244 245/* -- start the camera -- */246static int sd_start(struct gspca_dev *gspca_dev)247{248	struct sd *sd = (struct sd *) gspca_dev;249 250	/* initialize the JPEG header */251	jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,252			gspca_dev->pixfmt.width,253			0x22);		/* JPEG 411 */254 255	/* the JPEG quality shall be 85% */256	jpeg_set_qual(sd->jpeg_hdr, 85);257 258	reg_r(gspca_dev, 0x00, 0x2520, 1);259	msleep(8);260 261	/* start the capture */262	wait_status_0(gspca_dev);263	reg_w(gspca_dev, 0x31, 0x0000, 0x0004);	/* start request */264	wait_status_1(gspca_dev);265	wait_status_0(gspca_dev);266	msleep(200);267 268	sd->pkt_seq = 0;269	return gspca_dev->usb_err;270}271 272static void sd_stopN(struct gspca_dev *gspca_dev)273{274	/* stop the capture */275	wait_status_0(gspca_dev);276	reg_w(gspca_dev, 0x31, 0x0000, 0x0000);	/* stop request */277	wait_status_1(gspca_dev);278	wait_status_0(gspca_dev);279}280 281/* move a packet adding 0x00 after 0xff */282static void add_packet(struct gspca_dev *gspca_dev,283			u8 *data,284			int len)285{286	int i;287 288	i = 0;289	do {290		if (data[i] == 0xff) {291			gspca_frame_add(gspca_dev, INTER_PACKET,292					data, i + 1);293			len -= i;294			data += i;295			*data = 0x00;296			i = 0;297		}298	} while (++i < len);299	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);300}301 302static void sd_pkt_scan(struct gspca_dev *gspca_dev,303			u8 *data,			/* isoc packet */304			int len)			/* iso packet length */305{306	struct sd *sd = (struct sd *) gspca_dev;307	static const u8 ffd9[] = {0xff, 0xd9};308 309	/* image packets start with:310	 *	02 8n311	 * with <n> bit:312	 *	0x01: even (0) / odd (1) image313	 *	0x02: end of image when set314	 */315	if (len < 3)316		return;				/* empty packet */317	if (*data == 0x02) {318		if (data[1] & 0x02) {319			sd->pkt_seq = !(data[1] & 1);320			add_packet(gspca_dev, data + 2, len - 2);321			gspca_frame_add(gspca_dev, LAST_PACKET,322					ffd9, 2);323			return;324		}325		if ((data[1] & 1) != sd->pkt_seq)326			goto err;327		if (gspca_dev->last_packet_type == LAST_PACKET)328			gspca_frame_add(gspca_dev, FIRST_PACKET,329					sd->jpeg_hdr, JPEG_HDR_SZ);330		add_packet(gspca_dev, data + 2, len - 2);331		return;332	}333err:334	gspca_dev->last_packet_type = DISCARD_PACKET;335}336 337static int sd_s_ctrl(struct v4l2_ctrl *ctrl)338{339	struct gspca_dev *gspca_dev =340		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);341 342	gspca_dev->usb_err = 0;343 344	if (!gspca_dev->streaming)345		return 0;346 347	switch (ctrl->id) {348	case V4L2_CID_BRIGHTNESS:349		setbrightness(gspca_dev, ctrl->val);350		break;351	case V4L2_CID_CONTRAST:352		setcontrast(gspca_dev, ctrl->val);353		break;354	case V4L2_CID_HUE:355		sethue(gspca_dev, ctrl->val);356		break;357	case V4L2_CID_SATURATION:358		setcolor(gspca_dev, ctrl->val);359		break;360	case V4L2_CID_SHARPNESS:361		setsharpness(gspca_dev, ctrl->val);362		break;363	}364	return gspca_dev->usb_err;365}366 367static const struct v4l2_ctrl_ops sd_ctrl_ops = {368	.s_ctrl = sd_s_ctrl,369};370 371static int sd_init_controls(struct gspca_dev *gspca_dev)372{373	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;374 375	gspca_dev->vdev.ctrl_handler = hdl;376	v4l2_ctrl_handler_init(hdl, 5);377	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,378			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);379	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,380			V4L2_CID_CONTRAST, 0, 8, 1, 1);381	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,382			V4L2_CID_HUE, 0, 255, 1, 0);383	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,384			V4L2_CID_SATURATION, 0, 8, 1, 1);385	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,386			V4L2_CID_SHARPNESS, 0, 255, 1, 0);387 388	if (hdl->error) {389		pr_err("Could not initialize controls\n");390		return hdl->error;391	}392	return 0;393}394 395/* sub-driver description */396static const struct sd_desc sd_desc = {397	.name = MODULE_NAME,398	.config = sd_config,399	.init = sd_init,400	.init_controls = sd_init_controls,401	.isoc_init = sd_isoc_init,402	.start = sd_start,403	.stopN = sd_stopN,404	.pkt_scan = sd_pkt_scan,405};406 407/* -- module initialisation -- */408static const struct usb_device_id device_table[] = {409	{USB_DEVICE(0x04fc, 0x1528)},410	{}411};412MODULE_DEVICE_TABLE(usb, device_table);413 414/* -- device connect -- */415static int sd_probe(struct usb_interface *intf,416			const struct usb_device_id *id)417{418	/* the video interface for isochronous transfer is 1 */419	if (intf->cur_altsetting->desc.bInterfaceNumber != 1)420		return -ENODEV;421 422	return gspca_dev_probe2(intf, id, &sd_desc, sizeof(struct sd),423				THIS_MODULE);424}425 426static struct usb_driver sd_driver = {427	.name = MODULE_NAME,428	.id_table = device_table,429	.probe = sd_probe,430	.disconnect = gspca_disconnect,431#ifdef CONFIG_PM432	.suspend = gspca_suspend,433	.resume = gspca_resume,434	.reset_resume = gspca_resume,435#endif436};437 438module_usb_driver(sd_driver);439