?? usbd-monitor.c
字號(hào):
/* * 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:
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -