summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGaurav Singhal <gsinghal@codeaurora.org>2016-04-03 23:37:56 +0530
committerKyle Yan <kyan@codeaurora.org>2016-06-10 15:13:25 -0700
commit917e41ac91a9de2c215607a054530870090a10a9 (patch)
tree4cb7bd1ad29c305e1d7d8e9a8e7743270b4fcb84
parent87574457d010fe9e6001c862ef2a0a8bba9b3e80 (diff)
NFC: Error handling correction in probe
Error handling check added in probe function and memory cleanup in remove function. Change-Id: Ic8f02dcc89e716ec88b711496d1e43754b95968d Signed-off-by: Gaurav Singhal <gsinghal@codeaurora.org>
-rw-r--r--drivers/nfc/nq-nci.c160
1 files changed, 110 insertions, 50 deletions
diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c
index 9053944ef459..a2ff438627ed 100644
--- a/drivers/nfc/nq-nci.c
+++ b/drivers/nfc/nq-nci.c
@@ -69,7 +69,7 @@ struct nqx_dev {
/* read buffer*/
size_t kbuflen;
u8 *kbuf;
-
+ struct nqx_platform_data *pdata;
};
static int nfcc_reboot(struct notifier_block *notifier, unsigned long val,
@@ -150,6 +150,11 @@ static ssize_t nfc_read(struct file *filp, char __user *buf,
int ret;
int irq_gpio_val = 0;
+ if (!nqx_dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+
if (count > nqx_dev->kbuflen)
count = nqx_dev->kbuflen;
@@ -178,23 +183,27 @@ static ssize_t nfc_read(struct file *filp, char __user *buf,
}
tmp = nqx_dev->kbuf;
-
+ if (!tmp) {
+ dev_err(&nqx_dev->client->dev,
+ "%s: device doesn't exist anymore\n", __func__);
+ ret = -ENODEV;
+ goto err;
+ }
memset(tmp, 0x00, count);
+
/* Read data */
ret = i2c_master_recv(nqx_dev->client, tmp, count);
-
- mutex_unlock(&nqx_dev->read_mutex);
-
if (ret < 0) {
dev_err(&nqx_dev->client->dev,
"%s: i2c_master_recv returned %d\n", __func__, ret);
- return ret;
+ goto err;
}
if (ret > count) {
dev_err(&nqx_dev->client->dev,
"%s: received too many bytes from i2c (%d)\n",
__func__, ret);
- return -EIO;
+ ret = -EIO;
+ goto err;
}
#ifdef NFC_KERNEL_BU
dev_dbg(&nqx_dev->client->dev, "%s : NfcNciRx %x %x %x\n",
@@ -203,12 +212,15 @@ static ssize_t nfc_read(struct file *filp, char __user *buf,
if (copy_to_user(buf, tmp, ret)) {
dev_warn(&nqx_dev->client->dev,
"%s : failed to copy to user space\n", __func__);
- return -EFAULT;
+ ret = -EFAULT;
+ goto err;
}
+ mutex_unlock(&nqx_dev->read_mutex);
return ret;
err:
mutex_unlock(&nqx_dev->read_mutex);
+out:
return ret;
}
@@ -216,25 +228,34 @@ static ssize_t nfc_write(struct file *filp, const char __user *buf,
size_t count, loff_t *offset)
{
struct nqx_dev *nqx_dev = filp->private_data;
- char *tmp;
+ char *tmp = NULL;
int ret = 0;
+ if (!nqx_dev) {
+ ret = -ENODEV;
+ goto out;
+ }
if (count > nqx_dev->kbuflen) {
dev_err(&nqx_dev->client->dev, "%s: out of memory\n",
__func__);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out;
}
tmp = memdup_user(buf, count);
-
- if (IS_ERR(tmp))
- return PTR_ERR(tmp);
+ if (IS_ERR(tmp)) {
+ dev_err(&nqx_dev->client->dev, "%s: memdup_user failed\n",
+ __func__);
+ ret = PTR_ERR(tmp);
+ goto out;
+ }
ret = i2c_master_send(nqx_dev->client, tmp, count);
if (ret != count) {
dev_err(&nqx_dev->client->dev,
"%s: failed to write %d\n", __func__, ret);
ret = -EIO;
+ goto out_free;
}
#ifdef NFC_KERNEL_BU
dev_dbg(&nqx_dev->client->dev,
@@ -243,7 +264,9 @@ static ssize_t nfc_write(struct file *filp, const char __user *buf,
tmp[0], tmp[1], tmp[2]);
#endif
usleep_range(1000, 1100);
+out_free:
kfree(tmp);
+out:
return ret;
}
@@ -559,28 +582,35 @@ static int nqx_probe(struct i2c_client *client,
if (client->dev.of_node) {
platform_data = devm_kzalloc(&client->dev,
sizeof(struct nqx_platform_data), GFP_KERNEL);
- if (!platform_data)
- return -ENOMEM;
+ if (!platform_data) {
+ r = -ENOMEM;
+ goto err_platform_data;
+ }
r = nfc_parse_dt(&client->dev, platform_data);
if (r)
- return r;
- } else {
+ goto err_free_data;
+ } else
platform_data = client->dev.platform_data;
- }
+
dev_dbg(&client->dev,
"%s, inside nfc-nci flags = %x\n",
__func__, client->flags);
+
if (platform_data == NULL) {
dev_err(&client->dev, "%s: failed\n", __func__);
- return -ENODEV;
+ r = -ENODEV;
+ goto err_platform_data;
}
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "%s: need I2C_FUNC_I2C\n", __func__);
- return -ENODEV;
+ r = -ENODEV;
+ goto err_free_data;
}
nqx_dev = kzalloc(sizeof(*nqx_dev), GFP_KERNEL);
- if (nqx_dev == NULL)
- return -ENOMEM;
+ if (nqx_dev == NULL) {
+ r = -ENOMEM;
+ goto err_free_data;
+ }
nqx_dev->client = client;
nqx_dev->kbuflen = MAX_BUFFER_SIZE;
nqx_dev->kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_KERNEL);
@@ -595,7 +625,7 @@ static int nqx_probe(struct i2c_client *client,
r = gpio_request(platform_data->en_gpio, "nfc_reset_gpio");
if (r) {
dev_err(&client->dev,
- "%s: unable to request gpio [%d]\n",
+ "%s: unable to request nfc reset gpio [%d]\n",
__func__,
platform_data->en_gpio);
goto err_mem;
@@ -603,36 +633,36 @@ static int nqx_probe(struct i2c_client *client,
r = gpio_direction_output(platform_data->en_gpio, 0);
if (r) {
dev_err(&client->dev,
- "%s: unable to set direction for gpio [%d]\n",
+ "%s: unable to set direction for nfc reset gpio [%d]\n",
__func__,
platform_data->en_gpio);
goto err_en_gpio;
}
} else {
- dev_err(&client->dev, "%s: dis gpio not provided\n", __func__);
+ dev_err(&client->dev,
+ "%s: nfc reset gpio not provided\n", __func__);
goto err_mem;
}
if (gpio_is_valid(platform_data->irq_gpio)) {
r = gpio_request(platform_data->irq_gpio, "nfc_irq_gpio");
if (r) {
- dev_err(&client->dev, "%s: unable to req irq gpio [%d]\n",
+ dev_err(&client->dev, "%s: unable to request nfc irq gpio [%d]\n",
__func__, platform_data->irq_gpio);
goto err_en_gpio;
}
r = gpio_direction_input(platform_data->irq_gpio);
if (r) {
-
dev_err(&client->dev,
- "%s: unable to set direction for irq gpio [%d]\n",
+ "%s: unable to set direction for nfc irq gpio [%d]\n",
__func__,
platform_data->irq_gpio);
- goto err_irq;
+ goto err_irq_gpio;
}
irqn = gpio_to_irq(platform_data->irq_gpio);
if (irqn < 0) {
r = irqn;
- goto err_irq;
+ goto err_irq_gpio;
}
client->irq = irqn;
} else {
@@ -644,47 +674,49 @@ static int nqx_probe(struct i2c_client *client,
"nfc_firm_gpio");
if (r) {
dev_err(&client->dev,
- "%s: unable to request firm gpio [%d]\n",
+ "%s: unable to request nfc firmware gpio [%d]\n",
__func__, platform_data->firm_gpio);
- goto err_irq;
+ goto err_irq_gpio;
}
r = gpio_direction_output(platform_data->firm_gpio, 0);
if (r) {
dev_err(&client->dev,
- "%s: cannot set direction for firm gpio [%d]\n",
+ "%s: cannot set direction for nfc firmware gpio [%d]\n",
__func__, platform_data->firm_gpio);
- goto err_irq;
+ goto err_firm_gpio;
}
- nqx_dev->firm_gpio = platform_data->firm_gpio;
} else {
dev_err(&client->dev,
"%s: firm gpio not provided\n", __func__);
+ goto err_irq_gpio;
}
if (gpio_is_valid(platform_data->clkreq_gpio)) {
r = gpio_request(platform_data->clkreq_gpio,
"nfc_clkreq_gpio");
if (r) {
dev_err(&client->dev,
- "%s: unable to request clk gpio [%d]\n",
+ "%s: unable to request nfc clkreq gpio [%d]\n",
__func__, platform_data->clkreq_gpio);
- goto err_clkreq_gpio;
+ goto err_firm_gpio;
}
r = gpio_direction_input(platform_data->clkreq_gpio);
if (r) {
dev_err(&client->dev,
- "%s: cannot set direction for clk gpio [%d]\n",
+ "%s: cannot set direction for nfc clkreq gpio [%d]\n",
__func__, platform_data->clkreq_gpio);
goto err_clkreq_gpio;
}
- nqx_dev->clkreq_gpio = platform_data->clkreq_gpio;
} else {
dev_err(&client->dev,
"%s: clkreq gpio not provided\n", __func__);
+ goto err_firm_gpio;
}
nqx_dev->en_gpio = platform_data->en_gpio;
nqx_dev->irq_gpio = platform_data->irq_gpio;
nqx_dev->firm_gpio = platform_data->firm_gpio;
+ nqx_dev->clkreq_gpio = platform_data->clkreq_gpio;
+ nqx_dev->pdata = platform_data;
/* init mutex and queues */
init_waitqueue_head(&nqx_dev->read_wq);
@@ -719,6 +751,8 @@ static int nqx_probe(struct i2c_client *client,
r = nfcc_hw_check(client, platform_data->en_gpio);
if (r) {
+ /* make sure NFCC is not enabled */
+ gpio_set_value(platform_data->en_gpio, 0);
/* We don't think there is hardware switch NFC OFF */
goto err_request_hw_check_failed;
}
@@ -729,39 +763,46 @@ static int nqx_probe(struct i2c_client *client,
dev_err(&client->dev,
"%s: cannot register reboot notifier(err = %d)\n",
__func__, r);
- goto err_request_notifier_failed;
+ /*
+ * nfcc_hw_check function not doing memory
+ * allocation so using same goto target here
+ */
+ goto err_request_hw_check_failed;
}
- device_init_wakeup(&client->dev, true);
- device_set_wakeup_capable(&client->dev, true);
- i2c_set_clientdata(client, nqx_dev);
#ifdef NFC_KERNEL_BU
r = nqx_clock_select(nqx_dev);
if (r < 0) {
dev_err(&client->dev,
"%s: nqx_clock_select failed\n", __func__);
- goto err_request_notifier_failed;
+ goto err_clock_en_failed;
}
gpio_set_value(platform_data->en_gpio, 1);
#endif
+ device_init_wakeup(&client->dev, true);
+ device_set_wakeup_capable(&client->dev, true);
+ i2c_set_clientdata(client, nqx_dev);
+
dev_err(&client->dev,
"%s: probing NFCC NQxxx exited successfully\n",
__func__);
return 0;
-err_request_notifier_failed:
+#ifdef NFC_KERNEL_BU
+err_clock_en_failed:
unregister_reboot_notifier(&nfcc_notifier);
+#endif
err_request_hw_check_failed:
- /* make sure NFCC is not enabled */
- gpio_set_value(platform_data->en_gpio, 0);
+ free_irq(client->irq, nqx_dev);
err_request_irq_failed:
misc_deregister(&nqx_dev->nqx_device);
err_misc_register:
mutex_destroy(&nqx_dev->read_mutex);
err_clkreq_gpio:
gpio_free(platform_data->clkreq_gpio);
-err_irq:
- free_irq(client->irq, nqx_dev);
+err_firm_gpio:
+ gpio_free(platform_data->firm_gpio);
+err_irq_gpio:
gpio_free(platform_data->irq_gpio);
err_en_gpio:
gpio_free(platform_data->en_gpio);
@@ -769,6 +810,10 @@ err_mem:
kfree(nqx_dev->kbuf);
err_free_dev:
kfree(nqx_dev);
+err_free_data:
+ if (client->dev.of_node)
+ devm_kfree(&client->dev, platform_data);
+err_platform_data:
dev_err(&client->dev,
"%s: probing nqxx failed, check hardware\n",
__func__);
@@ -777,17 +822,32 @@ err_free_dev:
static int nqx_remove(struct i2c_client *client)
{
+ int ret = 0;
struct nqx_dev *nqx_dev;
nqx_dev = i2c_get_clientdata(client);
+ if (!nqx_dev) {
+ dev_err(&client->dev,
+ "%s: device doesn't exist anymore\n", __func__);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ unregister_reboot_notifier(&nfcc_notifier);
free_irq(client->irq, nqx_dev);
misc_deregister(&nqx_dev->nqx_device);
mutex_destroy(&nqx_dev->read_mutex);
+ gpio_free(nqx_dev->clkreq_gpio);
+ gpio_free(nqx_dev->firm_gpio);
gpio_free(nqx_dev->irq_gpio);
gpio_free(nqx_dev->en_gpio);
kfree(nqx_dev->kbuf);
+ if (client->dev.of_node)
+ devm_kfree(&client->dev, nqx_dev->pdata);
+
kfree(nqx_dev);
- return 0;
+err:
+ return ret;
}
static int nqx_suspend(struct device *device)