Re: [PATCH 2/2] UIO CMT test program

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Magnus,

Thanks for your patch!

On Sun, Mar 21, 2021 at 1:12 PM Magnus Damm <damm@xxxxxxxxxxxxx> wrote:
> --- /dev/null   2019-10-16 00:27:13.659405289 +0900
> +++ uio-cmt-test-20210321.c     2021-03-21 19:41:24.469083859 +0900
> @@ -0,0 +1,179 @@
> +/*
> + * uio-cmt-test-20210321.c - UIO CMT example test code, 20210321 Magnus Damm
> + *
> + * A small linux program that programs the CMT timer and waits for IRQs
> + *
> + * Compile for Linux using:
> + * $ cross-gcc -o uio-cmt-test uio-cmt-test.c
> + *
> + * Designed to work with the Linux UIO kernel driver uio_pdrv_genirq.c
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <fcntl.h>
> +
> +static int fgets_with_openclose(char *fname, char *buf, size_t maxlen) {
> +       FILE *fp;
> +
> +       if ((fp = fopen(fname, "r")) != NULL) {
> +               fgets(buf, maxlen, fp);
> +               fclose(fp);
> +               return strlen(buf);

If buf[] contains no terminating NUL character, this will read beyond the
end of the buffer.

> +       } else {
> +               return -1;
> +       }
> +}
> +
> +struct uio_device {
> +       char *name;
> +       char *path;
> +       int fd;
> +};
> +
> +#define MAXUIOIDS  100
> +#define MAXNAMELEN 256
> +
> +static int locate_uio_device(char *name, struct uio_device *udp)
> +{
> +       char fname[MAXNAMELEN], buf[MAXNAMELEN];
> +       int uio_id, i;
> +
> +       for (uio_id = 0; uio_id < MAXUIOIDS; uio_id++) {
> +               sprintf(fname, "/sys/class/uio/uio%d/name", uio_id);

asprintf()?

> +               if (fgets_with_openclose(fname, buf, MAXNAMELEN) < 0)
> +                       continue;
> +               if (strncmp(name, buf, strlen(name)) == 0)
> +                       break;
> +       }
> +
> +       if (uio_id >= MAXUIOIDS)
> +               return -1;
> +
> +       udp->name = strdup(buf);
> +       udp->path = strdup(fname);
> +       udp->path[strlen(udp->path) - 4] = '\0';
> +
> +       sprintf(buf, "/dev/uio%d", uio_id);

asprintf()

> +       udp->fd = open(buf, O_RDWR|O_SYNC /*| O_NONBLOCK*/);
> +
> +       if (udp->fd < 0) {
> +               perror("open");
> +               return -1;
> +       }
> +
> +       return 0;
> +}
> +
> +/* offsets apply to sh73a0 */
> +#define CMT_CMSTR 0x000 /* start/stop register, some bits reserved as 1 */
> +#define CMT_CMSTR_CH0 (1 << 0) /* set bit to one to start channel */
> +#define CMT_CMCSR 0x10 /* 0x124 enables interrupts and selects CLK/8 */
> +#define CMT_CMCSR_CMF (1 << 15) /* clear bit to ack compare match event */
> +#define CMT_CMCNT 0x14 /* counting up, set to 0 */
> +#define CMT_CMCOR 0x18 /* match value, set to ~0 */
> +
> +struct uio_map {
> +       unsigned long address;
> +       unsigned long size;
> +       void *iomem;
> +};
> +
> +static int setup_uio_map(struct uio_device *udp, int nr, struct uio_map *ump)
> +{
> +       char fname[MAXNAMELEN], buf[MAXNAMELEN];
> +
> +       sprintf(fname, "%s/maps/map%d/addr", udp->path, nr);

asprintf()

> +       if (fgets_with_openclose(fname, buf, MAXNAMELEN) <= 0)
> +               return -1;
> +
> +       ump->address = strtoul(buf, NULL, 0);
> +
> +       sprintf(fname, "%s/maps/map%d/size", udp->path, nr);

asprintf()

> +       if (fgets_with_openclose(fname, buf, MAXNAMELEN) <= 0)
> +               return -1;
> +
> +       ump->size = strtoul(buf, NULL, 0);
> +
> +       ump->iomem = mmap(0, ump->size,
> +                         PROT_READ|PROT_WRITE, MAP_SHARED,
> +                         udp->fd, nr * getpagesize());
> +
> +       if (ump->iomem == MAP_FAILED)
> +               return -1;
> +
> +       return 0;
> +}
> +
> +struct uio_device uio_dev;
> +struct uio_map uio_mmio;
> +
> +int main(int argc, char *argv[])
> +{
> +       int k;

unsigned int

> +       int ret;
> +
> +       ret = locate_uio_device("timer", &uio_dev);
> +       if (ret < 0)
> +               return ret;
> +
> +       printf("found matching UIO device at %s\n", uio_dev.path);
> +
> +       ret = setup_uio_map(&uio_dev, 0, &uio_mmio);
> +       if (ret < 0)
> +               return ret;
> +
> +       {
> +               unsigned long *cmstr = (uio_mmio.iomem + CMT_CMSTR);
> +               unsigned short *cmcsr = (uio_mmio.iomem + CMT_CMCSR);
> +               unsigned long *cmcor = (uio_mmio.iomem + CMT_CMCOR);

This is not portable across 32-bit/64-bit platforms.

uint32_t *...

> +
> +               /* Stop timer channel */
> +               *cmstr &= ~CMT_CMSTR_CH0;
> +
> +               /* Initialize CMCSR */
> +               *cmcsr = 0x124;
> +
> +               /* Initialize CMCOR */
> +               *cmcor = (32768 / 8) * 2; /* interrupt after about 2s */
> +
> +               /* Enable interrupt in UIO driver */
> +               {
> +                       unsigned long enable = 1;

uint32_t

> +                       write(uio_dev.fd, &enable, sizeof(u_long));
> +               }
> +
> +               /* Start timer channel */
> +               *cmstr |= CMT_CMSTR_CH0;
> +
> +               /* test by processing 3 interrupts */
> +               for (k = 0; k < 3; k++) {
> +                       /* Wait for interrupt */
> +                       {
> +                               unsigned long n_pending;

uint32_t

> +                               read(uio_dev.fd, &n_pending, sizeof(u_long));
> +                       }
> +
> +                       printf("IRQ nr %d\n", k);
> +
> +                       /* ack match in CMCSR */
> +                       *cmcsr &= ~CMT_CMCSR_CMF;
> +
> +                       /* Enable interrupt in UIO driver */
> +                       {
> +                               unsigned long enable = 1;
> +                               write(uio_dev.fd, &enable, sizeof(u_long));
> +                       }
> +               }
> +
> +               /* Stop timer channel */
> +               *cmstr &= ~CMT_CMSTR_CH0;
> +       }
> +
> +       return 0;
> +}

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds



[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux