diff options
Diffstat (limited to 'drivers/input/misc/winbond-cir.c')
| -rw-r--r-- | drivers/input/misc/winbond-cir.c | 1608 | 
1 files changed, 0 insertions, 1608 deletions
diff --git a/drivers/input/misc/winbond-cir.c b/drivers/input/misc/winbond-cir.c deleted file mode 100644 index 64f1de7960c..00000000000 --- a/drivers/input/misc/winbond-cir.c +++ /dev/null @@ -1,1608 +0,0 @@ -/* - *  winbond-cir.c - Driver for the Consumer IR functionality of Winbond - *                  SuperI/O chips. - * - *  Currently supports the Winbond WPCD376i chip (PNP id WEC1022), but - *  could probably support others (Winbond WEC102X, NatSemi, etc) - *  with minor modifications. - * - *  Original Author: David Härdeman <david@hardeman.nu> - *     Copyright (C) 2009 David Härdeman <david@hardeman.nu> - * - *  Dedicated to Matilda, my newborn daughter, without whose loving attention - *  this driver would have been finished in half the time and with a fraction - *  of the bugs. - * - *  Written using: - *    o Winbond WPCD376I datasheet helpfully provided by Jesse Barnes at Intel - *    o NatSemi PC87338/PC97338 datasheet (for the serial port stuff) - *    o DSDT dumps - * - *  Supported features: - *    o RC6 - *    o Wake-On-CIR functionality - * - *  To do: - *    o Test NEC and RC5 - * - *  Left as an exercise for the reader: - *    o Learning (I have neither the hardware, nor the need) - *    o IR Transmit (ibid) - * - *  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/module.h> -#include <linux/pnp.h> -#include <linux/interrupt.h> -#include <linux/timer.h> -#include <linux/input.h> -#include <linux/leds.h> -#include <linux/list.h> -#include <linux/spinlock.h> -#include <linux/pci_ids.h> -#include <linux/io.h> -#include <linux/bitrev.h> -#include <linux/bitops.h> -#include <linux/slab.h> - -#define DRVNAME "winbond-cir" - -/* CEIR Wake-Up Registers, relative to data->wbase                      */ -#define WBCIR_REG_WCEIR_CTL	0x03 /* CEIR Receiver Control		*/ -#define WBCIR_REG_WCEIR_STS	0x04 /* CEIR Receiver Status		*/ -#define WBCIR_REG_WCEIR_EV_EN	0x05 /* CEIR Receiver Event Enable	*/ -#define WBCIR_REG_WCEIR_CNTL	0x06 /* CEIR Receiver Counter Low	*/ -#define WBCIR_REG_WCEIR_CNTH	0x07 /* CEIR Receiver Counter High	*/ -#define WBCIR_REG_WCEIR_INDEX	0x08 /* CEIR Receiver Index		*/ -#define WBCIR_REG_WCEIR_DATA	0x09 /* CEIR Receiver Data		*/ -#define WBCIR_REG_WCEIR_CSL	0x0A /* CEIR Re. Compare Strlen		*/ -#define WBCIR_REG_WCEIR_CFG1	0x0B /* CEIR Re. Configuration 1	*/ -#define WBCIR_REG_WCEIR_CFG2	0x0C /* CEIR Re. Configuration 2	*/ - -/* CEIR Enhanced Functionality Registers, relative to data->ebase       */ -#define WBCIR_REG_ECEIR_CTS	0x00 /* Enhanced IR Control Status	*/ -#define WBCIR_REG_ECEIR_CCTL	0x01 /* Infrared Counter Control	*/ -#define WBCIR_REG_ECEIR_CNT_LO	0x02 /* Infrared Counter LSB		*/ -#define WBCIR_REG_ECEIR_CNT_HI	0x03 /* Infrared Counter MSB		*/ -#define WBCIR_REG_ECEIR_IREM	0x04 /* Infrared Emitter Status		*/ - -/* SP3 Banked Registers, relative to data->sbase                        */ -#define WBCIR_REG_SP3_BSR	0x03 /* Bank Select, all banks		*/ -				      /* Bank 0				*/ -#define WBCIR_REG_SP3_RXDATA	0x00 /* FIFO RX data (r)		*/ -#define WBCIR_REG_SP3_TXDATA	0x00 /* FIFO TX data (w)		*/ -#define WBCIR_REG_SP3_IER	0x01 /* Interrupt Enable		*/ -#define WBCIR_REG_SP3_EIR	0x02 /* Event Identification (r)	*/ -#define WBCIR_REG_SP3_FCR	0x02 /* FIFO Control (w)		*/ -#define WBCIR_REG_SP3_MCR	0x04 /* Mode Control			*/ -#define WBCIR_REG_SP3_LSR	0x05 /* Link Status			*/ -#define WBCIR_REG_SP3_MSR	0x06 /* Modem Status			*/ -#define WBCIR_REG_SP3_ASCR	0x07 /* Aux Status and Control		*/ -				      /* Bank 2				*/ -#define WBCIR_REG_SP3_BGDL	0x00 /* Baud Divisor LSB		*/ -#define WBCIR_REG_SP3_BGDH	0x01 /* Baud Divisor MSB		*/ -#define WBCIR_REG_SP3_EXCR1	0x02 /* Extended Control 1		*/ -#define WBCIR_REG_SP3_EXCR2	0x04 /* Extended Control 2		*/ -#define WBCIR_REG_SP3_TXFLV	0x06 /* TX FIFO Level			*/ -#define WBCIR_REG_SP3_RXFLV	0x07 /* RX FIFO Level			*/ -				      /* Bank 3				*/ -#define WBCIR_REG_SP3_MRID	0x00 /* Module Identification		*/ -#define WBCIR_REG_SP3_SH_LCR	0x01 /* LCR Shadow			*/ -#define WBCIR_REG_SP3_SH_FCR	0x02 /* FCR Shadow			*/ -				      /* Bank 4				*/ -#define WBCIR_REG_SP3_IRCR1	0x02 /* Infrared Control 1		*/ -				      /* Bank 5				*/ -#define WBCIR_REG_SP3_IRCR2	0x04 /* Infrared Control 2		*/ -				      /* Bank 6				*/ -#define WBCIR_REG_SP3_IRCR3	0x00 /* Infrared Control 3		*/ -#define WBCIR_REG_SP3_SIR_PW	0x02 /* SIR Pulse Width		*/ -				      /* Bank 7				*/ -#define WBCIR_REG_SP3_IRRXDC	0x00 /* IR RX Demod Control		*/ -#define WBCIR_REG_SP3_IRTXMC	0x01 /* IR TX Mod Control		*/ -#define WBCIR_REG_SP3_RCCFG	0x02 /* CEIR Config			*/ -#define WBCIR_REG_SP3_IRCFG1	0x04 /* Infrared Config 1		*/ -#define WBCIR_REG_SP3_IRCFG4	0x07 /* Infrared Config 4		*/ - -/* - * Magic values follow - */ - -/* No interrupts for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */ -#define WBCIR_IRQ_NONE		0x00 -/* RX data bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */ -#define WBCIR_IRQ_RX		0x01 -/* Over/Under-flow bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */ -#define WBCIR_IRQ_ERR		0x04 -/* Led enable/disable bit for WBCIR_REG_ECEIR_CTS */ -#define WBCIR_LED_ENABLE	0x80 -/* RX data available bit for WBCIR_REG_SP3_LSR */ -#define WBCIR_RX_AVAIL		0x01 -/* RX disable bit for WBCIR_REG_SP3_ASCR */ -#define WBCIR_RX_DISABLE	0x20 -/* Extended mode enable bit for WBCIR_REG_SP3_EXCR1 */ -#define WBCIR_EXT_ENABLE	0x01 -/* Select compare register in WBCIR_REG_WCEIR_INDEX (bits 5 & 6) */ -#define WBCIR_REGSEL_COMPARE	0x10 -/* Select mask register in WBCIR_REG_WCEIR_INDEX (bits 5 & 6) */ -#define WBCIR_REGSEL_MASK	0x20 -/* Starting address of selected register in WBCIR_REG_WCEIR_INDEX */ -#define WBCIR_REG_ADDR0		0x00 - -/* Valid banks for the SP3 UART */ -enum wbcir_bank { -	WBCIR_BANK_0          = 0x00, -	WBCIR_BANK_1          = 0x80, -	WBCIR_BANK_2          = 0xE0, -	WBCIR_BANK_3          = 0xE4, -	WBCIR_BANK_4          = 0xE8, -	WBCIR_BANK_5          = 0xEC, -	WBCIR_BANK_6          = 0xF0, -	WBCIR_BANK_7          = 0xF4, -}; - -/* Supported IR Protocols */ -enum wbcir_protocol { -	IR_PROTOCOL_RC5          = 0x0, -	IR_PROTOCOL_NEC          = 0x1, -	IR_PROTOCOL_RC6          = 0x2, -}; - -/* Misc */ -#define WBCIR_NAME	"Winbond CIR" -#define WBCIR_ID_FAMILY          0xF1 /* Family ID for the WPCD376I	*/ -#define	WBCIR_ID_CHIP            0x04 /* Chip ID for the WPCD376I	*/ -#define IR_KEYPRESS_TIMEOUT       250 /* FIXME: should be per-protocol? */ -#define INVALID_SCANCODE   0x7FFFFFFF /* Invalid with all protos	*/ -#define WAKEUP_IOMEM_LEN         0x10 /* Wake-Up I/O Reg Len		*/ -#define EHFUNC_IOMEM_LEN         0x10 /* Enhanced Func I/O Reg Len	*/ -#define SP_IOMEM_LEN             0x08 /* Serial Port 3 (IR) Reg Len	*/ -#define WBCIR_MAX_IDLE_BYTES       10 - -static DEFINE_SPINLOCK(wbcir_lock); -static DEFINE_RWLOCK(keytable_lock); - -struct wbcir_key { -	u32 scancode; -	unsigned int keycode; -}; - -struct wbcir_keyentry { -	struct wbcir_key key; -	struct list_head list; -}; - -static struct wbcir_key rc6_def_keymap[] = { -	{ 0x800F0400, KEY_NUMERIC_0		}, -	{ 0x800F0401, KEY_NUMERIC_1		}, -	{ 0x800F0402, KEY_NUMERIC_2		}, -	{ 0x800F0403, KEY_NUMERIC_3		}, -	{ 0x800F0404, KEY_NUMERIC_4		}, -	{ 0x800F0405, KEY_NUMERIC_5		}, -	{ 0x800F0406, KEY_NUMERIC_6		}, -	{ 0x800F0407, KEY_NUMERIC_7		}, -	{ 0x800F0408, KEY_NUMERIC_8		}, -	{ 0x800F0409, KEY_NUMERIC_9		}, -	{ 0x800F041D, KEY_NUMERIC_STAR		}, -	{ 0x800F041C, KEY_NUMERIC_POUND		}, -	{ 0x800F0410, KEY_VOLUMEUP		}, -	{ 0x800F0411, KEY_VOLUMEDOWN		}, -	{ 0x800F0412, KEY_CHANNELUP		}, -	{ 0x800F0413, KEY_CHANNELDOWN		}, -	{ 0x800F040E, KEY_MUTE			}, -	{ 0x800F040D, KEY_VENDOR		}, /* Vista Logo Key */ -	{ 0x800F041E, KEY_UP			}, -	{ 0x800F041F, KEY_DOWN			}, -	{ 0x800F0420, KEY_LEFT			}, -	{ 0x800F0421, KEY_RIGHT			}, -	{ 0x800F0422, KEY_OK			}, -	{ 0x800F0423, KEY_ESC			}, -	{ 0x800F040F, KEY_INFO			}, -	{ 0x800F040A, KEY_CLEAR			}, -	{ 0x800F040B, KEY_ENTER			}, -	{ 0x800F045B, KEY_RED			}, -	{ 0x800F045C, KEY_GREEN			}, -	{ 0x800F045D, KEY_YELLOW		}, -	{ 0x800F045E, KEY_BLUE			}, -	{ 0x800F045A, KEY_TEXT			}, -	{ 0x800F0427, KEY_SWITCHVIDEOMODE	}, -	{ 0x800F040C, KEY_POWER			}, -	{ 0x800F0450, KEY_RADIO			}, -	{ 0x800F0448, KEY_PVR			}, -	{ 0x800F0447, KEY_AUDIO			}, -	{ 0x800F0426, KEY_EPG			}, -	{ 0x800F0449, KEY_CAMERA		}, -	{ 0x800F0425, KEY_TV			}, -	{ 0x800F044A, KEY_VIDEO			}, -	{ 0x800F0424, KEY_DVD			}, -	{ 0x800F0416, KEY_PLAY			}, -	{ 0x800F0418, KEY_PAUSE			}, -	{ 0x800F0419, KEY_STOP			}, -	{ 0x800F0414, KEY_FASTFORWARD		}, -	{ 0x800F041A, KEY_NEXT			}, -	{ 0x800F041B, KEY_PREVIOUS		}, -	{ 0x800F0415, KEY_REWIND		}, -	{ 0x800F0417, KEY_RECORD		}, -}; - -/* Registers and other state is protected by wbcir_lock */ -struct wbcir_data { -	unsigned long wbase;        /* Wake-Up Baseaddr		*/ -	unsigned long ebase;        /* Enhanced Func. Baseaddr	*/ -	unsigned long sbase;        /* Serial Port Baseaddr	*/ -	unsigned int  irq;          /* Serial Port IRQ		*/ - -	struct input_dev *input_dev; -	struct timer_list timer_keyup; -	struct led_trigger *rxtrigger; -	struct led_trigger *txtrigger; -	struct led_classdev led; - -	u32 last_scancode; -	unsigned int last_keycode; -	u8 last_toggle; -	u8 keypressed; -	unsigned long keyup_jiffies; -	unsigned int idle_count; - -	/* RX irdata and parsing state */ -	unsigned long irdata[30]; -	unsigned int irdata_count; -	unsigned int irdata_idle; -	unsigned int irdata_off; -	unsigned int irdata_error; - -	/* Protected by keytable_lock */ -	struct list_head keytable; -}; - -static enum wbcir_protocol protocol = IR_PROTOCOL_RC6; -module_param(protocol, uint, 0444); -MODULE_PARM_DESC(protocol, "IR protocol to use " -		 "(0 = RC5, 1 = NEC, 2 = RC6A, default)"); - -static int invert; /* default = 0 */ -module_param(invert, bool, 0444); -MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver"); - -static unsigned int wake_sc = 0x800F040C; -module_param(wake_sc, uint, 0644); -MODULE_PARM_DESC(wake_sc, "Scancode of the power-on IR command"); - -static unsigned int wake_rc6mode = 6; -module_param(wake_rc6mode, uint, 0644); -MODULE_PARM_DESC(wake_rc6mode, "RC6 mode for the power-on command " -		 "(0 = 0, 6 = 6A, default)"); - - - -/***************************************************************************** - * - * UTILITY FUNCTIONS - * - *****************************************************************************/ - -/* Caller needs to hold wbcir_lock */ -static void -wbcir_set_bits(unsigned long addr, u8 bits, u8 mask) -{ -	u8 val; - -	val = inb(addr); -	val = ((val & ~mask) | (bits & mask)); -	outb(val, addr); -} - -/* Selects the register bank for the serial port */ -static inline void -wbcir_select_bank(struct wbcir_data *data, enum wbcir_bank bank) -{ -	outb(bank, data->sbase + WBCIR_REG_SP3_BSR); -} - -static enum led_brightness -wbcir_led_brightness_get(struct led_classdev *led_cdev) -{ -	struct wbcir_data *data = container_of(led_cdev, -					       struct wbcir_data, -					       led); - -	if (inb(data->ebase + WBCIR_REG_ECEIR_CTS) & WBCIR_LED_ENABLE) -		return LED_FULL; -	else -		return LED_OFF; -} - -static void -wbcir_led_brightness_set(struct led_classdev *led_cdev, -			    enum led_brightness brightness) -{ -	struct wbcir_data *data = container_of(led_cdev, -					       struct wbcir_data, -					       led); - -	wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CTS, -		       brightness == LED_OFF ? 0x00 : WBCIR_LED_ENABLE, -		       WBCIR_LED_ENABLE); -} - -/* Manchester encodes bits to RC6 message cells (see wbcir_parse_rc6) */ -static u8 -wbcir_to_rc6cells(u8 val) -{ -	u8 coded = 0x00; -	int i; - -	val &= 0x0F; -	for (i = 0; i < 4; i++) { -		if (val & 0x01) -			coded |= 0x02 << (i * 2); -		else -			coded |= 0x01 << (i * 2); -		val >>= 1; -	} - -	return coded; -} - - - -/***************************************************************************** - * - * INPUT FUNCTIONS - * - *****************************************************************************/ - -static unsigned int -wbcir_do_getkeycode(struct wbcir_data *data, u32 scancode) -{ -	struct wbcir_keyentry *keyentry; -	unsigned int keycode = KEY_RESERVED; -	unsigned long flags; - -	read_lock_irqsave(&keytable_lock, flags); - -	list_for_each_entry(keyentry, &data->keytable, list) { -		if (keyentry->key.scancode == scancode) { -			keycode = keyentry->key.keycode; -			break; -		} -	} - -	read_unlock_irqrestore(&keytable_lock, flags); -	return keycode; -} - -static int -wbcir_getkeycode(struct input_dev *dev, -		 unsigned int scancode, unsigned int *keycode) -{ -	struct wbcir_data *data = input_get_drvdata(dev); - -	*keycode = wbcir_do_getkeycode(data, scancode); -	return 0; -} - -static int -wbcir_setkeycode(struct input_dev *dev, -		 unsigned int scancode, unsigned int keycode) -{ -	struct wbcir_data *data = input_get_drvdata(dev); -	struct wbcir_keyentry *keyentry; -	struct wbcir_keyentry *new_keyentry; -	unsigned long flags; -	unsigned int old_keycode = KEY_RESERVED; - -	new_keyentry = kmalloc(sizeof(*new_keyentry), GFP_KERNEL); -	if (!new_keyentry) -		return -ENOMEM; - -	write_lock_irqsave(&keytable_lock, flags); - -	list_for_each_entry(keyentry, &data->keytable, list) { -		if (keyentry->key.scancode != scancode) -			continue; - -		old_keycode = keyentry->key.keycode; -		keyentry->key.keycode = keycode; - -		if (keyentry->key.keycode == KEY_RESERVED) { -			list_del(&keyentry->list); -			kfree(keyentry); -		} - -		break; -	} - -	set_bit(keycode, dev->keybit); - -	if (old_keycode == KEY_RESERVED) { -		new_keyentry->key.scancode = scancode; -		new_keyentry->key.keycode = keycode; -		list_add(&new_keyentry->list, &data->keytable); -	} else { -		kfree(new_keyentry); -		clear_bit(old_keycode, dev->keybit); -		list_for_each_entry(keyentry, &data->keytable, list) { -			if (keyentry->key.keycode == old_keycode) { -				set_bit(old_keycode, dev->keybit); -				break; -			} -		} -	} - -	write_unlock_irqrestore(&keytable_lock, flags); -	return 0; -} - -/* - * Timer function to report keyup event some time after keydown is - * reported by the ISR. - */ -static void -wbcir_keyup(unsigned long cookie) -{ -	struct wbcir_data *data = (struct wbcir_data *)cookie; -	unsigned long flags; - -	/* -	 * data->keyup_jiffies is used to prevent a race condition if a -	 * hardware interrupt occurs at this point and the keyup timer -	 * event is moved further into the future as a result. -	 * -	 * The timer will then be reactivated and this function called -	 * again in the future. We need to exit gracefully in that case -	 * to allow the input subsystem to do its auto-repeat magic or -	 * a keyup event might follow immediately after the keydown. -	 */ - -	spin_lock_irqsave(&wbcir_lock, flags); - -	if (time_is_after_eq_jiffies(data->keyup_jiffies) && data->keypressed) { -		data->keypressed = 0; -		led_trigger_event(data->rxtrigger, LED_OFF); -		input_report_key(data->input_dev, data->last_keycode, 0); -		input_sync(data->input_dev); -	} - -	spin_unlock_irqrestore(&wbcir_lock, flags); -} - -static void -wbcir_keydown(struct wbcir_data *data, u32 scancode, u8 toggle) -{ -	unsigned int keycode; - -	/* Repeat? */ -	if (data->last_scancode == scancode && -	    data->last_toggle == toggle && -	    data->keypressed) -		goto set_timer; -	data->last_scancode = scancode; - -	/* Do we need to release an old keypress? */ -	if (data->keypressed) { -		input_report_key(data->input_dev, data->last_keycode, 0); -		input_sync(data->input_dev); -		data->keypressed = 0; -	} - -	/* Report scancode */ -	input_event(data->input_dev, EV_MSC, MSC_SCAN, (int)scancode); - -	/* Do we know this scancode? */ -	keycode = wbcir_do_getkeycode(data, scancode); -	if (keycode == KEY_RESERVED) -		goto set_timer; - -	/* Register a keypress */ -	input_report_key(data->input_dev, keycode, 1); -	data->keypressed = 1; -	data->last_keycode = keycode; -	data->last_toggle = toggle; - -set_timer: -	input_sync(data->input_dev); -	led_trigger_event(data->rxtrigger, -			  data->keypressed ? LED_FULL : LED_OFF); -	data->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT); -	mod_timer(&data->timer_keyup, data->keyup_jiffies); -} - - - -/***************************************************************************** - * - * IR PARSING FUNCTIONS - * - *****************************************************************************/ - -/* Resets all irdata */ -static void -wbcir_reset_irdata(struct wbcir_data *data) -{ -	memset(data->irdata, 0, sizeof(data->irdata)); -	data->irdata_count = 0; -	data->irdata_off = 0; -	data->irdata_error = 0; -	data->idle_count = 0; -} - -/* Adds one bit of irdata */ -static void -add_irdata_bit(struct wbcir_data *data, int set) -{ -	if (data->irdata_count >= sizeof(data->irdata) * 8) { -		data->irdata_error = 1; -		return; -	} - -	if (set) -		__set_bit(data->irdata_count, data->irdata); -	data->irdata_count++; -} - -/* Gets count bits of irdata */ -static u16 -get_bits(struct wbcir_data *data, int count) -{ -	u16 val = 0x0; - -	if (data->irdata_count - data->irdata_off < count) { -		data->irdata_error = 1; -		return 0x0; -	} - -	while (count > 0) { -		val <<= 1; -		if (test_bit(data->irdata_off, data->irdata)) -			val |= 0x1; -		count--; -		data->irdata_off++; -	} - -	return val; -} - -/* Reads 16 cells and converts them to a byte */ -static u8 -wbcir_rc6cells_to_byte(struct wbcir_data *data) -{ -	u16 raw = get_bits(data, 16); -	u8 val = 0x00; -	int bit; - -	for (bit = 0; bit < 8; bit++) { -		switch (raw & 0x03) { -		case 0x01: -			break; -		case 0x02: -			val |= (0x01 << bit); -			break; -		default: -			data->irdata_error = 1; -			break; -		} -		raw >>= 2; -	} - -	return val; -} - -/* Decodes a number of bits from raw RC5 data */ -static u8 -wbcir_get_rc5bits(struct wbcir_data *data, unsigned int count) -{ -	u16 raw = get_bits(data, count * 2); -	u8 val = 0x00; -	int bit; - -	for (bit = 0; bit < count; bit++) { -		switch (raw & 0x03) { -		case 0x01: -			val |= (0x01 << bit); -			break; -		case 0x02: -			break; -		default: -			data->irdata_error = 1; -			break; -		} -		raw >>= 2; -	} - -	return val; -} - -static void -wbcir_parse_rc6(struct device *dev, struct wbcir_data *data) -{ -	/* -	 * Normal bits are manchester coded as follows: -	 * cell0 + cell1 = logic "0" -	 * cell1 + cell0 = logic "1" -	 * -	 * The IR pulse has the following components: -	 * -	 * Leader		- 6 * cell1 - discarded -	 * Gap    		- 2 * cell0 - discarded -	 * Start bit		- Normal Coding - always "1" -	 * Mode Bit 2 - 0	- Normal Coding -	 * Toggle bit		- Normal Coding with double bit time, -	 *			  e.g. cell0 + cell0 + cell1 + cell1 -	 *			  means logic "0". -	 * -	 * The rest depends on the mode, the following modes are known: -	 * -	 * MODE 0: -	 *  Address Bit 7 - 0	- Normal Coding -	 *  Command Bit 7 - 0	- Normal Coding -	 * -	 * MODE 6: -	 *  The above Toggle Bit is used as a submode bit, 0 = A, 1 = B. -	 *  Submode B is for pointing devices, only remotes using submode A -	 *  are supported. -	 * -	 *  Customer range bit	- 0 => Customer = 7 bits, 0...127 -	 *                        1 => Customer = 15 bits, 32768...65535 -	 *  Customer Bits	- Normal Coding -	 * -	 *  Customer codes are allocated by Philips. The rest of the bits -	 *  are customer dependent. The following is commonly used (and the -	 *  only supported config): -	 * -	 *  Toggle Bit		- Normal Coding -	 *  Address Bit 6 - 0	- Normal Coding -	 *  Command Bit 7 - 0	- Normal Coding -	 * -	 * All modes are followed by at least 6 * cell0. -	 * -	 * MODE 0 msglen: -	 *  1 * 2 (start bit) + 3 * 2 (mode) + 2 * 2 (toggle) + -	 *  8 * 2 (address) + 8 * 2 (command) = -	 *  44 cells -	 * -	 * MODE 6A msglen: -	 *  1 * 2 (start bit) + 3 * 2 (mode) + 2 * 2 (submode) + -	 *  1 * 2 (customer range bit) + 7/15 * 2 (customer bits) + -	 *  1 * 2 (toggle bit) + 7 * 2 (address) + 8 * 2 (command) = -	 *  60 - 76 cells -	 */ -	u8 mode; -	u8 toggle; -	u16 customer = 0x0; -	u8 address; -	u8 command; -	u32 scancode; - -	/* Leader mark */ -	while (get_bits(data, 1) && !data->irdata_error) -		/* Do nothing */; - -	/* Leader space */ -	if (get_bits(data, 1)) { -		dev_dbg(dev, "RC6 - Invalid leader space\n"); -		return; -	} - -	/* Start bit */ -	if (get_bits(data, 2) != 0x02) { -		dev_dbg(dev, "RC6 - Invalid start bit\n"); -		return; -	} - -	/* Mode */ -	mode = get_bits(data, 6); -	switch (mode) { -	case 0x15: /* 010101 = b000 */ -		mode = 0; -		break; -	case 0x29: /* 101001 = b110 */ -		mode = 6; -		break; -	default: -		dev_dbg(dev, "RC6 - Invalid mode\n"); -		return; -	} - -	/* Toggle bit / Submode bit */ -	toggle = get_bits(data, 4); -	switch (toggle) { -	case 0x03: -		toggle = 0; -		break; -	case 0x0C: -		toggle = 1; -		break; -	default: -		dev_dbg(dev, "RC6 - Toggle bit error\n"); -		break; -	} - -	/* Customer */ -	if (mode == 6) { -		if (toggle != 0) { -			dev_dbg(dev, "RC6B - Not Supported\n"); -			return; -		} - -		customer = wbcir_rc6cells_to_byte(data); - -		if (customer & 0x80) { -			/* 15 bit customer value */ -			customer <<= 8; -			customer |= wbcir_rc6cells_to_byte(data); -		} -	} - -	/* Address */ -	address = wbcir_rc6cells_to_byte(data); -	if (mode == 6) { -		toggle = address >> 7; -		address &= 0x7F; -	} - -	/* Command */ -	command = wbcir_rc6cells_to_byte(data); - -	/* Create scancode */ -	scancode =  command; -	scancode |= address << 8; -	scancode |= customer << 16; - -	/* Last sanity check */ -	if (data->irdata_error) { -		dev_dbg(dev, "RC6 - Cell error(s)\n"); -		return; -	} - -	dev_dbg(dev, "IR-RC6 ad 0x%02X cm 0x%02X cu 0x%04X " -		"toggle %u mode %u scan 0x%08X\n", -		address, -		command, -		customer, -		(unsigned int)toggle, -		(unsigned int)mode, -		scancode); - -	wbcir_keydown(data, scancode, toggle); -} - -static void -wbcir_parse_rc5(struct device *dev, struct wbcir_data *data) -{ -	/* -	 * Bits are manchester coded as follows: -	 * cell1 + cell0 = logic "0" -	 * cell0 + cell1 = logic "1" -	 * (i.e. the reverse of RC6) -	 * -	 * Start bit 1		- "1" - discarded -	 * Start bit 2		- Must be inverted to get command bit 6 -	 * Toggle bit -	 * Address Bit 4 - 0 -	 * Command Bit 5 - 0 -	 */ -	u8 toggle; -	u8 address; -	u8 command; -	u32 scancode; - -	/* Start bit 1 */ -	if (!get_bits(data, 1)) { -		dev_dbg(dev, "RC5 - Invalid start bit\n"); -		return; -	} - -	/* Start bit 2 */ -	if (!wbcir_get_rc5bits(data, 1)) -		command = 0x40; -	else -		command = 0x00; - -	toggle   = wbcir_get_rc5bits(data, 1); -	address  = wbcir_get_rc5bits(data, 5); -	command |= wbcir_get_rc5bits(data, 6); -	scancode = address << 7 | command; - -	/* Last sanity check */ -	if (data->irdata_error) { -		dev_dbg(dev, "RC5 - Invalid message\n"); -		return; -	} - -	dev_dbg(dev, "IR-RC5 ad %u cm %u t %u s %u\n", -		(unsigned int)address, -		(unsigned int)command, -		(unsigned int)toggle, -		(unsigned int)scancode); - -	wbcir_keydown(data, scancode, toggle); -} - -static void -wbcir_parse_nec(struct device *dev, struct wbcir_data *data) -{ -	/* -	 * Each bit represents 560 us. -	 * -	 * Leader		- 9 ms burst -	 * Gap			- 4.5 ms silence -	 * Address1 bit 0 - 7	- Address 1 -	 * Address2 bit 0 - 7	- Address 2 -	 * Command1 bit 0 - 7	- Command 1 -	 * Command2 bit 0 - 7	- Command 2 -	 * -	 * Note the bit order! -	 * -	 * With the old NEC protocol, Address2 was the inverse of Address1 -	 * and Command2 was the inverse of Command1 and were used as -	 * an error check. -	 * -	 * With NEC extended, Address1 is the LSB of the Address and -	 * Address2 is the MSB, Command parsing remains unchanged. -	 * -	 * A repeat message is coded as: -	 * Leader		- 9 ms burst -	 * Gap			- 2.25 ms silence -	 * Repeat		- 560 us active -	 */ -	u8 address1; -	u8 address2; -	u8 command1; -	u8 command2; -	u16 address; -	u32 scancode; - -	/* Leader mark */ -	while (get_bits(data, 1) && !data->irdata_error) -		/* Do nothing */; - -	/* Leader space */ -	if (get_bits(data, 4)) { -		dev_dbg(dev, "NEC - Invalid leader space\n"); -		return; -	} - -	/* Repeat? */ -	if (get_bits(data, 1)) { -		if (!data->keypressed) { -			dev_dbg(dev, "NEC - Stray repeat message\n"); -			return; -		} - -		dev_dbg(dev, "IR-NEC repeat s %u\n", -			(unsigned int)data->last_scancode); - -		wbcir_keydown(data, data->last_scancode, data->last_toggle); -		return; -	} - -	/* Remaining leader space */ -	if (get_bits(data, 3)) { -		dev_dbg(dev, "NEC - Invalid leader space\n"); -		return; -	} - -	address1  = bitrev8(get_bits(data, 8)); -	address2  = bitrev8(get_bits(data, 8)); -	command1  = bitrev8(get_bits(data, 8)); -	command2  = bitrev8(get_bits(data, 8)); - -	/* Sanity check */ -	if (data->irdata_error) { -		dev_dbg(dev, "NEC - Invalid message\n"); -		return; -	} - -	/* Check command validity */ -	if (command1 != ~command2) { -		dev_dbg(dev, "NEC - Command bytes mismatch\n"); -		return; -	} - -	/* Check for extended NEC protocol */ -	address = address1; -	if (address1 != ~address2) -		address |= address2 << 8; - -	scancode = address << 8 | command1; - -	dev_dbg(dev, "IR-NEC ad %u cm %u s %u\n", -		(unsigned int)address, -		(unsigned int)command1, -		(unsigned int)scancode); - -	wbcir_keydown(data, scancode, !data->last_toggle); -} - - - -/***************************************************************************** - * - * INTERRUPT FUNCTIONS - * - *****************************************************************************/ - -static irqreturn_t -wbcir_irq_handler(int irqno, void *cookie) -{ -	struct pnp_dev *device = cookie; -	struct wbcir_data *data = pnp_get_drvdata(device); -	struct device *dev = &device->dev; -	u8 status; -	unsigned long flags; -	u8 irdata[8]; -	int i; -	unsigned int hw; - -	spin_lock_irqsave(&wbcir_lock, flags); - -	wbcir_select_bank(data, WBCIR_BANK_0); - -	status = inb(data->sbase + WBCIR_REG_SP3_EIR); - -	if (!(status & (WBCIR_IRQ_RX | WBCIR_IRQ_ERR))) { -		spin_unlock_irqrestore(&wbcir_lock, flags); -		return IRQ_NONE; -	} - -	if (status & WBCIR_IRQ_ERR) -		data->irdata_error = 1; - -	if (!(status & WBCIR_IRQ_RX)) -		goto out; - -	/* Since RXHDLEV is set, at least 8 bytes are in the FIFO */ -	insb(data->sbase + WBCIR_REG_SP3_RXDATA, &irdata[0], 8); - -	for (i = 0; i < sizeof(irdata); i++) { -		hw = hweight8(irdata[i]); -		if (hw > 4) -			add_irdata_bit(data, 0); -		else -			add_irdata_bit(data, 1); - -		if (hw == 8) -			data->idle_count++; -		else -			data->idle_count = 0; -	} - -	if (data->idle_count > WBCIR_MAX_IDLE_BYTES) { -		/* Set RXINACTIVE... */ -		outb(WBCIR_RX_DISABLE, data->sbase + WBCIR_REG_SP3_ASCR); - -		/* ...and drain the FIFO */ -		while (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_AVAIL) -			inb(data->sbase + WBCIR_REG_SP3_RXDATA); - -		dev_dbg(dev, "IRDATA:\n"); -		for (i = 0; i < data->irdata_count; i += BITS_PER_LONG) -			dev_dbg(dev, "0x%08lX\n", data->irdata[i/BITS_PER_LONG]); - -		switch (protocol) { -		case IR_PROTOCOL_RC5: -			wbcir_parse_rc5(dev, data); -			break; -		case IR_PROTOCOL_RC6: -			wbcir_parse_rc6(dev, data); -			break; -		case IR_PROTOCOL_NEC: -			wbcir_parse_nec(dev, data); -			break; -		} - -		wbcir_reset_irdata(data); -	} - -out: -	spin_unlock_irqrestore(&wbcir_lock, flags); -	return IRQ_HANDLED; -} - - - -/***************************************************************************** - * - * SETUP/INIT/SUSPEND/RESUME FUNCTIONS - * - *****************************************************************************/ - -static void -wbcir_shutdown(struct pnp_dev *device) -{ -	struct device *dev = &device->dev; -	struct wbcir_data *data = pnp_get_drvdata(device); -	int do_wake = 1; -	u8 match[11]; -	u8 mask[11]; -	u8 rc6_csl = 0; -	int i; - -	memset(match, 0, sizeof(match)); -	memset(mask, 0, sizeof(mask)); - -	if (wake_sc == INVALID_SCANCODE || !device_may_wakeup(dev)) { -		do_wake = 0; -		goto finish; -	} - -	switch (protocol) { -	case IR_PROTOCOL_RC5: -		if (wake_sc > 0xFFF) { -			do_wake = 0; -			dev_err(dev, "RC5 - Invalid wake scancode\n"); -			break; -		} - -		/* Mask = 13 bits, ex toggle */ -		mask[0] = 0xFF; -		mask[1] = 0x17; - -		match[0]  = (wake_sc & 0x003F);      /* 6 command bits */ -		match[0] |= (wake_sc & 0x0180) >> 1; /* 2 address bits */ -		match[1]  = (wake_sc & 0x0E00) >> 9; /* 3 address bits */ -		if (!(wake_sc & 0x0040))             /* 2nd start bit  */ -			match[1] |= 0x10; - -		break; - -	case IR_PROTOCOL_NEC: -		if (wake_sc > 0xFFFFFF) { -			do_wake = 0; -			dev_err(dev, "NEC - Invalid wake scancode\n"); -			break; -		} - -		mask[0] = mask[1] = mask[2] = mask[3] = 0xFF; - -		match[1] = bitrev8((wake_sc & 0xFF)); -		match[0] = ~match[1]; - -		match[3] = bitrev8((wake_sc & 0xFF00) >> 8); -		if (wake_sc > 0xFFFF) -			match[2] = bitrev8((wake_sc & 0xFF0000) >> 16); -		else -			match[2] = ~match[3]; - -		break; - -	case IR_PROTOCOL_RC6: - -		if (wake_rc6mode == 0) { -			if (wake_sc > 0xFFFF) { -				do_wake = 0; -				dev_err(dev, "RC6 - Invalid wake scancode\n"); -				break; -			} - -			/* Command */ -			match[0] = wbcir_to_rc6cells(wake_sc >>  0); -			mask[0]  = 0xFF; -			match[1] = wbcir_to_rc6cells(wake_sc >>  4); -			mask[1]  = 0xFF; - -			/* Address */ -			match[2] = wbcir_to_rc6cells(wake_sc >>  8); -			mask[2]  = 0xFF; -			match[3] = wbcir_to_rc6cells(wake_sc >> 12); -			mask[3]  = 0xFF; - -			/* Header */ -			match[4] = 0x50; /* mode1 = mode0 = 0, ignore toggle */ -			mask[4]  = 0xF0; -			match[5] = 0x09; /* start bit = 1, mode2 = 0 */ -			mask[5]  = 0x0F; - -			rc6_csl = 44; - -		} else if (wake_rc6mode == 6) { -			i = 0; - -			/* Command */ -			match[i]  = wbcir_to_rc6cells(wake_sc >>  0); -			mask[i++] = 0xFF; -			match[i]  = wbcir_to_rc6cells(wake_sc >>  4); -			mask[i++] = 0xFF; - -			/* Address + Toggle */ -			match[i]  = wbcir_to_rc6cells(wake_sc >>  8); -			mask[i++] = 0xFF; -			match[i]  = wbcir_to_rc6cells(wake_sc >> 12); -			mask[i++] = 0x3F; - -			/* Customer bits 7 - 0 */ -			match[i]  = wbcir_to_rc6cells(wake_sc >> 16); -			mask[i++] = 0xFF; -			match[i]  = wbcir_to_rc6cells(wake_sc >> 20); -			mask[i++] = 0xFF; - -			if (wake_sc & 0x80000000) { -				/* Customer range bit and bits 15 - 8 */ -				match[i]  = wbcir_to_rc6cells(wake_sc >> 24); -				mask[i++] = 0xFF; -				match[i]  = wbcir_to_rc6cells(wake_sc >> 28); -				mask[i++] = 0xFF; -				rc6_csl = 76; -			} else if (wake_sc <= 0x007FFFFF) { -				rc6_csl = 60; -			} else { -				do_wake = 0; -				dev_err(dev, "RC6 - Invalid wake scancode\n"); -				break; -			} - -			/* Header */ -			match[i]  = 0x93; /* mode1 = mode0 = 1, submode = 0 */ -			mask[i++] = 0xFF; -			match[i]  = 0x0A; /* start bit = 1, mode2 = 1 */ -			mask[i++] = 0x0F; - -		} else { -			do_wake = 0; -			dev_err(dev, "RC6 - Invalid wake mode\n"); -		} - -		break; - -	default: -		do_wake = 0; -		break; -	} - -finish: -	if (do_wake) { -		/* Set compare and compare mask */ -		wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_INDEX, -			       WBCIR_REGSEL_COMPARE | WBCIR_REG_ADDR0, -			       0x3F); -		outsb(data->wbase + WBCIR_REG_WCEIR_DATA, match, 11); -		wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_INDEX, -			       WBCIR_REGSEL_MASK | WBCIR_REG_ADDR0, -			       0x3F); -		outsb(data->wbase + WBCIR_REG_WCEIR_DATA, mask, 11); - -		/* RC6 Compare String Len */ -		outb(rc6_csl, data->wbase + WBCIR_REG_WCEIR_CSL); - -		/* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */ -		wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17); - -		/* Clear BUFF_EN, Clear END_EN, Set MATCH_EN */ -		wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x01, 0x07); - -		/* Set CEIR_EN */ -		wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x01, 0x01); - -	} else { -		/* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */ -		wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07); - -		/* Clear CEIR_EN */ -		wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01); -	} - -	/* Disable interrupts */ -	wbcir_select_bank(data, WBCIR_BANK_0); -	outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER); - -	/* -	 * ACPI will set the HW disable bit for SP3 which means that the -	 * output signals are left in an undefined state which may cause -	 * spurious interrupts which we need to ignore until the hardware -	 * is reinitialized. -	 */ -	disable_irq(data->irq); -} - -static int -wbcir_suspend(struct pnp_dev *device, pm_message_t state) -{ -	wbcir_shutdown(device); -	return 0; -} - -static void -wbcir_init_hw(struct wbcir_data *data) -{ -	u8 tmp; - -	/* Disable interrupts */ -	wbcir_select_bank(data, WBCIR_BANK_0); -	outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER); - -	/* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */ -	tmp = protocol << 4; -	if (invert) -		tmp |= 0x08; -	outb(tmp, data->wbase + WBCIR_REG_WCEIR_CTL); - -	/* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */ -	wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17); - -	/* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */ -	wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07); - -	/* Set RC5 cell time to correspond to 36 kHz */ -	wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CFG1, 0x4A, 0x7F); - -	/* Set IRTX_INV */ -	if (invert) -		outb(0x04, data->ebase + WBCIR_REG_ECEIR_CCTL); -	else -		outb(0x00, data->ebase + WBCIR_REG_ECEIR_CCTL); - -	/* -	 * Clear IR LED, set SP3 clock to 24Mhz -	 * set SP3_IRRX_SW to binary 01, helpfully not documented -	 */ -	outb(0x10, data->ebase + WBCIR_REG_ECEIR_CTS); - -	/* Enable extended mode */ -	wbcir_select_bank(data, WBCIR_BANK_2); -	outb(WBCIR_EXT_ENABLE, data->sbase + WBCIR_REG_SP3_EXCR1); - -	/* -	 * Configure baud generator, IR data will be sampled at -	 * a bitrate of: (24Mhz * prescaler) / (divisor * 16). -	 * -	 * The ECIR registers include a flag to change the -	 * 24Mhz clock freq to 48Mhz. -	 * -	 * It's not documented in the specs, but fifo levels -	 * other than 16 seems to be unsupported. -	 */ - -	/* prescaler 1.0, tx/rx fifo lvl 16 */ -	outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2); - -	/* Set baud divisor to generate one byte per bit/cell */ -	switch (protocol) { -	case IR_PROTOCOL_RC5: -		outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL); -		break; -	case IR_PROTOCOL_RC6: -		outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL); -		break; -	case IR_PROTOCOL_NEC: -		outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL); -		break; -	} -	outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH); - -	/* Set CEIR mode */ -	wbcir_select_bank(data, WBCIR_BANK_0); -	outb(0xC0, data->sbase + WBCIR_REG_SP3_MCR); -	inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */ -	inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */ - -	/* Disable RX demod, run-length encoding/decoding, set freq span */ -	wbcir_select_bank(data, WBCIR_BANK_7); -	outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG); - -	/* Disable timer */ -	wbcir_select_bank(data, WBCIR_BANK_4); -	outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1); - -	/* Enable MSR interrupt, Clear AUX_IRX */ -	wbcir_select_bank(data, WBCIR_BANK_5); -	outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR2); - -	/* Disable CRC */ -	wbcir_select_bank(data, WBCIR_BANK_6); -	outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3); - -	/* Set RX/TX (de)modulation freq, not really used */ -	wbcir_select_bank(data, WBCIR_BANK_7); -	outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC); -	outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC); - -	/* Set invert and pin direction */ -	if (invert) -		outb(0x10, data->sbase + WBCIR_REG_SP3_IRCFG4); -	else -		outb(0x00, data->sbase + WBCIR_REG_SP3_IRCFG4); - -	/* Set FIFO thresholds (RX = 8, TX = 3), reset RX/TX */ -	wbcir_select_bank(data, WBCIR_BANK_0); -	outb(0x97, data->sbase + WBCIR_REG_SP3_FCR); - -	/* Clear AUX status bits */ -	outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR); - -	/* Enable interrupts */ -	wbcir_reset_irdata(data); -	outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER); -} - -static int -wbcir_resume(struct pnp_dev *device) -{ -	struct wbcir_data *data = pnp_get_drvdata(device); - -	wbcir_init_hw(data); -	enable_irq(data->irq); - -	return 0; -} - -static int __devinit -wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) -{ -	struct device *dev = &device->dev; -	struct wbcir_data *data; -	int err; - -	if (!(pnp_port_len(device, 0) == EHFUNC_IOMEM_LEN && -	      pnp_port_len(device, 1) == WAKEUP_IOMEM_LEN && -	      pnp_port_len(device, 2) == SP_IOMEM_LEN)) { -		dev_err(dev, "Invalid resources\n"); -		return -ENODEV; -	} - -	data = kzalloc(sizeof(*data), GFP_KERNEL); -	if (!data) { -		err = -ENOMEM; -		goto exit; -	} - -	pnp_set_drvdata(device, data); - -	data->ebase = pnp_port_start(device, 0); -	data->wbase = pnp_port_start(device, 1); -	data->sbase = pnp_port_start(device, 2); -	data->irq = pnp_irq(device, 0); - -	if (data->wbase == 0 || data->ebase == 0 || -	    data->sbase == 0 || data->irq == 0) { -		err = -ENODEV; -		dev_err(dev, "Invalid resources\n"); -		goto exit_free_data; -	} - -	dev_dbg(&device->dev, "Found device " -		"(w: 0x%lX, e: 0x%lX, s: 0x%lX, i: %u)\n", -		data->wbase, data->ebase, data->sbase, data->irq); - -	if (!request_region(data->wbase, WAKEUP_IOMEM_LEN, DRVNAME)) { -		dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", -			data->wbase, data->wbase + WAKEUP_IOMEM_LEN - 1); -		err = -EBUSY; -		goto exit_free_data; -	} - -	if (!request_region(data->ebase, EHFUNC_IOMEM_LEN, DRVNAME)) { -		dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", -			data->ebase, data->ebase + EHFUNC_IOMEM_LEN - 1); -		err = -EBUSY; -		goto exit_release_wbase; -	} - -	if (!request_region(data->sbase, SP_IOMEM_LEN, DRVNAME)) { -		dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", -			data->sbase, data->sbase + SP_IOMEM_LEN - 1); -		err = -EBUSY; -		goto exit_release_ebase; -	} - -	err = request_irq(data->irq, wbcir_irq_handler, -			  IRQF_DISABLED, DRVNAME, device); -	if (err) { -		dev_err(dev, "Failed to claim IRQ %u\n", data->irq); -		err = -EBUSY; -		goto exit_release_sbase; -	} - -	led_trigger_register_simple("cir-tx", &data->txtrigger); -	if (!data->txtrigger) { -		err = -ENOMEM; -		goto exit_free_irq; -	} - -	led_trigger_register_simple("cir-rx", &data->rxtrigger); -	if (!data->rxtrigger) { -		err = -ENOMEM; -		goto exit_unregister_txtrigger; -	} - -	data->led.name = "cir::activity"; -	data->led.default_trigger = "cir-rx"; -	data->led.brightness_set = wbcir_led_brightness_set; -	data->led.brightness_get = wbcir_led_brightness_get; -	err = led_classdev_register(&device->dev, &data->led); -	if (err) -		goto exit_unregister_rxtrigger; - -	data->input_dev = input_allocate_device(); -	if (!data->input_dev) { -		err = -ENOMEM; -		goto exit_unregister_led; -	} - -	data->input_dev->evbit[0] = BIT(EV_KEY); -	data->input_dev->name = WBCIR_NAME; -	data->input_dev->phys = "wbcir/cir0"; -	data->input_dev->id.bustype = BUS_HOST; -	data->input_dev->id.vendor  = PCI_VENDOR_ID_WINBOND; -	data->input_dev->id.product = WBCIR_ID_FAMILY; -	data->input_dev->id.version = WBCIR_ID_CHIP; -	data->input_dev->getkeycode = wbcir_getkeycode; -	data->input_dev->setkeycode = wbcir_setkeycode; -	input_set_capability(data->input_dev, EV_MSC, MSC_SCAN); -	input_set_drvdata(data->input_dev, data); - -	err = input_register_device(data->input_dev); -	if (err) -		goto exit_free_input; - -	data->last_scancode = INVALID_SCANCODE; -	INIT_LIST_HEAD(&data->keytable); -	setup_timer(&data->timer_keyup, wbcir_keyup, (unsigned long)data); - -	/* Load default keymaps */ -	if (protocol == IR_PROTOCOL_RC6) { -		int i; -		for (i = 0; i < ARRAY_SIZE(rc6_def_keymap); i++) { -			err = wbcir_setkeycode(data->input_dev, -					       (int)rc6_def_keymap[i].scancode, -					       (int)rc6_def_keymap[i].keycode); -			if (err) -				goto exit_unregister_keys; -		} -	} - -	device_init_wakeup(&device->dev, 1); - -	wbcir_init_hw(data); - -	return 0; - -exit_unregister_keys: -	if (!list_empty(&data->keytable)) { -		struct wbcir_keyentry *key; -		struct wbcir_keyentry *keytmp; - -		list_for_each_entry_safe(key, keytmp, &data->keytable, list) { -			list_del(&key->list); -			kfree(key); -		} -	} -	input_unregister_device(data->input_dev); -	/* Can't call input_free_device on an unregistered device */ -	data->input_dev = NULL; -exit_free_input: -	input_free_device(data->input_dev); -exit_unregister_led: -	led_classdev_unregister(&data->led); -exit_unregister_rxtrigger: -	led_trigger_unregister_simple(data->rxtrigger); -exit_unregister_txtrigger: -	led_trigger_unregister_simple(data->txtrigger); -exit_free_irq: -	free_irq(data->irq, device); -exit_release_sbase: -	release_region(data->sbase, SP_IOMEM_LEN); -exit_release_ebase: -	release_region(data->ebase, EHFUNC_IOMEM_LEN); -exit_release_wbase: -	release_region(data->wbase, WAKEUP_IOMEM_LEN); -exit_free_data: -	kfree(data); -	pnp_set_drvdata(device, NULL); -exit: -	return err; -} - -static void __devexit -wbcir_remove(struct pnp_dev *device) -{ -	struct wbcir_data *data = pnp_get_drvdata(device); -	struct wbcir_keyentry *key; -	struct wbcir_keyentry *keytmp; - -	/* Disable interrupts */ -	wbcir_select_bank(data, WBCIR_BANK_0); -	outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER); - -	del_timer_sync(&data->timer_keyup); - -	free_irq(data->irq, device); - -	/* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */ -	wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17); - -	/* Clear CEIR_EN */ -	wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01); - -	/* Clear BUFF_EN, END_EN, MATCH_EN */ -	wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07); - -	/* This will generate a keyup event if necessary */ -	input_unregister_device(data->input_dev); - -	led_trigger_unregister_simple(data->rxtrigger); -	led_trigger_unregister_simple(data->txtrigger); -	led_classdev_unregister(&data->led); - -	/* This is ok since &data->led isn't actually used */ -	wbcir_led_brightness_set(&data->led, LED_OFF); - -	release_region(data->wbase, WAKEUP_IOMEM_LEN); -	release_region(data->ebase, EHFUNC_IOMEM_LEN); -	release_region(data->sbase, SP_IOMEM_LEN); - -	list_for_each_entry_safe(key, keytmp, &data->keytable, list) { -		list_del(&key->list); -		kfree(key); -	} - -	kfree(data); - -	pnp_set_drvdata(device, NULL); -} - -static const struct pnp_device_id wbcir_ids[] = { -	{ "WEC1022", 0 }, -	{ "", 0 } -}; -MODULE_DEVICE_TABLE(pnp, wbcir_ids); - -static struct pnp_driver wbcir_driver = { -	.name     = WBCIR_NAME, -	.id_table = wbcir_ids, -	.probe    = wbcir_probe, -	.remove   = __devexit_p(wbcir_remove), -	.suspend  = wbcir_suspend, -	.resume   = wbcir_resume, -	.shutdown = wbcir_shutdown -}; - -static int __init -wbcir_init(void) -{ -	int ret; - -	switch (protocol) { -	case IR_PROTOCOL_RC5: -	case IR_PROTOCOL_NEC: -	case IR_PROTOCOL_RC6: -		break; -	default: -		printk(KERN_ERR DRVNAME ": Invalid protocol argument\n"); -		return -EINVAL; -	} - -	ret = pnp_register_driver(&wbcir_driver); -	if (ret) -		printk(KERN_ERR DRVNAME ": Unable to register driver\n"); - -	return ret; -} - -static void __exit -wbcir_exit(void) -{ -	pnp_unregister_driver(&wbcir_driver); -} - -MODULE_AUTHOR("David Härdeman <david@hardeman.nu>"); -MODULE_DESCRIPTION("Winbond SuperI/O Consumer IR Driver"); -MODULE_LICENSE("GPL"); - -module_init(wbcir_init); -module_exit(wbcir_exit); - -  | 
