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

📄 pcwd_usb.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	Berkshire USB-PC Watchdog Card Driver * *	(c) Copyright 2004 Wim Van Sebroeck <wim@iguana.be>. * *	Based on source code of the following authors: *	  Ken Hollis <kenji@bitgate.com>, *	  Alan Cox <alan@redhat.com>, *	  Matt Domsch <Matt_Domsch@dell.com>, *	  Rob Radez <rob@osinvestor.com>, *	  Greg Kroah-Hartman <greg@kroah.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. * *	Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor *	provide warranty for any of this software. This material is *	provided "AS-IS" and at no charge. * *	Thanks also to Simon Machell at Berkshire Products Inc. for *	providing the test hardware. More info is available at *	http://www.berkprod.com/ or http://www.pcwatchdog.com/ */#include <linux/config.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/types.h>#include <linux/delay.h>#include <linux/miscdevice.h>#include <linux/watchdog.h>#include <linux/notifier.h>#include <linux/reboot.h>#include <linux/fs.h>#include <linux/smp_lock.h>#include <linux/completion.h>#include <asm/uaccess.h>#include <linux/usb.h>#ifdef CONFIG_USB_DEBUG	static int debug = 1;#else	static int debug;#endif/* Use our own dbg macro */#undef dbg#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG PFX format "\n" , ## arg); } while (0)/* Module and Version Information */#define DRIVER_VERSION "1.01"#define DRIVER_DATE "15 Mar 2005"#define DRIVER_AUTHOR "Wim Van Sebroeck <wim@iguana.be>"#define DRIVER_DESC "Berkshire USB-PC Watchdog driver"#define DRIVER_LICENSE "GPL"#define DRIVER_NAME "pcwd_usb"#define PFX DRIVER_NAME ": "MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE(DRIVER_LICENSE);MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);MODULE_ALIAS_MISCDEV(TEMP_MINOR);/* Module Parameters */module_param(debug, int, 0);MODULE_PARM_DESC(debug, "Debug enabled or not");#define WATCHDOG_HEARTBEAT 2	/* 2 sec default heartbeat */static int heartbeat = WATCHDOG_HEARTBEAT;module_param(heartbeat, int, 0);MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");static int nowayout = WATCHDOG_NOWAYOUT;module_param(nowayout, int, 0);MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");/* The vendor and product id's for the USB-PC Watchdog card */#define USB_PCWD_VENDOR_ID	0x0c98#define USB_PCWD_PRODUCT_ID	0x1140/* table of devices that work with this driver */static struct usb_device_id usb_pcwd_table [] = {	{ USB_DEVICE(USB_PCWD_VENDOR_ID, USB_PCWD_PRODUCT_ID) },	{ }					/* Terminating entry */};MODULE_DEVICE_TABLE (usb, usb_pcwd_table);/* according to documentation max. time to process a command for the USB * watchdog card is 100 or 200 ms, so we give it 250 ms to do it's job */#define USB_COMMAND_TIMEOUT	250/* Watchdog's internal commands */#define CMD_READ_TEMP			0x02	/* Read Temperature; Re-trigger Watchdog */#define CMD_TRIGGER			CMD_READ_TEMP#define CMD_GET_STATUS			0x04	/* Get Status Information */#define CMD_GET_FIRMWARE_VERSION	0x08	/* Get Firmware Version */#define CMD_GET_DIP_SWITCH_SETTINGS	0x0c	/* Get Dip Switch Settings */#define CMD_READ_WATCHDOG_TIMEOUT	0x18	/* Read Current Watchdog Time */#define CMD_WRITE_WATCHDOG_TIMEOUT	0x19	/* Write Current Watchdog Time */#define CMD_ENABLE_WATCHDOG		0x30	/* Enable / Disable Watchdog */#define CMD_DISABLE_WATCHDOG		CMD_ENABLE_WATCHDOG/* Some defines that I like to be somewhere else like include/linux/usb_hid.h */#define HID_REQ_SET_REPORT		0x09#define HID_DT_REPORT			(USB_TYPE_CLASS | 0x02)/* We can only use 1 card due to the /dev/watchdog restriction */static int cards_found;/* some internal variables */static unsigned long is_active;static char expect_release;/* Structure to hold all of our device specific stuff */struct usb_pcwd_private {	struct usb_device *	udev;			/* save off the usb device pointer */	struct usb_interface *	interface;		/* the interface for this device */	unsigned int		interface_number;	/* the interface number used for cmd's */	unsigned char *		intr_buffer;		/* the buffer to intr data */	dma_addr_t		intr_dma;		/* the dma address for the intr buffer */	size_t			intr_size;		/* the size of the intr buffer */	struct urb *		intr_urb;		/* the urb used for the intr pipe */	unsigned char		cmd_command;		/* The command that is reported back */	unsigned char		cmd_data_msb;		/* The data MSB that is reported back */	unsigned char		cmd_data_lsb;		/* The data LSB that is reported back */	atomic_t		cmd_received;		/* true if we received a report after a command */	int			exists;			/* Wether or not the device exists */	struct semaphore	sem;			/* locks this structure */};static struct usb_pcwd_private *usb_pcwd_device;/* prevent races between open() and disconnect() */static DECLARE_MUTEX (disconnect_sem);/* local function prototypes */static int usb_pcwd_probe	(struct usb_interface *interface, const struct usb_device_id *id);static void usb_pcwd_disconnect	(struct usb_interface *interface);/* usb specific object needed to register this driver with the usb subsystem */static struct usb_driver usb_pcwd_driver = {	.owner =	THIS_MODULE,	.name =		DRIVER_NAME,	.probe =	usb_pcwd_probe,	.disconnect =	usb_pcwd_disconnect,	.id_table =	usb_pcwd_table,};static void usb_pcwd_intr_done(struct urb *urb, struct pt_regs *regs){	struct usb_pcwd_private *usb_pcwd = (struct usb_pcwd_private *)urb->context;	unsigned char *data = usb_pcwd->intr_buffer;	int retval;	switch (urb->status) {	case 0:			/* success */		break;	case -ECONNRESET:	/* unlink */	case -ENOENT:	case -ESHUTDOWN:		/* this urb is terminated, clean up */		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);		return;	/* -EPIPE:  should clear the halt */	default:		/* error */		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);		goto resubmit;	}	dbg("received following data cmd=0x%02x msb=0x%02x lsb=0x%02x",		data[0], data[1], data[2]);	usb_pcwd->cmd_command  = data[0];	usb_pcwd->cmd_data_msb = data[1];	usb_pcwd->cmd_data_lsb = data[2];	/* notify anyone waiting that the cmd has finished */	atomic_set (&usb_pcwd->cmd_received, 1);resubmit:	retval = usb_submit_urb (urb, GFP_ATOMIC);	if (retval)		printk(KERN_ERR PFX "can't resubmit intr, usb_submit_urb failed with result %d\n",			retval);}static int usb_pcwd_send_command(struct usb_pcwd_private *usb_pcwd, unsigned char cmd,	unsigned char *msb, unsigned char *lsb){	int got_response, count;	unsigned char buf[6];	/* We will not send any commands if the USB PCWD device does not exist */	if ((!usb_pcwd) || (!usb_pcwd->exists))		return -1;	/* The USB PC Watchdog uses a 6 byte report format. The board currently uses	 * only 3 of the six bytes of the report. */	buf[0] = cmd;			/* Byte 0 = CMD */	buf[1] = *msb;			/* Byte 1 = Data MSB */	buf[2] = *lsb;			/* Byte 2 = Data LSB */	buf[3] = buf[4] = buf[5] = 0;	/* All other bytes not used */	dbg("sending following data cmd=0x%02x msb=0x%02x lsb=0x%02x",		buf[0], buf[1], buf[2]);	atomic_set (&usb_pcwd->cmd_received, 0);	if (usb_control_msg(usb_pcwd->udev, usb_sndctrlpipe(usb_pcwd->udev, 0),			HID_REQ_SET_REPORT, HID_DT_REPORT,			0x0200, usb_pcwd->interface_number, buf, sizeof(buf),			USB_COMMAND_TIMEOUT) != sizeof(buf)) {		dbg("usb_pcwd_send_command: error in usb_control_msg for cmd 0x%x 0x%x 0x%x\n", cmd, *msb, *lsb);	}	/* wait till the usb card processed the command,	 * with a max. timeout of USB_COMMAND_TIMEOUT */	got_response = 0;	for (count = 0; (count < USB_COMMAND_TIMEOUT) && (!got_response); count++) {		mdelay(1);		if (atomic_read (&usb_pcwd->cmd_received))			got_response = 1;	}	if ((got_response) && (cmd == usb_pcwd->cmd_command)) {		/* read back response */		*msb = usb_pcwd->cmd_data_msb;		*lsb = usb_pcwd->cmd_data_lsb;	}	return got_response;}static int usb_pcwd_start(struct usb_pcwd_private *usb_pcwd){	unsigned char msb = 0x00;	unsigned char lsb = 0x00;	int retval;	/* Enable Watchdog */	retval = usb_pcwd_send_command(usb_pcwd, CMD_ENABLE_WATCHDOG, &msb, &lsb);	if ((retval == 0) || (lsb == 0)) {		printk(KERN_ERR PFX "Card did not acknowledge enable attempt\n");		return -1;	}	return 0;}static int usb_pcwd_stop(struct usb_pcwd_private *usb_pcwd){	unsigned char msb = 0xA5;	unsigned char lsb = 0xC3;	int retval;	/* Disable Watchdog */	retval = usb_pcwd_send_command(usb_pcwd, CMD_DISABLE_WATCHDOG, &msb, &lsb);	if ((retval == 0) || (lsb != 0)) {		printk(KERN_ERR PFX "Card did not acknowledge disable attempt\n");		return -1;	}	return 0;}static int usb_pcwd_keepalive(struct usb_pcwd_private *usb_pcwd){	unsigned char dummy;	/* Re-trigger Watchdog */	usb_pcwd_send_command(usb_pcwd, CMD_TRIGGER, &dummy, &dummy);	return 0;}static int usb_pcwd_set_heartbeat(struct usb_pcwd_private *usb_pcwd, int t){	unsigned char msb = t / 256;	unsigned char lsb = t % 256;	if ((t < 0x0001) || (t > 0xFFFF))		return -EINVAL;	/* Write new heartbeat to watchdog */	usb_pcwd_send_command(usb_pcwd, CMD_WRITE_WATCHDOG_TIMEOUT, &msb, &lsb);	heartbeat = t;	return 0;}static int usb_pcwd_get_temperature(struct usb_pcwd_private *usb_pcwd, int *temperature){	unsigned char msb, lsb;	usb_pcwd_send_command(usb_pcwd, CMD_READ_TEMP, &msb, &lsb);	/*	 * Convert celsius to fahrenheit, since this was	 * the decided 'standard' for this return value.	 */	*temperature = (lsb * 9 / 5) + 32;	return 0;}/* *	/dev/watchdog handling */static ssize_t usb_pcwd_write(struct file *file, const char __user *data,			      size_t len, loff_t *ppos){	/* See if we got the magic character 'V' and reload the timer */	if (len) {		if (!nowayout) {			size_t i;			/* note: just in case someone wrote the magic character			 * five months ago... */			expect_release = 0;			/* scan to see whether or not we got the magic character */			for (i = 0; i != len; i++) {				char c;				if(get_user(c, data+i))					return -EFAULT;				if (c == 'V')					expect_release = 42;			}		}		/* someone wrote to us, we should reload the timer */		usb_pcwd_keepalive(usb_pcwd_device);	}	return len;}static int usb_pcwd_ioctl(struct inode *inode, struct file *file,			  unsigned int cmd, unsigned long arg){	void __user *argp = (void __user *)arg;	int __user *p = argp;	static struct watchdog_info ident = {		.options =		WDIOF_KEEPALIVEPING |					WDIOF_SETTIMEOUT |					WDIOF_MAGICCLOSE,		.firmware_version =	1,		.identity =		DRIVER_NAME,	};	switch (cmd) {		case WDIOC_GETSUPPORT:			return copy_to_user(argp, &ident,				sizeof (ident)) ? -EFAULT : 0;		case WDIOC_GETSTATUS:		case WDIOC_GETBOOTSTATUS:			return put_user(0, p);		case WDIOC_GETTEMP:		{			int temperature;			if (usb_pcwd_get_temperature(usb_pcwd_device, &temperature))				return -EFAULT;			return put_user(temperature, p);		}		case WDIOC_KEEPALIVE:			usb_pcwd_keepalive(usb_pcwd_device);			return 0;		case WDIOC_SETOPTIONS:		{			int new_options, retval = -EINVAL;			if (get_user (new_options, p))				return -EFAULT;			if (new_options & WDIOS_DISABLECARD) {				usb_pcwd_stop(usb_pcwd_device);

⌨️ 快捷键说明

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