1575 lines · 38.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0+/* * f_printer.c - USB printer function driver * * Copied from drivers/usb/gadget/legacy/printer.c, * which was: * * printer.c -- Printer gadget driver * * Copyright (C) 2003-2005 David Brownell * Copyright (C) 2006 Craig W. Nadler */ #include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/mutex.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/idr.h>#include <linux/timer.h>#include <linux/list.h>#include <linux/interrupt.h>#include <linux/device.h>#include <linux/moduleparam.h>#include <linux/fs.h>#include <linux/poll.h>#include <linux/types.h>#include <linux/ctype.h>#include <linux/cdev.h>#include <linux/kref.h> #include <asm/byteorder.h>#include <linux/io.h>#include <linux/irq.h>#include <linux/uaccess.h>#include <linux/unaligned.h> #include <linux/usb/ch9.h>#include <linux/usb/composite.h>#include <linux/usb/gadget.h>#include <linux/usb/g_printer.h> #include "u_printer.h" #define PRINTER_MINORS		4#define GET_DEVICE_ID		0#define GET_PORT_STATUS		1#define SOFT_RESET		2 #define DEFAULT_Q_LEN		10 /* same as legacy g_printer gadget */ static int major, minors;static const struct class usb_gadget_class = {	.name = "usb_printer_gadget",}; static DEFINE_IDA(printer_ida);static DEFINE_MUTEX(printer_ida_lock); /* protects access do printer_ida */ /*-------------------------------------------------------------------------*/ struct printer_dev {	spinlock_t		lock;		/* lock this structure */	/* lock buffer lists during read/write calls */	struct mutex		lock_printer_io;	struct usb_gadget	*gadget;	s8			interface;	struct usb_ep		*in_ep, *out_ep;	struct kref             kref;	struct list_head	rx_reqs;	/* List of free RX structs */	struct list_head	rx_reqs_active;	/* List of Active RX xfers */	struct list_head	rx_buffers;	/* List of completed xfers */	/* wait until there is data to be read. */	wait_queue_head_t	rx_wait;	struct list_head	tx_reqs;	/* List of free TX structs */	struct list_head	tx_reqs_active; /* List of Active TX xfers */	/* Wait until there are write buffers available to use. */	wait_queue_head_t	tx_wait;	/* Wait until all write buffers have been sent. */	wait_queue_head_t	tx_flush_wait;	struct usb_request	*current_rx_req;	size_t			current_rx_bytes;	u8			*current_rx_buf;	u8			printer_status;	u8			reset_printer;	int			minor;	struct cdev		printer_cdev;	u8			printer_cdev_open;	wait_queue_head_t	wait;	unsigned		q_len;	char			**pnp_string;	/* We don't own memory! */	struct usb_function	function;}; static inline struct printer_dev *func_to_printer(struct usb_function *f){	return container_of(f, struct printer_dev, function);} /*-------------------------------------------------------------------------*/ /* * DESCRIPTORS ... most are static, but strings and (full) configuration * descriptors are built on demand. */ /* holds our biggest descriptor */#define USB_DESC_BUFSIZE		256#define USB_BUFSIZE			8192 static struct usb_interface_descriptor intf_desc = {	.bLength =		sizeof(intf_desc),	.bDescriptorType =	USB_DT_INTERFACE,	.bNumEndpoints =	2,	.bInterfaceClass =	USB_CLASS_PRINTER,	.bInterfaceSubClass =	1,	/* Printer Sub-Class */	.bInterfaceProtocol =	2,	/* Bi-Directional */	.iInterface =		0}; static struct usb_endpoint_descriptor fs_ep_in_desc = {	.bLength =		USB_DT_ENDPOINT_SIZE,	.bDescriptorType =	USB_DT_ENDPOINT,	.bEndpointAddress =	USB_DIR_IN,	.bmAttributes =		USB_ENDPOINT_XFER_BULK}; static struct usb_endpoint_descriptor fs_ep_out_desc = {	.bLength =		USB_DT_ENDPOINT_SIZE,	.bDescriptorType =	USB_DT_ENDPOINT,	.bEndpointAddress =	USB_DIR_OUT,	.bmAttributes =		USB_ENDPOINT_XFER_BULK}; static struct usb_descriptor_header *fs_printer_function[] = {	(struct usb_descriptor_header *) &intf_desc,	(struct usb_descriptor_header *) &fs_ep_in_desc,	(struct usb_descriptor_header *) &fs_ep_out_desc,	NULL}; /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. */ static struct usb_endpoint_descriptor hs_ep_in_desc = {	.bLength =		USB_DT_ENDPOINT_SIZE,	.bDescriptorType =	USB_DT_ENDPOINT,	.bmAttributes =		USB_ENDPOINT_XFER_BULK,	.wMaxPacketSize =	cpu_to_le16(512)}; static struct usb_endpoint_descriptor hs_ep_out_desc = {	.bLength =		USB_DT_ENDPOINT_SIZE,	.bDescriptorType =	USB_DT_ENDPOINT,	.bmAttributes =		USB_ENDPOINT_XFER_BULK,	.wMaxPacketSize =	cpu_to_le16(512)}; static struct usb_descriptor_header *hs_printer_function[] = {	(struct usb_descriptor_header *) &intf_desc,	(struct usb_descriptor_header *) &hs_ep_in_desc,	(struct usb_descriptor_header *) &hs_ep_out_desc,	NULL}; /* * Added endpoint descriptors for 3.0 devices */ static struct usb_endpoint_descriptor ss_ep_in_desc = {	.bLength =              USB_DT_ENDPOINT_SIZE,	.bDescriptorType =      USB_DT_ENDPOINT,	.bmAttributes =         USB_ENDPOINT_XFER_BULK,	.wMaxPacketSize =       cpu_to_le16(1024),}; static struct usb_ss_ep_comp_descriptor ss_ep_in_comp_desc = {	.bLength =              sizeof(ss_ep_in_comp_desc),	.bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,}; static struct usb_endpoint_descriptor ss_ep_out_desc = {	.bLength =              USB_DT_ENDPOINT_SIZE,	.bDescriptorType =      USB_DT_ENDPOINT,	.bmAttributes =         USB_ENDPOINT_XFER_BULK,	.wMaxPacketSize =       cpu_to_le16(1024),}; static struct usb_ss_ep_comp_descriptor ss_ep_out_comp_desc = {	.bLength =              sizeof(ss_ep_out_comp_desc),	.bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,}; static struct usb_descriptor_header *ss_printer_function[] = {	(struct usb_descriptor_header *) &intf_desc,	(struct usb_descriptor_header *) &ss_ep_in_desc,	(struct usb_descriptor_header *) &ss_ep_in_comp_desc,	(struct usb_descriptor_header *) &ss_ep_out_desc,	(struct usb_descriptor_header *) &ss_ep_out_comp_desc,	NULL}; /* maxpacket and other transfer characteristics vary by speed. */static inline struct usb_endpoint_descriptor *ep_desc(struct usb_gadget *gadget,					struct usb_endpoint_descriptor *fs,					struct usb_endpoint_descriptor *hs,					struct usb_endpoint_descriptor *ss){	switch (gadget->speed) {	case USB_SPEED_SUPER_PLUS:	case USB_SPEED_SUPER:		return ss;	case USB_SPEED_HIGH:		return hs;	default:		return fs;	}} /*-------------------------------------------------------------------------*/ static void printer_dev_free(struct kref *kref){	struct printer_dev *dev = container_of(kref, struct printer_dev, kref); 	kfree(dev);} static struct usb_request *printer_req_alloc(struct usb_ep *ep, unsigned len, gfp_t gfp_flags){	struct usb_request	*req; 	req = usb_ep_alloc_request(ep, gfp_flags); 	if (req != NULL) {		req->length = len;		req->buf = kmalloc(len, gfp_flags);		if (req->buf == NULL) {			usb_ep_free_request(ep, req);			return NULL;		}	} 	return req;} static voidprinter_req_free(struct usb_ep *ep, struct usb_request *req){	if (ep != NULL && req != NULL) {		kfree(req->buf);		usb_ep_free_request(ep, req);	}} /*-------------------------------------------------------------------------*/ static void rx_complete(struct usb_ep *ep, struct usb_request *req){	struct printer_dev	*dev = ep->driver_data;	int			status = req->status;	unsigned long		flags; 	spin_lock_irqsave(&dev->lock, flags); 	list_del_init(&req->list);	/* Remode from Active List */ 	switch (status) { 	/* normal completion */	case 0:		if (req->actual > 0) {			list_add_tail(&req->list, &dev->rx_buffers);			DBG(dev, "G_Printer : rx length %d\n", req->actual);		} else {			list_add(&req->list, &dev->rx_reqs);		}		break; 	/* software-driven interface shutdown */	case -ECONNRESET:		/* unlink */	case -ESHUTDOWN:		/* disconnect etc */		VDBG(dev, "rx shutdown, code %d\n", status);		list_add(&req->list, &dev->rx_reqs);		break; 	/* for hardware automagic (such as pxa) */	case -ECONNABORTED:		/* endpoint reset */		DBG(dev, "rx %s reset\n", ep->name);		list_add(&req->list, &dev->rx_reqs);		break; 	/* data overrun */	case -EOVERFLOW:		fallthrough; 	default:		DBG(dev, "rx status %d\n", status);		list_add(&req->list, &dev->rx_reqs);		break;	} 	wake_up_interruptible(&dev->rx_wait);	spin_unlock_irqrestore(&dev->lock, flags);} static void tx_complete(struct usb_ep *ep, struct usb_request *req){	struct printer_dev	*dev = ep->driver_data; 	switch (req->status) {	default:		VDBG(dev, "tx err %d\n", req->status);		fallthrough;	case -ECONNRESET:		/* unlink */	case -ESHUTDOWN:		/* disconnect etc */		break;	case 0:		break;	} 	spin_lock(&dev->lock);	/* Take the request struct off the active list and put it on the	 * free list.	 */	list_del_init(&req->list);	list_add(&req->list, &dev->tx_reqs);	wake_up_interruptible(&dev->tx_wait);	if (likely(list_empty(&dev->tx_reqs_active)))		wake_up_interruptible(&dev->tx_flush_wait); 	spin_unlock(&dev->lock);} /*-------------------------------------------------------------------------*/ static intprinter_open(struct inode *inode, struct file *fd){	struct printer_dev	*dev;	unsigned long		flags;	int			ret = -EBUSY; 	dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev); 	spin_lock_irqsave(&dev->lock, flags); 	if (dev->interface < 0) {		spin_unlock_irqrestore(&dev->lock, flags);		return -ENODEV;	} 	if (!dev->printer_cdev_open) {		dev->printer_cdev_open = 1;		fd->private_data = dev;		ret = 0;		/* Change the printer status to show that it's on-line. */		dev->printer_status |= PRINTER_SELECTED;		kref_get(&dev->kref);	} 	spin_unlock_irqrestore(&dev->lock, flags); 	return ret;} static intprinter_close(struct inode *inode, struct file *fd){	struct printer_dev	*dev = fd->private_data;	unsigned long		flags; 	spin_lock_irqsave(&dev->lock, flags);	dev->printer_cdev_open = 0;	fd->private_data = NULL;	/* Change printer status to show that the printer is off-line. */	dev->printer_status &= ~PRINTER_SELECTED;	spin_unlock_irqrestore(&dev->lock, flags); 	kref_put(&dev->kref, printer_dev_free); 	return 0;} /* This function must be called with interrupts turned off. */static voidsetup_rx_reqs(struct printer_dev *dev){	struct usb_request              *req; 	while (likely(!list_empty(&dev->rx_reqs))) {		int error; 		req = container_of(dev->rx_reqs.next,				struct usb_request, list);		list_del_init(&req->list); 		/* The USB Host sends us whatever amount of data it wants to		 * so we always set the length field to the full USB_BUFSIZE.		 * If the amount of data is more than the read() caller asked		 * for it will be stored in the request buffer until it is		 * asked for by read().		 */		req->length = USB_BUFSIZE;		req->complete = rx_complete; 		/* here, we unlock, and only unlock, to avoid deadlock. */		spin_unlock(&dev->lock);		error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);		spin_lock(&dev->lock);		if (error) {			DBG(dev, "rx submit --> %d\n", error);			list_add(&req->list, &dev->rx_reqs);			break;		}		/* if the req is empty, then add it into dev->rx_reqs_active. */		else if (list_empty(&req->list))			list_add(&req->list, &dev->rx_reqs_active);	}} static ssize_tprinter_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr){	struct printer_dev		*dev = fd->private_data;	unsigned long			flags;	size_t				size, not_copied, copied;	size_t				bytes_copied;	struct usb_request		*req;	/* This is a pointer to the current USB rx request. */	struct usb_request		*current_rx_req;	/* This is the number of bytes in the current rx buffer. */	size_t				current_rx_bytes;	/* This is a pointer to the current rx buffer. */	u8				*current_rx_buf; 	if (len == 0)		return -EINVAL; 	DBG(dev, "printer_read trying to read %d bytes\n", (int)len); 	mutex_lock(&dev->lock_printer_io);	spin_lock_irqsave(&dev->lock, flags); 	if (dev->interface < 0)		goto out_disabled; 	/* We will use this flag later to check if a printer reset happened	 * after we turn interrupts back on.	 */	dev->reset_printer = 0; 	setup_rx_reqs(dev);	/* this dropped the lock - need to retest */	if (dev->interface < 0)		goto out_disabled; 	bytes_copied = 0;	current_rx_req = dev->current_rx_req;	current_rx_bytes = dev->current_rx_bytes;	current_rx_buf = dev->current_rx_buf;	dev->current_rx_req = NULL;	dev->current_rx_bytes = 0;	dev->current_rx_buf = NULL; 	/* Check if there is any data in the read buffers. Please note that	 * current_rx_bytes is the number of bytes in the current rx buffer.	 * If it is zero then check if there are any other rx_buffers that	 * are on the completed list. We are only out of data if all rx	 * buffers are empty.	 */	if ((current_rx_bytes == 0) &&			(likely(list_empty(&dev->rx_buffers)))) {		/* Turn interrupts back on before sleeping. */		spin_unlock_irqrestore(&dev->lock, flags); 		/*		 * If no data is available check if this is a NON-Blocking		 * call or not.		 */		if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {			mutex_unlock(&dev->lock_printer_io);			return -EAGAIN;		} 		/* Sleep until data is available */		wait_event_interruptible(dev->rx_wait,				(likely(!list_empty(&dev->rx_buffers))));		spin_lock_irqsave(&dev->lock, flags);		if (dev->interface < 0)			goto out_disabled;	} 

Lines 1–500 of 1575.