凌云实验室IGKBoard开发板BSP开发相关文件
guowenxue
2023-11-06 e8a7f91c44d7c2d600ab56b1a2d1a0cc9adbfb2a
Add driver user space test code
4 files added
719 ■■■■■ changed files
kernel/drivers/uapi/fbtest.c 395 ●●●●● patch | view | raw | blame | history
kernel/drivers/uapi/makefile 76 ●●●●● patch | view | raw | blame | history
kernel/drivers/uapi/test_key.c 173 ●●●●● patch | view | raw | blame | history
kernel/drivers/uapi/test_led.c 75 ●●●●● patch | view | raw | blame | history
kernel/drivers/uapi/fbtest.c
New file
@@ -0,0 +1,395 @@
/********************************************************************************
 *      Copyright:  (C) 2021 Guo Wenxue<Email:guowenxue@gmail.com QQ:281143292>
 *                  All rights reserved.
 *
 *       Filename:  fbtest.c
 *    Description:  This program used to:
 *                  1, Show framebuffer device information
 *                  2, Show RGB color on LCD full screen
 *                  3, Show BMP file on LCD;
 *
 *        Version:  1.0.0(08/26/22)
 *         Author:  Guo Wenxue <wenxue.guo@avnet.com>
 *      ChangeLog:  1, Release initial version on "08/26/22 12:56:31"
 *
 ********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <getopt.h>
#include <libgen.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <linux/fb.h>
#include <sys/mman.h>
#define PROG_VERSION      "1.0.0"
enum
{
    CMD_SHOW_INFO, /* show LCD info  */
    CMD_SHOW_RGB,  /* show RGB color */
    CMD_SHOW_BMP,  /* show BMP file  */
};
typedef struct fb_ctx_s
{
    int                       fd;       /* framebuffer file descriptor */
    char                      dev[64];  /* framebuffer device name */
    long                      fb_size;  /* framebuffer size */
    int                       pix_size; /* lcd screen pix size  */
    struct fb_var_screeninfo  vinfo;    /* framebuffer var information */
    char                     *fbp;      /* framebuffer mmap() address */
} fb_ctx_t;
int fb_init(fb_ctx_t *fb_ctx);
int fb_term(fb_ctx_t *fb_ctx);
int show_rgb(fb_ctx_t *fb_ctx, int times);
int show_bmp(fb_ctx_t *fb_ctx, char *bmp_file);
static void program_usage(char *progname)
{
    printf("Usage: %s [OPTION]...\n", progname);
    printf(" %s is a program to show RGB color or BMP file on LCD screen\n", progname);
    printf("\nMandatory arguments to long options are mandatory for short options too:\n");
    printf(" -d[device  ]  Specify framebuffer device, such as: /dev/fb0\n");
    printf(" -c[color   ]  Display RGB corlor on LCD screen for some times, such as: -c 3\n");
    printf(" -b[bmp     ]  Display BMP file, such as: -b bg.bmp\n");
    printf(" -h[help    ]  Display this help information\n");
    printf(" -v[version ]  Display the program version\n");
    printf("\n%s version %s\n", progname, PROG_VERSION);
    return;
}
int main (int argc, char **argv)
{
    fb_ctx_t                  fb_ctx;
    char                     *progname=NULL;
    char                     *bmp_file=NULL;
    char                     *fb_dev="/dev/fb0";
    int                       cmd = CMD_SHOW_INFO;
    int                       opt, times;
    struct option long_options[] = {
        {"device", required_argument, NULL, 'd'},
        {"color", required_argument, NULL, 'c'},
        {"bmp", required_argument, NULL, 'b'},
        {"version", no_argument, NULL, 'v'},
        {"help", no_argument, NULL, 'h'},
        {NULL, 0, NULL, 0}
    };
    progname = (char *)basename(argv[0]);
    /* Parser the command line parameters */
    while ((opt = getopt_long(argc, argv, "d:c:b:vh", long_options, NULL)) != -1)
    {
        switch (opt)
        {
            case 'd': /* Set framebuffer device */
                 fb_dev = optarg;
                break;
            case 'b': /* Set BMP file */
                bmp_file = optarg;
                cmd = CMD_SHOW_BMP;
                break;
            case 'c': /* Show RGB color */
                times = atoi(optarg);
                cmd = CMD_SHOW_RGB;
                break;
            case 'v':  /* Get software version */
                printf("%s version %s\n", progname, PROG_VERSION);
                return 0;
            case 'h':  /* Get help information */
                program_usage(progname);
                return 0;
            default:
                break;
        }
    }
    memset(&fb_ctx, 0, sizeof(fb_ctx));
    strncpy(fb_ctx.dev, fb_dev, sizeof(fb_ctx.dev));
    if( fb_init(&fb_ctx) < 0 )
    {
        printf("ERROR: Initial framebuffer device '%s' failure.\n", fb_ctx.dev);
        return 1;
    }
    switch( cmd )
    {
        case CMD_SHOW_RGB:
            show_rgb(&fb_ctx, times);
            break;
        case CMD_SHOW_BMP:
            show_bmp(&fb_ctx, bmp_file);
            break;
        default:
            break;
    }
    fb_term(&fb_ctx);
    return 0;
}
int fb_get_var_screeninfo(int fd, struct fb_var_screeninfo *vinfo)
{
    if( fd<0 || !vinfo )
    {
        printf("ERROR: Invalid input arguments\n");
        return -1;
    }
    if(ioctl(fd, FBIOGET_VSCREENINFO, vinfo))
    {
        printf("ERROR: ioctl() get variable info failure: %s\n", strerror(errno));
        return -2;
    }
    printf("LCD information : %dx%d, bpp:%d rgba:%d/%d,%d/%d,%d/%d,%d/%d\n", vinfo->xres, vinfo->yres, vinfo->bits_per_pixel,
            vinfo->red.length, vinfo->red.offset, vinfo->green.length, vinfo->green.offset,
            vinfo->blue.length,vinfo->blue.offset, vinfo->transp.length, vinfo->transp.offset);
    return 0;
}
int fb_init(fb_ctx_t *fb_ctx)
{
    struct fb_var_screeninfo    *vinfo;
    if( !fb_ctx || !strlen(fb_ctx->dev) )
    {
        printf("ERROR: Invalid input arguments\n");
        return -1;
    }
    if( (fb_ctx->fd=open(fb_ctx->dev, O_RDWR)) < 0 )
    {
        printf("ERROR: Open framebuffer device '%s' failure: %s\n", fb_ctx->dev, strerror(errno));
        return -2;
    }
    fb_get_var_screeninfo(fb_ctx->fd, &fb_ctx->vinfo);
    vinfo = &fb_ctx->vinfo;
    fb_ctx->fb_size = vinfo->xres * vinfo->yres * vinfo->bits_per_pixel / 8;
    fb_ctx->pix_size = vinfo->xres * vinfo->yres;
    fb_ctx->fbp =(char *)mmap(0, fb_ctx->fb_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_ctx->fd ,0);
    if ( !fb_ctx->fbp )
    {
        printf ("ERROR: Framebuffer mmap() failure: %s\n", strerror(errno));
        return -2;
    }
    vinfo->xoffset = 0;
    vinfo->yoffset = 0;
    return 0;
}
int fb_term(fb_ctx_t *fb_ctx)
{
    if( !fb_ctx )
    {
        printf("ERROR: Invalid input arguments\n");
        return -1;
    }
    munmap(fb_ctx->fbp, fb_ctx->fb_size);
    close (fb_ctx->fd);
    return 0;
}
int show_rgb_screen(fb_ctx_t *fb_ctx)
{
    struct fb_var_screeninfo    *vinfo;
    char                        *fb_addr;
    int                          interval = 1;
    int                          i, color;
    int                          bpp_bytes;
    if( !fb_ctx )
    {
        printf("ERROR: Invalid input arguments\n");
        return -1;
    }
    vinfo = &fb_ctx->vinfo;
    bpp_bytes = vinfo->bits_per_pixel / 8;
    printf("show full screen on red\n");
    color = (1<<vinfo->red.length-1) << vinfo->red.offset;
    fb_addr = fb_ctx->fbp;
    for(i=0; i<fb_ctx->pix_size; i++)
    {
        memcpy(fb_addr, &color, bpp_bytes);
        fb_addr += bpp_bytes;
    }
    sleep(interval);
    printf("show full screen on green\n");
    color = (1<<vinfo->green.length-1) << vinfo->green.offset;
    fb_addr = fb_ctx->fbp;
    for(i=0; i<fb_ctx->pix_size; i++)
    {
        memcpy(fb_addr, &color, bpp_bytes);
        fb_addr += bpp_bytes;
    }
    sleep(interval);
    printf("show full screen on blue\n");
    color = (1<<vinfo->blue.length-1) << vinfo->blue.offset;
    fb_addr = fb_ctx->fbp;
    for(i=0; i<fb_ctx->pix_size; i++)
    {
        memcpy(fb_addr, &color, bpp_bytes);
        fb_addr += bpp_bytes;
    }
    sleep(interval);
    return 0;
}
int show_rgb(fb_ctx_t *fb_ctx, int times)
{
    int       i;
    if( !fb_ctx )
    {
        printf("ERROR: Invalid input arguments\n");
        return -1;
    }
    for(i=0; i<times; i++)
    {
        show_rgb_screen(fb_ctx);
    }
    return 0;
}
/* BMP format: https://blog.csdn.net/weixin_39756273/article/details/110585675  */
typedef struct bmp_file_head_s
{
    uint8_t  bfType[2];        /* BMP file type: "BM" */
    int32_t bfSize;           /* BMP file size */
    int32_t bfReserved;       /* reserved */
    int32_t bfoffBits;        /* image data offset */
}__attribute__((packed)) bmp_file_head_t;
typedef struct bmp_bitmap_info_s
{
    int32_t biSize;           /* this struture size */
    int32_t biWidth;          /* image width in pix */
    int32_t biHeight;         /* image height in pix */
    uint16_t biPlanes;         /* display planes, always be 1 */
    uint16_t biBitCount;       /* bpp: 1,4,8,16,24,32 */
    int32_t biCompress;       /* compress type */
    int32_t biSizeImage;      /* image size in byte */
    int32_t biXPelsPerMeter;  /* x-res in pix/m */
    int32_t biYPelsPerMeter;  /* y-res in pix/m */
    int32_t biClrUsed;
    int32_t biClrImportant;
}__attribute__((packed)) bmp_bitmap_info_t;
/*
 * BMP image file format:
 * +----------------+------------------+--------------------+---------------+
 * | File Head(14B) | Bitmap Info(40B) | color palette(OPT) |  bitmap data  |
 * +----------------+------------------+--------------------+---------------+
 */
