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

📄 ps3-vuart.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		return result;	dev_dbg(&dev->core, "%s:%d: status: %lxh\n", __func__, __LINE__,		status);	if (status & INTERRUPT_MASK_DISCONNECT) {		priv->stats.disconnect_interrupts++;		result = ps3_vuart_handle_interrupt_disconnect(dev);		if (result)			ps3_vuart_disable_interrupt_disconnect(dev);	}	if (status & INTERRUPT_MASK_TX) {		priv->stats.tx_interrupts++;		result = ps3_vuart_handle_interrupt_tx(dev);		if (result)			ps3_vuart_disable_interrupt_tx(dev);	}	if (status & INTERRUPT_MASK_RX) {		priv->stats.rx_interrupts++;		result = ps3_vuart_handle_interrupt_rx(dev);		if (result)			ps3_vuart_disable_interrupt_rx(dev);	}	return 0;}struct vuart_bus_priv {	struct ports_bmp *bmp;	unsigned int virq;	struct semaphore probe_mutex;	int use_count;	struct ps3_system_bus_device *devices[PORT_COUNT];} static vuart_bus_priv;/** * ps3_vuart_irq_handler - first stage interrupt handler * * Loops finding any interrupting port and its associated instance data. * Passes control to the second stage port specific interrupt handler.  Loops * until all outstanding interrupts are serviced. */static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private){	struct vuart_bus_priv *bus_priv = _private;	BUG_ON(!bus_priv);	while (1) {		unsigned int port;		dump_ports_bmp(bus_priv->bmp);		port = (BITS_PER_LONG - 1) - __ilog2(bus_priv->bmp->status);		if (port == BITS_PER_LONG)			break;		BUG_ON(port >= PORT_COUNT);		BUG_ON(!bus_priv->devices[port]);		ps3_vuart_handle_port_interrupt(bus_priv->devices[port]);	}	return IRQ_HANDLED;}static int ps3_vuart_bus_interrupt_get(void){	int result;	pr_debug(" -> %s:%d\n", __func__, __LINE__);	vuart_bus_priv.use_count++;	BUG_ON(vuart_bus_priv.use_count > 2);	if (vuart_bus_priv.use_count != 1) {		return 0;	}	BUG_ON(vuart_bus_priv.bmp);	vuart_bus_priv.bmp = kzalloc(sizeof(struct ports_bmp), GFP_KERNEL);	if (!vuart_bus_priv.bmp) {		pr_debug("%s:%d: kzalloc failed.\n", __func__, __LINE__);		result = -ENOMEM;		goto fail_bmp_malloc;	}	result = ps3_vuart_irq_setup(PS3_BINDING_CPU_ANY, vuart_bus_priv.bmp,		&vuart_bus_priv.virq);	if (result) {		pr_debug("%s:%d: ps3_vuart_irq_setup failed (%d)\n",			__func__, __LINE__, result);		result = -EPERM;		goto fail_alloc_irq;	}	result = request_irq(vuart_bus_priv.virq, ps3_vuart_irq_handler,		IRQF_DISABLED, "vuart", &vuart_bus_priv);	if (result) {		pr_debug("%s:%d: request_irq failed (%d)\n",			__func__, __LINE__, result);		goto fail_request_irq;	}	pr_debug(" <- %s:%d: ok\n", __func__, __LINE__);	return result;fail_request_irq:	ps3_vuart_irq_destroy(vuart_bus_priv.virq);	vuart_bus_priv.virq = NO_IRQ;fail_alloc_irq:	kfree(vuart_bus_priv.bmp);	vuart_bus_priv.bmp = NULL;fail_bmp_malloc:	vuart_bus_priv.use_count--;	pr_debug(" <- %s:%d: failed\n", __func__, __LINE__);	return result;}static int ps3_vuart_bus_interrupt_put(void){	pr_debug(" -> %s:%d\n", __func__, __LINE__);	vuart_bus_priv.use_count--;	BUG_ON(vuart_bus_priv.use_count < 0);	if (vuart_bus_priv.use_count != 0)		return 0;	free_irq(vuart_bus_priv.virq, &vuart_bus_priv);	ps3_vuart_irq_destroy(vuart_bus_priv.virq);	vuart_bus_priv.virq = NO_IRQ;	kfree(vuart_bus_priv.bmp);	vuart_bus_priv.bmp = NULL;	pr_debug(" <- %s:%d\n", __func__, __LINE__);	return 0;}static int ps3_vuart_probe(struct ps3_system_bus_device *dev){	int result;	struct ps3_vuart_port_driver *drv;	struct ps3_vuart_port_priv *priv = NULL;	dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);	drv = ps3_system_bus_dev_to_vuart_drv(dev);	dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__,		drv->core.core.name);	BUG_ON(!drv);	if (dev->port_number >= PORT_COUNT) {		BUG();		return -EINVAL;	}	down(&vuart_bus_priv.probe_mutex);	result = ps3_vuart_bus_interrupt_get();	if (result)		goto fail_setup_interrupt;	if (vuart_bus_priv.devices[dev->port_number]) {		dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__,			__LINE__, dev->port_number);		result = -EBUSY;		goto fail_busy;	}	vuart_bus_priv.devices[dev->port_number] = dev;	/* Setup dev->driver_priv. */	dev->driver_priv = kzalloc(sizeof(struct ps3_vuart_port_priv),		GFP_KERNEL);	if (!dev->driver_priv) {		result = -ENOMEM;		goto fail_dev_malloc;	}	priv = to_port_priv(dev);	INIT_LIST_HEAD(&priv->tx_list.head);	spin_lock_init(&priv->tx_list.lock);	INIT_LIST_HEAD(&priv->rx_list.head);	spin_lock_init(&priv->rx_list.lock);	INIT_WORK(&priv->rx_list.work.work, NULL);	priv->rx_list.work.trigger = 0;	priv->rx_list.work.dev = dev;	/* clear stale pending interrupts */	ps3_vuart_clear_rx_bytes(dev, 0);	ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX);	ps3_vuart_set_triggers(dev, 1, 1);	if (drv->probe)		result = drv->probe(dev);	else {		result = 0;		dev_info(&dev->core, "%s:%d: no probe method\n", __func__,			__LINE__);	}	if (result) {		dev_dbg(&dev->core, "%s:%d: drv->probe failed\n",			__func__, __LINE__);		goto fail_probe;	}	up(&vuart_bus_priv.probe_mutex);	return result;fail_probe:	ps3_vuart_set_interrupt_mask(dev, 0);	kfree(dev->driver_priv);	dev->driver_priv = NULL;fail_dev_malloc:	vuart_bus_priv.devices[dev->port_number] = NULL;fail_busy:	ps3_vuart_bus_interrupt_put();fail_setup_interrupt:	up(&vuart_bus_priv.probe_mutex);	dev_dbg(&dev->core, "%s:%d: failed\n", __func__, __LINE__);	return result;}/** * ps3_vuart_cleanup - common cleanup helper. * @dev: The struct ps3_system_bus_device instance. * * Cleans interrupts and HV resources.  Must be called with * vuart_bus_priv.probe_mutex held.  Used by ps3_vuart_remove and * ps3_vuart_shutdown.  After this call, polled reading will still work. */static int ps3_vuart_cleanup(struct ps3_system_bus_device *dev){	dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);	ps3_vuart_cancel_async(dev);	ps3_vuart_set_interrupt_mask(dev, 0);	ps3_vuart_bus_interrupt_put();	return 0;}/** * ps3_vuart_remove - Completely clean the device instance. * @dev: The struct ps3_system_bus_device instance. * * Cleans all memory, interrupts and HV resources.  After this call the * device can no longer be used. */static int ps3_vuart_remove(struct ps3_system_bus_device *dev){	struct ps3_vuart_port_priv *priv = to_port_priv(dev);	struct ps3_vuart_port_driver *drv;	BUG_ON(!dev);	down(&vuart_bus_priv.probe_mutex);	dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__,		dev->match_id);	if (!dev->core.driver) {		dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__,			__LINE__);		up(&vuart_bus_priv.probe_mutex);		return 0;	}	drv = ps3_system_bus_dev_to_vuart_drv(dev);	BUG_ON(!drv);	if (drv->remove) {		drv->remove(dev);	} else {		dev_dbg(&dev->core, "%s:%d: no remove method\n", __func__,		__LINE__);		BUG();	}	ps3_vuart_cleanup(dev);	vuart_bus_priv.devices[dev->port_number] = NULL;	kfree(priv);	priv = NULL;	dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);	up(&vuart_bus_priv.probe_mutex);	return 0;}/** * ps3_vuart_shutdown - Cleans interrupts and HV resources. * @dev: The struct ps3_system_bus_device instance. * * Cleans interrupts and HV resources.  After this call the * device can still be used in polling mode.  This behavior required * by sys-manager to be able to complete the device power operation * sequence. */static int ps3_vuart_shutdown(struct ps3_system_bus_device *dev){	struct ps3_vuart_port_driver *drv;	BUG_ON(!dev);	down(&vuart_bus_priv.probe_mutex);	dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__,		dev->match_id);	if (!dev->core.driver) {		dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__,			__LINE__);		up(&vuart_bus_priv.probe_mutex);		return 0;	}	drv = ps3_system_bus_dev_to_vuart_drv(dev);	BUG_ON(!drv);	if (drv->shutdown)		drv->shutdown(dev);	else if (drv->remove) {		dev_dbg(&dev->core, "%s:%d: no shutdown, calling remove\n",			__func__, __LINE__);		drv->remove(dev);	} else {		dev_dbg(&dev->core, "%s:%d: no shutdown method\n", __func__,			__LINE__);		BUG();	}	ps3_vuart_cleanup(dev);	dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);	up(&vuart_bus_priv.probe_mutex);	return 0;}static int __init ps3_vuart_bus_init(void){	pr_debug("%s:%d:\n", __func__, __LINE__);	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))		return -ENODEV;	init_MUTEX(&vuart_bus_priv.probe_mutex);	return 0;}static void __exit ps3_vuart_bus_exit(void){	pr_debug("%s:%d:\n", __func__, __LINE__);}core_initcall(ps3_vuart_bus_init);module_exit(ps3_vuart_bus_exit);/** * ps3_vuart_port_driver_register - Add a vuart port device driver. */int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv){	int result;	pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.core.name);	BUG_ON(!drv->core.match_id);	BUG_ON(!drv->core.core.name);	drv->core.probe = ps3_vuart_probe;	drv->core.remove = ps3_vuart_remove;	drv->core.shutdown = ps3_vuart_shutdown;	result = ps3_system_bus_driver_register(&drv->core);	return result;}EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register);/** * ps3_vuart_port_driver_unregister - Remove a vuart port device driver. */void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv){	pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.core.name);	ps3_system_bus_driver_unregister(&drv->core);}EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_unregister);

⌨️ 快捷键说明

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