diff options
author | Gaurav Singhal <gsinghal@codeaurora.org> | 2016-04-03 23:37:56 +0530 |
---|---|---|
committer | Kyle Yan <kyan@codeaurora.org> | 2016-06-10 15:13:25 -0700 |
commit | 917e41ac91a9de2c215607a054530870090a10a9 (patch) | |
tree | 4cb7bd1ad29c305e1d7d8e9a8e7743270b4fcb84 | |
parent | 87574457d010fe9e6001c862ef2a0a8bba9b3e80 (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.c | 160 |
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) |