Subject: [RFC PATCH 2/2] Hardware button support for Wireless cards: rt2x00

From: Ivo van Doorn <[email-masked]>
Date: Thu, 25 May 2006 17:16:03 +0200

Use radiobtn interface for radio hardware button support in rt2x00

Signed-off-by: Ivo van Doorn <[email-masked]>

diff -uprN wireless-dev/drivers/net/wireless/d80211/rt2x00/Kconfig wireless-dev-radiobtn/drivers/net/wireless/d80211/rt2x00/Kconfig
--- wireless-dev/drivers/net/wireless/d80211/rt2x00/Kconfig	2006-05-06 21:11:03.000000000 +0200
+++ wireless-dev-radiobtn/drivers/net/wireless/d80211/rt2x00/Kconfig	2006-05-25 16:32:23.000000000 +0200
@@ -17,7 +17,7 @@ config RT2400PCI
 
 config RT2400PCI_BUTTON
 	bool "Ralink rt2400 hardware button support"
-	depends on RT2400PCI && X86
+	depends on RT2400PCI && RADIOBTN
 	---help---
 	In some notebooks the rt2400 chipset is integrated in the machine,
 	with this option enabled the device will periodically poll the
@@ -40,7 +40,7 @@ config RT2500PCI
 
 config RT2500PCI_BUTTON
 	bool "Ralink rt2500 hardware button support"
-	depends on RT2500PCI && X86
+	depends on RT2500PCI && RADIOBTN
 	---help---
 	In some notebooks the rt2500 chipset is integrated in the machine,
 	with this option enabled the device will periodically poll the
@@ -61,9 +61,9 @@ config RT61PCI
 
 	When compiled as a module, this driver will be called "rt61pci.ko".
 
-config RT2500PCI_BUTTON
+config RT61PCI_BUTTON
 	bool "Ralink rt61 hardware button support"
-	depends on RT61PCI && X86
+	depends on RT61PCI && RADIOBTN
 	---help---
 	In some notebooks the rt61 chipset is integrated in the machine,
 	with this option enabled the device will periodically poll the
diff -uprN wireless-dev/drivers/net/wireless/d80211/rt2x00/rt2400pci.c wireless-dev-radiobtn/drivers/net/wireless/d80211/rt2x00/rt2400pci.c
--- wireless-dev/drivers/net/wireless/d80211/rt2x00/rt2400pci.c	2006-05-06 21:11:03.000000000 +0200
+++ wireless-dev-radiobtn/drivers/net/wireless/d80211/rt2x00/rt2400pci.c	2006-05-25 16:54:07.000000000 +0200
@@ -51,6 +51,7 @@
 
 #ifdef CONFIG_RT2400PCI_BUTTON
 #define CONFIG_RT2X00_BUTTON
+#include <linux/radiobtn.h>
 #endif /* CONFIG_RT2400PCI_BUTTON */
 
 #include "rt2x00.h"
