/*
* Copyright (C) 2006 - 2007 Ivo van Doorn
* Copyright (C) 2007 Dmitry Torokhov
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
*
* 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.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/workqueue.h>
#include <linux/capability.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/rfkill.h>
#include <linux/spinlock.h>
#include <linux/miscdevice.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include "rfkill.h"
#define POLL_INTERVAL (5 * HZ)
#define RFKILL_BLOCK_HW BIT(0)
#define RFKILL_BLOCK_SW BIT(1)
#define RFKILL_BLOCK_SW_PREV BIT(2)
#define RFKILL_BLOCK_ANY (RFKILL_BLOCK_HW |\
RFKILL_BLOCK_SW |\
RFKILL_BLOCK_SW_PREV)
#define RFKILL_BLOCK_SW_SETCALL BIT(31)
struct rfkill {
spinlock_t lock;
const char *name;
enum rfkill_type type;
unsigned long state;
u32 idx;
bool registered;
bool suspended;
bool persistent;
const struct rfkill_ops *ops;
void *data;
#ifdef CONFIG_RFKILL_LEDS
struct led_trigger led_trigger;
const char *ledtrigname;
#endif
struct device dev;
struct list_head node;
struct delayed_work poll_work;
struct work_struct uevent_work;
struct work_struct sync_work;
};
#define to_rfkill(d) container_of(d, struct rfkill, dev)
struct rfkill_int_event {
struct list_head list;
struct rfkill_event ev;
};
struct rfkill_data {
struct list_head list;
struct list_head events;
struct mutex mtx;
wait_queue_head_t read_wait;
bool input_handler;
};
MODULE_AUTHOR("Ivo van Doorn <IvDoorn@gmail.com>");
MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
MODULE_DESCRIPTION("RF switch support");
MODULE_LICENSE("GPL");
/*
* The locking here should be made much smarter, we currently have
* a bit of a stupid situation because drivers might want to register
* the rfkill struct under their own lock, and take this lock during
* rfkill method calls -- which will cause an AB-BA deadlock situation.
*
* To fix that, we need to rework this code here to be mostly lock-free
* and only use the mutex for list manipulations, not to protect the
* various other global variables. Then we can avoid holding the mutex
* around driver operations, and all is happy.
*/
static LIST_HEAD(rfkill_list); /* list of registered rf switches */
static DEFINE_MUTEX(rfkill_global_mutex);
static LIST_HEAD(rfkill_fds); /* list of open fds of /dev/rfkill */
static unsigned int rfkill_default_state = 1;
module_param_named(default_state, rfkill_default_state, uint, 0444);
MODULE_PARM_DESC(default_state,
"Default initial state for all radio types, 0 = radio off");
static struct {
bool cur, sav;
} rfkill_global_states[NUM_RFKILL_TYPES];
static bool rfkill_epo_lock_active;
#ifdef CONFIG_RFKILL_LEDS
static void rfkill_led_trigger_event(struct rfkill *rfkill)
{
struct led_trigger *trigger;
if (!rfkill->registered)
return;
trigger = &rfkill->led_trigger;
if (rfkill->state & RFKILL_BLOCK_ANY)
led_trigger_event(trigger, LED_OFF);
else
led_trigger_event(trigger, LED_FULL);
}
static void rfkill_led_trigger_activate(struct led_classdev *led)
{
struct rfkill *rfkill;
rfkill = container_of(led->trigger, struct rfkill, led_trigger);
rfkill_led_trigger_event(rfkill);
}
const char *rfkill_get_led_trigger_name(struct rfkill *rfkill)
{
<