⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial.c

📁 ARM S3C2410 USB SLAVE LINUX驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
				&gs_fullspeed_out_desc);
			ret = usb_ep_enable(ep,ep_desc);
			if (ret == 0) {
				ep->driver_data = dev;
				dev->dev_out_ep = ep;
				dev->dev_out_ep_desc = ep_desc;
			} else {
				printk(KERN_ERR "gs_set_config: cannot enable out endpoint %s, ret=%d\n",
					ep->name, ret);
				goto exit_reset_config;
			}
		}

	}

	if (dev->dev_in_ep == NULL || dev->dev_out_ep == NULL
	|| (config != GS_BULK_CONFIG_ID && dev->dev_notify_ep == NULL)) {
		printk(KERN_ERR "gs_set_config: cannot find endpoints\n");
		ret = -ENODEV;
		goto exit_reset_config;
	}

	/* allocate and queue read requests */
	ep = dev->dev_out_ep;
	for (i=0; i<read_q_size && ret == 0; i++) {
		if ((req=gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC))) {
			req->complete = gs_read_complete;
			if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
				printk(KERN_ERR "gs_set_config: cannot queue read request, ret=%d\n",
					ret);
			}
		} else {
			printk(KERN_ERR "gs_set_config: cannot allocate read requests\n");
			ret = -ENOMEM;
			goto exit_reset_config;
		}
	}

	/* allocate write requests, and put on free list */
	ep = dev->dev_in_ep;
	for (i=0; i<write_q_size; i++) {
		if ((req_entry=gs_alloc_req_entry(ep, ep->maxpacket, GFP_ATOMIC))) {
			req_entry->re_req->complete = gs_write_complete;
			list_add(&req_entry->re_entry, &dev->dev_req_list);
		} else {
			printk(KERN_ERR "gs_set_config: cannot allocate write requests\n");
			ret = -ENOMEM;
			goto exit_reset_config;
		}
	}

	printk(KERN_INFO "gs_set_config: %s configured, %s speed %s config\n",
		GS_LONG_NAME,
		gadget->speed == USB_SPEED_HIGH ? "high" : "full",
		config == GS_BULK_CONFIG_ID ? "BULK" : "CDC-ACM");

	return 0;

exit_reset_config:
	gs_reset_config(dev);
	return ret;
}

/*
 * gs_reset_config
 *
 * Mark the device as not configured, disable all endpoints,
 * which forces completion of pending I/O and frees queued
 * requests, and free the remaining write requests on the
 * free list.
 *
 * The device lock must be held when calling this function.
 */
static void gs_reset_config(struct gs_dev *dev)
{
	struct gs_req_entry *req_entry;

	if (dev == NULL) {
		printk(KERN_ERR "gs_reset_config: NULL device pointer\n");
		return;
	}

	if (dev->dev_config == GS_NO_CONFIG_ID)
		return;

	dev->dev_config = GS_NO_CONFIG_ID;

	/* free write requests on the free list */
	while(!list_empty(&dev->dev_req_list)) {
		req_entry = list_entry(dev->dev_req_list.next,
			struct gs_req_entry, re_entry);
		list_del(&req_entry->re_entry);
		gs_free_req_entry(dev->dev_in_ep, req_entry);
	}

	/* disable endpoints, forcing completion of pending i/o; */
	/* completion handlers free their requests in this case */
	if (dev->dev_notify_ep) {
		usb_ep_disable(dev->dev_notify_ep);
		dev->dev_notify_ep = NULL;
	}
	if (dev->dev_in_ep) {
		usb_ep_disable(dev->dev_in_ep);
		dev->dev_in_ep = NULL;
	}
	if (dev->dev_out_ep) {
		usb_ep_disable(dev->dev_out_ep);
		dev->dev_out_ep = NULL;
	}
}

/*
 * gs_build_config_buf
 *
 * Builds the config descriptors in the given buffer and returns the
 * length, or a negative error number.
 */
