aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/spi/spidev.c55
1 files changed, 43 insertions, 12 deletions
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 4eb7a980e670..92c909eed6b5 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -223,7 +223,7 @@ static int spidev_message(struct spidev_data *spidev,
223 struct spi_transfer *k_xfers; 223 struct spi_transfer *k_xfers;
224 struct spi_transfer *k_tmp; 224 struct spi_transfer *k_tmp;
225 struct spi_ioc_transfer *u_tmp; 225 struct spi_ioc_transfer *u_tmp;
226 unsigned n, total; 226 unsigned n, total, tx_total, rx_total;
227 u8 *tx_buf, *rx_buf; 227 u8 *tx_buf, *rx_buf;
228 int status = -EFAULT; 228 int status = -EFAULT;
229 229
@@ -239,33 +239,52 @@ static int spidev_message(struct spidev_data *spidev,
239 tx_buf = spidev->tx_buffer; 239 tx_buf = spidev->tx_buffer;
240 rx_buf = spidev->rx_buffer; 240 rx_buf = spidev->rx_buffer;
241 total = 0; 241 total = 0;
242 tx_total = 0;
243 rx_total = 0;
242 for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers; 244 for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
243 n; 245 n;
244 n--, k_tmp++, u_tmp++) { 246 n--, k_tmp++, u_tmp++) {
245 k_tmp->len = u_tmp->len; 247 k_tmp->len = u_tmp->len;
246 248
247 total += k_tmp->len; 249 total += k_tmp->len;
248 if (total > bufsiz) { 250 /* Since the function returns the total length of transfers
251 * on success, restrict the total to positive int values to
252 * avoid the return value looking like an error. Also check
253 * each transfer length to avoid arithmetic overflow.
254 */
255 if (total > INT_MAX || k_tmp->len > INT_MAX) {
249 status = -EMSGSIZE; 256 status = -EMSGSIZE;
250 goto done; 257 goto done;
251 } 258 }
252 259
253 if (u_tmp->rx_buf) { 260 if (u_tmp->rx_buf) {
261 /* this transfer needs space in RX bounce buffer */
262 rx_total += k_tmp->len;
263 if (rx_total > bufsiz) {
264 status = -EMSGSIZE;
265 goto done;
266 }
254 k_tmp->rx_buf = rx_buf; 267 k_tmp->rx_buf = rx_buf;
255 if (!access_ok(VERIFY_WRITE, (u8 __user *) 268 if (!access_ok(VERIFY_WRITE, (u8 __user *)
256 (uintptr_t) u_tmp->rx_buf, 269 (uintptr_t) u_tmp->rx_buf,
257 u_tmp->len)) 270 u_tmp->len))
258 goto done; 271 goto done;
272 rx_buf += k_tmp->len;
259 } 273 }
260 if (u_tmp->tx_buf) { 274 if (u_tmp->tx_buf) {
275 /* this transfer needs space in TX bounce buffer */
276 tx_total += k_tmp->len;
277 if (tx_total > bufsiz) {
278 status = -EMSGSIZE;
279 goto done;
280 }
261 k_tmp->tx_buf = tx_buf; 281 k_tmp->tx_buf = tx_buf;
262 if (copy_from_user(tx_buf, (const u8 __user *) 282 if (copy_from_user(tx_buf, (const u8 __user *)
263 (uintptr_t) u_tmp->tx_buf, 283 (uintptr_t) u_tmp->tx_buf,
264 u_tmp->len)) 284 u_tmp->len))
265 goto done; 285 goto done;
286 tx_buf += k_tmp->len;
266 } 287 }
267 tx_buf += k_tmp->len;
268 rx_buf += k_tmp->len;
269 288
270 k_tmp->cs_change = !!u_tmp->cs_change; 289 k_tmp->cs_change = !!u_tmp->cs_change;
271 k_tmp->tx_nbits = u_tmp->tx_nbits; 290 k_tmp->tx_nbits = u_tmp->tx_nbits;
@@ -303,8 +322,8 @@ static int spidev_message(struct spidev_data *spidev,
303 status = -EFAULT; 322 status = -EFAULT;
304 goto done; 323 goto done;
305 } 324 }
325 rx_buf += u_tmp->len;
306 } 326 }
307 rx_buf += u_tmp->len;
308 } 327 }
309 status = total; 328 status = total;
310 329
@@ -684,6 +703,14 @@ static const struct file_operations spidev_fops = {
684 703
685static struct class *spidev_class; 704static struct class *spidev_class;
686 705
706#ifdef CONFIG_OF
707static const struct of_device_id spidev_dt_ids[] = {
708 { .compatible = "rohm,dh2228fv" },
709 {},
710};
711MODULE_DEVICE_TABLE(of, spidev_dt_ids);
712#endif
713
687/*-------------------------------------------------------------------------*/ 714/*-------------------------------------------------------------------------*/
688 715
689static int spidev_probe(struct spi_device *spi) 716static int spidev_probe(struct spi_device *spi)
@@ -692,6 +719,17 @@ static int spidev_probe(struct spi_device *spi)
692 int status; 719 int status;
693 unsigned long minor; 720 unsigned long minor;
694 721
722 /*
723 * spidev should never be referenced in DT without a specific
724 * compatbile string, it is a Linux implementation thing
725 * rather than a description of the hardware.
726 */
727 if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) {
728 dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n");
729 WARN_ON(spi->dev.of_node &&
730 !of_match_device(spidev_dt_ids, &spi->dev));
731 }
732
695 /* Allocate driver data */ 733 /* Allocate driver data */
696 spidev = kzalloc(sizeof(*spidev), GFP_KERNEL); 734 spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
697 if (!spidev) 735 if (!spidev)
@@ -758,13 +796,6 @@ static int spidev_remove(struct spi_device *spi)
758 return 0; 796 return 0;
759} 797}
760 798
761static const struct of_device_id spidev_dt_ids[] = {
762 { .compatible = "rohm,dh2228fv" },
763 {},
764};
765
766MODULE_DEVICE_TABLE(of, spidev_dt_ids);
767
768static struct spi_driver spidev_spi_driver = { 799static struct spi_driver spidev_spi_driver = {
769 .driver = { 800 .driver = {
770 .name = "spidev", 801 .name = "spidev",