int show_bmp(fb_ctx_t *fb_ctx, char *bmp_file)
{
    struct fb_var_screeninfo    *vinfo;
    char                        *fb_addr;
    bmp_file_head_t            *file_head;
    bmp_bitmap_info_t          *bitmap_info;
    struct stat                 statbuf;
    char                       *f_addr;
    char                       *d_addr;
    char                       *p_addr;
    int                         fd;
    int                         bpp_bytes;
    int                         i, j;
    int                         width, height;
    if( !fb_ctx || !bmp_file )
    {
        printf("ERROR: Invalid input arguments\n");
        return -1;
    }
    if( (fd=open(bmp_file, O_RDONLY)) < 0 )
    {
        printf("ERROR: Open file '%s' failure: %s\n", bmp_file, strerror(errno));
        return -2;
    }
    fstat(fd, &statbuf);
    f_addr =(char *)mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd ,0);
    if ( !f_addr )
    {
        printf ("ERROR: BMP file mmap() failure: %s\n", strerror(errno));
        return -2;
    }
    /* BMP file header */
    file_head = (bmp_file_head_t *)f_addr;
    if( memcmp(file_head->bfType, "BM", 2) != 0)
    {
        printf("ERROR: It's not a BMP file\n");
        return -3;
    }
    /* BMP bitmap information header */
    bitmap_info = (bmp_bitmap_info_t *)(f_addr+sizeof(bmp_file_head_t));
    /* BMP bitmap data */
    d_addr = f_addr + file_head->bfoffBits;
    vinfo = &fb_ctx->vinfo;
    fb_addr = fb_ctx->fbp;
    bpp_bytes = vinfo->bits_per_pixel / 8;
    width = bitmap_info->biWidth>vinfo->xres ? vinfo->xres : bitmap_info->biWidth;
    height = bitmap_info->biHeight>vinfo->yres ? vinfo->yres : bitmap_info->biHeight;
    printf("BMP file '%s': %dx%d and display %dx%d\n", bmp_file, bitmap_info->biWidth, bitmap_info->biHeight, width, height);
    /* if biHeight is positive, the bitmap is a bottom-up DIB */
    for(i=0; i<height; i++)
    {
        p_addr=d_addr+(height-1-i)*bitmap_info->biWidth*bpp_bytes;
        memcpy(fb_addr, p_addr, bpp_bytes*width);
        fb_addr += bpp_bytes * vinfo->xres;
    }
    munmap(f_addr, statbuf.st_size);
    close (fd);
    return 0;
}
kernel/drivers/uapi/makefile
New file
@@ -0,0 +1,76 @@
#*********************************************************************************
#      Copyright:  (C) 2021 Guo Wenxue <guowenxue@gmail.com>
#                  All rights reserved.
#
#       Filename:  Makefile
#    Description:  This Makefile used to compile all the C source code file in current
#                  folder to respective excutable binary files.
#
#        Version:  1.0.0(11/17/2021~)
#                  Author:  Guo Wenxue <guowenxue@gmail.com>
#      ChangeLog:  1, Release initial version on "11/17/2021 01:29:33 PM"
#
#********************************************************************************/
PWD=$(shell pwd)
INSTPATH=/tftp
CROSS_COMPILE=/opt/gcc-aarch32-10.3-2021.07/bin/arm-none-linux-gnueabihf-
export CC=${CROSS_COMPILE}gcc
export CXX=${CROSS_COMPILE}g++
export AR=${CROSS_COMPILE}ar
export AS=${CROSS_COMPILE}as
export RANLIB=${CROSS_COMPILE}ranlib
export STRIP=${CROSS_COMPILE}strip
LIB_PATH=$(shell dirname ${PWD})
LIB_NAME=$(shell basename ${LIB_PATH})
CFLAGS+=-I${LIB_PATH}
#LDFLAGS+=-L${LIB_PATH} -l${LIB_NAME}
#LDFLAGS+=-static
SRCS = $(wildcard ${VPATH}/*.c)
OBJS = $(patsubst %.c,%.o,$(SRCS))
SRCFILES = $(wildcard *.c)
BINARIES=$(SRCFILES:%.c=%)
all: entry binaries install
libs:
    make -C ..
entry:
    @echo " ";
    @echo " =========================================================";
    @echo " **      Cross  compile \"${BINARIES}\"                   ";
    @echo " =========================================================";
    @make clean
binaries:  ${BINARIES}
    @echo " Compile over"
%:  %.c
    $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
tag:
    @ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R .
    @cscope -Rbq
install:
    cp $(BINARIES) ${INSTPATH}
clean:
    @rm -f version.h
    @rm -f *.o *.lo $(BINARIES)
    @rm -rf *.gdb *.a *.so *.elf*
    @rm -f *.log
distclean: clean
    @rm -f  tags cscope*
.PHONY: clean entry
kernel/drivers/uapi/test_key.c
New file
@@ -0,0 +1,173 @@
/*********************************************************************************
 *      Copyright:  (C) 2021 Guo Wenxue<Email:guowenxue@gmail.com QQ:281143292>
 *                  All rights reserved.
 *
 *       Filename:  test_key.c
 *    Description:  This file used to test GPIO button driver builtin Linux kernel on ARM board
 *
 *        Version:  1.0.0(11/17/2021~)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "11/17/2021 02:46:18 PM"
 *
 ********************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <libgen.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#include <linux/kd.h>
#include <linux/keyboard.h>
#if 0 /* Just for comment here, Reference to linux-3.3/include/linux/input.h */
struct input_event
{
    struct timeval time;
    __u16 type;  /* 0x00:EV_SYN 0x01:EV_KEY 0x04:EV_MSC 0x11:EV_LED*/
    __u16 code;  /* key value, which key */
    __s32 value; /* 1: Pressed  0:Not pressed  2:Always Pressed */
};
#endif
#define EV_RELEASED        0
#define EV_PRESSED         1
#define BUTTON_CNT         10
void usage(char *name);
void display_button_event(struct input_event *ev, int cnt);
int main(int argc, char **argv)
{
    char                  *kbd_dev = "/dev/input/event2";
    char                  kbd_name[256] = "Unknown";
    int                   kbd_fd = -1;
    int                   rv, opt;
    int                   size = sizeof (struct input_event);
    fd_set                rds;
    struct input_event    ev[BUTTON_CNT];
    struct option long_options[] = {
        {"device", required_argument, NULL, 'd'},
        {"help", no_argument, NULL, 'h'},
        {NULL, 0, NULL, 0}
    };
    while ((opt = getopt_long(argc, argv, "d:h", long_options, NULL)) != -1)
    {
        switch (opt)
        {
            case 'd':
                kbd_dev = optarg;
                break;
            case 'h':
                usage(argv[0]);
                return 0;
            default:
                break;
        }
    }
    if(NULL == kbd_dev)
    {
        usage(argv[0]);
        return -1;
    }
    if ((getuid ()) != 0)
        printf ("You are not root! This may not work...\n");
    if ((kbd_fd = open(kbd_dev, O_RDONLY)) < 0)
    {
        printf("Open %s failure: %s", kbd_dev, strerror(errno));
        return -1;
    }
    ioctl (kbd_fd, EVIOCGNAME (sizeof (kbd_name)), kbd_name);
    printf ("Monitor input device %s (%s) event on poll mode:\n", kbd_dev, kbd_name);
    while (1)
    {
        FD_ZERO(&rds);
        FD_SET(kbd_fd, &rds);
        rv = select(kbd_fd + 1, &rds, NULL, NULL, NULL);
        if (rv < 0)
        {
            printf("Select() system call failure: %s\n", strerror(errno));
            goto CleanUp;
        }
        else if (FD_ISSET(kbd_fd, &rds))
        {
            if ((rv = read (kbd_fd, ev, size*BUTTON_CNT )) < size)
            {
                printf("Reading data from kbd_fd failure: %s\n", strerror(errno));
                break;
            }
            else
            {
                display_button_event(ev, rv/size);
            }
        }
    }
CleanUp:
    close(kbd_fd);
    return 0;
}
void usage(char *name)
{
    char *progname = NULL;
    char *ptr = NULL;
    ptr = strdup(name);
    progname = basename(ptr);
    printf("Usage: %s [-p] -d <device>\n", progname);
    printf(" -d[device  ] button device name\n");
    printf(" -p[poll    ] Use poll mode, or default use infinit loop.\n");
    printf(" -h[help    ] Display this help information\n");
    free(ptr);
    return;
}
void display_button_event(struct input_event *ev, int cnt)
{
    int i;
    struct timeval        pressed_time, duration_time;
    for(i=0; i<cnt; i++)
    {
        if(EV_KEY==ev[i].type && EV_PRESSED==ev[i].value)
        {
            pressed_time = ev[i].time;
            printf("Keypad[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);
        }
        if(EV_KEY==ev[i].type && EV_RELEASED==ev[i].value)
        {
            timersub(&ev[i].time, &pressed_time, &duration_time);
            printf("keypad[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);
            printf("keypad[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);
        }
    } /*  for(i=0; i<cnt; i++) */
}
kernel/drivers/uapi/test_led.c
New file
@@ -0,0 +1,75 @@
/*********************************************************************************
 *      Copyright:  (C) 2021 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  test_led.c
 *    Description:  This file is imx6ull LED test program
 *
 *        Version:  1.0.0(2021年11月17日)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "2021年11月17日 22时59分31秒"
 *
 ********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define CLASS_LED    "/sys/class/leds"
int turn_led(char *which, unsigned char brightness);
int main (int argc, char **argv)
{
    while(1)
    {
        turn_led("sysled", 255);
        sleep(1);
        turn_led("sysled", 0);
        sleep(1);
    }
    return 0;
}
int turn_led(char *which, unsigned char brightness)
{
    char            led_path[64] = {0x0};
    char            buf[5] = {0x0};
    int             fd = -1;
    int             rv = 0;
    if( !which )
    {
        printf("%s() Invalid input arguments\n", __func__);
        return -1;
    }
    snprintf(led_path, sizeof(led_path), "%s/%s/brightness", CLASS_LED, which);
    if( (fd=open(led_path, O_WRONLY)) < 0 )
    {
        printf("Open led file '%s' failure: %s\n", strerror(errno));
        return -2;
    }
    snprintf(buf, sizeof(buf), "%d", brightness);
    if( write(fd, buf, strlen(buf)) < 0 )
    {
        printf("Open led file '%s' failure: %s\n", strerror(errno));
        rv = -3;
    }
    close(fd);
    return rv;
}