static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
	u8 type, unsigned int index, int is_otg)
{
	int len;
	int high_speed;
	const struct usb_config_descriptor *config_desc;
	const struct usb_descriptor_header **function;

	if (index >= gs_device_desc.bNumConfigurations)
		return -EINVAL;

	/* other speed switches high and full speed */
	high_speed = (speed == USB_SPEED_HIGH);
	if (type == USB_DT_OTHER_SPEED_CONFIG)
		high_speed = !high_speed;

	if (use_acm) {
		config_desc = &gs_acm_config_desc;
		function = GS_SPEED_SELECT(high_speed,
			gs_acm_highspeed_function,
			gs_acm_fullspeed_function);
	} else {
		config_desc = &gs_bulk_config_desc;
		function = GS_SPEED_SELECT(high_speed,
			gs_bulk_highspeed_function,
			gs_bulk_fullspeed_function);
	}

	/* for now, don't advertise srp-only devices */
	if (!is_otg)
		function++;

	len = usb_gadget_config_buf(config_desc, buf, GS_MAX_DESC_LEN, function);
	if (len < 0)
		return len;

	((struct usb_config_descriptor *)buf)->bDescriptorType = type;

	return len;
}

/*
 * gs_alloc_req
 *
 * Allocate a usb_request and its buffer.  Returns a pointer to the
 * usb_request or NULL if there is an error.
 */
static struct usb_request *
gs_alloc_req(struct usb_ep *ep, unsigned int len, unsigned kmalloc_flags)
{
	struct usb_request *req;

	if (ep == NULL)
		return NULL;

	req = usb_ep_alloc_request(ep, kmalloc_flags);

	if (req != NULL) {
		req->length = len;
		req->buf = kmalloc(len, kmalloc_flags);
		if (req->buf == NULL) {
			usb_ep_free_request(ep, req);
			return NULL;
		}
	}

	return req;
}

/*
 * gs_free_req
 *
 * Free a usb_request and its buffer.
 */
static void gs_free_req(struct usb_ep *ep, struct usb_request *req)
{
	if (ep != NULL && req != NULL) {
		kfree(req->buf);
		usb_ep_free_request(ep, req);
	}
}

/*
 * gs_alloc_req_entry
 *
 * Allocates a request and its buffer, using the given
 * endpoint, buffer len, and kmalloc flags.
 */
static struct gs_req_entry *
gs_alloc_req_entry(struct usb_ep *ep, unsigned len, unsigned kmalloc_flags)
{
	struct gs_req_entry	*req;

	req = kmalloc(sizeof(struct gs_req_entry), kmalloc_flags);
	if (req == NULL)
		return NULL;

	req->re_req = gs_alloc_req(ep, len, kmalloc_flags);
	if (req->re_req == NULL) {
		kfree(req);
		return NULL;
	}

	req->re_req->context = req;

	return req;
}

/*
 * gs_free_req_entry
 *
 * Frees a request and its buffer.
 */
static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req)
{
	if (ep != NULL && req != NULL) {
		if (req->re_req != NULL)
			gs_free_req(ep, req->re_req);
		kfree(req);
	}
}

/*
 * gs_alloc_ports
 *
 * Allocate all ports and set the gs_dev struct to point to them.
 * Return 0 if successful, or a negative error number.
 *
 * The device lock is normally held when calling this function.
 */
static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags)
{
	int i;
	struct gs_port *port;

	if (dev == NULL)
		return -EIO;

	for (i=0; i<GS_NUM_PORTS; i++) {
		if ((port=(struct gs_port *)kmalloc(sizeof(struct gs_port), kmalloc_flags)) == NULL)
			return -ENOMEM;

		memset(port, 0, sizeof(struct gs_port));
		port->port_dev = dev;
		port->port_num = i;
		port->port_line_coding.dwDTERate = cpu_to_le32(GS_DEFAULT_DTE_RATE);
		port->port_line_coding.bCharFormat = GS_DEFAULT_CHAR_FORMAT;
		port->port_line_coding.bParityType = GS_DEFAULT_PARITY;
		port->port_line_coding.bDataBits = GS_DEFAULT_DATA_BITS;
		spin_lock_init(&port->port_lock);
		init_waitqueue_head(&port->port_write_wait);

		dev->dev_port[i] = port;
	}

	return 0;
}

/*
 * gs_free_ports
 *
 * Free all closed ports.  Open ports are disconnected by
 * freeing their write buffers, setting their device pointers
 * and the pointers to them in the device to NULL.  These
 * ports will be freed when closed.
 *
 * The device lock is normally held when calling this function.
 */
