Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

media: dw2102: Don't translate i2c read into write

The code ignored the I2C_M_RD flag on I2C messages. Instead it assumed
an i2c transaction with a single message must be a write operation and a
transaction with two messages would be a read operation.

Though this works for the driver code, it leads to problems once the i2c
device is exposed to code not knowing this convention. For example,
I did "insmod i2c-dev" and issued read requests from userspace, which
were translated into write requests and destroyed the EEPROM of my
device.

So, just check and respect the I2C_M_READ flag, which indicates a read
when set on a message. If it is absent, it is a write message.

Incidentally, changing from the case statement to a while loop allows
the code to lift the limitation to two i2c messages per transaction.

There are 4 more *_i2c_transfer functions affected by the same behaviour
and limitation that should be fixed in the same way.

Link: https://lore.kernel.org/linux-media/20220116112238.74171-2-micha@freedict.org
Signed-off-by: Michael Bunk <micha@freedict.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>

authored by

Michael Bunk and committed by
Mauro Carvalho Chehab
0e148a52 c6ad2b92

+73 -47
+73 -47
drivers/media/usb/dvb-usb/dw2102.c
··· 716 716 { 717 717 struct dvb_usb_device *d = i2c_get_adapdata(adap); 718 718 struct dw2102_state *state; 719 + int j; 719 720 720 721 if (!d) 721 722 return -ENODEV; ··· 730 729 return -EAGAIN; 731 730 } 732 731 733 - switch (num) { 734 - case 1: 735 - switch (msg[0].addr) { 732 + j = 0; 733 + while (j < num) { 734 + switch (msg[j].addr) { 736 735 case SU3000_STREAM_CTRL: 737 - state->data[0] = msg[0].buf[0] + 0x36; 736 + state->data[0] = msg[j].buf[0] + 0x36; 738 737 state->data[1] = 3; 739 738 state->data[2] = 0; 740 739 if (dvb_usb_generic_rw(d, state->data, 3, ··· 746 745 if (dvb_usb_generic_rw(d, state->data, 1, 747 746 state->data, 2, 0) < 0) 748 747 err("i2c transfer failed."); 749 - msg[0].buf[1] = state->data[0]; 750 - msg[0].buf[0] = state->data[1]; 748 + msg[j].buf[1] = state->data[0]; 749 + msg[j].buf[0] = state->data[1]; 751 750 break; 752 751 default: 753 - if (3 + msg[0].len > sizeof(state->data)) { 754 - warn("i2c wr: len=%d is too big!\n", 755 - msg[0].len); 752 + /* if the current write msg is followed by a another 753 + * read msg to/from the same address 754 + */ 755 + if ((j+1 < num) && (msg[j+1].flags & I2C_M_RD) && 756 + (msg[j].addr == msg[j+1].addr)) { 757 + /* join both i2c msgs to one usb read command */ 758 + if (4 + msg[j].len > sizeof(state->data)) { 759 + warn("i2c combined wr/rd: write len=%d is too big!\n", 760 + msg[j].len); 761 + num = -EOPNOTSUPP; 762 + break; 763 + } 764 + if (1 + msg[j+1].len > sizeof(state->data)) { 765 + warn("i2c combined wr/rd: read len=%d is too big!\n", 766 + msg[j+1].len); 767 + num = -EOPNOTSUPP; 768 + break; 769 + } 770 + 771 + state->data[0] = 0x09; 772 + state->data[1] = msg[j].len; 773 + state->data[2] = msg[j+1].len; 774 + state->data[3] = msg[j].addr; 775 + memcpy(&state->data[4], msg[j].buf, msg[j].len); 776 + 777 + if (dvb_usb_generic_rw(d, state->data, msg[j].len + 4, 778 + state->data, msg[j+1].len + 1, 0) < 0) 779 + err("i2c transfer failed."); 780 + 781 + memcpy(msg[j+1].buf, &state->data[1], msg[j+1].len); 782 + j++; 783 + break; 784 + } 785 + 786 + if (msg[j].flags & I2C_M_RD) { 787 + /* single read */ 788 + if (1 + msg[j].len > sizeof(state->data)) { 789 + warn("i2c rd: len=%d is too big!\n", msg[j].len); 790 + num = -EOPNOTSUPP; 791 + break; 792 + } 793 + 794 + state->data[0] = 0x09; 795 + state->data[1] = 0; 796 + state->data[2] = msg[j].len; 797 + state->data[3] = msg[j].addr; 798 + memcpy(&state->data[4], msg[j].buf, msg[j].len); 799 + 800 + if (dvb_usb_generic_rw(d, state->data, 4, 801 + state->data, msg[j].len + 1, 0) < 0) 802 + err("i2c transfer failed."); 803 + 804 + memcpy(msg[j].buf, &state->data[1], msg[j].len); 805 + break; 806 + } 807 + 808 + /* single write */ 809 + if (3 + msg[j].len > sizeof(state->data)) { 810 + warn("i2c wr: len=%d is too big!\n", msg[j].len); 756 811 num = -EOPNOTSUPP; 757 812 break; 758 813 } 759 814 760 - /* always i2c write*/ 761 815 state->data[0] = 0x08; 762 - state->data[1] = msg[0].addr; 763 - state->data[2] = msg[0].len; 816 + state->data[1] = msg[j].addr; 817 + state->data[2] = msg[j].len; 764 818 765 - memcpy(&state->data[3], msg[0].buf, msg[0].len); 819 + memcpy(&state->data[3], msg[j].buf, msg[j].len); 766 820 767 - if (dvb_usb_generic_rw(d, state->data, msg[0].len + 3, 821 + if (dvb_usb_generic_rw(d, state->data, msg[j].len + 3, 768 822 state->data, 1, 0) < 0) 769 823 err("i2c transfer failed."); 824 + } // switch 825 + j++; 770 826 771 - } 772 - break; 773 - case 2: 774 - /* always i2c read */ 775 - if (4 + msg[0].len > sizeof(state->data)) { 776 - warn("i2c rd: len=%d is too big!\n", 777 - msg[0].len); 778 - num = -EOPNOTSUPP; 779 - break; 780 - } 781 - if (1 + msg[1].len > sizeof(state->data)) { 782 - warn("i2c rd: len=%d is too big!\n", 783 - msg[1].len); 784 - num = -EOPNOTSUPP; 785 - break; 786 - } 787 - 788 - state->data[0] = 0x09; 789 - state->data[1] = msg[0].len; 790 - state->data[2] = msg[1].len; 791 - state->data[3] = msg[0].addr; 792 - memcpy(&state->data[4], msg[0].buf, msg[0].len); 793 - 794 - if (dvb_usb_generic_rw(d, state->data, msg[0].len + 4, 795 - state->data, msg[1].len + 1, 0) < 0) 796 - err("i2c transfer failed."); 797 - 798 - memcpy(msg[1].buf, &state->data[1], msg[1].len); 799 - break; 800 - default: 801 - warn("more than 2 i2c messages at a time is not handled yet."); 802 - break; 803 - } 827 + } // while 804 828 mutex_unlock(&d->data_mutex); 805 829 mutex_unlock(&d->i2c_mutex); 806 830 return num;