source: rtems/testsuites/libtests/i2c01/init.c @ 9d0913d1

4.11
Last change on this file since 9d0913d1 was 9d0913d1, checked in by Sebastian Huber <sebastian.huber@…>, on May 27, 2015 at 10:48:22 AM

libtests/i2c01: Avoid stack overflow

  • Property mode set to 100644
File size: 14.5 KB
Line 
1/*
2 * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#ifdef HAVE_CONFIG_H
16  #include "config.h"
17#endif
18
19#include <dev/i2c/i2c.h>
20#include <dev/i2c/eeprom.h>
21#include <dev/i2c/gpio-nxp-pca9535.h>
22#include <dev/i2c/switch-nxp-pca9548a.h>
23
24#include <sys/ioctl.h>
25#include <sys/stat.h>
26#include <errno.h>
27#include <fcntl.h>
28#include <stdlib.h>
29#include <string.h>
30#include <unistd.h>
31
32#include <rtems/libcsupport.h>
33
34#include "tmacros.h"
35
36const char rtems_test_name[] = "I2C 1";
37
38#define SPARE_ADDRESS_BITS 3
39
40#define DEVICE_SIMPLE_READ_WRITE (0UL << SPARE_ADDRESS_BITS)
41
42#define DEVICE_EEPROM (1UL << SPARE_ADDRESS_BITS)
43
44#define DEVICE_GPIO_NXP_PCA9535 (2UL << SPARE_ADDRESS_BITS)
45
46#define DEVICE_SWITCH_NXP_PCA9548A (3UL << SPARE_ADDRESS_BITS)
47
48#define EEPROM_SIZE 512
49
50typedef struct test_device test_device;
51
52struct test_device {
53  int (*transfer)(
54    i2c_bus *bus,
55    i2c_msg *msgs,
56    uint32_t msg_count,
57    test_device *dev
58  );
59};
60
61typedef struct {
62  test_device base;
63  char buf[3];
64} test_device_simple_read_write;
65
66typedef struct {
67  test_device base;
68  unsigned current_reg;
69  uint8_t regs[8];
70} test_device_gpio_nxp_pca9535;
71
72typedef struct {
73  test_device base;
74  unsigned current_address;
75  uint8_t data[EEPROM_SIZE];
76} test_device_eeprom;
77
78typedef struct {
79  test_device base;
80  uint8_t control;
81} test_device_switch_nxp_pca9548a;
82
83typedef struct {
84  i2c_bus base;
85  unsigned long clock;
86  test_device *devices[4];
87  test_device_simple_read_write simple_read_write;
88  test_device_gpio_nxp_pca9535 gpio_nxp_pca9535;
89  test_device_eeprom eeprom;
90  test_device_switch_nxp_pca9548a switch_nxp_pca9548a;
91} test_bus;
92
93static const char bus_path[] = "/dev/i2c-0";
94
95static const char gpio_nxp_pca9535_path[] = "/dev/i2c-0.gpio-nxp-pc9535-0";
96
97static const char eeprom_path[] = "/dev/i2c-0.eeprom-0";
98
99static const char switch_nxp_pca9548a_path[] =
100  "/dev/i2c-0.switch-nxp-pca9548a-0";
101
102static void cyclic_inc(unsigned *val, unsigned cycle)
103{
104  unsigned v = *val;
105  unsigned m = cycle - 1U;
106
107  *val = (v & ~m) + ((v + 1U) & m);
108}
109
110static int test_simple_read_write_transfer(
111  i2c_bus *bus,
112  i2c_msg *msgs,
113  uint32_t msg_count,
114  test_device *base
115)
116{
117  test_device_simple_read_write *dev = (test_device_simple_read_write *) base;
118
119  if (msg_count == 1 && msgs[0].len == sizeof(dev->buf)) {
120    if ((msgs[0].flags & I2C_M_RD) != 0) {
121      memcpy(msgs[0].buf, &dev->buf[0], sizeof(dev->buf));
122    } else {
123      memcpy(&dev->buf[0], msgs[0].buf, sizeof(dev->buf));
124    }
125
126    return 0;
127  } else {
128    return -EIO;
129  }
130}
131
132static int test_gpio_nxp_pca9535_transfer(
133  i2c_bus *bus,
134  i2c_msg *msgs,
135  uint32_t msg_count,
136  test_device *base
137)
138{
139  test_device_gpio_nxp_pca9535 *dev = (test_device_gpio_nxp_pca9535 *) base;
140  i2c_msg *first = &msgs[0];
141  i2c_msg *second = &msgs[1];
142  int i;
143
144  /* Get command byte */
145  if (
146    msg_count < 1
147      || (first->flags & I2C_M_RD) != 0
148      || first->len < 1
149  ) {
150    return -EIO;
151  }
152
153  dev->current_reg = first->buf[0];
154
155  if (first->len > 1) {
156    /* Write */
157
158    if (msg_count != 1) {
159      return -EIO;
160    }
161
162    for (i = 1; i < first->len; ++i) {
163      dev->regs[dev->current_reg] = first->buf[i];
164
165      /* Output is input */
166      if (dev->current_reg == 2) {
167        dev->regs[0] = first->buf[i];
168      } else if (dev->current_reg == 3) {
169        dev->regs[1] = first->buf[i];
170      }
171
172      cyclic_inc(&dev->current_reg, 2);
173    }
174  } else {
175    /* Read */
176
177    if (msg_count != 2) {
178      return -EIO;
179    }
180
181    for (i = 0; i < second->len; ++i) {
182      second->buf[i] = dev->regs[dev->current_reg];
183      cyclic_inc(&dev->current_reg, 2);
184    }
185  }
186
187  return 0;
188}
189
190static int test_eeprom_transfer(
191  i2c_bus *bus,
192  i2c_msg *msgs,
193  uint32_t msg_count,
194  test_device *base
195)
196{
197  test_device_eeprom *dev = (test_device_eeprom *) base;
198  i2c_msg *msg = &msgs[0];
199  uint32_t i;
200
201  if (msg_count > 0 && (msg->flags & I2C_M_RD) == 0) {
202    if (msg->len < 1) {
203      return -EIO;
204    }
205
206    dev->current_address = msg->buf[0] | ((msg->addr & 0x1) << 8);
207    --msg->len;
208    ++msg->buf;
209  }
210
211  for (i = 0; i < msg_count; ++i) {
212    int j;
213
214    msg = &msgs[i];
215
216    if ((msg->flags & I2C_M_RD) != 0) {
217      for (j = 0; j < msg->len; ++j) {
218        msg->buf[j] = dev->data[dev->current_address];
219        cyclic_inc(&dev->current_address, sizeof(dev->data));
220      }
221    } else {
222      for (j = 0; j < msg->len; ++j) {
223        dev->data[dev->current_address] = msg->buf[j];
224        cyclic_inc(&dev->current_address, 8);
225      }
226    }
227  }
228
229  return 0;
230}
231
232static int test_switch_nxp_pca9548a_transfer(
233  i2c_bus *bus,
234  i2c_msg *msgs,
235  uint32_t msg_count,
236  test_device *base
237)
238{
239  test_device_switch_nxp_pca9548a *dev = (test_device_switch_nxp_pca9548a *) base;
240  uint32_t i;
241
242  for (i = 0; i < msg_count; ++i) {
243    i2c_msg *msg = &msgs[i];
244    int j;
245
246    if ((msg->flags & I2C_M_RD) != 0) {
247      for (j = 0; j < msg->len; ++j) {
248        msg->buf[j] = dev->control;
249      }
250    } else {
251      for (j = 0; j < msg->len; ++j) {
252        dev->control = msg->buf[j];
253      }
254    }
255  }
256
257  return 0;
258}
259
260static int test_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t msg_count)
261{
262  test_bus *bus = (test_bus *) base;
263  uint16_t addr;
264  test_device *dev;
265
266  addr = msgs[0].addr >> SPARE_ADDRESS_BITS;
267  if (addr >= RTEMS_ARRAY_SIZE(bus->devices)) {
268    return -EIO;
269  }
270
271  dev = bus->devices[addr];
272
273  return (*dev->transfer)(&bus->base, msgs, msg_count, dev);
274}
275
276static int test_set_clock(i2c_bus *base, unsigned long clock)
277{
278  test_bus *bus = (test_bus *) base;
279
280  bus->clock = clock;
281
282  return 0;
283}
284
285static void test_destroy(i2c_bus *base)
286{
287  i2c_bus_destroy_and_free(base);
288}
289
290static void test_simple_read_write(test_bus *bus, int fd)
291{
292  static const char zero[] = { 0, 0, 0 };
293  static const char abc[] = { 'a', 'b', 'c' };
294
295  int rv;
296  char buf[3];
297  ssize_t n;
298
299  rv = ioctl(fd, I2C_SLAVE, DEVICE_SIMPLE_READ_WRITE);
300  rtems_test_assert(rv == 0);
301
302  errno = 0;
303  rv = ioctl(fd, 0xb00b);
304  rtems_test_assert(rv == -1);
305  rtems_test_assert(errno == ENOTTY);
306
307  errno = 0;
308  n = write(fd, &buf[0], 1000);
309  rtems_test_assert(n == -1);
310  rtems_test_assert(errno == EIO);
311
312  errno = 0;
313  n = read(fd, &buf[0], 1000);
314  rtems_test_assert(n == -1);
315  rtems_test_assert(errno == EIO);
316
317  rtems_test_assert(
318    memcmp(&bus->simple_read_write.buf[0], &zero[0], sizeof(buf)) == 0
319  );
320
321  n = write(fd, &abc[0], sizeof(buf));
322  rtems_test_assert(n == (ssize_t) sizeof(buf));
323
324  rtems_test_assert(
325    memcmp(&bus->simple_read_write.buf[0], &abc[0], sizeof(buf)) == 0
326  );
327
328  n = read(fd, &buf[0], sizeof(buf));
329  rtems_test_assert(n == (ssize_t) sizeof(buf));
330
331  rtems_test_assert(memcmp(&buf[0], &abc[0], sizeof(buf)) == 0);
332}
333
334static void test_gpio_nxp_pca9535(void)
335{
336  int rv;
337  int fd;
338  uint16_t val;
339
340  rv = i2c_dev_register_gpio_nxp_pca9535(
341    &bus_path[0],
342    &gpio_nxp_pca9535_path[0],
343    DEVICE_GPIO_NXP_PCA9535
344  );
345  rtems_test_assert(rv == 0);
346
347  fd = open(&gpio_nxp_pca9535_path[0], O_RDWR);
348  rtems_test_assert(fd >= 0);
349
350  rv = gpio_nxp_pca9535_get_input(fd, &val);
351  rtems_test_assert(rv == 0);
352  rtems_test_assert(val == 0);
353
354  rv = gpio_nxp_pca9535_get_output(fd, &val);
355  rtems_test_assert(rv == 0);
356  rtems_test_assert(val == 0);
357
358  rv = gpio_nxp_pca9535_set_output(fd, 0xa5ef);
359  rtems_test_assert(rv == 0);
360
361  rv = gpio_nxp_pca9535_get_input(fd, &val);
362  rtems_test_assert(rv == 0);
363  rtems_test_assert(val == 0xa5ef);
364
365  rv = gpio_nxp_pca9535_get_output(fd, &val);
366  rtems_test_assert(rv == 0);
367  rtems_test_assert(val == 0xa5ef);
368
369  rv = gpio_nxp_pca9535_clear_and_set_output(fd, 0x0ff0, 0x0170);
370  rtems_test_assert(rv == 0);
371
372  rv = gpio_nxp_pca9535_get_polarity_inversion(fd, &val);
373  rtems_test_assert(rv == 0);
374  rtems_test_assert(val == 0);
375
376  rv = gpio_nxp_pca9535_set_polarity_inversion(fd, 0x5afe);
377  rtems_test_assert(rv == 0);
378
379  rv = gpio_nxp_pca9535_get_config(fd, &val);
380  rtems_test_assert(rv == 0);
381  rtems_test_assert(val == 0);
382
383  rv = gpio_nxp_pca9535_set_config(fd, 0x2bcd);
384  rtems_test_assert(rv == 0);
385
386  rv = gpio_nxp_pca9535_get_input(fd, &val);
387  rtems_test_assert(rv == 0);
388  rtems_test_assert(val == 0xa17f);
389
390  rv = gpio_nxp_pca9535_get_output(fd, &val);
391  rtems_test_assert(rv == 0);
392  rtems_test_assert(val == 0xa17f);
393
394  rv = gpio_nxp_pca9535_get_polarity_inversion(fd, &val);
395  rtems_test_assert(rv == 0);
396  rtems_test_assert(val == 0x5afe);
397
398  rv = gpio_nxp_pca9535_get_config(fd, &val);
399  rtems_test_assert(rv == 0);
400  rtems_test_assert(val == 0x2bcd);
401
402  rv = close(fd);
403  rtems_test_assert(rv == 0);
404
405  rv = unlink(&gpio_nxp_pca9535_path[0]);
406  rtems_test_assert(rv == 0);
407}
408
409static void test_eeprom(void)
410{
411  int rv;
412  int fd_in;
413  int fd_out;
414  struct stat st;
415  uint8_t in[EEPROM_SIZE];
416  uint8_t out[EEPROM_SIZE];
417  ssize_t n;
418  off_t off;
419  size_t i;
420
421  rv = i2c_dev_register_eeprom(
422    &bus_path[0],
423    &eeprom_path[0],
424    DEVICE_EEPROM,
425    1,
426    8,
427    sizeof(out),
428    0
429  );
430  rtems_test_assert(rv == 0);
431
432  fd_in = open(&eeprom_path[0], O_RDWR);
433  rtems_test_assert(fd_in >= 0);
434
435  fd_out = open(&eeprom_path[0], O_RDWR);
436  rtems_test_assert(fd_out >= 0);
437
438  rv = fstat(fd_in, &st);
439  rtems_test_assert(rv == 0);
440  rtems_test_assert(st.st_blksize == 8);
441  rtems_test_assert(st.st_size == sizeof(out));
442
443  memset(&out[0], 0, sizeof(out));
444
445  n = read(fd_in, &in[0], sizeof(in) + 1);
446  rtems_test_assert(n == (ssize_t) sizeof(in));
447
448  rtems_test_assert(memcmp(&in[0], &out[0], sizeof(in)) == 0);
449
450  off = lseek(fd_in, 0, SEEK_CUR);
451  rtems_test_assert(off == sizeof(out));
452
453  for (i = 0; i < sizeof(out); ++i) {
454    off = lseek(fd_out, 0, SEEK_CUR);
455    rtems_test_assert(off == i);
456
457    out[i] = (uint8_t) i;
458
459    n = write(fd_out, &out[i], sizeof(out[i]));
460    rtems_test_assert(n == (ssize_t) sizeof(out[i]));
461
462    off = lseek(fd_in, 0, SEEK_SET);
463    rtems_test_assert(off == 0);
464
465    n = read(fd_in, &in[0], sizeof(in));
466    rtems_test_assert(n == (ssize_t) sizeof(in));
467
468    rtems_test_assert(memcmp(&in[0], &out[0], sizeof(in)) == 0);
469  }
470
471  rv = close(fd_in);
472  rtems_test_assert(rv == 0);
473
474  rv = close(fd_out);
475  rtems_test_assert(rv == 0);
476
477  rv = unlink(&eeprom_path[0]);
478  rtems_test_assert(rv == 0);
479}
480
481static void test_switch_nxp_pca9548a(void)
482{
483  int rv;
484  int fd;
485  uint8_t val;
486
487  rv = i2c_dev_register_switch_nxp_pca9548a(
488    &bus_path[0],
489    &switch_nxp_pca9548a_path[0],
490    DEVICE_SWITCH_NXP_PCA9548A
491  );
492  rtems_test_assert(rv == 0);
493
494  fd = open(&switch_nxp_pca9548a_path[0], O_RDWR);
495  rtems_test_assert(fd >= 0);
496
497  rv = switch_nxp_pca9548a_get_control(fd, &val);
498  rtems_test_assert(rv == 0);
499  rtems_test_assert(val == 0);
500
501  rv = switch_nxp_pca9548a_set_control(fd, 0xa5);
502  rtems_test_assert(rv == 0);
503
504  rv = switch_nxp_pca9548a_get_control(fd, &val);
505  rtems_test_assert(rv == 0);
506  rtems_test_assert(val == 0xa5);
507
508  rv = close(fd);
509  rtems_test_assert(rv == 0);
510
511  rv = unlink(&switch_nxp_pca9548a_path[0]);
512  rtems_test_assert(rv == 0);
513}
514
515static void test(void)
516{
517  rtems_resource_snapshot snapshot;
518  test_bus *bus;
519  int rv;
520  int fd;
521
522  rtems_resource_snapshot_take(&snapshot);
523
524  bus = (test_bus *) i2c_bus_alloc_and_init(sizeof(*bus));
525  rtems_test_assert(bus != NULL);
526
527  bus->base.transfer = test_transfer;
528  bus->base.set_clock = test_set_clock;
529  bus->base.destroy = test_destroy;
530  bus->base.functionality = I2C_FUNC_I2C | I2C_FUNC_PROTOCOL_MANGLING
531    | I2C_FUNC_NOSTART;
532
533  bus->simple_read_write.base.transfer = test_simple_read_write_transfer;
534  bus->devices[0] = &bus->simple_read_write.base;
535
536  bus->eeprom.base.transfer = test_eeprom_transfer;
537  bus->devices[1] = &bus->eeprom.base;
538
539  bus->gpio_nxp_pca9535.base.transfer = test_gpio_nxp_pca9535_transfer;
540  bus->devices[2] = &bus->gpio_nxp_pca9535.base;
541
542  bus->switch_nxp_pca9548a.base.transfer = test_switch_nxp_pca9548a_transfer;
543  bus->devices[3] = &bus->switch_nxp_pca9548a.base;
544
545  rv = i2c_bus_register(&bus->base, &bus_path[0]);
546  rtems_test_assert(rv == 0);
547
548  fd = open(&bus_path[0], O_RDWR);
549  rtems_test_assert(fd >= 0);
550
551  rtems_test_assert(bus->clock == 0);
552  rv = ioctl(fd, I2C_BUS_SET_CLOCK, 0xdeadbeefUL);
553  rtems_test_assert(rv == 0);
554  rtems_test_assert(bus->clock == 0xdeadbeef);
555
556  rv = ioctl(fd, I2C_BUS_OBTAIN);
557  rtems_test_assert(rv == 0);
558
559  rv = ioctl(fd, I2C_BUS_RELEASE);
560  rtems_test_assert(rv == 0);
561
562  rtems_test_assert(!bus->base.ten_bit_address);
563
564  rv = ioctl(fd, I2C_TENBIT, 1UL);
565  rtems_test_assert(rv == 0);
566  rtems_test_assert(bus->base.ten_bit_address);
567
568  rv = ioctl(fd, I2C_TENBIT, 0UL);
569  rtems_test_assert(rv == 0);
570  rtems_test_assert(!bus->base.ten_bit_address);
571
572  rtems_test_assert(!bus->base.use_pec);
573
574  rv = ioctl(fd, I2C_PEC, 1UL);
575  rtems_test_assert(rv == 0);
576  rtems_test_assert(bus->base.use_pec);
577
578  rv = ioctl(fd, I2C_PEC, 0UL);
579  rtems_test_assert(rv == 0);
580  rtems_test_assert(!bus->base.use_pec);
581
582  rv = ioctl(fd, I2C_SLAVE, 123UL);
583  rtems_test_assert(rv == 0);
584  rtems_test_assert(bus->base.default_address == 123);
585
586  rv = ioctl(fd, I2C_SLAVE_FORCE, 456UL);
587  rtems_test_assert(rv == 0);
588  rtems_test_assert(bus->base.default_address == 456);
589
590  rtems_test_assert(bus->base.retries == 0);
591
592  rv = ioctl(fd, I2C_RETRIES, 1UL);
593  rtems_test_assert(rv == 0);
594  rtems_test_assert(bus->base.retries == 1);
595
596  rv = ioctl(fd, I2C_RETRIES, 0UL);
597  rtems_test_assert(rv == 0);
598  rtems_test_assert(bus->base.retries == 0);
599
600  rtems_test_assert(bus->base.timeout == 0);
601
602  rv = ioctl(fd, I2C_TIMEOUT, 1UL);
603  rtems_test_assert(rv == 0);
604  rtems_test_assert(bus->base.timeout == 5);
605
606  rv = ioctl(fd, I2C_TIMEOUT, 0UL);
607  rtems_test_assert(rv == 0);
608  rtems_test_assert(bus->base.timeout == 0);
609
610  test_simple_read_write(bus, fd);
611  test_eeprom();
612  test_gpio_nxp_pca9535();
613  test_switch_nxp_pca9548a();
614
615  rv = close(fd);
616  rtems_test_assert(rv == 0);
617
618  rv = unlink(&bus_path[0]);
619  rtems_test_assert(rv == 0);
620
621  rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
622}
623
624static void Init(rtems_task_argument arg)
625{
626  TEST_BEGIN();
627
628  test();
629
630  TEST_END();
631  rtems_test_exit(0);
632}
633
634#define CONFIGURE_MICROSECONDS_PER_TICK 2000
635
636#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
637#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
638
639#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 7
640
641#define CONFIGURE_MAXIMUM_TASKS 1
642
643#define CONFIGURE_MAXIMUM_SEMAPHORES 1
644
645#define CONFIGURE_INIT_TASK_STACK_SIZE (RTEMS_MINIMUM_STACK_SIZE + 2 * EEPROM_SIZE)
646
647#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
648
649#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
650
651#define CONFIGURE_INIT
652
653#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.