drivers/i2c/busses/i2c-tiny-usb.c

Source file repositories/reference/linux-study-clean/drivers/i2c/busses/i2c-tiny-usb.c

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-tiny-usb.c
Extension
.c
Size
7874 bytes
Lines
303
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_tiny_usb {
	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 */
};

static int usb_read(struct i2c_adapter *adapter, int cmd,
		    int value, int index, void *data, int len)
{
	struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
	void *dmadata = kmalloc(len, GFP_KERNEL);
	int ret;

	if (!dmadata)
		return -ENOMEM;

	/* do control transfer */
	ret = usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
			       cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
			       USB_DIR_IN, value, index, dmadata, len, 2000);

	memcpy(data, dmadata, len);
	kfree(dmadata);
	return ret;
}

static int usb_write(struct i2c_adapter *adapter, int cmd,
		     int value, int index, void *data, int len)
{
	struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
	void *dmadata = kmemdup(data, len, GFP_KERNEL);
	int ret;

	if (!dmadata)
		return -ENOMEM;

	/* do control transfer */
	ret = usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
			       cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
			       value, index, dmadata, len, 2000);

	kfree(dmadata);
	return ret;
}

static int i2c_tiny_usb_probe(struct usb_interface *interface,
			      const struct usb_device_id *id)
{
	struct i2c_tiny_usb *dev;
	int retval = -ENOMEM;
	u16 version;

	if (interface->intf_assoc &&
	    interface->intf_assoc->bFunctionClass != USB_CLASS_VENDOR_SPEC)
		return -ENODEV;

	dev_dbg(&interface->dev, "probing usb device\n");

	/* allocate memory for our device state and initialize it */
	dev = kzalloc_obj(*dev);
	if (!dev)
		goto error;

	dev->usb_dev = interface_to_usbdev(interface);
	dev->interface = interface;

	/* save our data pointer in this interface device */
	usb_set_intfdata(interface, dev);

	version = le16_to_cpu(dev->usb_dev->descriptor.bcdDevice);
	dev_info(&interface->dev,
		 "version %x.%02x found at bus %03d address %03d\n",
		 version >> 8, version & 0xff,
		 dev->usb_dev->bus->busnum, dev->usb_dev->devnum);

	/* setup i2c adapter description */
	dev->adapter.owner = THIS_MODULE;
	dev->adapter.class = I2C_CLASS_HWMON;
	dev->adapter.quirks = &usb_quirks;
	dev->adapter.algo = &usb_algorithm;
	dev->adapter.algo_data = dev;
	snprintf(dev->adapter.name, sizeof(dev->adapter.name),
		 "i2c-tiny-usb at bus %03d device %03d",
		 dev->usb_dev->bus->busnum, dev->usb_dev->devnum);

	if (usb_write(&dev->adapter, CMD_SET_DELAY, delay, 0, NULL, 0) != 0) {
		retval = dev_err_probe(&dev->adapter.dev, -EIO,
				       "failure setting delay to %dus\n", delay);
		goto error;
	}

Annotation

Implementation Notes