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

📄 ps3-vuart.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
 * Used to clear pending rx interrupt source.  Will not block. */void ps3_vuart_clear_rx_bytes(struct ps3_system_bus_device *dev,	unsigned int bytes){	int result;	struct ps3_vuart_port_priv *priv = to_port_priv(dev);	u64 bytes_waiting;	void* tmp;	result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes_waiting);	BUG_ON(result);	bytes = bytes ? min(bytes, (unsigned int)bytes_waiting) : bytes_waiting;	dev_dbg(&dev->core, "%s:%d: %u\n", __func__, __LINE__, bytes);	if (!bytes)		return;	/* Add some extra space for recently arrived data. */	bytes += 128;	tmp = kmalloc(bytes, GFP_KERNEL);	if (!tmp)		return;	ps3_vuart_raw_read(dev, tmp, bytes, &bytes_waiting);	kfree(tmp);	/* Don't include these bytes in the stats. */	priv->stats.bytes_read -= bytes_waiting;}EXPORT_SYMBOL_GPL(ps3_vuart_clear_rx_bytes);/** * struct list_buffer - An element for a port device fifo buffer list. */struct list_buffer {	struct list_head link;	const unsigned char *head;	const unsigned char *tail;	unsigned long dbg_number;	unsigned char data[];};/** * ps3_vuart_write - the entry point for writing data to a port * @dev: The struct ps3_system_bus_device instance. * * If the port is idle on entry as much of the incoming data is written to * the port as the port will accept.  Otherwise a list buffer is created * and any remaning incoming data is copied to that buffer.  The buffer is * then enqueued for transmision via the transmit interrupt. */int ps3_vuart_write(struct ps3_system_bus_device *dev, const void *buf,	unsigned int bytes){	static unsigned long dbg_number;	int result;	struct ps3_vuart_port_priv *priv = to_port_priv(dev);	unsigned long flags;	struct list_buffer *lb;	dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,		bytes, bytes);	spin_lock_irqsave(&priv->tx_list.lock, flags);	if (list_empty(&priv->tx_list.head)) {		unsigned long bytes_written;		result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written);		spin_unlock_irqrestore(&priv->tx_list.lock, flags);		if (result) {			dev_dbg(&dev->core,				"%s:%d: ps3_vuart_raw_write failed\n",				__func__, __LINE__);			return result;		}		if (bytes_written == bytes) {			dev_dbg(&dev->core, "%s:%d: wrote %xh bytes\n",				__func__, __LINE__, bytes);			return 0;		}		bytes -= bytes_written;		buf += bytes_written;	} else		spin_unlock_irqrestore(&priv->tx_list.lock, flags);	lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL);	if (!lb) {		return -ENOMEM;	}	memcpy(lb->data, buf, bytes);	lb->head = lb->data;	lb->tail = lb->data + bytes;	lb->dbg_number = ++dbg_number;	spin_lock_irqsave(&priv->tx_list.lock, flags);	list_add_tail(&lb->link, &priv->tx_list.head);	ps3_vuart_enable_interrupt_tx(dev);	spin_unlock_irqrestore(&priv->tx_list.lock, flags);	dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n",		__func__, __LINE__, lb->dbg_number, bytes);	return 0;}EXPORT_SYMBOL_GPL(ps3_vuart_write);/** * ps3_vuart_queue_rx_bytes - Queue waiting bytes into the buffer list. * @dev: The struct ps3_system_bus_device instance. * @bytes_queued: Number of bytes queued to the buffer list. * * Must be called with priv->rx_list.lock held. */static int ps3_vuart_queue_rx_bytes(struct ps3_system_bus_device *dev,	u64 *bytes_queued){	static unsigned long dbg_number;	int result;	struct ps3_vuart_port_priv *priv = to_port_priv(dev);	struct list_buffer *lb;	u64 bytes;	*bytes_queued = 0;	result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes);	BUG_ON(result);	if (result)		return -EIO;	if (!bytes)		return 0;	/* Add some extra space for recently arrived data. */	bytes += 128;	lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_ATOMIC);	if (!lb)		return -ENOMEM;	ps3_vuart_raw_read(dev, lb->data, bytes, &bytes);	lb->head = lb->data;	lb->tail = lb->data + bytes;	lb->dbg_number = ++dbg_number;	list_add_tail(&lb->link, &priv->rx_list.head);	priv->rx_list.bytes_held += bytes;	dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n",		__func__, __LINE__, lb->dbg_number, bytes);	*bytes_queued = bytes;	return 0;}/** * ps3_vuart_read - The entry point for reading data from a port. * * Queue data waiting at the port, and if enough bytes to satisfy the request * are held in the buffer list those bytes are dequeued and copied to the * caller's buffer.  Emptied list buffers are retiered.  If the request cannot * be statified by bytes held in the list buffers -EAGAIN is returned. */int ps3_vuart_read(struct ps3_system_bus_device *dev, void *buf,	unsigned int bytes){	int result;	struct ps3_vuart_port_priv *priv = to_port_priv(dev);	unsigned long flags;	struct list_buffer *lb, *n;	unsigned long bytes_read;	dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,		bytes, bytes);	spin_lock_irqsave(&priv->rx_list.lock, flags);	/* Queue rx bytes here for polled reads. */	while (priv->rx_list.bytes_held < bytes) {		u64 tmp;		result = ps3_vuart_queue_rx_bytes(dev, &tmp);		if (result || !tmp) {			dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n",				__func__, __LINE__,				bytes - priv->rx_list.bytes_held);			spin_unlock_irqrestore(&priv->rx_list.lock, flags);			return -EAGAIN;		}	}	list_for_each_entry_safe(lb, n, &priv->rx_list.head, link) {		bytes_read = min((unsigned int)(lb->tail - lb->head), bytes);		memcpy(buf, lb->head, bytes_read);		buf += bytes_read;		bytes -= bytes_read;		priv->rx_list.bytes_held -= bytes_read;		if (bytes_read < lb->tail - lb->head) {			lb->head += bytes_read;			dev_dbg(&dev->core, "%s:%d: buf_%lu: dequeued %lxh "				"bytes\n", __func__, __LINE__, lb->dbg_number,				bytes_read);			spin_unlock_irqrestore(&priv->rx_list.lock, flags);			return 0;		}		dev_dbg(&dev->core, "%s:%d: buf_%lu: free, dequeued %lxh "			"bytes\n", __func__, __LINE__, lb->dbg_number,			bytes_read);		list_del(&lb->link);		kfree(lb);	}	spin_unlock_irqrestore(&priv->rx_list.lock, flags);	return 0;}EXPORT_SYMBOL_GPL(ps3_vuart_read);/** * ps3_vuart_work - Asynchronous read handler. */static void ps3_vuart_work(struct work_struct *work){	struct ps3_system_bus_device *dev =		ps3_vuart_work_to_system_bus_dev(work);	struct ps3_vuart_port_driver *drv =		ps3_system_bus_dev_to_vuart_drv(dev);	BUG_ON(!drv);	drv->work(dev);}int ps3_vuart_read_async(struct ps3_system_bus_device *dev, unsigned int bytes){	struct ps3_vuart_port_priv *priv = to_port_priv(dev);	unsigned long flags;	if (priv->rx_list.work.trigger) {		dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n",			__func__, __LINE__);		return -EAGAIN;	}	BUG_ON(!bytes);	PREPARE_WORK(&priv->rx_list.work.work, ps3_vuart_work);	spin_lock_irqsave(&priv->rx_list.lock, flags);	if (priv->rx_list.bytes_held >= bytes) {		dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n",			__func__, __LINE__, bytes);		schedule_work(&priv->rx_list.work.work);		spin_unlock_irqrestore(&priv->rx_list.lock, flags);		return 0;	}	priv->rx_list.work.trigger = bytes;	spin_unlock_irqrestore(&priv->rx_list.lock, flags);	dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n", __func__,		__LINE__, bytes, bytes);	return 0;}EXPORT_SYMBOL_GPL(ps3_vuart_read_async);void ps3_vuart_cancel_async(struct ps3_system_bus_device *dev){	to_port_priv(dev)->rx_list.work.trigger = 0;}EXPORT_SYMBOL_GPL(ps3_vuart_cancel_async);/** * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler * * Services the transmit interrupt for the port.  Writes as much data from the * buffer list as the port will accept.  Retires any emptied list buffers and * adjusts the final list buffer state for a partial write. */static int ps3_vuart_handle_interrupt_tx(struct ps3_system_bus_device *dev){	int result = 0;	struct ps3_vuart_port_priv *priv = to_port_priv(dev);	unsigned long flags;	struct list_buffer *lb, *n;	unsigned long bytes_total = 0;	dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);	spin_lock_irqsave(&priv->tx_list.lock, flags);	list_for_each_entry_safe(lb, n, &priv->tx_list.head, link) {		unsigned long bytes_written;		result = ps3_vuart_raw_write(dev, lb->head, lb->tail - lb->head,			&bytes_written);		if (result) {			dev_dbg(&dev->core,				"%s:%d: ps3_vuart_raw_write failed\n",				__func__, __LINE__);			break;		}		bytes_total += bytes_written;		if (bytes_written < lb->tail - lb->head) {			lb->head += bytes_written;			dev_dbg(&dev->core,				"%s:%d cleared buf_%lu, %lxh bytes\n",				__func__, __LINE__, lb->dbg_number,				bytes_written);			goto port_full;		}		dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__,			lb->dbg_number);		list_del(&lb->link);		kfree(lb);	}	ps3_vuart_disable_interrupt_tx(dev);port_full:	spin_unlock_irqrestore(&priv->tx_list.lock, flags);	dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n",		__func__, __LINE__, bytes_total);	return result;}/** * ps3_vuart_handle_interrupt_rx - third stage receive interrupt handler * * Services the receive interrupt for the port.  Creates a list buffer and * copies all waiting port data to that buffer and enqueues the buffer in the * buffer list.  Buffer list data is dequeued via ps3_vuart_read. */static int ps3_vuart_handle_interrupt_rx(struct ps3_system_bus_device *dev){	int result;	struct ps3_vuart_port_priv *priv = to_port_priv(dev);	unsigned long flags;	u64 bytes;	dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);	spin_lock_irqsave(&priv->rx_list.lock, flags);	result = ps3_vuart_queue_rx_bytes(dev, &bytes);	if (result) {		spin_unlock_irqrestore(&priv->rx_list.lock, flags);		return result;	}	if (priv->rx_list.work.trigger && priv->rx_list.bytes_held		>= priv->rx_list.work.trigger) {		dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n",			__func__, __LINE__, priv->rx_list.work.trigger);		priv->rx_list.work.trigger = 0;		schedule_work(&priv->rx_list.work.work);	}	spin_unlock_irqrestore(&priv->rx_list.lock, flags);	return result;}static int ps3_vuart_handle_interrupt_disconnect(	struct ps3_system_bus_device *dev){	dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);	BUG_ON("no support");	return -1;}/** * ps3_vuart_handle_port_interrupt - second stage interrupt handler * * Services any pending interrupt types for the port.  Passes control to the * third stage type specific interrupt handler.  Returns control to the first * stage handler after one iteration. */static int ps3_vuart_handle_port_interrupt(struct ps3_system_bus_device *dev){	int result;	struct ps3_vuart_port_priv *priv = to_port_priv(dev);	unsigned long status;	result = ps3_vuart_get_interrupt_status(dev, &status);	if (result)

⌨️ 快捷键说明

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