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

Merge remote-tracking branches 'spi/topic/spidev' and 'spi/topic/spidev-test' into spi-next

+138 -32
+95 -20
Documentation/spi/spidev_test.c
··· 15 15 #include <unistd.h> 16 16 #include <stdio.h> 17 17 #include <stdlib.h> 18 + #include <string.h> 18 19 #include <getopt.h> 19 20 #include <fcntl.h> 20 21 #include <sys/ioctl.h> ··· 35 34 static uint8_t bits = 8; 36 35 static uint32_t speed = 500000; 37 36 static uint16_t delay; 37 + static int verbose; 38 38 39 - static void transfer(int fd) 39 + uint8_t default_tx[] = { 40 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 41 + 0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 42 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 43 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 44 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 45 + 0xF0, 0x0D, 46 + }; 47 + 48 + uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, }; 49 + char *input_tx; 50 + 51 + static void hex_dump(const void *src, size_t length, size_t line_size, char *prefix) 52 + { 53 + int i = 0; 54 + const unsigned char *address = src; 55 + const unsigned char *line = address; 56 + unsigned char c; 57 + 58 + printf("%s | ", prefix); 59 + while (length-- > 0) { 60 + printf("%02X ", *address++); 61 + if (!(++i % line_size) || (length == 0 && i % line_size)) { 62 + if (length == 0) { 63 + while (i++ % line_size) 64 + printf("__ "); 65 + } 66 + printf(" | "); /* right close */ 67 + while (line < address) { 68 + c = *line++; 69 + printf("%c", (c < 33 || c == 255) ? 0x2E : c); 70 + } 71 + printf("\n"); 72 + if (length > 0) 73 + printf("%s | ", prefix); 74 + } 75 + } 76 + } 77 + 78 + /* 79 + * Unescape - process hexadecimal escape character 80 + * converts shell input "\x23" -> 0x23 81 + */ 82 + int unespcape(char *_dst, char *_src, size_t len) 83 + { 84 + int ret = 0; 85 + char *src = _src; 86 + char *dst = _dst; 87 + unsigned int ch; 88 + 89 + while (*src) { 90 + if (*src == '\\' && *(src+1) == 'x') { 91 + sscanf(src + 2, "%2x", &ch); 92 + src += 4; 93 + *dst++ = (unsigned char)ch; 94 + } else { 95 + *dst++ = *src++; 96 + } 97 + ret++; 98 + } 99 + return ret; 100 + } 101 + 102 + static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len) 40 103 { 41 104 int ret; 42 - uint8_t tx[] = { 43 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 44 - 0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 45 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 46 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 47 - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 48 - 0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD, 49 - 0xF0, 0x0D, 50 - }; 51 - uint8_t rx[ARRAY_SIZE(tx)] = {0, }; 105 + 52 106 struct spi_ioc_transfer tr = { 53 107 .tx_buf = (unsigned long)tx, 54 108 .rx_buf = (unsigned long)rx, 55 - .len = ARRAY_SIZE(tx), 109 + .len = len, 56 110 .delay_usecs = delay, 57 111 .speed_hz = speed, 58 112 .bits_per_word = bits, ··· 132 76 if (ret < 1) 133 77 pabort("can't send spi message"); 134 78 135 - for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { 136 - if (!(ret % 6)) 137 - puts(""); 138 - printf("%.2X ", rx[ret]); 139 - } 140 - puts(""); 79 + if (verbose) 80 + hex_dump(tx, len, 32, "TX"); 81 + hex_dump(rx, len, 32, "RX"); 141 82 } 142 83 143 84 static void print_usage(const char *prog) ··· 150 97 " -L --lsb least significant bit first\n" 151 98 " -C --cs-high chip select active high\n" 152 99 " -3 --3wire SI/SO signals shared\n" 100 + " -v --verbose Verbose (show tx buffer)\n" 101 + " -p Send data (e.g. \"1234\\xde\\xad\")\n" 153 102 " -N --no-cs no chip select\n" 154 103 " -R --ready slave pulls low to pause\n" 155 104 " -2 --dual dual transfer\n" ··· 176 121 { "no-cs", 0, 0, 'N' }, 177 122 { "ready", 0, 0, 'R' }, 178 123 { "dual", 0, 0, '2' }, 124 + { "verbose", 0, 0, 'v' }, 179 125 { "quad", 0, 0, '4' }, 180 126 { NULL, 0, 0, 0 }, 181 127 }; 182 128 int c; 183 129 184 - c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24", lopts, NULL); 130 + c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24p:v", lopts, NULL); 185 131 186 132 if (c == -1) 187 133 break; ··· 221 165 case 'N': 222 166 mode |= SPI_NO_CS; 223 167 break; 168 + case 'v': 169 + verbose = 1; 170 + break; 224 171 case 'R': 225 172 mode |= SPI_READY; 173 + break; 174 + case 'p': 175 + input_tx = optarg; 226 176 break; 227 177 case '2': 228 178 mode |= SPI_TX_DUAL; ··· 253 191 { 254 192 int ret = 0; 255 193 int fd; 194 + uint8_t *tx; 195 + uint8_t *rx; 196 + int size; 256 197 257 198 parse_opts(argc, argv); 258 199 ··· 300 235 printf("bits per word: %d\n", bits); 301 236 printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); 302 237 303 - transfer(fd); 238 + if (input_tx) { 239 + size = strlen(input_tx+1); 240 + tx = malloc(size); 241 + rx = malloc(size); 242 + size = unespcape((char *)tx, input_tx, size); 243 + transfer(fd, tx, rx, size); 244 + free(rx); 245 + free(tx); 246 + } else { 247 + transfer(fd, default_tx, default_rx, sizeof(default_tx)); 248 + } 304 249 305 250 close(fd); 306 251
+43 -12
drivers/spi/spidev.c
··· 223 223 struct spi_transfer *k_xfers; 224 224 struct spi_transfer *k_tmp; 225 225 struct spi_ioc_transfer *u_tmp; 226 - unsigned n, total; 226 + unsigned n, total, tx_total, rx_total; 227 227 u8 *tx_buf, *rx_buf; 228 228 int status = -EFAULT; 229 229 ··· 239 239 tx_buf = spidev->tx_buffer; 240 240 rx_buf = spidev->rx_buffer; 241 241 total = 0; 242 + tx_total = 0; 243 + rx_total = 0; 242 244 for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers; 243 245 n; 244 246 n--, k_tmp++, u_tmp++) { 245 247 k_tmp->len = u_tmp->len; 246 248 247 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 256 status = -EMSGSIZE; 250 257 goto done; 251 258 } 252 259 253 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 267 k_tmp->rx_buf = rx_buf; 255 268 if (!access_ok(VERIFY_WRITE, (u8 __user *) 256 269 (uintptr_t) u_tmp->rx_buf, 257 270 u_tmp->len)) 258 271 goto done; 272 + rx_buf += k_tmp->len; 259 273 } 260 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 281 k_tmp->tx_buf = tx_buf; 262 282 if (copy_from_user(tx_buf, (const u8 __user *) 263 283 (uintptr_t) u_tmp->tx_buf, 264 284 u_tmp->len)) 265 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 289 k_tmp->cs_change = !!u_tmp->cs_change; 271 290 k_tmp->tx_nbits = u_tmp->tx_nbits; ··· 322 303 status = -EFAULT; 323 304 goto done; 324 305 } 306 + rx_buf += u_tmp->len; 325 307 } 326 - rx_buf += u_tmp->len; 327 308 } 328 309 status = total; 329 310 ··· 703 684 704 685 static struct class *spidev_class; 705 686 687 + #ifdef CONFIG_OF 688 + static const struct of_device_id spidev_dt_ids[] = { 689 + { .compatible = "rohm,dh2228fv" }, 690 + {}, 691 + }; 692 + MODULE_DEVICE_TABLE(of, spidev_dt_ids); 693 + #endif 694 + 706 695 /*-------------------------------------------------------------------------*/ 707 696 708 697 static int spidev_probe(struct spi_device *spi) ··· 718 691 struct spidev_data *spidev; 719 692 int status; 720 693 unsigned long minor; 694 + 695 + /* 696 + * spidev should never be referenced in DT without a specific 697 + * compatbile string, it is a Linux implementation thing 698 + * rather than a description of the hardware. 699 + */ 700 + if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) { 701 + dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n"); 702 + WARN_ON(spi->dev.of_node && 703 + !of_match_device(spidev_dt_ids, &spi->dev)); 704 + } 721 705 722 706 /* Allocate driver data */ 723 707 spidev = kzalloc(sizeof(*spidev), GFP_KERNEL); ··· 795 757 796 758 return 0; 797 759 } 798 - 799 - static const struct of_device_id spidev_dt_ids[] = { 800 - { .compatible = "rohm,dh2228fv" }, 801 - {}, 802 - }; 803 - 804 - MODULE_DEVICE_TABLE(of, spidev_dt_ids); 805 760 806 761 static struct spi_driver spidev_spi_driver = { 807 762 .driver = {