summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPar-Gunnar Hjalmdahl <par-gunnar.p.hjalmdahl@stericsson.com>2011-08-29 09:29:05 +0530
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:05:51 +0200
commit0e9b14d010fe2fa1eb5e1690e32e101e1adf9dab (patch)
treea7fdce790177301cedef819b5907894bc1d5743e
parentd224ba380d6433d109eac46c94c18299258f9f28 (diff)
cg2900: Fix crash when transport is closed
This patch fixes crashes caused by transport being removed while users of the CG2900 driver still exist. ST-Ericsson Linux next: Not tested, ER 336652 ST-Ericsson ID: 336652 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I6318ce1086097a4fa63a1793b6795b01ea939715 Signed-off-by: Par-Gunnar Hjalmdahl <par-gunnar.p.hjalmdahl@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/21781 Reviewed-by: QATEST Reviewed-by: Lukasz RYMANOWSKI <lukasz.rymanowski@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/29795 Reviewed-by: Virupax SADASHIVPETIMATH <virupax.sadashivpetimath@stericsson.com> Tested-by: Virupax SADASHIVPETIMATH <virupax.sadashivpetimath@stericsson.com>
-rw-r--r--drivers/staging/cg2900/bluetooth/btcg2900.c1
-rw-r--r--drivers/staging/cg2900/bluetooth/cg2900_uart.c37
-rw-r--r--drivers/staging/cg2900/mfd/cg2900_audio.c29
-rw-r--r--drivers/staging/cg2900/mfd/cg2900_char_devices.c21
4 files changed, 74 insertions, 14 deletions
diff --git a/drivers/staging/cg2900/bluetooth/btcg2900.c b/drivers/staging/cg2900/bluetooth/btcg2900.c
index 0eb39523c1e..e1895c9ff70 100644
--- a/drivers/staging/cg2900/bluetooth/btcg2900.c
+++ b/drivers/staging/cg2900/bluetooth/btcg2900.c
@@ -1061,6 +1061,7 @@ static int remove_common(struct platform_device *pdev,
goto finished;
BT_INFO("Unregistering CG2900");
+ info->hdev->driver_data = NULL;
err = hci_unregister_dev(info->hdev);
if (err)
BT_ERR("Can not unregister HCI device (%d)", err);
diff --git a/drivers/staging/cg2900/bluetooth/cg2900_uart.c b/drivers/staging/cg2900/bluetooth/cg2900_uart.c
index 4417525306a..d7a1fb1044f 100644
--- a/drivers/staging/cg2900/bluetooth/cg2900_uart.c
+++ b/drivers/staging/cg2900/bluetooth/cg2900_uart.c
@@ -333,9 +333,10 @@ static void wake_up_chip(struct uart_info *uart_info);
*/
static bool is_chip_flow_off(struct uart_info *uart_info)
{
- int lines;
+ int lines = 0;
- lines = hci_uart_tiocmget(uart_info->hu);
+ if (uart_info->hu)
+ lines = hci_uart_tiocmget(uart_info->hu);
if (lines & TIOCM_CTS)
return false;
@@ -577,6 +578,11 @@ static void wake_up_chip(struct uart_info *uart_info)
if (!timeout_jiffies && uart_info->sleep_state != CHIP_RESUMING)
return;
+ if (!uart_info->hu) {
+ dev_err(MAIN_DEV, "wake_up_chip: UART not open\n");
+ return;
+ }
+
mutex_lock(&(uart_info->sleep_state_lock));
/*
@@ -602,7 +608,7 @@ static void wake_up_chip(struct uart_info *uart_info)
/* Disable IRQ only when it was enabled. */
unset_cts_irq(uart_info);
(void)hci_uart_set_baudrate(uart_info->hu,
- uart_info->baud_rate);
+ uart_info->baud_rate);
enable_uart_pins(uart_info);
@@ -650,6 +656,11 @@ static void set_chip_sleep_mode(struct work_struct *work)
if (!timeout_jiffies)
return;
+ if (!uart_info->hu) {
+ dev_err(MAIN_DEV, "set_chip_sleep_mode: UART not open\n");
+ return;
+ }
+
if (uart_info->tx_in_progress || uart_info->rx_in_progress) {
dev_dbg(MAIN_DEV, "Not going to sleep, TX/RX in progress\n");
return;
@@ -674,13 +685,12 @@ static void set_chip_sleep_mode(struct work_struct *work)
* Set baud zero.
* This cause shut off UART clock as well.
*/
- (void)hci_uart_set_baudrate(uart_info->hu,
- ZERO_BAUD_RATE);
+ (void)hci_uart_set_baudrate(uart_info->hu, ZERO_BAUD_RATE);
err = set_cts_irq(uart_info);
if (err < 0) {
enable_uart_pins(uart_info);
(void)hci_uart_set_baudrate(uart_info->hu,
- uart_info->baud_rate);
+ uart_info->baud_rate);
hci_uart_flow_ctrl(uart_info->hu, FLOW_ON);
hci_uart_set_break(uart_info->hu, BREAK_OFF);
@@ -1060,6 +1070,11 @@ static void work_do_transmit(struct work_struct *work)
kfree(current_work);
+ if (!uart_info->hu) {
+ dev_err(MAIN_DEV, "work_do_transmit: UART not open\n");
+ return;
+ }
+
spin_lock_bh(&(uart_info->transmission_lock));
/* Mark that there is an ongoing transfer. */
uart_info->tx_in_progress = true;
@@ -1129,6 +1144,11 @@ static int set_baud_rate(struct hci_uart *hu, int baud)
return -EALREADY;
}
+ if (!uart_info->hu) {
+ dev_err(MAIN_DEV, "set_baud_rate: UART not open\n");
+ return -EFAULT;
+ }
+
/*
* Wait some time to be sure that any RX process has finished (which
* flows on RTS in the end) before flowing off the RTS.
@@ -1244,6 +1264,11 @@ static int uart_open(struct cg2900_chip_dev *dev)
struct hci_command_hdr *cmd;
struct uart_info *uart_info = dev_get_drvdata(dev->dev);
+ if (!uart_info->hu) {
+ dev_err(MAIN_DEV, "uart_open: UART not open\n");
+ return -EACCES;
+ }
+
/*
* Chip has just been started up. It has a system to autodetect
* exact baud rate and transport to use. There are only a few commands
diff --git a/drivers/staging/cg2900/mfd/cg2900_audio.c b/drivers/staging/cg2900/mfd/cg2900_audio.c
index 6eadd96b2de..a7b8eda4305 100644
--- a/drivers/staging/cg2900/mfd/cg2900_audio.c
+++ b/drivers/staging/cg2900/mfd/cg2900_audio.c
@@ -111,6 +111,7 @@ struct endpoint_config_node {
* audio channel.
* @dev_fm: Device registered by this driver for the FM
* audio channel.
+ * @filp: Current char device file pointer.
* @management_mutex: Mutex for handling access to CG2900 Audio driver
* management.
* @bt_mutex: Mutex for handling access to BT audio channel.
@@ -136,6 +137,7 @@ struct audio_info {
struct device *parent;
struct device *dev_bt;
struct device *dev_fm;
+ struct file *filp;
struct mutex management_mutex;
struct mutex bt_mutex;
struct mutex fm_mutex;
@@ -2825,6 +2827,7 @@ static int audio_dev_open(struct inode *inode, struct file *filp)
}
filp->private_data = char_dev_info;
char_dev_info->info = info;
+ info->filp = filp;
mutex_init(&char_dev_info->management_mutex);
mutex_init(&char_dev_info->rw_mutex);
@@ -2861,7 +2864,14 @@ static int audio_dev_release(struct inode *inode, struct file *filp)
{
int err = 0;
struct char_dev_info *dev = filp->private_data;
- struct audio_info *info = dev->info;
+ struct audio_info *info;
+
+ if (!dev) {
+ pr_err("audio_dev_release: Transport closed");
+ return -EBADF;
+ }
+
+ info = dev->info;
dev_dbg(BT_DEV, "audio_dev_release\n");
@@ -2879,6 +2889,7 @@ static int audio_dev_release(struct inode *inode, struct file *filp)
kfree(dev);
filp->private_data = NULL;
+ info->filp = NULL;
return err;
}
@@ -2907,11 +2918,18 @@ static ssize_t audio_dev_read(struct file *filp, char __user *buf, size_t count,
loff_t *f_pos)
{
struct char_dev_info *dev = filp->private_data;
- struct audio_info *info = dev->info;
+ struct audio_info *info;
unsigned int bytes_to_copy;
int err = 0;
struct sk_buff *skb;
+ if (!dev) {
+ pr_err("audio_dev_read: Transport closed");
+ return -EBADF;
+ }
+
+ info = dev->info;
+
dev_dbg(BT_DEV, "audio_dev_read count %d\n", count);
mutex_lock(&dev->rw_mutex);
@@ -2988,7 +3006,7 @@ static ssize_t audio_dev_write(struct file *filp, const char __user *buf,
pr_debug("audio_dev_write count %d", count);
if (!dev) {
- pr_err("No dev supplied in private data");
+ pr_err("audio_dev_write: Transport closed");
return -EBADF;
}
info = dev->info;
@@ -3170,7 +3188,7 @@ static unsigned int audio_dev_poll(struct file *filp, poll_table *wait)
unsigned int mask = 0;
if (!dev) {
- pr_err("No dev supplied in private data");
+ pr_err("audio_dev_poll: Transport closed");
return POLLERR | POLLRDHUP;
}
info = dev->info;
@@ -3344,6 +3362,9 @@ static int common_remove(struct audio_info *info, struct device *dev)
dev_err(dev, "Error %d deregistering misc dev\n", err);
info->misc_registered = false;
+ if (info->filp)
+ info->filp->private_data = NULL;
+
dev_info(dev, "CG2900 Audio driver removed\n");
return err;
}
diff --git a/drivers/staging/cg2900/mfd/cg2900_char_devices.c b/drivers/staging/cg2900/mfd/cg2900_char_devices.c
index 0f1627e82ac..10f7d38d4a0 100644
--- a/drivers/staging/cg2900/mfd/cg2900_char_devices.c
+++ b/drivers/staging/cg2900/mfd/cg2900_char_devices.c
@@ -37,6 +37,7 @@
* struct char_dev_user - Stores device information.
* @dev: Current device.
* @miscdev: Registered device struct.
+ * @filp: Current file pointer.
* @name: Name of device.
* @rx_queue: Data queue.
* @rx_wait_queue: Wait queue.
@@ -48,6 +49,7 @@
struct char_dev_user {
struct device *dev;
struct miscdevice miscdev;
+ struct file *filp;
char *name;
struct sk_buff_head rx_queue;
wait_queue_head_t rx_wait_queue;
@@ -147,6 +149,7 @@ static int char_dev_open(struct inode *inode, struct file *filp)
}
filp->private_data = dev;
+ dev->filp = filp;
user = dev_get_platdata(dev->dev);
/* First initiate wait queues for this device. */
@@ -188,7 +191,7 @@ static int char_dev_release(struct inode *inode, struct file *filp)
pr_debug("char_dev_release");
if (!dev) {
- pr_err("Calling with NULL pointer");
+ pr_err("char_dev_release: Calling with NULL pointer");
return -EBADF;
}
@@ -203,6 +206,7 @@ static int char_dev_release(struct inode *inode, struct file *filp)
dev_info(MAIN_DEV, "char_dev %s closed\n", dev->name);
filp->private_data = NULL;
+ dev->filp = NULL;
wake_up_interruptible(&dev->rx_wait_queue);
wake_up_interruptible(&dev->reset_wait_queue);
@@ -241,7 +245,7 @@ static ssize_t char_dev_read(struct file *filp, char __user *buf, size_t count,
pr_debug("char_dev_read");
if (!dev) {
- pr_err("Calling with NULL pointer");
+ pr_err("char_dev_read: Calling with NULL pointer");
return -EBADF;
}
mutex_lock(&dev->read_mutex);
@@ -322,7 +326,7 @@ static ssize_t char_dev_write(struct file *filp, const char __user *buf,
pr_debug("char_dev_write");
if (!dev) {
- pr_err("Calling with NULL pointer");
+ pr_err("char_dev_write: Calling with NULL pointer");
return -EBADF;
}
@@ -386,6 +390,11 @@ static long char_dev_unlocked_ioctl(struct file *filp, unsigned int cmd,
int ret_val;
void __user *user_arg = (void __user *)arg;
+ if (!dev) {
+ pr_err("char_dev_unlocked_ioctl: Calling with NULL pointer");
+ return -EBADF;
+ }
+
dev_dbg(dev->dev, "char_dev_unlocked_ioctl for %s\n"
"\tDIR: %d\n"
"\tTYPE: %d\n"
@@ -464,7 +473,7 @@ static unsigned int char_dev_poll(struct file *filp, poll_table *wait)
unsigned int mask = 0;
if (!dev) {
- pr_debug("Device not open");
+ pr_debug("char_dev_poll: Device not open");
return POLLERR | POLLRDHUP;
}
@@ -526,6 +535,10 @@ static void remove_dev(struct char_dev_user *dev_usr)
mutex_destroy(&dev_usr->read_mutex);
mutex_destroy(&dev_usr->write_mutex);
+ dev_usr->dev = NULL;
+ if (dev_usr->filp)
+ dev_usr->filp->private_data = NULL;
+
/* Remove device node in file system. */
misc_deregister(&dev_usr->miscdev);
kfree(dev_usr);