drivers/media/usb/gspca/stv0680.c

Source file repositories/reference/linux-study-clean/drivers/media/usb/gspca/stv0680.c

File Facts

System
Linux kernel
Corpus path
drivers/media/usb/gspca/stv0680.c
Extension
.c
Size
9653 bytes
Lines
340
Domain
Driver Families
Bucket
drivers/media
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct sd {
	struct gspca_dev gspca_dev;		/* !! must be the first item */
	struct v4l2_pix_format mode;
	u8 orig_mode;
	u8 video_mode;
	u8 current_mode;
};

static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val,
		       int size)
{
	int ret;
	u8 req_type = 0;
	unsigned int pipe = 0;

	switch (set) {
	case 0: /*  0xc1  */
		req_type = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
		pipe = usb_rcvctrlpipe(gspca_dev->dev, 0);
		break;
	case 1: /*  0x41  */
		req_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
		pipe = usb_sndctrlpipe(gspca_dev->dev, 0);
		break;
	case 2:	/*  0x80  */
		req_type = USB_DIR_IN | USB_RECIP_DEVICE;
		pipe = usb_rcvctrlpipe(gspca_dev->dev, 0);
		break;
	case 3:	/*  0x40  */
		req_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
		pipe = usb_sndctrlpipe(gspca_dev->dev, 0);
		break;
	}

	ret = usb_control_msg(gspca_dev->dev, pipe,
			      req, req_type,
			      val, 0, gspca_dev->usb_buf, size, 500);

	if ((ret < 0) && (req != 0x0a))
		pr_err("usb_control_msg error %i, request = 0x%x, error = %i\n",
		       set, req, ret);

	return ret;
}

static int stv0680_handle_error(struct gspca_dev *gspca_dev, int ret)
{
	stv_sndctrl(gspca_dev, 0, 0x80, 0, 0x02); /* Get Last Error */
	gspca_err(gspca_dev, "last error: %i,  command = 0x%x\n",
		  gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
	return ret;
}

static int stv0680_get_video_mode(struct gspca_dev *gspca_dev)
{
	/* Note not sure if this init of usb_buf is really necessary */
	memset(gspca_dev->usb_buf, 0, 8);
	gspca_dev->usb_buf[0] = 0x0f;

	if (stv_sndctrl(gspca_dev, 0, 0x87, 0, 0x08) != 0x08) {
		gspca_err(gspca_dev, "Get_Camera_Mode failed\n");
		return stv0680_handle_error(gspca_dev, -EIO);
	}

	return gspca_dev->usb_buf[0]; /* 01 = VGA, 03 = QVGA, 00 = CIF */
}

static int stv0680_set_video_mode(struct gspca_dev *gspca_dev, u8 mode)
{
	struct sd *sd = (struct sd *) gspca_dev;

	if (sd->current_mode == mode)
		return 0;

	memset(gspca_dev->usb_buf, 0, 8);
	gspca_dev->usb_buf[0] = mode;

	if (stv_sndctrl(gspca_dev, 3, 0x07, 0x0100, 0x08) != 0x08) {
		gspca_err(gspca_dev, "Set_Camera_Mode failed\n");
		return stv0680_handle_error(gspca_dev, -EIO);
	}

	/* Verify we got what we've asked for */
	if (stv0680_get_video_mode(gspca_dev) != mode) {
		gspca_err(gspca_dev, "Error setting camera video mode!\n");
		return -EIO;
	}

	sd->current_mode = mode;

Annotation

Implementation Notes