* [PATCH 1/2] em28xx: reduce stack usage in sensor probing functions
@ 2017-02-19 18:29 Frank Schäfer
2017-02-19 18:29 ` [PATCH 2/2] em28xx: simplify ID-reading from Micron sensors Frank Schäfer
0 siblings, 1 reply; 7+ messages in thread
From: Frank Schäfer @ 2017-02-19 18:29 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, arnd, Frank Schäfer
It's no longer necessary to keep the i2c_client in the device struct
unmodified until a sensor is found, so reduce stack usage in
em28xx_probe_sensor_micron() and em28xx_probe_sensor_omnivision() by using
a pointer to the client instead of a local copy.
Reported-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Frank Schäfer <fschaefer.oss@googlemail.com>
---
drivers/media/usb/em28xx/em28xx-camera.c | 42 +++++++++++++++-----------------
1 file changed, 20 insertions(+), 22 deletions(-)
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index 89c890ba7dd6..7b4129ab1cf9 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -110,44 +110,44 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
__be16 id_be;
u16 id;
- struct i2c_client client = dev->i2c_client[dev->def_i2c_bus];
+ struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
dev->em28xx_sensor = EM28XX_NOSENSOR;
for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) {
- client.addr = micron_sensor_addrs[i];
+ client->addr = micron_sensor_addrs[i];
/* NOTE: i2c_smbus_read_word_data() doesn't work with BE data */
/* Read chip ID from register 0x00 */
reg = 0x00;
- ret = i2c_master_send(&client, ®, 1);
+ ret = i2c_master_send(client, ®, 1);
if (ret < 0) {
if (ret != -ENXIO)
dev_err(&dev->intf->dev,
"couldn't read from i2c device 0x%02x: error %i\n",
- client.addr << 1, ret);
+ client->addr << 1, ret);
continue;
}
- ret = i2c_master_recv(&client, (u8 *)&id_be, 2);
+ ret = i2c_master_recv(client, (u8 *)&id_be, 2);
if (ret < 0) {
dev_err(&dev->intf->dev,
"couldn't read from i2c device 0x%02x: error %i\n",
- client.addr << 1, ret);
+ client->addr << 1, ret);
continue;
}
id = be16_to_cpu(id_be);
/* Read chip ID from register 0xff */
reg = 0xff;
- ret = i2c_master_send(&client, ®, 1);
+ ret = i2c_master_send(client, ®, 1);
if (ret < 0) {
dev_err(&dev->intf->dev,
"couldn't read from i2c device 0x%02x: error %i\n",
- client.addr << 1, ret);
+ client->addr << 1, ret);
continue;
}
- ret = i2c_master_recv(&client, (u8 *)&id_be, 2);
+ ret = i2c_master_recv(client, (u8 *)&id_be, 2);
if (ret < 0) {
dev_err(&dev->intf->dev,
"couldn't read from i2c device 0x%02x: error %i\n",
- client.addr << 1, ret);
+ client->addr << 1, ret);
continue;
}
/* Validate chip ID to be sure we have a Micron device */
@@ -197,7 +197,6 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
dev_info(&dev->intf->dev,
"sensor %s detected\n", name);
- dev->i2c_client[dev->def_i2c_bus].addr = client.addr;
return 0;
}
@@ -213,30 +212,30 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev)
char *name;
u8 reg;
u16 id;
- struct i2c_client client = dev->i2c_client[dev->def_i2c_bus];
+ struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
dev->em28xx_sensor = EM28XX_NOSENSOR;
/* NOTE: these devices have the register auto incrementation disabled
* by default, so we have to use single byte reads ! */
for (i = 0; omnivision_sensor_addrs[i] != I2C_CLIENT_END; i++) {
- client.addr = omnivision_sensor_addrs[i];
+ client->addr = omnivision_sensor_addrs[i];
/* Read manufacturer ID from registers 0x1c-0x1d (BE) */
reg = 0x1c;
- ret = i2c_smbus_read_byte_data(&client, reg);
+ ret = i2c_smbus_read_byte_data(client, reg);
if (ret < 0) {
if (ret != -ENXIO)
dev_err(&dev->intf->dev,
"couldn't read from i2c device 0x%02x: error %i\n",
- client.addr << 1, ret);
+ client->addr << 1, ret);
continue;
}
id = ret << 8;
reg = 0x1d;
- ret = i2c_smbus_read_byte_data(&client, reg);
+ ret = i2c_smbus_read_byte_data(client, reg);
if (ret < 0) {
dev_err(&dev->intf->dev,
"couldn't read from i2c device 0x%02x: error %i\n",
- client.addr << 1, ret);
+ client->addr << 1, ret);
continue;
}
id += ret;
@@ -245,20 +244,20 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev)
continue;
/* Read product ID from registers 0x0a-0x0b (BE) */
reg = 0x0a;
- ret = i2c_smbus_read_byte_data(&client, reg);
+ ret = i2c_smbus_read_byte_data(client, reg);
if (ret < 0) {
dev_err(&dev->intf->dev,
"couldn't read from i2c device 0x%02x: error %i\n",
- client.addr << 1, ret);
+ client->addr << 1, ret);
continue;
}
id = ret << 8;
reg = 0x0b;
- ret = i2c_smbus_read_byte_data(&client, reg);
+ ret = i2c_smbus_read_byte_data(client, reg);
if (ret < 0) {
dev_err(&dev->intf->dev,
"couldn't read from i2c device 0x%02x: error %i\n",
- client.addr << 1, ret);
+ client->addr << 1, ret);
continue;
}
id += ret;
@@ -309,7 +308,6 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev)
dev_info(&dev->intf->dev,
"sensor %s detected\n", name);
- dev->i2c_client[dev->def_i2c_bus].addr = client.addr;
return 0;
}
--
2.11.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/2] em28xx: simplify ID-reading from Micron sensors
2017-02-19 18:29 [PATCH 1/2] em28xx: reduce stack usage in sensor probing functions Frank Schäfer
@ 2017-02-19 18:29 ` Frank Schäfer
[not found] ` <20170322114606.1feeb960@vento.lan>
0 siblings, 1 reply; 7+ messages in thread
From: Frank Schäfer @ 2017-02-19 18:29 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, arnd, Frank Schäfer
Use i2c_smbus_read_word_data() instead of i2c_master_send() and
i2c_master_recv() for reading the ID of Micorn sensors.
Bytes need to be swapped afterwards, because i2c_smbus_read_word_data()
assumes that the received bytes are little-endian byte order (as specified
by smbus), while Micron sensors with 16 bit register width use big endian
byte order.
Signed-off-by: Frank Schäfer <fschaefer.oss@googlemail.com>
---
drivers/media/usb/em28xx/em28xx-camera.c | 28 ++++------------------------
1 file changed, 4 insertions(+), 24 deletions(-)
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index 7b4129ab1cf9..4839479624e7 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -106,8 +106,6 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
{
int ret, i;
char *name;
- u8 reg;
- __be16 id_be;
u16 id;
struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
@@ -115,10 +113,8 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
dev->em28xx_sensor = EM28XX_NOSENSOR;
for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) {
client->addr = micron_sensor_addrs[i];
- /* NOTE: i2c_smbus_read_word_data() doesn't work with BE data */
/* Read chip ID from register 0x00 */
- reg = 0x00;
- ret = i2c_master_send(client, ®, 1);
+ ret = i2c_smbus_read_word_data(client, 0x00); /* assumes LE */
if (ret < 0) {
if (ret != -ENXIO)
dev_err(&dev->intf->dev,
@@ -126,24 +122,9 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
client->addr << 1, ret);
continue;
}
- ret = i2c_master_recv(client, (u8 *)&id_be, 2);
- if (ret < 0) {
- dev_err(&dev->intf->dev,
- "couldn't read from i2c device 0x%02x: error %i\n",
- client->addr << 1, ret);
- continue;
- }
- id = be16_to_cpu(id_be);
+ id = swab16(ret); /* LE -> BE */
/* Read chip ID from register 0xff */
- reg = 0xff;
- ret = i2c_master_send(client, ®, 1);
- if (ret < 0) {
- dev_err(&dev->intf->dev,
- "couldn't read from i2c device 0x%02x: error %i\n",
- client->addr << 1, ret);
- continue;
- }
- ret = i2c_master_recv(client, (u8 *)&id_be, 2);
+ ret = i2c_smbus_read_word_data(client, 0xff);
if (ret < 0) {
dev_err(&dev->intf->dev,
"couldn't read from i2c device 0x%02x: error %i\n",
@@ -151,10 +132,9 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
continue;
}
/* Validate chip ID to be sure we have a Micron device */
- if (id != be16_to_cpu(id_be))
+ if (id != swab16(ret))
continue;
/* Check chip ID */
- id = be16_to_cpu(id_be);
switch (id) {
case 0x1222:
name = "MT9V012"; /* MI370 */ /* 640x480 */
--
2.11.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] em28xx: simplify ID-reading from Micron sensors
[not found] ` <20170323095612.72216892@vento.lan>
@ 2017-03-23 18:03 ` Frank Schäfer
2017-03-24 19:16 ` Mauro Carvalho Chehab
0 siblings, 1 reply; 7+ messages in thread
From: Frank Schäfer @ 2017-03-23 18:03 UTC (permalink / raw)
To: Mauro Carvalho Chehab; +Cc: linux-media, mchehab, arnd
Am 23.03.2017 um 13:56 schrieb Mauro Carvalho Chehab:
> Em Thu, 23 Mar 2017 13:01:32 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> Am 22.03.2017 um 15:46 schrieb Mauro Carvalho Chehab:
>>> Em Sun, 19 Feb 2017 19:29:18 +0100
>>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>>>
>>>> Use i2c_smbus_read_word_data() instead of i2c_master_send() and
>>>> i2c_master_recv() for reading the ID of Micorn sensors.
>>>> Bytes need to be swapped afterwards, because i2c_smbus_read_word_data()
>>>> assumes that the received bytes are little-endian byte order (as specified
>>>> by smbus), while Micron sensors with 16 bit register width use big endian
>>>> byte order.
>>>>
>>>> Signed-off-by: Frank Schäfer <fschaefer.oss@googlemail.com>
>>>> ---
>>>> drivers/media/usb/em28xx/em28xx-camera.c | 28 ++++------------------------
>>>> 1 file changed, 4 insertions(+), 24 deletions(-)
>>>>
>>>> diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
>>>> index 7b4129ab1cf9..4839479624e7 100644
>>>> --- a/drivers/media/usb/em28xx/em28xx-camera.c
>>>> +++ b/drivers/media/usb/em28xx/em28xx-camera.c
>>>> @@ -106,8 +106,6 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
>>>> {
>>>> int ret, i;
>>>> char *name;
>>>> - u8 reg;
>>>> - __be16 id_be;
>>>> u16 id;
>>>>
>>>> struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
>>>> @@ -115,10 +113,8 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
>>>> dev->em28xx_sensor = EM28XX_NOSENSOR;
>>>> for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) {
>>>> client->addr = micron_sensor_addrs[i];
>>>> - /* NOTE: i2c_smbus_read_word_data() doesn't work with BE data */
>>>> /* Read chip ID from register 0x00 */
>>>> - reg = 0x00;
>>>> - ret = i2c_master_send(client, ®, 1);
>>>> + ret = i2c_smbus_read_word_data(client, 0x00); /* assumes LE */
>>>> if (ret < 0) {
>>>> if (ret != -ENXIO)
>>>> dev_err(&dev->intf->dev,
>>>> @@ -126,24 +122,9 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
>>>> client->addr << 1, ret);
>>>> continue;
>>>> }
>>>> - ret = i2c_master_recv(client, (u8 *)&id_be, 2);
>>>> - if (ret < 0) {
>>>> - dev_err(&dev->intf->dev,
>>>> - "couldn't read from i2c device 0x%02x: error %i\n",
>>>> - client->addr << 1, ret);
>>>> - continue;
>>>> - }
>>>> - id = be16_to_cpu(id_be);
>>>> + id = swab16(ret); /* LE -> BE */
>>> That's wrong! You can't assume that CPU is BE, as some archs use LE.
>>>
>>> You should, instead, call le16_to_cpu(), to be sure that it will be
>>> doing the right thing.
>>>
>>> Something like:
>>>
>>> id = le16_to_cpu((__le16)ret);
>> SMBus read/write word transfers are always LE (see SMBus spec section
>> 6.5.5),
>> which is also what i2c_smbus_xfer_emulated() assumes:
>> http://lxr.free-electrons.com/source/drivers/i2c/i2c-core.c#L3485
> I got that part, but, if the CPU is also LE, doing swab16() is
> wrong. It should swap it *only* if the CPU is BE.
No, it should always be swapped, because the bytes are always transfered
in the wrong order.
The cpu endianess doesn't matter, (0x12 << 8) | 0x34 is always 0x1234.
Regards,
Frank
> le16_to_cpu() should do the right thing, e. g. swap for BE
> CPUs or not swap otherwise.
>
> Thanks,
> Mauro
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] em28xx: simplify ID-reading from Micron sensors
2017-03-23 18:03 ` Frank Schäfer
@ 2017-03-24 19:16 ` Mauro Carvalho Chehab
2017-03-26 14:24 ` Frank Schäfer
0 siblings, 1 reply; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2017-03-24 19:16 UTC (permalink / raw)
To: Frank Schäfer; +Cc: linux-media, mchehab, arnd
Em Thu, 23 Mar 2017 19:03:20 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> Am 23.03.2017 um 13:56 schrieb Mauro Carvalho Chehab:
> > Em Thu, 23 Mar 2017 13:01:32 +0100
> > Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> >
> >> Am 22.03.2017 um 15:46 schrieb Mauro Carvalho Chehab:
> >>> Em Sun, 19 Feb 2017 19:29:18 +0100
> >>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> >>>
> >>>> Use i2c_smbus_read_word_data() instead of i2c_master_send() and
> >>>> i2c_master_recv() for reading the ID of Micorn sensors.
> >>>> Bytes need to be swapped afterwards, because i2c_smbus_read_word_data()
> >>>> assumes that the received bytes are little-endian byte order (as specified
> >>>> by smbus), while Micron sensors with 16 bit register width use big endian
> >>>> byte order.
> >>>>
> >>>> Signed-off-by: Frank Schäfer <fschaefer.oss@googlemail.com>
> >>>> ---
> >>>> drivers/media/usb/em28xx/em28xx-camera.c | 28 ++++------------------------
> >>>> 1 file changed, 4 insertions(+), 24 deletions(-)
> >>>>
> >>>> diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
> >>>> index 7b4129ab1cf9..4839479624e7 100644
> >>>> --- a/drivers/media/usb/em28xx/em28xx-camera.c
> >>>> +++ b/drivers/media/usb/em28xx/em28xx-camera.c
> >>>> @@ -106,8 +106,6 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
> >>>> {
> >>>> int ret, i;
> >>>> char *name;
> >>>> - u8 reg;
> >>>> - __be16 id_be;
> >>>> u16 id;
> >>>>
> >>>> struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
> >>>> @@ -115,10 +113,8 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
> >>>> dev->em28xx_sensor = EM28XX_NOSENSOR;
> >>>> for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) {
> >>>> client->addr = micron_sensor_addrs[i];
> >>>> - /* NOTE: i2c_smbus_read_word_data() doesn't work with BE data */
> >>>> /* Read chip ID from register 0x00 */
> >>>> - reg = 0x00;
> >>>> - ret = i2c_master_send(client, ®, 1);
> >>>> + ret = i2c_smbus_read_word_data(client, 0x00); /* assumes LE */
> >>>> if (ret < 0) {
> >>>> if (ret != -ENXIO)
> >>>> dev_err(&dev->intf->dev,
> >>>> @@ -126,24 +122,9 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
> >>>> client->addr << 1, ret);
> >>>> continue;
> >>>> }
> >>>> - ret = i2c_master_recv(client, (u8 *)&id_be, 2);
> >>>> - if (ret < 0) {
> >>>> - dev_err(&dev->intf->dev,
> >>>> - "couldn't read from i2c device 0x%02x: error %i\n",
> >>>> - client->addr << 1, ret);
> >>>> - continue;
> >>>> - }
> >>>> - id = be16_to_cpu(id_be);
> >>>> + id = swab16(ret); /* LE -> BE */
> >>> That's wrong! You can't assume that CPU is BE, as some archs use LE.
> >>>
> >>> You should, instead, call le16_to_cpu(), to be sure that it will be
> >>> doing the right thing.
> >>>
> >>> Something like:
> >>>
> >>> id = le16_to_cpu((__le16)ret);
> >> SMBus read/write word transfers are always LE (see SMBus spec section
> >> 6.5.5),
> >> which is also what i2c_smbus_xfer_emulated() assumes:
> >> http://lxr.free-electrons.com/source/drivers/i2c/i2c-core.c#L3485
> > I got that part, but, if the CPU is also LE, doing swab16() is
> > wrong. It should swap it *only* if the CPU is BE.
> No, it should always be swapped, because the bytes are always transfered
> in the wrong order.
> The cpu endianess doesn't matter, (0x12 << 8) | 0x34 is always 0x1234.
You still didn't get it.
Let's assume that the ID is 0x148c (MT9M112).
This value, represented in low endian, is stored in memory as:
unsigned char __id[2] = { 0x8c, 0x14 };
If we do:
u16 ret = *(u16 *)__id;
What's stored at "ret" will depend if the sistem is LE or BE:
on LE, ret == 0x148c
on BE, ret == 0x8c14
If you do:
u16 id = swapb16(val)
you'll get:
on LE, id == 0x8c14
on BE, id == 0x148c
So, the value will be *wrong* at LE.
However, if you do:
id = le16_to_cpu((__le16)ret);
On LE, this will evaluate to id = ret, and on BE, to id = swab16(ret).
So, on both, you'll have:
id = 0x148c.
Thanks,
Mauro
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] em28xx: simplify ID-reading from Micron sensors
2017-03-24 19:16 ` Mauro Carvalho Chehab
@ 2017-03-26 14:24 ` Frank Schäfer
2017-04-10 18:06 ` Frank Schäfer
0 siblings, 1 reply; 7+ messages in thread
From: Frank Schäfer @ 2017-03-26 14:24 UTC (permalink / raw)
To: Mauro Carvalho Chehab; +Cc: linux-media, mchehab, arnd
Am 24.03.2017 um 20:16 schrieb Mauro Carvalho Chehab:
> Em Thu, 23 Mar 2017 19:03:20 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> Am 23.03.2017 um 13:56 schrieb Mauro Carvalho Chehab:
>>> Em Thu, 23 Mar 2017 13:01:32 +0100
>>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>>>
>>>> Am 22.03.2017 um 15:46 schrieb Mauro Carvalho Chehab:
>>>>> Em Sun, 19 Feb 2017 19:29:18 +0100
>>>>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>>>>>
>>>>>> Use i2c_smbus_read_word_data() instead of i2c_master_send() and
>>>>>> i2c_master_recv() for reading the ID of Micorn sensors.
>>>>>> Bytes need to be swapped afterwards, because i2c_smbus_read_word_data()
>>>>>> assumes that the received bytes are little-endian byte order (as specified
>>>>>> by smbus), while Micron sensors with 16 bit register width use big endian
>>>>>> byte order.
>>>>>>
>>>>>> Signed-off-by: Frank Schäfer <fschaefer.oss@googlemail.com>
>>>>>> ---
>>>>>> drivers/media/usb/em28xx/em28xx-camera.c | 28 ++++------------------------
>>>>>> 1 file changed, 4 insertions(+), 24 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
>>>>>> index 7b4129ab1cf9..4839479624e7 100644
>>>>>> --- a/drivers/media/usb/em28xx/em28xx-camera.c
>>>>>> +++ b/drivers/media/usb/em28xx/em28xx-camera.c
>>>>>> @@ -106,8 +106,6 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
>>>>>> {
>>>>>> int ret, i;
>>>>>> char *name;
>>>>>> - u8 reg;
>>>>>> - __be16 id_be;
>>>>>> u16 id;
>>>>>>
>>>>>> struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
>>>>>> @@ -115,10 +113,8 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
>>>>>> dev->em28xx_sensor = EM28XX_NOSENSOR;
>>>>>> for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) {
>>>>>> client->addr = micron_sensor_addrs[i];
>>>>>> - /* NOTE: i2c_smbus_read_word_data() doesn't work with BE data */
>>>>>> /* Read chip ID from register 0x00 */
>>>>>> - reg = 0x00;
>>>>>> - ret = i2c_master_send(client, ®, 1);
>>>>>> + ret = i2c_smbus_read_word_data(client, 0x00); /* assumes LE */
>>>>>> if (ret < 0) {
>>>>>> if (ret != -ENXIO)
>>>>>> dev_err(&dev->intf->dev,
>>>>>> @@ -126,24 +122,9 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
>>>>>> client->addr << 1, ret);
>>>>>> continue;
>>>>>> }
>>>>>> - ret = i2c_master_recv(client, (u8 *)&id_be, 2);
>>>>>> - if (ret < 0) {
>>>>>> - dev_err(&dev->intf->dev,
>>>>>> - "couldn't read from i2c device 0x%02x: error %i\n",
>>>>>> - client->addr << 1, ret);
>>>>>> - continue;
>>>>>> - }
>>>>>> - id = be16_to_cpu(id_be);
>>>>>> + id = swab16(ret); /* LE -> BE */
>>>>> That's wrong! You can't assume that CPU is BE, as some archs use LE.
>>>>>
>>>>> You should, instead, call le16_to_cpu(), to be sure that it will be
>>>>> doing the right thing.
>>>>>
>>>>> Something like:
>>>>>
>>>>> id = le16_to_cpu((__le16)ret);
>>>> SMBus read/write word transfers are always LE (see SMBus spec section
>>>> 6.5.5),
>>>> which is also what i2c_smbus_xfer_emulated() assumes:
>>>> http://lxr.free-electrons.com/source/drivers/i2c/i2c-core.c#L3485
>>> I got that part, but, if the CPU is also LE, doing swab16() is
>>> wrong. It should swap it *only* if the CPU is BE.
>> No, it should always be swapped, because the bytes are always transfered
>> in the wrong order.
>> The cpu endianess doesn't matter, (0x12 << 8) | 0x34 is always 0x1234.
> You still didn't get it.
>
> Let's assume that the ID is 0x148c (MT9M112).
>
> This value, represented in low endian, is stored in memory as:
>
> unsigned char __id[2] = { 0x8c, 0x14 };
>
> If we do:
> u16 ret = *(u16 *)__id;
>
> What's stored at "ret" will depend if the sistem is LE or BE:
>
> on LE, ret == 0x148c
> on BE, ret == 0x8c14
>
> If you do:
> u16 id = swapb16(val)
>
> you'll get:
>
> on LE, id == 0x8c14
> on BE, id == 0x148c
>
> So, the value will be *wrong* at LE.
>
> However, if you do:
> id = le16_to_cpu((__le16)ret);
>
> On LE, this will evaluate to id = ret, and on BE, to id = swab16(ret).
> So, on both, you'll have:
> id = 0x148c.
Can you please show me the code line(s) that make the value of the word
returned by i2c_smbus_read_word_data() cpu endianess dependent ? :)
Cheers,
Frank
>
>
> Thanks,
> Mauro
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] em28xx: simplify ID-reading from Micron sensors
2017-03-26 14:24 ` Frank Schäfer
@ 2017-04-10 18:06 ` Frank Schäfer
2017-04-15 13:03 ` Mauro Carvalho Chehab
0 siblings, 1 reply; 7+ messages in thread
From: Frank Schäfer @ 2017-04-10 18:06 UTC (permalink / raw)
To: Mauro Carvalho Chehab; +Cc: linux-media, mchehab, arnd
Am 26.03.2017 um 16:24 schrieb Frank Schäfer:
>
>
> Am 24.03.2017 um 20:16 schrieb Mauro Carvalho Chehab:
>> Em Thu, 23 Mar 2017 19:03:20 +0100
>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>>
>>> Am 23.03.2017 um 13:56 schrieb Mauro Carvalho Chehab:
>>>> Em Thu, 23 Mar 2017 13:01:32 +0100
>>>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>>>>
>>>>> Am 22.03.2017 um 15:46 schrieb Mauro Carvalho Chehab:
>>>>>> Em Sun, 19 Feb 2017 19:29:18 +0100
>>>>>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>>>>>>
>>>>>>> Use i2c_smbus_read_word_data() instead of i2c_master_send() and
>>>>>>> i2c_master_recv() for reading the ID of Micorn sensors.
>>>>>>> Bytes need to be swapped afterwards, because
>>>>>>> i2c_smbus_read_word_data()
>>>>>>> assumes that the received bytes are little-endian byte order (as
>>>>>>> specified
>>>>>>> by smbus), while Micron sensors with 16 bit register width use
>>>>>>> big endian
>>>>>>> byte order.
>>>>>>>
>>>>>>> Signed-off-by: Frank Schäfer <fschaefer.oss@googlemail.com>
>>>>>>> ---
>>>>>>> drivers/media/usb/em28xx/em28xx-camera.c | 28
>>>>>>> ++++------------------------
>>>>>>> 1 file changed, 4 insertions(+), 24 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/media/usb/em28xx/em28xx-camera.c
>>>>>>> b/drivers/media/usb/em28xx/em28xx-camera.c
>>>>>>> index 7b4129ab1cf9..4839479624e7 100644
>>>>>>> --- a/drivers/media/usb/em28xx/em28xx-camera.c
>>>>>>> +++ b/drivers/media/usb/em28xx/em28xx-camera.c
>>>>>>> @@ -106,8 +106,6 @@ static int em28xx_probe_sensor_micron(struct
>>>>>>> em28xx *dev)
>>>>>>> {
>>>>>>> int ret, i;
>>>>>>> char *name;
>>>>>>> - u8 reg;
>>>>>>> - __be16 id_be;
>>>>>>> u16 id;
>>>>>>> struct i2c_client *client =
>>>>>>> &dev->i2c_client[dev->def_i2c_bus];
>>>>>>> @@ -115,10 +113,8 @@ static int
>>>>>>> em28xx_probe_sensor_micron(struct em28xx *dev)
>>>>>>> dev->em28xx_sensor = EM28XX_NOSENSOR;
>>>>>>> for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END;
>>>>>>> i++) {
>>>>>>> client->addr = micron_sensor_addrs[i];
>>>>>>> - /* NOTE: i2c_smbus_read_word_data() doesn't work with
>>>>>>> BE data */
>>>>>>> /* Read chip ID from register 0x00 */
>>>>>>> - reg = 0x00;
>>>>>>> - ret = i2c_master_send(client, ®, 1);
>>>>>>> + ret = i2c_smbus_read_word_data(client, 0x00); /*
>>>>>>> assumes LE */
>>>>>>> if (ret < 0) {
>>>>>>> if (ret != -ENXIO)
>>>>>>> dev_err(&dev->intf->dev,
>>>>>>> @@ -126,24 +122,9 @@ static int
>>>>>>> em28xx_probe_sensor_micron(struct em28xx *dev)
>>>>>>> client->addr << 1, ret);
>>>>>>> continue;
>>>>>>> }
>>>>>>> - ret = i2c_master_recv(client, (u8 *)&id_be, 2);
>>>>>>> - if (ret < 0) {
>>>>>>> - dev_err(&dev->intf->dev,
>>>>>>> - "couldn't read from i2c device 0x%02x: error
>>>>>>> %i\n",
>>>>>>> - client->addr << 1, ret);
>>>>>>> - continue;
>>>>>>> - }
>>>>>>> - id = be16_to_cpu(id_be);
>>>>>>> + id = swab16(ret); /* LE -> BE */
>>>>>> That's wrong! You can't assume that CPU is BE, as some archs use LE.
>>>>>>
>>>>>> You should, instead, call le16_to_cpu(), to be sure that it will be
>>>>>> doing the right thing.
>>>>>>
>>>>>> Something like:
>>>>>>
>>>>>> id = le16_to_cpu((__le16)ret);
>>>>> SMBus read/write word transfers are always LE (see SMBus spec section
>>>>> 6.5.5),
>>>>> which is also what i2c_smbus_xfer_emulated() assumes:
>>>>> http://lxr.free-electrons.com/source/drivers/i2c/i2c-core.c#L3485
>>>> I got that part, but, if the CPU is also LE, doing swab16() is
>>>> wrong. It should swap it *only* if the CPU is BE.
>>> No, it should always be swapped, because the bytes are always
>>> transfered
>>> in the wrong order.
>>> The cpu endianess doesn't matter, (0x12 << 8) | 0x34 is always 0x1234.
>> You still didn't get it.
>>
>> Let's assume that the ID is 0x148c (MT9M112).
>>
>> This value, represented in low endian, is stored in memory as:
>>
>> unsigned char __id[2] = { 0x8c, 0x14 };
>>
>> If we do:
>> u16 ret = *(u16 *)__id;
>>
>> What's stored at "ret" will depend if the sistem is LE or BE:
>>
>> on LE, ret == 0x148c
>> on BE, ret == 0x8c14
>>
>> If you do:
>> u16 id = swapb16(val)
>>
>> you'll get:
>>
>> on LE, id == 0x8c14
>> on BE, id == 0x148c
>>
>> So, the value will be *wrong* at LE.
>>
>> However, if you do:
>> id = le16_to_cpu((__le16)ret);
>>
>> On LE, this will evaluate to id = ret, and on BE, to id = swab16(ret).
>> So, on both, you'll have:
>> id = 0x148c.
>
> Can you please show me the code line(s) that make the value of the
> word returned by i2c_smbus_read_word_data() cpu endianess dependent ? :)
>
Ping !?
Cheers,
Frank
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] em28xx: simplify ID-reading from Micron sensors
2017-04-10 18:06 ` Frank Schäfer
@ 2017-04-15 13:03 ` Mauro Carvalho Chehab
0 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2017-04-15 13:03 UTC (permalink / raw)
To: Frank Schäfer; +Cc: linux-media, mchehab, arnd
Em Mon, 10 Apr 2017 20:06:03 +0200
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> Am 26.03.2017 um 16:24 schrieb Frank Schäfer:
> >
> >
> > Am 24.03.2017 um 20:16 schrieb Mauro Carvalho Chehab:
> >> Em Thu, 23 Mar 2017 19:03:20 +0100
> >> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> >>
> >>> Am 23.03.2017 um 13:56 schrieb Mauro Carvalho Chehab:
> >>>> Em Thu, 23 Mar 2017 13:01:32 +0100
> >>>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> >>>>
> >>>>> Am 22.03.2017 um 15:46 schrieb Mauro Carvalho Chehab:
> >>>>>> Em Sun, 19 Feb 2017 19:29:18 +0100
> >>>>>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> >>>>>>
> >>>>>>> Use i2c_smbus_read_word_data() instead of i2c_master_send() and
> >>>>>>> i2c_master_recv() for reading the ID of Micorn sensors.
> >>>>>>> Bytes need to be swapped afterwards, because
> >>>>>>> i2c_smbus_read_word_data()
> >>>>>>> assumes that the received bytes are little-endian byte order (as
> >>>>>>> specified
> >>>>>>> by smbus), while Micron sensors with 16 bit register width use
> >>>>>>> big endian
> >>>>>>> byte order.
> >>>>>>>
> >>>>>>> Signed-off-by: Frank Schäfer <fschaefer.oss@googlemail.com>
> >>>>>>> ---
> >>>>>>> drivers/media/usb/em28xx/em28xx-camera.c | 28
> >>>>>>> ++++------------------------
> >>>>>>> 1 file changed, 4 insertions(+), 24 deletions(-)
> >>>>>>>
> >>>>>>> diff --git a/drivers/media/usb/em28xx/em28xx-camera.c
> >>>>>>> b/drivers/media/usb/em28xx/em28xx-camera.c
> >>>>>>> index 7b4129ab1cf9..4839479624e7 100644
> >>>>>>> --- a/drivers/media/usb/em28xx/em28xx-camera.c
> >>>>>>> +++ b/drivers/media/usb/em28xx/em28xx-camera.c
> >>>>>>> @@ -106,8 +106,6 @@ static int em28xx_probe_sensor_micron(struct
> >>>>>>> em28xx *dev)
> >>>>>>> {
> >>>>>>> int ret, i;
> >>>>>>> char *name;
> >>>>>>> - u8 reg;
> >>>>>>> - __be16 id_be;
> >>>>>>> u16 id;
> >>>>>>> struct i2c_client *client =
> >>>>>>> &dev->i2c_client[dev->def_i2c_bus];
> >>>>>>> @@ -115,10 +113,8 @@ static int
> >>>>>>> em28xx_probe_sensor_micron(struct em28xx *dev)
> >>>>>>> dev->em28xx_sensor = EM28XX_NOSENSOR;
> >>>>>>> for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END;
> >>>>>>> i++) {
> >>>>>>> client->addr = micron_sensor_addrs[i];
> >>>>>>> - /* NOTE: i2c_smbus_read_word_data() doesn't work with
> >>>>>>> BE data */
> >>>>>>> /* Read chip ID from register 0x00 */
> >>>>>>> - reg = 0x00;
> >>>>>>> - ret = i2c_master_send(client, ®, 1);
> >>>>>>> + ret = i2c_smbus_read_word_data(client, 0x00); /*
> >>>>>>> assumes LE */
> >>>>>>> if (ret < 0) {
> >>>>>>> if (ret != -ENXIO)
> >>>>>>> dev_err(&dev->intf->dev,
> >>>>>>> @@ -126,24 +122,9 @@ static int
> >>>>>>> em28xx_probe_sensor_micron(struct em28xx *dev)
> >>>>>>> client->addr << 1, ret);
> >>>>>>> continue;
> >>>>>>> }
> >>>>>>> - ret = i2c_master_recv(client, (u8 *)&id_be, 2);
> >>>>>>> - if (ret < 0) {
> >>>>>>> - dev_err(&dev->intf->dev,
> >>>>>>> - "couldn't read from i2c device 0x%02x: error
> >>>>>>> %i\n",
> >>>>>>> - client->addr << 1, ret);
> >>>>>>> - continue;
> >>>>>>> - }
> >>>>>>> - id = be16_to_cpu(id_be);
> >>>>>>> + id = swab16(ret); /* LE -> BE */
> >>>>>> That's wrong! You can't assume that CPU is BE, as some archs use LE.
> >>>>>>
> >>>>>> You should, instead, call le16_to_cpu(), to be sure that it will be
> >>>>>> doing the right thing.
> >>>>>>
> >>>>>> Something like:
> >>>>>>
> >>>>>> id = le16_to_cpu((__le16)ret);
> >>>>> SMBus read/write word transfers are always LE (see SMBus spec section
> >>>>> 6.5.5),
> >>>>> which is also what i2c_smbus_xfer_emulated() assumes:
> >>>>> http://lxr.free-electrons.com/source/drivers/i2c/i2c-core.c#L3485
> >>>> I got that part, but, if the CPU is also LE, doing swab16() is
> >>>> wrong. It should swap it *only* if the CPU is BE.
> >>> No, it should always be swapped, because the bytes are always
> >>> transfered
> >>> in the wrong order.
> >>> The cpu endianess doesn't matter, (0x12 << 8) | 0x34 is always 0x1234.
> >> You still didn't get it.
> >>
> >> Let's assume that the ID is 0x148c (MT9M112).
> >>
> >> This value, represented in low endian, is stored in memory as:
> >>
> >> unsigned char __id[2] = { 0x8c, 0x14 };
> >>
> >> If we do:
> >> u16 ret = *(u16 *)__id;
> >>
> >> What's stored at "ret" will depend if the sistem is LE or BE:
> >>
> >> on LE, ret == 0x148c
> >> on BE, ret == 0x8c14
> >>
> >> If you do:
> >> u16 id = swapb16(val)
> >>
> >> you'll get:
> >>
> >> on LE, id == 0x8c14
> >> on BE, id == 0x148c
> >>
> >> So, the value will be *wrong* at LE.
> >>
> >> However, if you do:
> >> id = le16_to_cpu((__le16)ret);
> >>
> >> On LE, this will evaluate to id = ret, and on BE, to id = swab16(ret).
> >> So, on both, you'll have:
> >> id = 0x148c.
> >
> > Can you please show me the code line(s) that make the value of the
> > word returned by i2c_smbus_read_word_data() cpu endianess dependent ? :)
> >
> Ping !?
Just found time today to read the code implementation for
i2c_smbus_read_word_data().
i2c_smbus_read_word_data() indeed does:
case I2C_SMBUS_WORD_DATA:
case I2C_SMBUS_PROC_CALL:
data->word = msgbuf1[0] | (msgbuf1[1] << 8);
So, it indeed stores data correctly, no matter the CPU endiannes.
So, the patch itself looks correct, but I found the description
misleading.
I would describe it as:
Use i2c_smbus_read_word_data() instead of i2c_master_send() and
i2c_master_recv() for reading the ID of Micorn sensors.
i2c_smbus_read_word_data() assumes that byes are in little-endian,
so, it uses:
data->word = msgbuf1[0] | (msgbuf1[1] << 8);
However, Micron datasheet describes the ID as if they were read
in big-endian. So, we need to change the byte order in order to
match the ID number as described on their datasheets.
With changing the description to something like that:
Acked-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Thanks,
Mauro
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2017-04-15 13:03 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-19 18:29 [PATCH 1/2] em28xx: reduce stack usage in sensor probing functions Frank Schäfer
2017-02-19 18:29 ` [PATCH 2/2] em28xx: simplify ID-reading from Micron sensors Frank Schäfer
[not found] ` <20170322114606.1feeb960@vento.lan>
[not found] ` <5107179d-74fd-3b98-5fc6-ba7051927ae2@googlemail.com>
[not found] ` <20170323095612.72216892@vento.lan>
2017-03-23 18:03 ` Frank Schäfer
2017-03-24 19:16 ` Mauro Carvalho Chehab
2017-03-26 14:24 ` Frank Schäfer
2017-04-10 18:06 ` Frank Schäfer
2017-04-15 13:03 ` Mauro Carvalho Chehab
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.