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

📄 usbd-monitor.c

📁 S3C2440ARM9开发板的USB驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/drivers/usbd/usbd-monitor.c - USB Device Cable Monitor * * Copyright (c) 2000, 2001, 2002 Lineo * Copyright (c) 2001 Hewlett Packard * * By:  *      Stuart Lynne <sl@lineo.com>,  *      Tom Rushworth <tbr@lineo.com>,  *      Bruce Balden <balden@lineo.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <linux/config.h>#include <linux/module.h>#include "usbd-export.h"#include "usbd-build.h"#include "usbd-module.h"MODULE_AUTHOR ("sl@lineo.com, tbr@lineo.com");MODULE_DESCRIPTION ("USB Device Monitor");USBD_MODULE_INFO ("usbd_monitor 0.3");EXPORT_NO_SYMBOLS;#include <linux/init.h>#include <linux/kernel.h>#include <linux/list.h>#include <asm/uaccess.h>#include <linux/netdevice.h>#include <linux/skbuff.h>#include <linux/etherdevice.h>#include <net/arp.h>#include <linux/rtnetlink.h>#include <linux/smp_lock.h>#include <linux/ctype.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/pkt_sched.h>#include <asm/io.h>#include <linux/proc_fs.h>#include <linux/kmod.h>/* * Architecture specific includes */#if defined(CONFIG_ARCH_SA1100) || defined(CONFIG_SABINAL_DISCOVERY)#include <asm/irq.h>#include <asm/hardware.h>#include "usbd.h"#include "usbd-func.h"#include "usbd-bus.h"#include "hotplug.h"/* pick up any required GPIO pin definitions */#if defined(CONFIG_ARCH_SA1100)#include "bi/sa1100.h"#endif#endif#if defined(CONFIG_PM)#include <linux/pm.h>#endif/* Module Parameters ************************************************************************* */typedef enum monitor_status {	MONITOR_UNKNOWN,	MONITOR_LOADING,	// loading due to cable connection interrupt	MONITOR_LOADED,		// loaded 	MONITOR_UNLOADING,	// unloading due to cable disconnection interrupt	MONITOR_UNLOADED,	// unloaded#ifdef CONFIG_PM	MONITOR_SUSPENDING,	// suspending due to power management event	MONITOR_SUSPENDED,	// suspended due to power management event	MONITOR_RESTORING,	// restoring #endif} monitor_status_t;/* struct monitor_bi_data - * * private data structure for this bus interface driver */struct monitor_data {	monitor_status_t status;	struct tq_struct monitor_bh;	struct tq_struct hotplug_bh;	int have_irq;#ifdef CONFIG_PM	struct pm_dev *pm_info;#endif};struct monitor_data monitor;void monitor_int_hndlr (int irq, void *dev_id, struct pt_regs *regs);/** * monitor_request_irq */int monitor_request_irq (void){#if defined(CONFIG_SA1100_USBCABLE_GPIO)	int rc;	printk (KERN_DEBUG "monitor_request_irq: %d %d\n", CONFIG_SA1100_USBCABLE_GPIO, SA1100_GPIO_TO_IRQ (CONFIG_SA1100_USBCABLE_GPIO));	if ((rc = request_irq (SA1100_GPIO_TO_IRQ (CONFIG_SA1100_USBCABLE_GPIO), monitor_int_hndlr, SA_SHIRQ, "USBD Monitor", &monitor))) {		printk (KERN_DEBUG "monitor_request_irq: failed: %d\n", rc);		return -EINVAL;	}	GPDR &= ~GPIO_GPIO (CONFIG_SA1100_USBCABLE_GPIO);	set_GPIO_IRQ_edge (GPIO_GPIO (CONFIG_SA1100_USBCABLE_GPIO), GPIO_BOTH_EDGES);#endif	return 0;}/** * monitor_free_irq */void monitor_free_irq (void){#if defined(CONFIG_SA1100_USBCABLE_GPIO)	free_irq (SA1100_GPIO_TO_IRQ (CONFIG_SA1100_USBCABLE_GPIO), NULL);#endif}/** * monitor_connected - connected to cable * * Return non-zero if via USB cable to USB Hub or Host */int monitor_connected (void){	int rc = 1;	/*	 * Architecture specific - determine connect status	 */	/*	 * SA-1100	 *	 * Only pay attention to the status if we also can control the pullup.	 */#if defined(CONFIG_SA1100_USBCABLE_GPIO) && defined(CONFIG_SA1100_CONNECT_GPIO)#ifdef CONFIG_SA1100_CONNECT_ACTIVE_HIGH	rc = (GPLR & GPIO_GPIO (23)) != 0;	printk (KERN_DEBUG "udc_connected: ACTIVE_HIGH: %d", rc);#else	rc = (GPLR & GPIO_GPIO (23)) == 0;	printk (KERN_DEBUG "udc_connected: ACTIVE_LOW: %d", rc);#endif#endif				/* CONFIG_ARCH_SA1100 && CONFIG_SA1100_USBCABLE_GPIO */	printk (KERN_DEBUG "monitor_connected: %d\n", rc);	return rc;}static char *hotplug_actions[] = {	"load",	"suspend",	"restore-loaded",	"restore-unloaded",	"unload"};/* indices for the hotplug_actions array, these must match the array */#define MHA_LOAD               0#define MHA_SUSPEND            1#define MHA_RESTORE_LOADED     2#define MHA_RESTORE_UNLOADED   3#define MHA_UNLOAD             4#if defined(CONFIG_USBD_PROCFS)#define HOTPLUG_SYNC_TIMEOUT  (10*HZ)static DECLARE_MUTEX_LOCKED (hotplug_done);static struct timer_list hotplug_timeout;static void hotplug_sync_over (unsigned long data){	printk (KERN_ERR "usbdmonitor: warning - hotplug script timed out\n");	up (&hotplug_done);}#endifstatic int monitor_exiting = 0;int monitor_hotplug (int action_ndx){	/* This should probably be serialized - if PM runs in a separate	   context, it would seem possible for someone to "rmmmod usbdmonitor"	   (e.g. via "at") at the same time time PM decides to suspend.	   Unfortunately, there is no airtight way to accomplish that inside	   this module - once PM has called the registered fn, the "race"	   is on :(. */	int rc;	if (action_ndx < 0 || action_ndx > MHA_UNLOAD) {		return (-EINVAL);	}	if (monitor_exiting) {		if (MHA_UNLOAD != action_ndx) {			return (-EINVAL);		}		if (MONITOR_UNLOADED == monitor.status || MONITOR_UNLOADING == monitor.status) {			/* No need to do it again... */			return (0);		}	}	printk (KERN_DEBUG "monitor_hotplug: agent: usbd interface: monitor action: %s\n", hotplug_actions[action_ndx]);#if defined(CONFIG_USBD_PROCFS)	/* Sync - fire up the script and wait for it to echo something to	   /proc/usb-monitor (or else PM SUSPEND may not work) */	init_MUTEX_LOCKED (&hotplug_done);	/* fire up the script */	rc = hotplug ("usbd", "monitor", hotplug_actions[action_ndx]);	if (0 == rc) {		/* wait for the nudge from a write to /proc/usb-monitor */		init_timer (&hotplug_timeout);		hotplug_timeout.data = 0;		hotplug_timeout.function = hotplug_sync_over;		hotplug_timeout.expires = jiffies + HOTPLUG_SYNC_TIMEOUT;		add_timer (&hotplug_timeout);		down_interruptible (&hotplug_done);		del_timer (&hotplug_timeout);	}#else	/* Async - fire up the script and return */	rc = hotplug ("usbd", "monitor", hotplug_actions[action_ndx]);#endif	return (rc);}#ifdef CONFIG_PM/** * monitor_suspend * * Check status, unload if required, set monitor status. */int monitor_suspend (void){	unsigned long flags;	local_irq_save (flags);	switch (monitor.status) {	case MONITOR_UNKNOWN:	case MONITOR_UNLOADED:		local_irq_restore (flags);		return 0;	case MONITOR_LOADING:	case MONITOR_UNLOADING:	case MONITOR_SUSPENDING:	case MONITOR_RESTORING:	case MONITOR_SUSPENDED:		// XXX we should wait for this		local_irq_restore (flags);		return -EINVAL;	case MONITOR_LOADED:		monitor.status = MONITOR_SUSPENDING;		local_irq_restore (flags);		monitor_hotplug (MHA_SUSPEND);		monitor.status = MONITOR_SUSPENDED;		return 0;	default:		return -EINVAL;	}}#endif/** * hotplug_bh -  * @ignored: * * Check connected status and load/unload as appropriate. */void hotplug_bh (void *ignored){	printk (KERN_DEBUG "hotplug_bh:\n");	if (monitor_connected ()) {		printk (KERN_DEBUG "monitor_restore: RESTORE_LOADED\n");		monitor_hotplug (MHA_RESTORE_LOADED);		monitor.status = MONITOR_LOADED;	} else {		printk (KERN_DEBUG "monitor_restore: RESTORE_UNLOADED\n");		monitor_hotplug (MHA_RESTORE_UNLOADED);		monitor.status = MONITOR_UNLOADED;	}	MOD_DEC_USE_COUNT;}/** * hotplug_schedule_bh - */void hotplug_schedule_bh (void){	printk (KERN_DEBUG "hotplug_schedule_bh: schedule bh\n");	if (monitor.hotplug_bh.sync) {		return;	}	MOD_INC_USE_COUNT;	if (!schedule_task (&monitor.hotplug_bh)) {		printk (KERN_DEBUG "monitor_schedule_bh: failed\n");		MOD_DEC_USE_COUNT;	}}#ifdef CONFIG_PM/** * monitor_restore * * Check status, load if required, set monitor status. */int monitor_restore (void){	unsigned long flags;	local_irq_save (flags);	switch (monitor.status) {	case MONITOR_SUSPENDED:		monitor.status = MONITOR_RESTORING;		local_irq_restore (flags);		hotplug_schedule_bh ();		return 0;	case MONITOR_UNKNOWN:	case MONITOR_UNLOADED:	case MONITOR_LOADING:	case MONITOR_UNLOADING:	case MONITOR_SUSPENDING:	case MONITOR_RESTORING:		// XXX we should wait for this		local_irq_restore (flags);		return -EINVAL;	case MONITOR_LOADED:		local_irq_restore (flags);		return 0;	default:		return -EINVAL;	}}/** * monitor_pm_event * * Handle power management event */static int monitor_pm_event (struct pm_dev *dev, pm_request_t rqst, void *unused){	int rc;	/* See comment regarding race condition at start of monitor_hotplug() */	MOD_INC_USE_COUNT;	rc = 0;	switch (rqst) {	case PM_SUSPEND:		// Force unloading		rc = monitor_suspend ();		printk (KERN_ERR "%s: suspend finished (rc=%d)\n", __FUNCTION__, rc);		break;	case PM_RESUME:

⌨️ 快捷键说明

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