drivers/media/usb/dvb-usb-v2/gl861.c

Source file repositories/reference/linux-study-clean/drivers/media/usb/dvb-usb-v2/gl861.c

File Facts

System
Linux kernel
Corpus path
drivers/media/usb/dvb-usb-v2/gl861.c
Extension
.c
Size
13967 bytes
Lines
579
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 gl861 {
	/* USB control message buffer */
	u8 buf[16];

	struct i2c_adapter *demod_sub_i2c;
	struct i2c_client  *i2c_client_demod;
	struct i2c_client  *i2c_client_tuner;
};

#define CMD_WRITE_SHORT     0x01
#define CMD_READ            0x02
#define CMD_WRITE           0x03

static int gl861_ctrl_msg(struct dvb_usb_device *d, u8 request, u16 value,
			  u16 index, void *data, u16 size)
{
	struct gl861 *ctx = d_to_priv(d);
	struct usb_interface *intf = d->intf;
	int ret;
	unsigned int pipe;
	u8 requesttype;

	mutex_lock(&d->usb_mutex);

	switch (request) {
	case CMD_WRITE:
		memcpy(ctx->buf, data, size);
		fallthrough;
	case CMD_WRITE_SHORT:
		pipe = usb_sndctrlpipe(d->udev, 0);
		requesttype = USB_TYPE_VENDOR | USB_DIR_OUT;
		break;
	case CMD_READ:
		pipe = usb_rcvctrlpipe(d->udev, 0);
		requesttype = USB_TYPE_VENDOR | USB_DIR_IN;
		break;
	default:
		ret = -EINVAL;
		goto err_mutex_unlock;
	}

	ret = usb_control_msg(d->udev, pipe, request, requesttype, value,
			      index, ctx->buf, size, 200);
	dev_dbg(&intf->dev, "%d | %02x %02x %*ph %*ph %*ph %s %*ph\n",
		ret, requesttype, request, 2, &value, 2, &index, 2, &size,
		(requesttype & USB_DIR_IN) ? "<<<" : ">>>", size, ctx->buf);
	if (ret < 0)
		goto err_mutex_unlock;

	if (request == CMD_READ)
		memcpy(data, ctx->buf, size);

	usleep_range(1000, 2000); /* Avoid I2C errors */

	mutex_unlock(&d->usb_mutex);

	return 0;

err_mutex_unlock:
	mutex_unlock(&d->usb_mutex);
	dev_dbg(&intf->dev, "failed %d\n", ret);
	return ret;
}

static int gl861_short_write(struct dvb_usb_device *d, u8 addr, u8 reg, u8 val)
{
	return gl861_ctrl_msg(d, CMD_WRITE_SHORT,
			      (addr << 9) | val, reg, NULL, 0);
}

static int gl861_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
				 int num)
{
	struct dvb_usb_device *d = i2c_get_adapdata(adap);
	struct usb_interface *intf = d->intf;
	struct gl861 *ctx = d_to_priv(d);
	int ret;
	u8 request, *data;
	u16 value, index, size;

	/* XXX: I2C adapter maximum data lengths are not tested */
	if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
		/* I2C write */
		if (msg[0].len < 2 || msg[0].len > sizeof(ctx->buf)) {
			ret = -EOPNOTSUPP;
			goto err;
		}

		value = (msg[0].addr << 1) << 8;
		index = msg[0].buf[0];

Annotation

Implementation Notes