static void gs_free_ports(struct gs_dev *dev)
{
	int i;
	unsigned long flags;
	struct gs_port *port;

	if (dev == NULL)
		return;

	for (i=0; i<GS_NUM_PORTS; i++) {
		if ((port=dev->dev_port[i]) != NULL) {
			dev->dev_port[i] = NULL;

			spin_lock_irqsave(&port->port_lock, flags);

			if (port->port_write_buf != NULL) {
				gs_buf_free(port->port_write_buf);
				port->port_write_buf = NULL;
			}

			if (port->port_open_count > 0 || port->port_in_use) {
				port->port_dev = NULL;
				wake_up_interruptible(&port->port_write_wait);
				if (port->port_tty) {
					wake_up_interruptible(&port->port_tty->read_wait);
					wake_up_interruptible(&port->port_tty->write_wait);
				}
				spin_unlock_irqrestore(&port->port_lock, flags);
			} else {
				spin_unlock_irqrestore(&port->port_lock, flags);
				kfree(port);
			}

		}
	}
}

/* Circular Buffer */

/*
 * gs_buf_alloc
 *
 * Allocate a circular buffer and all associated memory.
 */
static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags)
{
	struct gs_buf *gb;

	if (size == 0)
		return NULL;

	gb = (struct gs_buf *)kmalloc(sizeof(struct gs_buf), kmalloc_flags);
	if (gb == NULL)
		return NULL;

	gb->buf_buf = kmalloc(size, kmalloc_flags);
	if (gb->buf_buf == NULL) {
		kfree(gb);
		return NULL;
	}

	gb->buf_size = size;
	gb->buf_get = gb->buf_put = gb->buf_buf;

	return gb;
}

/*
 * gs_buf_free
 *
 * Free the buffer and all associated memory.
 */
void gs_buf_free(struct gs_buf *gb)
{
	if (gb) {
		kfree(gb->buf_buf);
		kfree(gb);
	}
}

/*
 * gs_buf_clear
 *
 * Clear out all data in the circular buffer.
 */
void gs_buf_clear(struct gs_buf *gb)
{
	if (gb != NULL)
		gb->buf_get = gb->buf_put;
		/* equivalent to a get of all data available */
}

/*
 * gs_buf_data_avail
 *
 * Return the number of bytes of data available in the circular
 * buffer.
 */
unsigned int gs_buf_data_avail(struct gs_buf *gb)
{
	if (gb != NULL)
		return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size;
	else
		return 0;
}

/*
 * gs_buf_space_avail
 *
 * Return the number of bytes of space available in the circular
 * buffer.
 */
unsigned int gs_buf_space_avail(struct gs_buf *gb)
{
	if (gb != NULL)
		return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size;
	else
		return 0;
}

/*
 * gs_buf_put
 *
 * Copy data data from a user buffer and put it into the circular buffer.
 * Restrict to the amount of space available.
 *
 * Return the number of bytes copied.
 */
unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
{
	unsigned int len;

	if (gb == NULL)
		return 0;

	len  = gs_buf_space_avail(gb);
	if (count > len)
		count = len;

	if (count == 0)
		return 0;

	len = gb->buf_buf + gb->buf_size - gb->buf_put;
	if (count > len) {
		memcpy(gb->buf_put, buf, len);
		memcpy(gb->buf_buf, buf+len, count - len);
		gb->buf_put = gb->buf_buf + count - len;
	} else {
		memcpy(gb->buf_put, buf, count);
		if (count < len)
			gb->buf_put += count;
		else /* count == len */
			gb->buf_put = gb->buf_buf;
	}

	return count;
}

/*
 * gs_buf_get
 *
 * Get data from the circular buffer and copy to the given buffer.
 * Restrict to the amount of data available.
 *
 * Return the number of bytes copied.
 */
unsigned int gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count)
{
	unsigned int len;

	if (gb == NULL)
		return 0;

	len = gs_buf_data_avail(gb);
	if (count > len)
		count = len;

	if (count == 0)
		return 0;

	len = gb->buf_buf + gb->buf_size - gb->buf_get;
	if (count > len) {
		memcpy(buf, gb->buf_get, len);
		memcpy(buf+len, gb->buf_buf, count - len);
		gb->buf_get = gb->buf_buf + count - len;
	} else {
		memcpy(buf, gb->buf_get, count);
		if (count < len)
			gb->buf_get += count;
		else /* count == len */
			gb->buf_get = gb->buf_buf;
	}

	return count;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -