// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2006 - 2007 Ivo van Doorn
* Copyright (C) 2007 Dmitry Torokhov
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
*/
#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/sched.h>
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/slab.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;
enum rfkill_type type;
unsigned long state;
u32 idx;
bool registered;
bool persistent;
bool polling_paused;
bool suspended;
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;
char name[];
};
#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<