#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <sched.h> #include <sys/mman.h> #include <errno.h> #include <linux/ioctl.h> #include <linux/types.h> #define MMIO_SUCCESS 0 #define MMIO_ERROR_DEVMEM -1 #define MMIO_ERROR_MMAP -2 #define PAD_TOP_BK_ADDR (0x00000B00) #define TOP_GPIO_OUT_OFFSET (0x0000006A) #define TOP_GPIO_IN_OFFSET (0x00000019) #define PAD_TOP_BK_ADDR (0x00000B00) #define TOP_GPIO_OUT_OFFSET (0x0000006A) #define TOP_GPIO_IN_OFFSET (0x00000019) #define GPIO_OUT_REG_ADDR (0x1F000000+(PAD_TOP_BK_ADDR<<1)+(TOP_GPIO_OUT_OFFSET<<2)) #define GPIO_IN_REG_ADDR (0x1F000000+(PAD_TOP_BK_ADDR<<1)+(TOP_GPIO_IN_OFFSET <<2)) #define BASE 0x1F001000 #define GPIO_NUM_RANGE_MIN 84 /* Linerequest flags */ #define GPIOHANDLE_REQUEST_INPUT (1UL << 0) #define GPIOHANDLE_REQUEST_OUTPUT (1UL << 1) #define GPIOHANDLE_REQUEST_ACTIVE_LOW (1UL << 2) #define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3) #define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4) #define GPIO_GET_CHIPINFO_IOCTL _IOR(0xB4, 0x01, struct gpiochip_info) #define GPIO_GET_LINEINFO_IOCTL _IOWR(0xB4, 0x02, struct gpioline_info) #define GPIO_GET_LINEHANDLE_IOCTL _IOWR(0xB4, 0x03, struct gpiohandle_request) #define GPIO_GET_LINEEVENT_IOCTL _IOWR(0xB4, 0x04, struct gpioevent_request) #define GPIOHANDLES_MAX 64 struct gpiohandle_request { __u32 lineoffsets[GPIOHANDLES_MAX]; __u32 flags; __u8 default_values[GPIOHANDLES_MAX]; char consumer_label[32]; __u32 lines; int fd; }; #ifdef DEBUG_ENV #define fprintff(fmt,args...) fprintf(fmt ,##args) #define DEBINFO __FILE__, __LINE__, __FUNCTION__ #else #define fprintff(fmt,args...) #endif int s500_mmio_init(void); int s500_mmio_set_output(int gpio_number, char *device_name); int s500_mmio_set_input(int gpio_number, char *device_name); void s500_mmio_set_high(int gpio_number); void s500_mmio_set_low(int gpio_number); int s500_mmio_read_input(int gpio_number); void set_max_priority(void); void set_default_priority(void);
gpio.c
#include "gpio.h"
volatile unsigned char *s500_mmio_gpio_out = NULL;
volatile unsigned char *s500_mmio_gpio_in = NULL;
off_t page_base;
off_t page_offset_in, page_offset_out;
int s500_mmio_init(void) {
if (s500_mmio_gpio_in == NULL && s500_mmio_gpio_out == NULL)
{
size_t pagesize = sysconf(_SC_PAGE_SIZE);
int fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd == -1) {
// Error opening /dev/mem. Probably not running as root.
return MMIO_ERROR_DEVMEM;
}
// Map GPIO memory to location in process space.
page_base = (GPIO_IN_REG_ADDR / pagesize) * pagesize;
page_offset_in = GPIO_IN_REG_ADDR - page_base;
fprintff(stdout, "page_offset_in=0x%X, page_offset_out=0x%x\n", page_offset_in, page_offset_out);
s500_mmio_gpio_in = mmap(NULL, page_offset_in+1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, page_base);
page_base = (GPIO_OUT_REG_ADDR / pagesize) * pagesize;
page_offset_out = GPIO_OUT_REG_ADDR - page_base;
s500_mmio_gpio_out = mmap(NULL, page_offset_out+1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, page_base);
close(fd);
if (s500_mmio_gpio_in == MAP_FAILED || s500_mmio_gpio_out == MAP_FAILED)
{
// Don't save the result if the memory mapping failed.
s500_mmio_gpio_in = NULL;
s500_mmio_gpio_out = NULL;
return MMIO_ERROR_MMAP;
}
}
return MMIO_SUCCESS;
}
int s500_mmio_set_input(int gpio_number, char *device_name)
{
int fd=0;
int ret=0;
char *chrdev_name;
struct gpiohandle_request req;
ret = asprintf(&chrdev_name, "/dev/%s", device_name);
if (ret < 0)
{
fprintf(stderr, "can't open /dev/%s", device_name);
return -ENOMEM;
}
fd = open(chrdev_name, 0);
if (fd == -1)
{
ret = -errno;
fprintf(stderr, "Failed to open %s\n", chrdev_name);
goto exit_close_error;
}
req.lineoffsets[0] = gpio_number;
req.flags = GPIOHANDLE_REQUEST_INPUT;
req.lines = 1;
ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
if (ret == -1)
{
ret = -errno;
fprintf(stderr, "Failed to issue GET LINEHANDLE IOCTL (%d)\n",ret);
goto exit_close_error;
}
exit_close_error:
if (close(fd) == -1)
perror("Failed to close GPIO character device file");
free(chrdev_name);
return ret;
}
int s500_mmio_set_output(int gpio_number, char *device_name)
{
int fd=0;
int ret=0;
char *chrdev_name;
struct gpiohandle_request req;
ret = asprintf(&chrdev_name, "/dev/%s", device_name);
if (ret < 0)
{
fprintf(stderr, "can't open /dev/%s", device_name);
return -ENOMEM;
}
fd = open(chrdev_name, 0);
if (fd == -1)
{
ret = -errno;
fprintf(stderr, "Failed to open %s\n", chrdev_name);
goto exit_close_error;
}
req.lineoffsets[0] = gpio_number;
req.flags = GPIOHANDLE_REQUEST_OUTPUT;
req.lines = 1;
ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
if (ret == -1)
{
ret = -errno;
fprintf(stderr, "Failed to issue GET LINEHANDLE IOCTL (%d)\n",ret);
goto exit_close_error;
}
exit_close_error:
if (close(fd) == -1)
perror("Failed to close GPIO character device file");
free(chrdev_name);
return ret;
}
int s500_mmio_read_input(int gpio_number) {
return (*(s500_mmio_gpio_in+page_offset_in) & (1 << (gpio_number - GPIO_NUM_RANGE_MIN )) ? 1 : 0);
}
void s500_mmio_set_high(int gpio_number)
{
*(s500_mmio_gpio_out+page_offset_out) |= (1 << (gpio_number-GPIO_NUM_RANGE_MIN));
}
void s500_mmio_set_low(int gpio_number)
{
*(s500_mmio_gpio_out+page_offset_out) &= (1 << (gpio_number-GPIO_NUM_RANGE_MIN));
}
void set_max_priority(void) {
struct sched_param sched;
memset(&sched, 0, sizeof(sched));
// Use FIFO scheduler with highest priority for the lowest chance of the kernel context switching.
sched.sched_priority = sched_get_priority_max(SCHED_FIFO);
sched_setscheduler(0, SCHED_FIFO, &sched);
}
void set_default_priority(void) {
struct sched_param sched;
memset(&sched, 0, sizeof(sched));
// Go back to default scheduler with default 0 priority.
sched.sched_priority = 0;
sched_setscheduler(0, SCHED_OTHER, &sched);
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "gpio.h"
int main (int argc, char **argv)
{
if (argc < 2)
{
printf("ex: ./main 88");
return;
}
int gpio_num=atoi(argv[1]);
int ret=0;
printf("num=%d\n", gpio_num);
if (s500_mmio_init() < 0)
printf("error open mem!n");
set_max_priority();
ret=s500_mmio_set_input(gpio_num, "gpiochip0");
for(;;)
{
ret=s500_mmio_read_input(gpio_num);
usleep(500*1000);
fprintf(stdout, "\rret=%d", ret);
fflush(stdout);
}
set_default_priority();
}
沒有留言:
張貼留言