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>
This commit is contained in:
parent
87574457d0
commit
917e41ac91
1 changed files with 110 additions and 50 deletions
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue