| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #include "gpiodpi.h" |
| |
| #ifdef __linux__ |
| #include <pty.h> |
| #elif __APPLE__ |
| #include <util.h> |
| #endif |
| |
| #include <assert.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <limits.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| void *gpiodpi_create(const char *name, int n_bits) { |
| struct gpiodpi_ctx *ctx = |
| (struct gpiodpi_ctx *)calloc(1, sizeof(struct gpiodpi_ctx)); |
| assert(ctx); |
| |
| // n_bits > 32 requires more sophisticated handling of svBitVecVal which we |
| // currently don't do. |
| assert(n_bits <= 32 && "n_bits must be <= 32"); |
| |
| ctx->n_bits = n_bits; |
| |
| char cwd[PATH_MAX]; |
| char *cwd_rv; |
| cwd_rv = getcwd(cwd, sizeof(cwd)); |
| assert(cwd_rv != NULL); |
| |
| int rv; |
| rv = snprintf(ctx->fifo_pathname, PATH_MAX, "%s/%s", cwd, name); |
| assert(rv <= PATH_MAX && rv > 0); |
| |
| rv = mkfifo(ctx->fifo_pathname, 0644); // writes are not supported currently |
| if (rv != 0) { |
| fprintf(stderr, "GPIO: Unable to create FIFO at %s: %s\n", |
| ctx->fifo_pathname, strerror(errno)); |
| return NULL; |
| } |
| |
| ctx->fifo_fd = open(ctx->fifo_pathname, O_RDWR); |
| if (ctx->fifo_fd < 0) { |
| fprintf(stderr, "GPIO: Unable to open FIFO at %s: %s\n", ctx->fifo_pathname, |
| strerror(errno)); |
| return NULL; |
| } |
| |
| printf( |
| "\n" |
| "GPIO: FIFO pipe created at %s for %d bit wide GPIO. Run\n" |
| "$ cat %s\n" |
| "to observe the output.\n", |
| ctx->fifo_pathname, ctx->n_bits, ctx->fifo_pathname); |
| |
| return (void *)ctx; |
| } |
| |
| void gpiodpi_device_to_host(void *ctx_void, svBitVecVal *gpio_data, |
| svBitVecVal *gpio_oe) { |
| struct gpiodpi_ctx *ctx = (struct gpiodpi_ctx *)ctx_void; |
| assert(ctx); |
| |
| // n_bits > 32 requires more sophisticated handling of svBitVecVal which we |
| // currently don't do (loop through the array of 32 bit values). |
| assert(ctx->n_bits <= 32 && "n_bits must be <= 32"); |
| |
| char gpio_str[32 + 1]; |
| for (int i = 0; i < ctx->n_bits; i++) { |
| gpio_str[ctx->n_bits - i - 1] = !!(gpio_data[0] & (1 << i)) + '0'; |
| } |
| |
| gpio_str[ctx->n_bits] = '\n'; |
| ssize_t written = write(ctx->fifo_fd, gpio_str, ctx->n_bits + 1); |
| assert(written == ctx->n_bits + 1); |
| } |
| |
| void gpiodpi_close(void *ctx_void) { |
| struct gpiodpi_ctx *ctx = (struct gpiodpi_ctx *)ctx_void; |
| if (!ctx) { |
| return; |
| } |
| int rv; |
| rv = close(ctx->fifo_fd); |
| if (rv != 0) { |
| printf("GPIO: Failed to close FIFO: %s\n", strerror(errno)); |
| } |
| rv = unlink(ctx->fifo_pathname); |
| if (rv != 0) { |
| printf("GPIO: Failed to unlink FIFO file at %s: %s\n", ctx->fifo_pathname, |
| strerror(errno)); |
| } |
| free(ctx); |
| } |