@@ -364,18 +365,58 @@ rt2x00_eeprom_multiread(
 /*
  * Hardware button poll handler.
  */
-static void
+static int
 rt2400pci_button_poll(unsigned long data)
 {
 	struct rt2x00_pci	*rt2x00pci = (struct rt2x00_pci*)data;
 	u32			reg;
 
 	rt2x00_register_read(rt2x00pci, GPIOCSR, &reg);
-	rt2x00pci_button_status(
-		rt2x00pci, rt2x00_get_field32(reg, GPIOCSR_BIT0));
+	return rt2x00_get_field32(reg, GPIOCSR_BIT0);
+}
+
+static void
+rt2400pci_enable_radio(unsigned long data)
+{
+	struct rt2x00_pci	*rt2x00pci = (struct rt2x00_pci*)data;
+	struct net_device	*net_dev = pci_get_drvdata(rt2x00pci->pci_dev);
+
+	rt2400pci_open(net_dev);
+}
+
+static void
+rt2400pci_disable_radio(unsigned long data)
+{
+	struct rt2x00_pci	*rt2x00pci = (struct rt2x00_pci*)data;
+	struct net_device	*net_dev = pci_get_drvdata(rt2x00pci->pci_dev);
+
+	rt2400pci_stop(net_dev);
+}
+
+static int
+rt2400pci_button_start(struct rt2x00_pci *rt2x00pci)
+{
+	struct radio_button	*button = &rt2x00pci->radio_button;
+
+	button->dev_name	= "rt2400pci";
+	button->data		= (unsigned long)rt2x00pci;
+	button->button_poll	= rt2400pci_button_poll;
+	button->enable_radio	= rt2400pci_enable_radio;
+	button->disable_radio	= rt2400pci_disable_radio;
+	button->poll_delay	= rt2x00_poll_delay;
+	button->current_state	= button->button_poll(button->data);
+
+	return radiobtn_register_device(button);
+}
+
+static void
+rt2400pci_button_stop(struct rt2x00_pci *rt2x00pci)
+{
+	radiobtn_unregister_device(&rt2x00pci->radio_button);
 }
 #else /* CONFIG_RT2400PCI_BUTTON */
-static void rt2400pci_button_poll(struct rt2x00_pci *rt2x00pci){}
+static int rt2400pci_button_start(struct rt2x00_pci *rt2x00pci){return 0;}
+static void rt2400pci_button_stop(struct rt2x00_pci *rt2x00pci){}
 #endif /* CONFIG_RT2400PCI_BUTTON */
 
 /*
@@ -2471,7 +2512,7 @@ rt2400pci_initialize(struct pci_dev *pci
 	/*
 	 * If required start hardware button polling.
 	 */
-	rt2x00pci_button_start(rt2x00pci, rt2400pci_button_poll);
+	rt2400pci_button_start(rt2x00pci);
 
 	/*
 	 * Register hardware.
@@ -2502,7 +2543,7 @@ rt2400pci_uninitialize(struct net_device
 	/*
 	 * Shutdown poll_timer for hardware button.
 	 */
-	rt2x00pci_button_stop(rt2x00pci);
+	rt2400pci_button_stop(rt2x00pci);
 
 	kfree(rt2x00pci->eeprom);
 
diff -uprN wireless-dev/drivers/net/wireless/d80211/rt2x00/rt2500pci.c wireless-dev-radiobtn/drivers/net/wireless/d80211/rt2x00/rt2500pci.c
--- wireless-dev/drivers/net/wireless/d80211/rt2x00/rt2500pci.c	2006-05-06 21:11:03.000000000 +0200
+++ wireless-dev-radiobtn/drivers/net/wireless/d80211/rt2x00/rt2500pci.c	2006-05-25 16:53:54.000000000 +0200
@@ -51,6 +51,7 @@
 
 #ifdef CONFIG_RT2500PCI_BUTTON
 #define CONFIG_RT2X00_BUTTON
+#include <linux/radiobtn.h>
 #endif /* CONFIG_RT2500PCI_BUTTON */
 
 #include "rt2x00.h"
@@ -364,18 +365,58 @@ rt2x00_eeprom_multiread(
 /*
  * Hardware button poll handler.
  */
-static void
+static int
 rt2500pci_button_poll(unsigned long data)
 {
 	struct rt2x00_pci	*rt2x00pci = (struct rt2x00_pci*)data;
 	u32			reg;
 
 	rt2x00_register_read(rt2x00pci, GPIOCSR, &reg);
-	rt2x00pci_button_status(
-		rt2x00pci, rt2x00_get_field32(reg, GPIOCSR_BIT0));
+	return rt2x00_get_field32(reg, GPIOCSR_BIT0);
+}
+
+static void
+rt2500pci_enable_radio(unsigned long data)
+{
+	struct rt2x00_pci	*rt2x00pci = (struct rt2x00_pci*)data;
+	struct net_device	*net_dev = pci_get_drvdata(rt2x00pci->pci_dev);
+
+	rt2500pci_open(net_dev);
+}
+
+static void
+rt2500pci_disable_radio(unsigned long data)
+{
+	struct rt2x00_pci	*rt2x00pci = (struct rt2x00_pci*)data;
+	struct net_device	*net_dev = pci_get_drvdata(rt2x00pci->pci_dev);
+
+	rt2500pci_stop(net_dev);
+}
+
+static int
+rt2500pci_button_start(struct rt2x00_pci *rt2x00pci)
+{
+	struct radio_button	*button = &rt2x00pci->radio_button;
+
+	button->dev_name	= "rt2500pci";
+	button->data		= (unsigned long)rt2x00pci;
+	button->button_poll	= rt2500pci_button_poll;
+	button->enable_radio	= rt2500pci_enable_radio;
+	button->disable_radio	= rt2500pci_disable_radio;
+	button->poll_delay	= rt2x00_poll_delay;
+	button->current_state	= button->button_poll(button->data);
+
+	return radiobtn_register_device(button);
+}
+
+static void
+rt2500pci_button_stop(struct rt2x00_pci *rt2x00pci)
+{
+	radiobtn_unregister_device(&rt2x00pci->radio_button);
 }
 #else /* CONFIG_RT2500PCI_BUTTON */
-static void rt2500pci_button_poll(struct rt2x00_pci *rt2x00pci){}
+static int rt2500pci_button_start(struct rt2x00_pci *rt2x00pci){return 0;}
+static void rt2500pci_button_stop(struct rt2x00_pci *rt2x00pci){}
 #endif /* CONFIG_RT2500PCI_BUTTON */
 
 /*
@@ -2774,7 +2815,7 @@ rt2500pci_initialize(struct pci_dev *pci
 	/*
 	 * If required start hardware button polling.
 	 */
-	rt2x00pci_button_start(rt2x00pci, rt2500pci_button_poll);
+	rt2500pci_button_start(rt2x00pci);
 
 	/*
 	 * Register hardware.
@@ -2805,7 +2846,7 @@ rt2500pci_uninitialize(struct net_device
 	/*
 	 * Shutdown poll_timer for hardware button.
 	 */
-	rt2x00pci_button_stop(rt2x00pci);
+	rt2500pci_button_stop(rt2x00pci);
 
 	kfree(rt2x00pci->eeprom);
 
diff -uprN wireless-dev/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h wireless-dev-radiobtn/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h
--- wireless-dev/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h	2006-05-06 21:11:03.000000000 +0200
+++ wireless-dev-radiobtn/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h	2006-05-25 16:33:46.000000000 +0200
@@ -45,37 +45,6 @@
 #define EEPROM_READ_OPCODE		0x06
 
 /*
- * HW button structure.
- */
-#ifdef CONFIG_RT2X00_BUTTON
-#include <acpi/acpi_bus.h>
-
-struct rt2x00_button{
-	/*
-	 * ACPI device for generation of ACPI events.
-	 */
-	struct acpi_device			acpi_dev;
-
-	/*
-	 * Timer for register polling.
-	 */
-	struct timer_list			poll_timer;
-
-	/*
-	 * Timer delay.
-	 */
-	short					poll_delay;
-
-	/*
-	 * Current status of button.
-	 */
-	short					button_status:1;
-	short					active_poll:1;
-	short					__pad:14;
-};
-#endif /* CONFIG_RT2X00_BUTTON */
-
-/*
  * data_entry
  * The data ring is a list of data entries.
  * Each entry holds a reference to the descriptor
@@ -123,7 +92,7 @@ struct rt2x00_pci{
 	struct pci_dev				*pci_dev;
 
 #ifdef CONFIG_RT2X00_BUTTON
-	struct rt2x00_button			button;
+	struct radio_button			button;
 #endif /* CONFIG_RT2X00_BUTTON */
 
 	/*
@@ -267,85 +236,11 @@ rt2x00pci_get_ring(struct rt2x00_pci *rt
 	return NULL;
 }
 
-/*
- * HW button variables & functions.
- * The delay between each poll is set by the module parameter.
- */
 #ifdef CONFIG_RT2X00_BUTTON
 /*
  * Module parameter.
  */
 static short rt2x00_poll_delay = 0;
-
-static inline void
-rt2x00pci_button_status(struct rt2x00_pci *rt2x00pci, char status)
-{
-	struct rt2x00_button	*button = &rt2x00pci->button;
-
-	if (!button->active_poll)
-		return;
-
-	if (status != button->button_status) {
-		button->button_status = status;
-		acpi_bus_generate_event(
-			&button->acpi_dev, ACPI_TYPE_EVENT, status);
-	}
-
-	button->poll_timer.expires = jiffies + button->poll_delay;
-
-	if (button->active_poll)
-		add_timer(&button->poll_timer);
-}
-
-static inline void
-rt2x00pci_button_start(struct rt2x00_pci *rt2x00pci,
-	void (*handler)(unsigned long data))
-{
-	struct rt2x00_button	*button = &rt2x00pci->button;
-
-	/*
-	 * Only enable polling when the user has
-	 * set the poll delay module parameter,
-	 * and the device contains a hardware button.
-	 */
-	if(!GET_FLAG(rt2x00pci, HARDWARE_BUTTON) || !rt2x00_poll_delay)
-		return;
-
-	strcpy(acpi_device_class(&button->acpi_dev), DRV_NAME "_button");
-	strcpy(acpi_device_bid(&button->acpi_dev), DRV_NAME);
-	strcpy(acpi_device_name(&button->acpi_dev), DRV_NAME);
-
-	init_timer(&button->poll_timer);
-
-	button->poll_delay = rt2x00_poll_delay * (HZ / 10);
-	button->button_status = 0;
-	button->active_poll = 1;
-
-	button->poll_timer.function = handler;
-	button->poll_timer.data = (unsigned long)rt2x00pci;
-	button->poll_timer.expires = jiffies + button->poll_delay;
-
-	add_timer(&button->poll_timer);
-}
-
-static inline void
-rt2x00pci_button_stop(struct rt2x00_pci *rt2x00pci)
-{
-	/*
-	 * Shutdown poll_timer for hardware button,
-	 * make sure only to disable polling when
-	 * it was enabled in the first place.
-	 */
-	if(!rt2x00pci->button.active_poll)
-		return;
-
-	rt2x00pci->button.active_poll = 0;
-	del_timer_sync(&rt2x00pci->button.poll_timer);
-}
-#else /* CONFIG_RT2X00_BUTTON */
-static inline void rt2x00pci_button_start(struct rt2x00_pci *rt2x00pci,
-	int (*handler)(struct rt2x00_pci *rt2x00pci)){}
-static inline void rt2x00pci_button_stop(struct rt2x00_pci *rt2x00pci){}
 #endif /* CONFIG_RT2X00_BUTTON */
 
 #endif /* RT2X00PCI_H */
diff -uprN wireless-dev/drivers/net/wireless/d80211/rt2x00/rt61pci.c wireless-dev-radiobtn/drivers/net/wireless/d80211/rt2x00/rt61pci.c
--- wireless-dev/drivers/net/wireless/d80211/rt2x00/rt61pci.c	2006-05-06 21:11:03.000000000 +0200
+++ wireless-dev-radiobtn/drivers/net/wireless/d80211/rt2x00/rt61pci.c	2006-05-25 16:54:30.000000000 +0200
@@ -52,6 +52,7 @@
 
 #ifdef CONFIG_RT61PCI_BUTTON
 #define CONFIG_RT2X00_BUTTON
+#include <linux/radiobtn.h>
 #endif /* CONFIG_RT61PCI_BUTTON */
 
 #include "rt2x00.h"
@@ -400,18 +401,58 @@ rt2x00_eeprom_multiread(
 /*
  * Hardware button poll handler.
  */
-static void
+static int
 rt61pci_button_poll(unsigned long data)
 {
 	struct rt2x00_pci	*rt2x00pci = (struct rt2x00_pci*)data;
 	u32			reg;
 
 	rt2x00_register_read(rt2x00pci, MAC_CSR13, &reg);
-	rt2x00pci_button_status(
-		rt2x00pci, rt2x00_get_field32(reg, MAC_CSR13_BIT5));
+	return rt2x00_get_field32(reg, MAC_CSR13_BIT5);
+}
+
+static void
+rt61pci_enable_radio(unsigned long data)
+{
+	struct rt2x00_pci	*rt2x00pci = (struct rt2x00_pci*)data;
+	struct net_device	*net_dev = pci_get_drvdata(rt2x00pci->pci_dev);
+
+	rt61pci_open(net_dev);
+}
+
+static void
+rt61pci_disable_radio(unsigned long data)
+{
+	struct rt2x00_pci	*rt2x00pci = (struct rt2x00_pci*)data;
+	struct net_device	*net_dev = pci_get_drvdata(rt2x00pci->pci_dev);
+
+	rt61pci_stop(net_dev);
+}
+
+static int
+rt61pci_button_start(struct rt2x00_pci *rt2x00pci)
+{
+	struct radio_button	*button = &rt2x00pci->radio_button;
+
+	button->dev_name	= "rt61pci";
+	button->data		= (unsigned long)rt2x00pci;
+	button->button_poll	= rt61pci_button_poll;
+	button->enable_radio	= rt61pci_enable_radio;
+	button->disable_radio	= rt61pci_disable_radio;
+	button->poll_delay	= rt2x00_poll_delay;
+	button->current_state	= button->button_poll(button->data);
+
+	return radiobtn_register_device(button);
+}
+
+static void
+rt61pci_button_stop(struct rt2x00_pci *rt2x00pci)
+{
+	radiobtn_unregister_device(&rt2x00pci->radio_button);
 }
 #else /* CONFIG_RT61PCI_BUTTON */
-static void rt61pci_button_poll(struct rt2x00_pci *rt2x00pci){}
+static int rt61pci_button_start(struct rt2x00_pci *rt2x00pci){return 0;}
+static void rt61pci_button_stop(struct rt2x00_pci *rt2x00pci){}
 #endif /* CONFIG_RT61PCI_BUTTON */
 
 /*
@@ -3324,7 +3365,7 @@ rt61pci_initialize(struct pci_dev *pci_d
 	/*
 	 * If required start hardware button polling.
 	 */
-	rt2x00pci_button_start(rt2x00pci, rt61pci_button_poll);
+	rt61pci_button_start(rt2x00pci);
 
 	/*
 	 * Register hardware.
@@ -3355,7 +3396,7 @@ rt61pci_uninitialize(struct net_device *
 	/*
 	 * Shutdown poll_timer for hardware button.
 	 */
-	rt2x00pci_button_stop(rt2x00pci);
+	rt61pci_button_stop(rt2x00pci);
 
 	kfree(rt2x00pci->eeprom);