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

[media] dibusb: don't do DMA on stack

The USB control messages require DMA to work. We cannot pass
a stack-allocated buffer, as it is not warranted that the
stack would be into a DMA enabled area.

Reviewed-by: Patrick Boettcher <patrick.boettcher@posteo.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

+86 -26
+83 -26
drivers/media/usb/dvb-usb/dibusb-common.c
··· 63 63 64 64 int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff) 65 65 { 66 - u8 b[3]; 66 + u8 *b; 67 67 int ret; 68 + 69 + b = kmalloc(3, GFP_KERNEL); 70 + if (!b) 71 + return -ENOMEM; 72 + 68 73 b[0] = DIBUSB_REQ_SET_IOCTL; 69 74 b[1] = DIBUSB_IOCTL_CMD_POWER_MODE; 70 75 b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP; 71 - ret = dvb_usb_generic_write(d,b,3); 76 + 77 + ret = dvb_usb_generic_write(d, b, 3); 78 + 79 + kfree(b); 80 + 72 81 msleep(10); 82 + 73 83 return ret; 74 84 } 75 85 EXPORT_SYMBOL(dibusb_power_ctrl); 76 86 77 87 int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) 78 88 { 79 - u8 b[3] = { 0 }; 80 89 int ret; 90 + u8 *b; 91 + 92 + b = kmalloc(3, GFP_KERNEL); 93 + if (!b) 94 + return -ENOMEM; 81 95 82 96 if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0) 83 - return ret; 97 + goto ret; 84 98 85 99 if (onoff) { 86 100 b[0] = DIBUSB_REQ_SET_STREAMING_MODE; 87 101 b[1] = 0x00; 88 - if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0) 89 - return ret; 102 + ret = dvb_usb_generic_write(adap->dev, b, 2); 103 + if (ret < 0) 104 + goto ret; 90 105 } 91 106 92 107 b[0] = DIBUSB_REQ_SET_IOCTL; 93 108 b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM; 94 - return dvb_usb_generic_write(adap->dev,b,3); 109 + ret = dvb_usb_generic_write(adap->dev, b, 3); 110 + 111 + ret: 112 + kfree(b); 113 + return ret; 95 114 } 96 115 EXPORT_SYMBOL(dibusb2_0_streaming_ctrl); 97 116 98 117 int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff) 99 118 { 100 - if (onoff) { 101 - u8 b[3] = { DIBUSB_REQ_SET_IOCTL, DIBUSB_IOCTL_CMD_POWER_MODE, DIBUSB_IOCTL_POWER_WAKEUP }; 102 - return dvb_usb_generic_write(d,b,3); 103 - } else 119 + u8 *b; 120 + int ret; 121 + 122 + if (!onoff) 104 123 return 0; 124 + 125 + b = kmalloc(3, GFP_KERNEL); 126 + if (!b) 127 + return -ENOMEM; 128 + 129 + b[0] = DIBUSB_REQ_SET_IOCTL; 130 + b[1] = DIBUSB_IOCTL_CMD_POWER_MODE; 131 + b[2] = DIBUSB_IOCTL_POWER_WAKEUP; 132 + 133 + ret = dvb_usb_generic_write(d, b, 3); 134 + 135 + kfree(b); 136 + 137 + return ret; 105 138 } 106 139 EXPORT_SYMBOL(dibusb2_0_power_ctrl); 107 140 108 141 static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr, 109 142 u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) 110 143 { 111 - u8 sndbuf[MAX_XFER_SIZE]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */ 112 - /* write only ? */ 113 - int wo = (rbuf == NULL || rlen == 0), 114 - len = 2 + wlen + (wo ? 0 : 2); 144 + u8 *sndbuf; 145 + int ret, wo, len; 115 146 116 - if (4 + wlen > sizeof(sndbuf)) { 147 + /* write only ? */ 148 + wo = (rbuf == NULL || rlen == 0); 149 + 150 + len = 2 + wlen + (wo ? 0 : 2); 151 + 152 + sndbuf = kmalloc(MAX_XFER_SIZE, GFP_KERNEL); 153 + if (!sndbuf) 154 + return -ENOMEM; 155 + 156 + if (4 + wlen > MAX_XFER_SIZE) { 117 157 warn("i2c wr: len=%d is too big!\n", wlen); 118 - return -EOPNOTSUPP; 158 + ret = -EOPNOTSUPP; 159 + goto ret; 119 160 } 120 161 121 162 sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ; 122 163 sndbuf[1] = (addr << 1) | (wo ? 0 : 1); 123 164 124 - memcpy(&sndbuf[2],wbuf,wlen); 165 + memcpy(&sndbuf[2], wbuf, wlen); 125 166 126 167 if (!wo) { 127 - sndbuf[wlen+2] = (rlen >> 8) & 0xff; 128 - sndbuf[wlen+3] = rlen & 0xff; 168 + sndbuf[wlen + 2] = (rlen >> 8) & 0xff; 169 + sndbuf[wlen + 3] = rlen & 0xff; 129 170 } 130 171 131 - return dvb_usb_generic_rw(d,sndbuf,len,rbuf,rlen,0); 172 + ret = dvb_usb_generic_rw(d, sndbuf, len, rbuf, rlen, 0); 173 + 174 + ret: 175 + kfree(sndbuf); 176 + return ret; 132 177 } 133 178 134 179 /* ··· 365 320 366 321 int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) 367 322 { 368 - u8 key[5],cmd = DIBUSB_REQ_POLL_REMOTE; 369 - dvb_usb_generic_rw(d,&cmd,1,key,5,0); 370 - dvb_usb_nec_rc_key_to_event(d,key,event,state); 371 - if (key[0] != 0) 372 - deb_info("key: %*ph\n", 5, key); 323 + u8 *buf; 324 + 325 + buf = kmalloc(5, GFP_KERNEL); 326 + if (!buf) 327 + return -ENOMEM; 328 + 329 + buf[0] = DIBUSB_REQ_POLL_REMOTE; 330 + 331 + dvb_usb_generic_rw(d, buf, 1, buf, 5, 0); 332 + 333 + dvb_usb_nec_rc_key_to_event(d, buf, event, state); 334 + 335 + if (buf[0] != 0) 336 + deb_info("key: %*ph\n", 5, buf); 337 + 338 + kfree(buf); 339 + 373 340 return 0; 374 341 } 375 342 EXPORT_SYMBOL(dibusb_rc_query);
+3
drivers/media/usb/dvb-usb/dibusb.h
··· 96 96 #define DIBUSB_IOCTL_CMD_ENABLE_STREAM 0x01 97 97 #define DIBUSB_IOCTL_CMD_DISABLE_STREAM 0x02 98 98 99 + /* Max transfer size done by I2C transfer functions */ 100 + #define MAX_XFER_SIZE 64 101 + 99 102 struct dibusb_state { 100 103 struct dib_fe_xfer_ops ops; 101 104 int mt2060_present;