drivers/usb/class/usblp.c

Source file repositories/reference/linux-study-clean/drivers/usb/class/usblp.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/class/usblp.c
Extension
.c
Size
40503 bytes
Lines
1489
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static const struct file_operations usblp_fops = {
	.owner =	THIS_MODULE,
	.read =		usblp_read,
	.write =	usblp_write,
	.poll =		usblp_poll,
	.unlocked_ioctl =	usblp_ioctl,
	.compat_ioctl =		usblp_ioctl,
	.open =		usblp_open,
	.release =	usblp_release,
	.llseek =	noop_llseek,
};

static char *usblp_devnode(const struct device *dev, umode_t *mode)
{
	return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
}

static struct usb_class_driver usblp_class = {
	.name =		"lp%d",
	.devnode =	usblp_devnode,
	.fops =		&usblp_fops,
	.minor_base =	USBLP_MINOR_BASE,
};

static ssize_t ieee1284_id_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct usb_interface *intf = to_usb_interface(dev);
	struct usblp *usblp = usb_get_intfdata(intf);

	if (usblp->device_id_string[0] == 0 &&
	    usblp->device_id_string[1] == 0)
		return 0;

	return sprintf(buf, "%s", usblp->device_id_string+2);
}

static DEVICE_ATTR_RO(ieee1284_id);

static struct attribute *usblp_attrs[] = {
	&dev_attr_ieee1284_id.attr,
	NULL,
};
ATTRIBUTE_GROUPS(usblp);

static int usblp_probe(struct usb_interface *intf,
		       const struct usb_device_id *id)
{
	struct usb_device *dev = interface_to_usbdev(intf);
	struct usblp *usblp;
	int protocol;
	int retval;

	/* Malloc and start initializing usblp structure so we can use it
	 * directly. */
	usblp = kzalloc_obj(struct usblp);
	if (!usblp) {
		retval = -ENOMEM;
		goto abort_ret;
	}
	usblp->dev = dev;
	mutex_init(&usblp->wmut);
	mutex_init(&usblp->mut);
	spin_lock_init(&usblp->lock);
	init_waitqueue_head(&usblp->rwait);
	init_waitqueue_head(&usblp->wwait);
	init_usb_anchor(&usblp->urbs);
	usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
	usblp->intf = usb_get_intf(intf);

	/* Malloc device ID string buffer to the largest expected length,
	 * since we can re-query it on an ioctl and a dynamic string
	 * could change in length. */
	usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL);
	if (!usblp->device_id_string) {
		retval = -ENOMEM;
		goto abort;
	}

	/*
	 * Allocate read buffer. We somewhat wastefully
	 * malloc both regardless of bidirectionality, because the
	 * alternate setting can be changed later via an ioctl.
	 */
	usblp->readbuf = kmalloc(USBLP_BUF_SIZE_IN, GFP_KERNEL);
	if (!usblp->readbuf) {
		retval = -ENOMEM;
		goto abort;
	}

	/* Allocate buffer for printer status */

Annotation

Implementation Notes