#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "piolib.h"
#include "piolib_priv.h"
#define PIO_MAX_INSTANCES 4
static __thread PIO __pio;
static PIO pio_instances[PIO_MAX_INSTANCES];
static uint num_instances;
static pthread_mutex_t pio_handle_lock;
void pio_select(PIO pio)
{
__pio = pio;
}
PIO pio_get_current(void)
{
PIO pio = __pio;
check_pio_param(pio);
return pio;
}
int pio_get_index(PIO pio)
{
int i;
for (i = 0; i < PIO_MAX_INSTANCES; i++)
{
if (pio == pio_instances[i])
return i;
}
return -1;
}
int pio_init(void)
{
#if LIBRARY_BUILD
const PIO_CHIP_T *const *start = &library_piochips[0];
const PIO_CHIP_T *const *end = &library_piochips[0] + library_piochips_count;
#else
const PIO_CHIP_T *const *start = &__start_piochips;
const PIO_CHIP_T *const *end = &__stop_piochips;
#endif
static bool initialised;
const PIO_CHIP_T * const *p;
uint i = 0;
int err;
if (initialised)
return 0;
num_instances = 0;
p = start;
while (p < end)
{
PIO_CHIP_T *chip = *p;
PIO pio = chip->create_instance(chip, i);
if (pio && !PIO_IS_ERR(pio)) {
pio_instances[num_instances++] = pio;
i++;
} else {
p++;
i = 0;
}
}
err = pthread_mutex_init(&pio_handle_lock, NULL);
if (err)
return err;
initialised = true;
return 0;
}
PIO pio_open(uint idx)
{
PIO pio = NULL;
int err;
err = pio_init();
if (err)
return PIO_ERR(err);
if (idx >= num_instances)
return PIO_ERR(-EINVAL);
pthread_mutex_lock(&pio_handle_lock);
pio = pio_instances[idx];
if (pio) {
if (pio->in_use)
err = -EBUSY;
else
pio->in_use = 1;
}
pthread_mutex_unlock(&pio_handle_lock);
if (err)
return PIO_ERR(err);
err = pio->chip->open_instance(pio);
if (err) {
pio->in_use = 0;
return PIO_ERR(err);
}
pio_select(pio);
return pio;
}
PIO pio_open_by_name(const char *name)
{
int err = -ENOENT;
uint i;
err = pio_init();
if (err)
return PIO_ERR(err);
for (i = 0; i < num_instances; i++) {
PIO p = pio_instances[i];
if (!strcmp(name, p->chip->name))
break;
}
if (i == num_instances)
return PIO_ERR(-ENOENT);
return pio_open(i);
}
PIO pio_open_helper(uint idx)
{
PIO pio = pio_instances[idx];
if (!pio || !pio->in_use) {
pio = pio_open(idx);
if (PIO_IS_ERR(pio)) {
printf("* Failed to open PIO device %d (error %d)\n",
idx, PIO_ERR_VAL(pio));
exit(1);
}
}
return pio;
}
void pio_close(PIO pio)
{
pio->chip->close_instance(pio);
pthread_mutex_lock(&pio_handle_lock);
pio->in_use = 0;
pthread_mutex_unlock(&pio_handle_lock);
}
void pio_panic(const char *msg)
{
fprintf(stderr, "PANIC: %s\n", msg);
exit(1);
}
void sleep_us(uint64_t us) {
const struct timespec tv = {
.tv_sec = (us / 1000000),
.tv_nsec = 1000ull * (us % 1000000)
};
nanosleep(&tv, NULL);
}