From: Benjamin Tissoires <hidden> Date: 2012-12-04 15:28:18
Hi guys,
Jean made a recent review of i2c-hid, and before this driver goes into
Linus' tree, here are some cleanups.
Patch 2 has not been detected by Jean, but it appeared while playing with
buffers allocation. So this is the only change not asked by the previous
review.
I still need to work on the mutex to protect the potential race on .open and
.close, but meanwhile, here is a first batch of patches.
Cheers,
Benjamin
Benjamin Tissoires (14):
HID: i2c-hid: change I2C name
HID: i2c-hid: fix memory corruption due to missing hid declarations
HID: i2c-hid: enhance Kconfig
HID: i2c-hid: fix checkpatch.pl warning
HID: i2c-hid: fix i2c_hid_dbg macro
HID: i2c-hid: remove unused static declarations
HID: i2c-hid: fix return paths
HID: i2c-hid: fix error messages
HID: i2c-hid: i2c_hid_get_report may fail
HID: i2c-hid: reorder allocation/free of buffers
HID: i2c-hid: remove unneeded test in i2c_hid_remove
HID: i2c-hid: remove extra .irq field in struct i2c_hid
HID: i2c-hid: also call i2c_hid_free_buffers in i2c_hid_remove
HID: i2c-hid: fix i2c_hid_get_raw_report count mismatches
drivers/hid/i2c-hid/Kconfig | 7 +-
drivers/hid/i2c-hid/i2c-hid.c | 184 ++++++++++++++++++++----------------------
2 files changed, 89 insertions(+), 102 deletions(-)
--
1.8.0.1
From: Benjamin Tissoires <hidden> Date: 2012-12-04 15:28:24
HID descriptors contains 4 bytes of reserved field.
The previous implementation was overriding the next fields in struct i2c_hid.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Benjamin Tissoires <hidden> Date: 2012-12-04 15:28:28
These definitions are not used here, but are defined by the specification.
Keeping some of them for documentation purposes.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 25 ++++++++++---------------
1 file changed, 10 insertions(+), 15 deletions(-)
From: Benjamin Tissoires <hidden> Date: 2012-12-04 15:28:36
Simplifies i2c_hid_alloc_buffers tests, and makes this function
responsible of the assignment of ihid->bufsize.
The condition for the reallocation in i2c_hid_start is then simpler.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 68 ++++++++++++++++++-------------------------
1 file changed, 28 insertions(+), 40 deletions(-)
@@ -465,48 +465,38 @@ static void i2c_hid_find_max_report(struct hid_device *hid, unsigned int type,}}-staticinti2c_hid_alloc_buffers(structi2c_hid*ihid)+staticvoidi2c_hid_free_buffers(structi2c_hid*ihid)+{+kfree(ihid->inbuf);+kfree(ihid->argsbuf);+kfree(ihid->cmdbuf);+ihid->inbuf=NULL;+ihid->cmdbuf=NULL;+ihid->argsbuf=NULL;+ihid->bufsize=0;+}++staticinti2c_hid_alloc_buffers(structi2c_hid*ihid,size_treport_size){/* the worst case is computed from the set_report command with a*reportID>15andthemaximumreportlength*/intargs_len=sizeof(__u8)+/* optional ReportID byte */sizeof(__u16)+/* data register */sizeof(__u16)+/* size of the report */-ihid->bufsize;/* report */--ihid->inbuf=kzalloc(ihid->bufsize,GFP_KERNEL);--if(!ihid->inbuf)-return-ENOMEM;+report_size;/* report */+ihid->inbuf=kzalloc(report_size,GFP_KERNEL);ihid->argsbuf=kzalloc(args_len,GFP_KERNEL);--if(!ihid->argsbuf){-kfree(ihid->inbuf);-return-ENOMEM;-}-ihid->cmdbuf=kzalloc(sizeof(unioncommand)+args_len,GFP_KERNEL);-if(!ihid->cmdbuf){-kfree(ihid->inbuf);-kfree(ihid->argsbuf);-ihid->inbuf=NULL;-ihid->argsbuf=NULL;+if(!ihid->inbuf||!ihid->argsbuf||!ihid->cmdbuf){+i2c_hid_free_buffers(ihid);return-ENOMEM;}-return0;-}+ihid->bufsize=report_size;-staticvoidi2c_hid_free_buffers(structi2c_hid*ihid)-{-kfree(ihid->inbuf);-kfree(ihid->argsbuf);-kfree(ihid->cmdbuf);-ihid->inbuf=NULL;-ihid->cmdbuf=NULL;-ihid->argsbuf=NULL;+return0;}staticinti2c_hid_get_raw_report(structhid_device*hid,
@@ -611,22 +601,19 @@ static int i2c_hid_start(struct hid_device *hid)structi2c_client*client=hid->driver_data;structi2c_hid*ihid=i2c_get_clientdata(client);intret;-intold_bufsize=ihid->bufsize;+unsignedintbufsize=HID_MIN_BUFFER_SIZE;-ihid->bufsize=HID_MIN_BUFFER_SIZE;-i2c_hid_find_max_report(hid,HID_INPUT_REPORT,&ihid->bufsize);-i2c_hid_find_max_report(hid,HID_OUTPUT_REPORT,&ihid->bufsize);-i2c_hid_find_max_report(hid,HID_FEATURE_REPORT,&ihid->bufsize);+i2c_hid_find_max_report(hid,HID_INPUT_REPORT,&bufsize);+i2c_hid_find_max_report(hid,HID_OUTPUT_REPORT,&bufsize);+i2c_hid_find_max_report(hid,HID_FEATURE_REPORT,&bufsize);-if(ihid->bufsize>old_bufsize||!ihid->inbuf||!ihid->cmdbuf){+if(bufsize>ihid->bufsize){i2c_hid_free_buffers(ihid);-ret=i2c_hid_alloc_buffers(ihid);+ret=i2c_hid_alloc_buffers(ihid,bufsize);-if(ret){-ihid->bufsize=old_bufsize;+if(ret)returnret;-}}if(!(hid->quirks&HID_QUIRK_NO_INIT_REPORTS))
@@ -844,8 +831,9 @@ static int __devinit i2c_hid_probe(struct i2c_client *client,/* we need to allocate the command buffer without knowing the maximum*sizeofthereports.Let'suseHID_MIN_BUFFER_SIZE,thenwedothe*realcomputationlater.*/-ihid->bufsize=HID_MIN_BUFFER_SIZE;-i2c_hid_alloc_buffers(ihid);+ret=i2c_hid_alloc_buffers(ihid,HID_MIN_BUFFER_SIZE);+if(ret<0)+gotoerr;ret=i2c_hid_fetch_hid_descriptor(ihid);if(ret<0)
From: Benjamin Tissoires <hidden> Date: 2012-12-04 15:28:42
The previous memcpy implementation relied on the size advertized by the
device. There were no guarantees that buf was big enough.
Some gymnastic is also required with the +2/-2 to take into account
the first 2 bytes where the total length is supplied by the device.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
From: Benjamin Tissoires <hidden> Date: 2012-12-04 15:28:58
In the case where the hid driver in charge of handling the hid part
of the device (hid-generic for instance) fails at probe, neither
i2c_hid_start nor i2c_hid_stop are called.
Thus, the buffers allocated in i2c_hid_probe are never freed.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 3 +++
1 file changed, 3 insertions(+)
From: Benjamin Tissoires <hidden> Date: 2012-12-04 15:29:35
There is no point in keeping the irq in i2c_hid as it's already
there in client.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
@@ -136,8 +136,6 @@ struct i2c_hid {unsignedlongflags;/* device flags */-intirq;/* the interrupt line irq */-wait_queue_head_twait;/* For waiting the interrupt */};
@@ -737,8 +735,6 @@ static int __devinit i2c_hid_init_irq(struct i2c_client *client)returnret;}-ihid->irq=client->irq;-return0;}
@@ -841,12 +837,12 @@ static int __devinit i2c_hid_probe(struct i2c_client *client,ret=i2c_hid_init_irq(client);if(ret<0)-gotoerr;+gotoerr_irq;hid=hid_allocate_device();if(IS_ERR(hid)){ret=PTR_ERR(hid);-gotoerr;+gotoerr_irq;}ihid->hid=hid;
@@ -876,10 +872,10 @@ static int __devinit i2c_hid_probe(struct i2c_client *client,err_mem_free:hid_destroy_device(hid);-err:-if(ihid->irq)-free_irq(ihid->irq,ihid);+err_irq:+free_irq(client->irq,ihid);+err:i2c_hid_free_buffers(ihid);kfree(ihid);returnret;
@@ -904,10 +900,9 @@ static int __devexit i2c_hid_remove(struct i2c_client *client)staticinti2c_hid_suspend(structdevice*dev){structi2c_client*client=to_i2c_client(dev);-structi2c_hid*ihid=i2c_get_clientdata(client);if(device_may_wakeup(&client->dev))-enable_irq_wake(ihid->irq);+enable_irq_wake(client->irq);/* Save some power */i2c_hid_set_power(client,I2C_HID_PWR_SLEEP);
From: Benjamin Tissoires <hidden> Date: 2012-12-04 15:29:37
ihid can not be null, so there are no reasons to test it.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 3 ---
1 file changed, 3 deletions(-)
@@ -741,10 +741,10 @@ static int __devinit i2c_hid_init_irq(struct i2c_client *client)IRQF_TRIGGER_FALLING|IRQF_ONESHOT,client->name,ihid);if(ret<0){-dev_dbg(&client->dev,+dev_warn(&client->dev,"Could not register for %s interrupt, irq = %d,"" ret = %d\n",-client->name,client->irq,ret);+client->name,client->irq,ret);returnret;}
@@ -770,7 +770,8 @@ static int __devinit i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)__func__,4,ihid->hdesc_buffer);if(ret){-dev_err(&client->dev,"HID_DESCR_LENGTH_CMD Fail (ret=%d)\n",+dev_err(&client->dev,+"unable to fetch the size of HID descriptor (ret=%d)\n",ret);return-ENODEV;}
From: Benjamin Tissoires <hidden> Date: 2012-12-04 15:30:38
Forwards appropriate return values.
As noone use the error returned by i2c_hid_get_input, let's make it
returning void.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
@@ -245,7 +245,7 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,if(ret){dev_err(&client->dev,"failed to retrieve report from device.\n");-return-EINVAL;+returnret;}return0;
@@ -290,7 +290,7 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,reportType,args,args_len,NULL,0);if(ret){dev_err(&client->dev,"failed to set a report to device.\n");-return-EINVAL;+returnret;}returndata_len;
@@ -334,7 +334,7 @@ static int i2c_hid_hwreset(struct i2c_client *client)return0;}-staticinti2c_hid_get_input(structi2c_hid*ihid)+staticvoidi2c_hid_get_input(structi2c_hid*ihid){intret,ret_size;intsize=le16_to_cpu(ihid->hdesc.wMaxInputLength);
@@ -342,11 +342,11 @@ static int i2c_hid_get_input(struct i2c_hid *ihid)ret=i2c_master_recv(ihid->client,ihid->inbuf,size);if(ret!=size){if(ret<0)-returnret;+return;dev_err(&ihid->client->dev,"%s: got %d data instead of %d\n",__func__,ret,size);-returnret;+return;}ret_size=ihid->inbuf[0]|ihid->inbuf[1]<<8;
@@ -355,13 +355,13 @@ static int i2c_hid_get_input(struct i2c_hid *ihid)/* host or device initiated RESET completed */if(test_and_clear_bit(I2C_HID_RESET_PENDING,&ihid->flags))wake_up(&ihid->wait);-return0;+return;}if(ret_size>size){dev_err(&ihid->client->dev,"%s: incomplete report (%d/%d)\n",__func__,size,ret_size);-return-EIO;+return;}i2c_hid_dbg(ihid,"input: %*ph\n",ret_size,ihid->inbuf);
@@ -370,7 +370,7 @@ static int i2c_hid_get_input(struct i2c_hid *ihid)hid_input_report(ihid->hid,HID_INPUT_REPORT,ihid->inbuf+2,ret_size-2,1);-return0;+return;}staticirqreturn_ti2c_hid_irq(intirq,void*dev_id)
From: Benjamin Tissoires <hidden> Date: 2012-12-04 15:31:09
The "comment" part can never be displayed, so we can remove it.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/Kconfig | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
@@ -7,15 +7,12 @@ config I2C_HIDdepends onI2C&&INPUTselectHID---help----SayYhereifyouwanttousetheHIDoveri2cprotocol-implementation.+SayYhereifyouuseakeyboard,atouchpad,atouchscreen,orany+otherHIDbaseddeviceswhichisconnectedtoyourcomputerviaI2C.Ifunsure,sayN.Thissupportisalsoavailableasamodule.Ifso,themodulewillbecalledi2c-hid.-comment"Input core support is needed for HID over I2C input layer"-depends onI2C_HID&&INPUT=n-endmenu
From: Benjamin Tissoires <hidden> Date: 2012-12-04 15:31:41
no I2C driver has "i2c" in its name. It makes more sense to call this
i2c driver "hid".
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Benjamin Tissoires <hidden> Date: 2012-12-04 15:33:39
We should not initialize to 0 static declarations.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -46,7 +46,7 @@#define I2C_HID_PWR_SLEEP 0x01/* debug option */-staticbooldebug=false;+staticbooldebug;module_param(debug,bool,0444);MODULE_PARM_DESC(debug,"print a lot of debug information");
From: Benjamin Tissoires <hidden> Date: 2012-12-04 15:34:56
If i2c_hid_get_report fails, exit i2c_hid_init_report.
The printk log is already called by i2c_hid_get_report, so no need
to add some more printks.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
From: Benjamin Tissoires <hidden> Date: 2012-12-04 15:35:26
This avoids the problematic case:
if (condition)
i2c_hid_dbg(ihid, "Blah blah %d\n", i);
else
do_something_very_important();
Which looks correct, however with the previous macro definition,
this expands to the unexpected:
if (condition) {
if (debug) \
dev_printk(KERN_DEBUG, &ihid->client->dev,
"Blah blah %d\n", i);
else
do_something_very_important();
}
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
From: Jean Delvare <hidden> Date: 2012-12-04 16:07:30
On Tue, 4 Dec 2012 16:27:42 +0100, Benjamin Tissoires wrote:
quoted hunk
no I2C driver has "i2c" in its name. It makes more sense to call this
i2c driver "hid".
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Jean Delvare <hidden> Date: 2012-12-04 21:42:17
On Tue, 4 Dec 2012 16:27:43 +0100, Benjamin Tissoires wrote:
quoted hunk
HID descriptors contains 4 bytes of reserved field.
The previous implementation was overriding the next fields in struct i2c_hid.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Jean Delvare <hidden> Date: 2012-12-04 21:43:11
On Tue, 4 Dec 2012 16:27:44 +0100, Benjamin Tissoires wrote:
quoted hunk
The "comment" part can never be displayed, so we can remove it.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/Kconfig | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
@@ -7,15 +7,12 @@ config I2C_HIDdepends onI2C&&INPUTselectHID---help----SayYhereifyouwanttousetheHIDoveri2cprotocol-implementation.+SayYhereifyouuseakeyboard,atouchpad,atouchscreen,orany+otherHIDbaseddeviceswhichisconnectedtoyourcomputerviaI2C.Ifunsure,sayN.Thissupportisalsoavailableasamodule.Ifso,themodulewillbecalledi2c-hid.-comment"Input core support is needed for HID over I2C input layer"-depends onI2C_HID&&INPUT=n-endmenu
Reviewed-by: Jean Delvare <redacted>
--
Jean Delvare
From: Jean Delvare <hidden> Date: 2012-12-04 21:43:59
On Tue, 4 Dec 2012 16:27:45 +0100, Benjamin Tissoires wrote:
quoted hunk
We should not initialize to 0 static declarations.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -46,7 +46,7 @@#define I2C_HID_PWR_SLEEP 0x01/* debug option */-staticbooldebug=false;+staticbooldebug;module_param(debug,bool,0444);MODULE_PARM_DESC(debug,"print a lot of debug information");
Reviewed-by: Jean Delvare <redacted>
--
Jean Delvare
From: Jean Delvare <hidden> Date: 2012-12-04 21:50:00
On Tue, 4 Dec 2012 16:27:46 +0100, Benjamin Tissoires wrote:
quoted hunk
This avoids the problematic case:
if (condition)
i2c_hid_dbg(ihid, "Blah blah %d\n", i);
else
do_something_very_important();
Which looks correct, however with the previous macro definition,
this expands to the unexpected:
if (condition) {
if (debug) \
dev_printk(KERN_DEBUG, &ihid->client->dev,
"Blah blah %d\n", i);
else
do_something_very_important();
}
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
From: Jean Delvare <hidden> Date: 2012-12-04 21:51:42
On Tue, 4 Dec 2012 16:27:47 +0100, Benjamin Tissoires wrote:
quoted hunk
These definitions are not used here, but are defined by the specification.
Keeping some of them for documentation purposes.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 25 ++++++++++---------------
1 file changed, 10 insertions(+), 15 deletions(-)
From: Jean Delvare <hidden> Date: 2012-12-05 09:47:53
On Tue, 4 Dec 2012 16:27:48 +0100, Benjamin Tissoires wrote:
quoted hunk
Forwards appropriate return values.
As noone use the error returned by i2c_hid_get_input, let's make it
returning void.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
@@ -245,7 +245,7 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,if(ret){dev_err(&client->dev,"failed to retrieve report from device.\n");-return-EINVAL;+returnret;}return0;
@@ -290,7 +290,7 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,reportType,args,args_len,NULL,0);if(ret){dev_err(&client->dev,"failed to set a report to device.\n");-return-EINVAL;+returnret;}returndata_len;
@@ -334,7 +334,7 @@ static int i2c_hid_hwreset(struct i2c_client *client)return0;}-staticinti2c_hid_get_input(structi2c_hid*ihid)+staticvoidi2c_hid_get_input(structi2c_hid*ihid){intret,ret_size;intsize=le16_to_cpu(ihid->hdesc.wMaxInputLength);
@@ -342,11 +342,11 @@ static int i2c_hid_get_input(struct i2c_hid *ihid)ret=i2c_master_recv(ihid->client,ihid->inbuf,size);if(ret!=size){if(ret<0)-returnret;+return;dev_err(&ihid->client->dev,"%s: got %d data instead of %d\n",__func__,ret,size);-returnret;+return;}ret_size=ihid->inbuf[0]|ihid->inbuf[1]<<8;
@@ -355,13 +355,13 @@ static int i2c_hid_get_input(struct i2c_hid *ihid)/* host or device initiated RESET completed */if(test_and_clear_bit(I2C_HID_RESET_PENDING,&ihid->flags))wake_up(&ihid->wait);-return0;+return;}if(ret_size>size){dev_err(&ihid->client->dev,"%s: incomplete report (%d/%d)\n",__func__,size,ret_size);-return-EIO;+return;}i2c_hid_dbg(ihid,"input: %*ph\n",ret_size,ihid->inbuf);
@@ -370,7 +370,7 @@ static int i2c_hid_get_input(struct i2c_hid *ihid)hid_input_report(ihid->hid,HID_INPUT_REPORT,ihid->inbuf+2,ret_size-2,1);-return0;+return;}staticirqreturn_ti2c_hid_irq(intirq,void*dev_id)
@@ -741,10 +741,10 @@ static int __devinit i2c_hid_init_irq(struct i2c_client *client)IRQF_TRIGGER_FALLING|IRQF_ONESHOT,client->name,ihid);if(ret<0){-dev_dbg(&client->dev,+dev_warn(&client->dev,"Could not register for %s interrupt, irq = %d,"" ret = %d\n",-client->name,client->irq,ret);+client->name,client->irq,ret);returnret;}
@@ -770,7 +770,8 @@ static int __devinit i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)__func__,4,ihid->hdesc_buffer);if(ret){-dev_err(&client->dev,"HID_DESCR_LENGTH_CMD Fail (ret=%d)\n",+dev_err(&client->dev,+"unable to fetch the size of HID descriptor (ret=%d)\n",ret);return-ENODEV;}
no I2C driver has "i2c" in its name. It makes more sense to call this
i2c driver "hid".
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
The "comment" part can never be displayed, so we can remove it.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/Kconfig | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
@@ -7,15 +7,12 @@ config I2C_HIDdepends onI2C&&INPUTselectHID---help----SayYhereifyouwanttousetheHIDoveri2cprotocol-implementation.+SayYhereifyouuseakeyboard,atouchpad,atouchscreen,orany+otherHIDbaseddeviceswhichisconnectedtoyourcomputerviaI2C.Ifunsure,sayN.Thissupportisalsoavailableasamodule.Ifso,themodulewillbecalledi2c-hid.-comment"Input core support is needed for HID over I2C input layer"-depends onI2C_HID&&INPUT=n-endmenu
We should not initialize to 0 static declarations.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -46,7 +46,7 @@#define I2C_HID_PWR_SLEEP 0x01/* debug option */-staticbooldebug=false;+staticbooldebug;module_param(debug,bool,0444);MODULE_PARM_DESC(debug,"print a lot of debug information");
This avoids the problematic case:
if (condition)
i2c_hid_dbg(ihid, "Blah blah %d\n", i);
else
do_something_very_important();
Which looks correct, however with the previous macro definition,
this expands to the unexpected:
if (condition) {
if (debug) \
dev_printk(KERN_DEBUG, &ihid->client->dev,
"Blah blah %d\n", i);
else
do_something_very_important();
}
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
From: Jean Delvare <hidden> Date: 2012-12-05 09:59:28
On Tue, 4 Dec 2012 16:27:50 +0100, Benjamin Tissoires wrote:
quoted hunk
If i2c_hid_get_report fails, exit i2c_hid_init_report.
The printk log is already called by i2c_hid_get_report, so no need
to add some more printks.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
OK, although I don't quite get the rationale for not reporting the
errors from i2c_hid_init_report() and i2c_hid_init_reports() to their
respective callers. Does the device have any chance to work properly if
i2c_hid_init_reports() fails?
Reviewed-by: Jean Delvare <redacted>
--
Jean Delvare
These definitions are not used here, but are defined by the specification.
Keeping some of them for documentation purposes.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 25 ++++++++++---------------
1 file changed, 10 insertions(+), 15 deletions(-)
Forwards appropriate return values.
As noone use the error returned by i2c_hid_get_input, let's make it
returning void.
Signed-off-by: Benjamin Tissoires <redacted>
@@ -245,7 +245,7 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,if(ret){dev_err(&client->dev,"failed to retrieve report from device.\n");-return-EINVAL;+returnret;}return0;
@@ -290,7 +290,7 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,reportType,args,args_len,NULL,0);if(ret){dev_err(&client->dev,"failed to set a report to device.\n");-return-EINVAL;+returnret;}returndata_len;
@@ -334,7 +334,7 @@ static int i2c_hid_hwreset(struct i2c_client *client)return0;}-staticinti2c_hid_get_input(structi2c_hid*ihid)+staticvoidi2c_hid_get_input(structi2c_hid*ihid){intret,ret_size;intsize=le16_to_cpu(ihid->hdesc.wMaxInputLength);
@@ -342,11 +342,11 @@ static int i2c_hid_get_input(struct i2c_hid *ihid)ret=i2c_master_recv(ihid->client,ihid->inbuf,size);if(ret!=size){if(ret<0)-returnret;+return;dev_err(&ihid->client->dev,"%s: got %d data instead of %d\n",__func__,ret,size);-returnret;+return;}ret_size=ihid->inbuf[0]|ihid->inbuf[1]<<8;
@@ -355,13 +355,13 @@ static int i2c_hid_get_input(struct i2c_hid *ihid)/* host or device initiated RESET completed */if(test_and_clear_bit(I2C_HID_RESET_PENDING,&ihid->flags))wake_up(&ihid->wait);-return0;+return;}if(ret_size>size){dev_err(&ihid->client->dev,"%s: incomplete report (%d/%d)\n",__func__,size,ret_size);-return-EIO;+return;}i2c_hid_dbg(ihid,"input: %*ph\n",ret_size,ihid->inbuf);
@@ -370,7 +370,7 @@ static int i2c_hid_get_input(struct i2c_hid *ihid)hid_input_report(ihid->hid,HID_INPUT_REPORT,ihid->inbuf+2,ret_size-2,1);-return0;+return;}staticirqreturn_ti2c_hid_irq(intirq,void*dev_id)
From: Benjamin Tissoires <hidden> Date: 2012-12-05 10:07:23
On Wed, Dec 5, 2012 at 10:59 AM, Jean Delvare [off-list ref] wrote:
On Tue, 4 Dec 2012 16:27:50 +0100, Benjamin Tissoires wrote:
quoted
If i2c_hid_get_report fails, exit i2c_hid_init_report.
The printk log is already called by i2c_hid_get_report, so no need
to add some more printks.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
OK, although I don't quite get the rationale for not reporting the
errors from i2c_hid_init_report() and i2c_hid_init_reports() to their
respective callers. Does the device have any chance to work properly if
i2c_hid_init_reports() fails?
Hi Jean,
first thanks for the review you have started.
For your question, the answer is yes, the device works properly even
if i2c_hid_init_reports().
IIRC, the only required steps are:
- get HID descriptor
- get HID report descriptors
- send reset
- set power on
i2c_hid_init_reports is not part of the specification for the boot
process, and the Windows driver does not retrieve the reports for
input reports at all (it does it though for the features).
Actually, the device I have does not implement get_report for inputs
(it returns 0), but it's not a problem for it to work.
I put the whole init_reports in place to get the features values
before sending them to the hid driver, and also to copy the behavior
of usbhid.
Cheers,
Benjamin
Reviewed-by: Jean Delvare <redacted>
--
Jean Delvare
@@ -741,10 +741,10 @@ static int __devinit i2c_hid_init_irq(struct i2c_client *client)IRQF_TRIGGER_FALLING|IRQF_ONESHOT,client->name,ihid);if(ret<0){-dev_dbg(&client->dev,+dev_warn(&client->dev,"Could not register for %s interrupt, irq = %d,"" ret = %d\n",-client->name,client->irq,ret);+client->name,client->irq,ret);returnret;}
@@ -770,7 +770,8 @@ static int __devinit i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)__func__,4,ihid->hdesc_buffer);if(ret){-dev_err(&client->dev,"HID_DESCR_LENGTH_CMD Fail (ret=%d)\n",+dev_err(&client->dev,+"unable to fetch the size of HID descriptor (ret=%d)\n",ret);return-ENODEV;}
From: Jean Delvare <hidden> Date: 2012-12-05 10:10:16
On Tue, 4 Dec 2012 16:27:51 +0100, Benjamin Tissoires wrote:
quoted hunk
Simplifies i2c_hid_alloc_buffers tests, and makes this function
responsible of the assignment of ihid->bufsize.
The condition for the reallocation in i2c_hid_start is then simpler.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 68 ++++++++++++++++++-------------------------
1 file changed, 28 insertions(+), 40 deletions(-)
@@ -465,48 +465,38 @@ static void i2c_hid_find_max_report(struct hid_device *hid, unsigned int type,}}-staticinti2c_hid_alloc_buffers(structi2c_hid*ihid)+staticvoidi2c_hid_free_buffers(structi2c_hid*ihid)+{+kfree(ihid->inbuf);+kfree(ihid->argsbuf);+kfree(ihid->cmdbuf);+ihid->inbuf=NULL;+ihid->cmdbuf=NULL;+ihid->argsbuf=NULL;+ihid->bufsize=0;+}++staticinti2c_hid_alloc_buffers(structi2c_hid*ihid,size_treport_size){/* the worst case is computed from the set_report command with a*reportID>15andthemaximumreportlength*/intargs_len=sizeof(__u8)+/* optional ReportID byte */sizeof(__u16)+/* data register */sizeof(__u16)+/* size of the report */-ihid->bufsize;/* report */--ihid->inbuf=kzalloc(ihid->bufsize,GFP_KERNEL);--if(!ihid->inbuf)-return-ENOMEM;+report_size;/* report */+ihid->inbuf=kzalloc(report_size,GFP_KERNEL);ihid->argsbuf=kzalloc(args_len,GFP_KERNEL);--if(!ihid->argsbuf){-kfree(ihid->inbuf);-return-ENOMEM;-}-ihid->cmdbuf=kzalloc(sizeof(unioncommand)+args_len,GFP_KERNEL);-if(!ihid->cmdbuf){-kfree(ihid->inbuf);-kfree(ihid->argsbuf);-ihid->inbuf=NULL;-ihid->argsbuf=NULL;+if(!ihid->inbuf||!ihid->argsbuf||!ihid->cmdbuf){+i2c_hid_free_buffers(ihid);return-ENOMEM;}-return0;-}+ihid->bufsize=report_size;-staticvoidi2c_hid_free_buffers(structi2c_hid*ihid)-{-kfree(ihid->inbuf);-kfree(ihid->argsbuf);-kfree(ihid->cmdbuf);-ihid->inbuf=NULL;-ihid->cmdbuf=NULL;-ihid->argsbuf=NULL;+return0;}staticinti2c_hid_get_raw_report(structhid_device*hid,
@@ -611,22 +601,19 @@ static int i2c_hid_start(struct hid_device *hid)structi2c_client*client=hid->driver_data;structi2c_hid*ihid=i2c_get_clientdata(client);intret;-intold_bufsize=ihid->bufsize;+unsignedintbufsize=HID_MIN_BUFFER_SIZE;-ihid->bufsize=HID_MIN_BUFFER_SIZE;-i2c_hid_find_max_report(hid,HID_INPUT_REPORT,&ihid->bufsize);-i2c_hid_find_max_report(hid,HID_OUTPUT_REPORT,&ihid->bufsize);-i2c_hid_find_max_report(hid,HID_FEATURE_REPORT,&ihid->bufsize);+i2c_hid_find_max_report(hid,HID_INPUT_REPORT,&bufsize);+i2c_hid_find_max_report(hid,HID_OUTPUT_REPORT,&bufsize);+i2c_hid_find_max_report(hid,HID_FEATURE_REPORT,&bufsize);-if(ihid->bufsize>old_bufsize||!ihid->inbuf||!ihid->cmdbuf){+if(bufsize>ihid->bufsize){i2c_hid_free_buffers(ihid);-ret=i2c_hid_alloc_buffers(ihid);+ret=i2c_hid_alloc_buffers(ihid,bufsize);-if(ret){-ihid->bufsize=old_bufsize;+if(ret)returnret;-}}if(!(hid->quirks&HID_QUIRK_NO_INIT_REPORTS))
@@ -844,8 +831,9 @@ static int __devinit i2c_hid_probe(struct i2c_client *client,/* we need to allocate the command buffer without knowing the maximum*sizeofthereports.Let'suseHID_MIN_BUFFER_SIZE,thenwedothe*realcomputationlater.*/-ihid->bufsize=HID_MIN_BUFFER_SIZE;-i2c_hid_alloc_buffers(ihid);+ret=i2c_hid_alloc_buffers(ihid,HID_MIN_BUFFER_SIZE);+if(ret<0)+gotoerr;ret=i2c_hid_fetch_hid_descriptor(ihid);if(ret<0)
Yes, looks much better.
Reviewed-by: Jean Delvare <redacted>
--
Jean Delvare
From: Benjamin Tissoires <hidden> Date: 2012-12-05 10:10:59
On Tue, Dec 4, 2012 at 10:42 PM, Jean Delvare [off-list ref] wrote:
On Tue, 4 Dec 2012 16:27:43 +0100, Benjamin Tissoires wrote:
quoted
HID descriptors contains 4 bytes of reserved field.
The previous implementation was overriding the next fields in struct i2c_hid.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
@@ -778,7 +779,7 @@ static int __devinit i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)}dsize=le16_to_cpu(hdesc->wHIDDescLength);-if(!dsize||dsize>HID_MAX_DESCRIPTOR_SIZE){+if(!dsize||dsize>sizeof(structi2c_hid_desc)){
Shouldn't !dsize rather be dsize < 4? You're reading hdesc->bcdVersion,
which is only defined if dsize >= 4 if I understand the code correctly.
Yes, you are right. Thanks.
Jiri, this patch is a prerequisite for "[PATCH 10/14] HID: i2c-hid:
reorder allocation/free of buffers".
could you please what for a v2 before applying 10/14?
Cheers,
Benjamin
quoted
dev_err(&client->dev, "weird size of HID descriptor (%u)\n",
dsize);
return -ENODEV;
From: Benjamin Tissoires <hidden> Date: 2012-12-05 10:12:46
On Wed, Dec 5, 2012 at 11:10 AM, Jean Delvare [off-list ref] wrote:
On Tue, 4 Dec 2012 16:27:51 +0100, Benjamin Tissoires wrote:
quoted
Simplifies i2c_hid_alloc_buffers tests, and makes this function
responsible of the assignment of ihid->bufsize.
The condition for the reallocation in i2c_hid_start is then simpler.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 68 ++++++++++++++++++-------------------------
1 file changed, 28 insertions(+), 40 deletions(-)
@@ -465,48 +465,38 @@ static void i2c_hid_find_max_report(struct hid_device *hid, unsigned int type,}}-staticinti2c_hid_alloc_buffers(structi2c_hid*ihid)+staticvoidi2c_hid_free_buffers(structi2c_hid*ihid)+{+kfree(ihid->inbuf);+kfree(ihid->argsbuf);+kfree(ihid->cmdbuf);+ihid->inbuf=NULL;+ihid->cmdbuf=NULL;+ihid->argsbuf=NULL;+ihid->bufsize=0;+}++staticinti2c_hid_alloc_buffers(structi2c_hid*ihid,size_treport_size){/* the worst case is computed from the set_report command with a*reportID>15andthemaximumreportlength*/intargs_len=sizeof(__u8)+/* optional ReportID byte */sizeof(__u16)+/* data register */sizeof(__u16)+/* size of the report */-ihid->bufsize;/* report */--ihid->inbuf=kzalloc(ihid->bufsize,GFP_KERNEL);--if(!ihid->inbuf)-return-ENOMEM;+report_size;/* report */+ihid->inbuf=kzalloc(report_size,GFP_KERNEL);ihid->argsbuf=kzalloc(args_len,GFP_KERNEL);--if(!ihid->argsbuf){-kfree(ihid->inbuf);-return-ENOMEM;-}-ihid->cmdbuf=kzalloc(sizeof(unioncommand)+args_len,GFP_KERNEL);-if(!ihid->cmdbuf){-kfree(ihid->inbuf);-kfree(ihid->argsbuf);-ihid->inbuf=NULL;-ihid->argsbuf=NULL;+if(!ihid->inbuf||!ihid->argsbuf||!ihid->cmdbuf){+i2c_hid_free_buffers(ihid);return-ENOMEM;}-return0;-}+ihid->bufsize=report_size;-staticvoidi2c_hid_free_buffers(structi2c_hid*ihid)-{-kfree(ihid->inbuf);-kfree(ihid->argsbuf);-kfree(ihid->cmdbuf);-ihid->inbuf=NULL;-ihid->cmdbuf=NULL;-ihid->argsbuf=NULL;+return0;}staticinti2c_hid_get_raw_report(structhid_device*hid,
@@ -611,22 +601,19 @@ static int i2c_hid_start(struct hid_device *hid)structi2c_client*client=hid->driver_data;structi2c_hid*ihid=i2c_get_clientdata(client);intret;-intold_bufsize=ihid->bufsize;+unsignedintbufsize=HID_MIN_BUFFER_SIZE;-ihid->bufsize=HID_MIN_BUFFER_SIZE;-i2c_hid_find_max_report(hid,HID_INPUT_REPORT,&ihid->bufsize);-i2c_hid_find_max_report(hid,HID_OUTPUT_REPORT,&ihid->bufsize);-i2c_hid_find_max_report(hid,HID_FEATURE_REPORT,&ihid->bufsize);+i2c_hid_find_max_report(hid,HID_INPUT_REPORT,&bufsize);+i2c_hid_find_max_report(hid,HID_OUTPUT_REPORT,&bufsize);+i2c_hid_find_max_report(hid,HID_FEATURE_REPORT,&bufsize);-if(ihid->bufsize>old_bufsize||!ihid->inbuf||!ihid->cmdbuf){+if(bufsize>ihid->bufsize){i2c_hid_free_buffers(ihid);-ret=i2c_hid_alloc_buffers(ihid);+ret=i2c_hid_alloc_buffers(ihid,bufsize);-if(ret){-ihid->bufsize=old_bufsize;+if(ret)returnret;-}}if(!(hid->quirks&HID_QUIRK_NO_INIT_REPORTS))
@@ -844,8 +831,9 @@ static int __devinit i2c_hid_probe(struct i2c_client *client,/* we need to allocate the command buffer without knowing the maximum*sizeofthereports.Let'suseHID_MIN_BUFFER_SIZE,thenwedothe*realcomputationlater.*/-ihid->bufsize=HID_MIN_BUFFER_SIZE;-i2c_hid_alloc_buffers(ihid);+ret=i2c_hid_alloc_buffers(ihid,HID_MIN_BUFFER_SIZE);+if(ret<0)+gotoerr;ret=i2c_hid_fetch_hid_descriptor(ihid);if(ret<0)
Yes, looks much better.
Reviewed-by: Jean Delvare <redacted>
Thanks Jean,
as mentioned in 2/14, this patch need the fix in 2/14 to be able to
work. Jiri, I'll try to send a v2 ASAP so that you can pick both in
the right order (otherwise, the bisect may fall between the two).
Cheers,
Benjamin
On Tue, 4 Dec 2012 16:27:43 +0100, Benjamin Tissoires wrote:
quoted
HID descriptors contains 4 bytes of reserved field.
The previous implementation was overriding the next fields in struct i2c_hid.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
@@ -778,7 +779,7 @@ static int __devinit i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)}dsize=le16_to_cpu(hdesc->wHIDDescLength);-if(!dsize||dsize>HID_MAX_DESCRIPTOR_SIZE){+if(!dsize||dsize>sizeof(structi2c_hid_desc)){
Shouldn't !dsize rather be dsize < 4? You're reading hdesc->bcdVersion,
which is only defined if dsize >= 4 if I understand the code correctly.
Yes, you are right. Thanks.
Jiri, this patch is a prerequisite for "[PATCH 10/14] HID: i2c-hid:
reorder allocation/free of buffers".
could you please what for a v2 before applying 10/14?
Absolutely. I still have to review 9, 10, 11, 12, 13, 14, so am dropping 2
and 10 from my attention for now.
--
Jiri Kosina
SUSE Labs
From: Jean Delvare <hidden> Date: 2012-12-05 10:14:03
On Tue, 4 Dec 2012 16:27:52 +0100, Benjamin Tissoires wrote:
quoted hunk
ihid can not be null, so there are no reasons to test it.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 3 ---
1 file changed, 3 deletions(-)
In the case where the hid driver in charge of handling the hid part
of the device (hid-generic for instance) fails at probe, neither
i2c_hid_start nor i2c_hid_stop are called.
Thus, the buffers allocated in i2c_hid_probe are never freed.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 3 +++
1 file changed, 3 insertions(+)
If i2c_hid_get_report fails, exit i2c_hid_init_report.
The printk log is already called by i2c_hid_get_report, so no need
to add some more printks.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
From: Jean Delvare <hidden> Date: 2012-12-05 10:29:41
On Tue, 4 Dec 2012 16:27:53 +0100, Benjamin Tissoires wrote:
quoted hunk
There is no point in keeping the irq in i2c_hid as it's already
there in client.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
@@ -136,8 +136,6 @@ struct i2c_hid {unsignedlongflags;/* device flags */-intirq;/* the interrupt line irq */-wait_queue_head_twait;/* For waiting the interrupt */};
@@ -737,8 +735,6 @@ static int __devinit i2c_hid_init_irq(struct i2c_client *client)returnret;}-ihid->irq=client->irq;-return0;}
@@ -841,12 +837,12 @@ static int __devinit i2c_hid_probe(struct i2c_client *client,ret=i2c_hid_init_irq(client);if(ret<0)-gotoerr;+gotoerr_irq;
Looks wrong. If i2c_hid_init_irq() failed, the irq couldn't be requested so you don't want to free it.
quoted hunk
hid = hid_allocate_device();
if (IS_ERR(hid)) {
ret = PTR_ERR(hid);
- goto err;
+ goto err_irq;
}
ihid->hid = hid;
ihid can not be null, so there are no reasons to test it.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 3 ---
1 file changed, 3 deletions(-)
From: Jean Delvare <hidden> Date: 2012-12-05 10:32:29
On Tue, 4 Dec 2012 16:27:54 +0100, Benjamin Tissoires wrote:
quoted hunk
In the case where the hid driver in charge of handling the hid part
of the device (hid-generic for instance) fails at probe, neither
i2c_hid_start nor i2c_hid_stop are called.
Thus, the buffers allocated in i2c_hid_probe are never freed.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 3 +++
1 file changed, 3 insertions(+)
From: Benjamin Tissoires <hidden> Date: 2012-12-05 10:40:07
Hi,
sorry, but when I re-read it, it seems that I missed a +2 in the call
of i2c_hid_get_report.
So Jean, Jiri, please ignore this one. I'm really sorry if you already
started reviewing it.
I'll send a v2 with the missing patches early this afternoon.
Cheers,
Benjamin
On Tue, Dec 4, 2012 at 4:27 PM, Benjamin Tissoires
[off-list ref] wrote:
quoted hunk
The previous memcpy implementation relied on the size advertized by the
device. There were no guarantees that buf was big enough.
Some gymnastic is also required with the +2/-2 to take into account
the first 2 bytes where the total length is supplied by the device.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/hid/i2c-hid/i2c-hid.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)