drivers/i2c/busses/i2c-diolan-u2c.c

Source file repositories/reference/linux-study-clean/drivers/i2c/busses/i2c-diolan-u2c.c

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-diolan-u2c.c
Extension
.c
Size
12886 bytes
Lines
513
Domain
Driver Families
Bucket
drivers/i2c
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 i2c_diolan_u2c {
	u8 obuffer[DIOLAN_OUTBUF_LEN];	/* output buffer */
	u8 ibuffer[DIOLAN_INBUF_LEN];	/* input buffer */
	int ep_in, ep_out;              /* Endpoints    */
	struct usb_device *usb_dev;	/* the usb device for this device */
	struct usb_interface *interface;/* the interface for this device */
	struct i2c_adapter adapter;	/* i2c related things */
	int olen;			/* Output buffer length */
	int ocount;			/* Number of enqueued messages */
};

static uint frequency = I2C_MAX_STANDARD_MODE_FREQ;	/* I2C clock frequency in Hz */

module_param(frequency, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(frequency, "I2C clock frequency in hertz");

/* usb layer */

/* Send command to device, and get response. */
static int diolan_usb_transfer(struct i2c_diolan_u2c *dev)
{
	int ret = 0;
	int actual;
	int i;

	if (!dev->olen || !dev->ocount)
		return -EINVAL;

	ret = usb_bulk_msg(dev->usb_dev,
			   usb_sndbulkpipe(dev->usb_dev, dev->ep_out),
			   dev->obuffer, dev->olen, &actual,
			   DIOLAN_USB_TIMEOUT);
	if (!ret) {
		for (i = 0; i < dev->ocount; i++) {
			int tmpret;

			tmpret = usb_bulk_msg(dev->usb_dev,
					      usb_rcvbulkpipe(dev->usb_dev,
							      dev->ep_in),
					      dev->ibuffer,
					      sizeof(dev->ibuffer), &actual,
					      DIOLAN_USB_TIMEOUT);
			/*
			 * Stop command processing if a previous command
			 * returned an error.
			 * Note that we still need to retrieve all messages.
			 */
			if (ret < 0)
				continue;
			ret = tmpret;
			if (ret == 0 && actual > 0) {
				switch (dev->ibuffer[actual - 1]) {
				case RESP_NACK:
					/*
					 * Return ENXIO if NACK was received as
					 * response to the address phase,
					 * EIO otherwise
					 */
					ret = i == 1 ? -ENXIO : -EIO;
					break;
				case RESP_TIMEOUT:
					ret = -ETIMEDOUT;
					break;
				case RESP_OK:
					/* strip off return code */
					ret = actual - 1;
					break;
				default:
					ret = -EIO;
					break;
				}
			}
		}
	}
	dev->olen = 0;
	dev->ocount = 0;
	return ret;
}

static int diolan_write_cmd(struct i2c_diolan_u2c *dev, bool flush)
{
	if (flush || dev->olen >= DIOLAN_FLUSH_LEN)
		return diolan_usb_transfer(dev);
	return 0;
}

/* Send command (no data) */
static int diolan_usb_cmd(struct i2c_diolan_u2c *dev, u8 command, bool flush)
{
	dev->obuffer[dev->olen++] = command;

Annotation

Implementation Notes