diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/spi/spidev.c | 55 |
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 | ||
| 685 | static struct class *spidev_class; | 704 | static struct class *spidev_class; |
| 686 | 705 | ||
| 706 | #ifdef CONFIG_OF | ||
| 707 | static const struct of_device_id spidev_dt_ids[] = { | ||
| 708 | { .compatible = "rohm,dh2228fv" }, | ||
| 709 | {}, | ||
| 710 | }; | ||
| 711 | MODULE_DEVICE_TABLE(of, spidev_dt_ids); | ||
| 712 | #endif | ||
| 713 | |||
| 687 | /*-------------------------------------------------------------------------*/ | 714 | /*-------------------------------------------------------------------------*/ |
| 688 | 715 | ||
| 689 | static int spidev_probe(struct spi_device *spi) | 716 | static 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 | ||
| 761 | static const struct of_device_id spidev_dt_ids[] = { | ||
| 762 | { .compatible = "rohm,dh2228fv" }, | ||
| 763 | {}, | ||
| 764 | }; | ||
| 765 | |||
| 766 | MODULE_DEVICE_TABLE(of, spidev_dt_ids); | ||
| 767 | |||
| 768 | static struct spi_driver spidev_spi_driver = { | 799 | static struct spi_driver spidev_spi_driver = { |
| 769 | .driver = { | 800 | .driver = { |
| 770 | .name = "spidev", | 801 | .name = "spidev", |
