drivers/media/usb/dvb-usb/dtv5100.c

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

File Facts

System
Linux kernel
Corpus path
drivers/media/usb/dvb-usb/dtv5100.c
Extension
.c
Size
5235 bytes
Lines
231
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 dtv5100_state {
	unsigned char data[80];
};

static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
			   u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
{
	struct dtv5100_state *st = d->priv;
	unsigned int pipe;
	u8 request;
	u8 type;
	u16 value;
	u16 index;

	switch (wlen) {
	case 1:
		/* write { reg }, read { value } */
		pipe = usb_rcvctrlpipe(d->udev, 0);
		request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ :
							DTV5100_TUNER_READ);
		type = USB_TYPE_VENDOR | USB_DIR_IN;
		value = 0;
		break;
	case 2:
		/* write { reg, value } */
		pipe = usb_sndctrlpipe(d->udev, 0);
		request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE :
							DTV5100_TUNER_WRITE);
		type = USB_TYPE_VENDOR | USB_DIR_OUT;
		value = wbuf[1];
		break;
	default:
		warn("wlen = %x, aborting.", wlen);
		return -EINVAL;
	}
	index = (addr << 8) + wbuf[0];

	if (rlen > sizeof(st->data)) {
		warn("rlen = %x is too big!\n", rlen);
		return -EINVAL;
	}

	memcpy(st->data, rbuf, rlen);
	msleep(1); /* avoid I2C errors */
	return usb_control_msg(d->udev, pipe, request,
			       type, value, index, st->data, rlen,
			       DTV5100_USB_TIMEOUT);
}

/* I2C */
static int dtv5100_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
			    int num)
{
	struct dvb_usb_device *d = i2c_get_adapdata(adap);
	int i;

	if (num > 2)
		return -EINVAL;

	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
		return -EAGAIN;

	for (i = 0; i < num; i++) {
		/* write/read request */
		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
			if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf,
					    msg[i].len, msg[i+1].buf,
					    msg[i+1].len) < 0)
				break;
			i++;
		} else if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf,
					   msg[i].len, NULL, 0) < 0)
				break;
	}

	mutex_unlock(&d->i2c_mutex);
	return i;
}

static u32 dtv5100_i2c_func(struct i2c_adapter *adapter)
{
	return I2C_FUNC_I2C;
}

static const struct i2c_algorithm dtv5100_i2c_algo = {
	.master_xfer   = dtv5100_i2c_xfer,
	.functionality = dtv5100_i2c_func,
};

/* Callbacks for DVB USB */

Annotation

Implementation Notes