Linux嵌入式驱动开发——platform机制的使用(led驱动示例实现)

简介: Linux嵌入式驱动开发——platform机制的使用(led驱动示例实现)

文章目录

linux内核分离思想,platform机制

使用platform的方式方法

struct platform_device如何使用

struct platform_driver如何使用

代码示例及操作步骤

相关问题

单设备文件多LED控制(代码示例)


linux内核分离思想,platform机制

分析:


  • 一个完整的硬件设备驱动必然包含两个部分:

  • 纯硬件相关内容:寄存器的起始地址,GPIO编号等;

  • 纯软件相关内容:if…else,混杂设备,接口等;

  • 纯软件用来操作纯硬件 。

  • 如果仅仅是硬件GPIO编号进行了改动,驱动的改动仅仅也只是修改硬件相关(寄存器的起始地址和GPIO编号)的修改,软件无需改动。

  • 但是实际修改过程中发现代码的改动量相当之大,如果让驱动代码的改动量小,移植性好,首先想到利用宏替换驱动代码中的硬件相关的内容

  • 但是寄存器的起始地址,GPIO编号他们同样是“事物”同样具有额外的其他属性,利用宏不能完整描述特性,势必要考虑到结构体进行描述

结论:


  • linux内核如何做到既可以让驱动的可移植性变得好并且对硬件信息的描述更加的丰富呢?

  • 利用linux内核的分离思想,platform机制分离思想:就是将驱动的纯硬件信息和纯软件信息进行彻底分开,一旦将来软件写好,就无需改动,将来驱动开发者的重心放在硬件信息即可,本质目的就是让驱动代码的可移植性变得非常好

  • 问:如何实现内核的分离思想呢?

  • 答:利用platform机制

  • 问:内核的platform机制如何实现的呢?

  • 答:ftp://DRV/ESD_DRV_09.ppt

  • 总结:驱动如果采用platform机制实现,只需关注以下两个数据结构:

struct platform_device
struct platform_driver

使用platform的方式方法

  • platform_device装载硬件信息的方法有三种:
  • 1.单独使用struct resource进行描述
  • 2.单独使用自定义的描述硬件信息的数据结构来描述
  • 3.可以同时使用struct resource和自定义的描述硬件信息的数据结构来描述硬件信息
  • 两个配套函数:
  • platform_device_register(&硬件节点对象)向内核dev链表添加注册硬件节点对象, 一旦添加完毕,什么遍历drv链表,什么匹配,什么调用probe函数,什么给probe函数传递硬件节点的首地址这些都是由内核完成!如果一旦匹配成功,硬件节点对象的首地址会传递给匹配成功的软件节点的probe函数

  • platform_device_unregister(&硬件节点对象) , 从内核的dev链表删除硬件节点对象,内核会调用软件节点的remove函数


struct platform_device如何使用

struct platform_device {
    const char  * name;
    int  id;
    struct resource * resource;
    u32  num_resources;
    struct device dev;
      .platform_data
    ...
   };


  • 功能:用于描述一个驱动中纯硬件信息
  • 成员说明:
  • name:硬件节点的名称,将来用于匹配,必须初始化
  • id:硬件节点的编号,如果dev链表上,仅有一个名称为name的硬件节点,id=-1即可,如果dev链表上,有多个名称为name(同名),通过id进行编号(0,1,2,…)
  • resource:装载纯硬件信息相关内容

struct resource 结构体描述


struct resource {
  unsigned long start;
  unsigned long end;
  unsigned long flags;
  ...
};


  • 功能:用于描述硬件信息
  • 成员:
  • start:起始硬件信息,例如:寄存器的起始地址

  • end:结束硬件信息,例如:寄存器的结束地址

  • flags:硬件信息的标志

  • IORESOURCE_MEM:用于指示此硬件信息为地址信息 0xC001C000这个物理地址可以用此标志修饰
  • IORESOURCE_IRQ:用于指示此硬件信息为GPIO信息,PAD_GPIO_C+12这个GPIO可以用此标志进行修饰
  • num_resources:用来指示用struct resource描述的硬件信息的个数

  • dev:此结构体变量中重点关注其中的void *platform_data字段

  • platform_data字段可以用来装载驱动开发者自定义的硬件信息

  • 例如:自定义的硬件信息


struct led_resource{
    .gpio
    .name
}
 struct btn_resource{
    .gpio
    .name
    .code
}


struct platform_driver如何使用

struct platform_driver {
  int (*probe)(struct platform_device *pdev);
  int (*remove)(struct platform_device *pdev);
  struct device_driver driver;
  ...
};


  • 功能:描述一个驱动中纯软件相关内容
  • 成员说明:
  • probe: 一旦纯硬件节点和纯软件节点匹配成功,内核就会调用此函数,也就是说此函数是否被调用,至关重要, probe函数被调用,说明硬件软件匹配成功,一个完整的,硬件设备驱动诞生,这样纯软件才可以踏踏实实访问, 纯硬件形参pdev指针指向匹配成功的硬件节点对象 。

  • remove:从dev链表删除硬件节点或者从drv链表删除
  • 软件节点,不管删除哪一个,都代表这个驱动不再完整
  • 此时内核就会调用remove函数
  • remove函数和probe函数是一对死对头!
  • 形参pdev指针指向匹配成功的硬件节点对象

  • driver:重点关注其中的name字段,此字段将来用于匹配


配套函数:


  • platform_driver_register(&软件节点对象) 向内核drv链表添加软件节点对象,内核会帮你遍历dev链表,帮你匹配,如果匹配成功,帮你调用probe函数,帮你把匹配成功的硬件节点传递给probe函数。

  • platform_driver_unregister(&软件节点对象) 从内核drv链表删除软件节点, 内核会调用软件节点的remove函数 。


代码示例及操作步骤

  • led_dev.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
//声明描述LED硬件相关的数据结构
struct led_resource {
    unsigned long phys_address; //寄存器的起始物理地址
    int size; //寄存器存储空间的大小
    int pin; //引脚编号
};
//定义初始化LED1的硬件信息对象
static struct led_resource led1 = {
    .phys_address = 0xC001C000,
    .size = 0x24,
    .pin = 17
};
//仅仅去除警告
static void led_release(struct device *dev) {}
//定义初始化描述LED的硬件信息节点对象
static struct platform_device led_dev = {
    .name = "tarena", //用于匹配
    .id = -1,//硬件节点编号
    .dev = {
        .platform_data = &led1,//装载自定义的硬件信息 
        .release = led_release //仅仅是为了去除警告而已
    }
};
static int led_dev_init(void)
{
    //1.向内核dev链表添加注册硬件节点对象即可
    //内核会帮你遍历drv链表,匹配,调用,传参
    platform_device_register(&led_dev);
    return 0;
}
static void led_dev_exit(void)
{
    //从内核的dev链表删除硬件节点对象
    platform_device_unregister(&led_dev);
}
module_init(led_dev_init);
module_exit(led_dev_exit);
MODULE_LICENSE("GPL");


  • led_drv.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/io.h>
#include <linux/uaccess.h>
//声明描述LED硬件信息的数据结构
struct led_resource {
    unsigned long phys_address;
    int size;
    int pin;
};
static void *gpiobase;
static unsigned long *gpioout, *gpiooutenb, *gpioaltfn0;
static int pin1;
#define LED_ON  0x100001
#define LED_OFF 0x100002
static long led_ioctl(struct file *file,
                        unsigned int cmd,
                        unsigned long arg)
{
    //1.分配内核缓冲区
    int kindex;
    //2.拷贝用户数据到内核
    copy_from_user(&kindex, (int *)arg,  sizeof(kindex));
    //3.解析用户命令
    switch(cmd) {
        case LED_ON:
                if(kindex == 1)
                    *gpioout &= ~(1 << pin1);
                /*else ... if*/
            break;
        case LED_OFF:
                if(kindex == 1)
                    *gpioout |= (1 << pin1);
                /*else ... if*/
            break;
        default:
            return -1;
    }
    return 0;
}
//定义初始化硬件操作接口对象
static struct file_operations led_fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = led_ioctl
};
//定义初始化混杂设备对象
static struct miscdevice led_misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "myled",
    .fops = &led_fops
};
//匹配成功,内核调用
//pdev:指向匹配成功的硬件节点
//pdev=led_dev.c中的&led_dev
static int led_probe(struct platform_device *pdev)
{
    //1.通过pdev指针获取自定义的硬件信息
    //pdata=&led1(led_dev.c中)
    struct led_resource *pdata = pdev->dev.platform_data;
    //2.处理硬件信息
    //2.1.将硬件寄存器的物理地址映射到内核虚拟地址上
    gpiobase = ioremap(pdata->phys_address, pdata->size);
    gpioout = (unsigned long *)(gpiobase + 0x00);
    gpiooutenb = (unsigned long *)(gpiobase + 0x04);
    gpioaltfn0 = (unsigned long *)(gpiobase + 0x20);
    //获取GPIO编号
    pin1 = pdata->pin;
    //2.2配置为GPIO功能,配置为输出,输出1
    *gpioaltfn0 &= ~(0x3 << (2*pin1));
    *gpioaltfn0 |= (1 << (2*pin1));
    *gpiooutenb |= (1 << pin1);
    *gpioout |= (1 << pin1);
    //3.注册混杂设备对象
    misc_register(&led_misc);
    return 0; //执行成功返回0,执行失败返回负值
}
//删除软件或者硬件节点,内核调用
//pdev:指向匹配成功的硬件节点
//pdev=led_dev.c中的&led_dev
static int led_remove(struct platform_device *pdev)
{
    //1.卸载混杂设备
    misc_deregister(&led_misc);
    //2.输出1,解除地址映射
    *gpioout |= (1 << pin1);
    iounmap(gpiobase);
    return 0; //执行成功返回0,执行失败返回负值
}
//定义初始化软件节点对象
static struct platform_driver led_drv = {
    .driver = {
        .name = "tarena" //用于匹配
    },
    .probe = led_probe, //匹配成功,内核调用
    .remove = led_remove, //卸载软件或者硬件,内核调用
};
static int led_drv_init(void)
{
    //1.向内核drv链表注册软件节点对象
    //什么遍历,什么匹配,什么调probe,什么传参都是内核完成
    platform_driver_register(&led_drv);
    return 0;
}
static void led_drv_exit(void)
{
    //1.从内核的drv链表删除软件节点对象
    //内核调用remove函数
    platform_driver_unregister(&led_drv);
}
module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");


  • Makefile
obj-m += led_drv.o led_dev.o
all:
  make -C /opt/kernel SUBDIRS=$(PWD) modules
clean:
  make -C /opt/kernel SUBDIRS=$(PWD) clean


  • led_test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#define LED_ON  0x100001 //开灯命令
#define LED_OFF 0x100002 //关灯命令
int main(int argc, char *argv[])
{
    int fd;
    int index; //分配用户缓冲区,保存操作灯的编号
    if(argc != 3) {
        printf("用法:%s <on|off> <1|2|3|4>\n", argv[0]);
        return -1;
    }
    //打开设备
    fd = open("/dev/myled", O_RDWR);
    if (fd < 0) {
        printf("打开设备失败!\n");
        return -1;
    }
    //"1"->1
    index = strtoul(argv[2], NULL, 0);
    //应用ioctl->软中断->内核sys_ioctl->驱动led_ioctl
    if(!strcmp(argv[1], "on"))
        ioctl(fd, LED_ON, &index);
    else if(!strcmp(argv[1], "off"))
        ioctl(fd, LED_OFF, &index);
    //关闭设备
    close(fd);
    return 0;
}


实施步骤:


  • 上位机执行:

mkdir /opt/drivers/day10/1.0 -p
   cd /opt/drivers/day10/1.0
   touch led_dev.c led_drv.c 
   vim led_drv.c
   vim Makefile
   make
   cp *.ko /opt/rootfs/home/drivers/


  • 下位机执行:

 

cd /home/drivers
   insmod led_dev.ko 
   insmod led_drv.ko //查看probe函数是否被调用
   rmmod led_drv //查看remove函数是否被调用
   rmmod led_dev          
   insmod led_drv.ko
   insmod led_dev.ko //查看probe函数是否被调用
   rmmod led_dev //查看remove函数是否被调用
   rmmod led_drv
  #使用test demo
/home# insmod led_drv.ko
/home# insmod led_dev.ko //查看probe函数是否被调用
/home# cat /proc/devices //查看当前设备号,使用的是混杂设备 所以主设备号固定为10
/home# cat /sys/class/misc/myled/dev 
10:41
/home# mknode /dev/myled c 10 41 //创建设备文件在/dev下
/home# ./led_test on 1 //点亮LED灯。
/home# ./led_test off 1 //关闭LED灯。

相关问题

  • 问:probe函数做哪些工作呢?

  • 答:明确:probe函数被调用预示着一个完整的驱动诞生预示着纯软件可以操作访问纯硬件

  • probe函数一般做如下工作:

  • 1.通过形参pdev指针获取匹配成功的纯硬件信息(寄存器物理地址,编号等)
  • 2.要处理获取到的纯硬件信息(各种该): 该地址映射的地址映射; 该申请资源的申请资源; 该注册的注册; 该初始化的初始化
  • 3.注册混杂设备或者字符设备给用户提供访问操作硬件的接口
  • 总结:2,3两个步骤之前都是在驱动的入口函数中完成, 而现在统一放在probe函数中完成 remove和probe对着干!

  • 问:probe函数通过形参pdev指针如何获取到纯硬件信息呢(resource描述的硬件信息)

  • 答:用以下函数即可获取
struct resource *platform_get_resource(
            struct platform_device *pdev,
            unsigned long flags,
            int index
            )


  • 函数功能:probe函数或者remove函数通过形参pdev 指针来获取到匹配成功的resource描述的硬件信息
  • 参数:
  • pdev:传递匹配成功的硬件节点的首地址
  • flags:要获取的硬件信息的类型,要不是IORESOURCE_MEM要不是IORESOURCE_IRQ
  • index:同类型资源的偏移量
  • 返回值:返回获取的resource描述的硬件信息对象首地址

单设备文件多LED控制(代码示例)

在led_dev.c文件中的申请多个LED的信息,在led_drv.c中获取并使用,具体如下:


  • led_dev.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <mach/platform.h>
#include <linux/gpio.h>
//声明描述LED硬件相关的数据结构
//定义初始化LED1的硬件信息对象
static struct resource led_info[] = {
    {
        .start = 0xC001C000,
        .end = 0xC001C000 + 0x24,
        .flags = IORESOURCE_MEM //地址类信息
    },
    {
        .start = 12,//GPIO编号
        .end = 12,//无效,为了好看
        .flags = IORESOURCE_IRQ
    },
    {
        .start = 7,
        .end = 7,
        .flags = IORESOURCE_IRQ
    },
    {
        .start = 11,
        .end = 11,
        .flags = IORESOURCE_IRQ
    }
};
//仅仅去除警告
static void led_release(struct device *dev) {}
//定义初始化描述LED的硬件信息节点对象
static struct platform_device led_dev = {
    .name = "tarena", //用于匹配
    .id = -1,//硬件节点编号
    .resource = led_info,//装载resource描述的硬件信息
    .num_resources = ARRAY_SIZE(led_info),//硬件信息个数
    .dev = {
        .release = led_release //仅仅是为了去除警告而已
    }
};
static int led_dev_init(void)
{
    //1.向内核dev链表添加注册硬件节点对象即可
    //内核会帮你遍历drv链表,匹配,调用,传参
    platform_device_register(&led_dev);
    printk("register device led_dev.\n");
    return 0;
}
static void led_dev_exit(void)
{
    //从内核的dev链表删除硬件节点对象
    platform_device_unregister(&led_dev);
    printk("unregister device led_dev.\n");
}
module_init(led_dev_init);
module_exit(led_dev_exit);
MODULE_LICENSE("GPL");


  • led_drv.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <mach/platform.h>
#include <linux/mm.h>
#include <linux/slab.h>
static void *gpiobase;
static unsigned long *gpiocout, *gpiocoutenb, *gpioaltfn0;
static int pin1;
static int pin2;
static int pin3;
#define LED_ON  0x100001
#define LED_OFF 0x100002
static long led_ioctl(struct file *file,
                        unsigned int cmd,
                        unsigned long arg)
{
    //1.分配内核缓冲区
    int kindex;
    //2.拷贝用户数据到内核
    copy_from_user(&kindex, (int *)arg,  sizeof(kindex));
    //3.解析用户命令
    switch(cmd) {
        case LED_ON:
                if(kindex == 1)
                    *gpiocout &= ~(1 << pin1);
                if(kindex == 2)
                    *gpiocout &= ~(1 << pin2);
                if(kindex == 3)
                    *gpiocout &= ~(1 << pin3);
                printk("open led on. kindex = %d\n", kindex);
            break;
        case LED_OFF:
                if(kindex == 1)
                    *gpiocout |= (1 << pin1);
                if(kindex == 2)
                    *gpiocout |= (1 << pin2);
                if(kindex == 3)
                    *gpiocout |= (1 << pin3);
                printk("open led off. kindex = %d\n", kindex);
            break;
        default:
            return -1;
    }
    return 0;
}
//定义初始化硬件操作接口对象
static struct file_operations led_fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = led_ioctl
};
//定义初始化混杂设备对象
static struct miscdevice led_misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "myled",
    .fops = &led_fops
};
//匹配成功,内核调用
//pdev:指向匹配成功的硬件节点
//pdev=led_dev.c中的&led_dev
static int led_probe(struct platform_device *pdev)
{
    //通过指针得到resource描述的硬件信息
    //preg_res = &led_info[0]
    //ppin_res = &led_info[1]
    struct resource *preg_res;
    struct resource *ppin_res_1;
    struct resource *ppin_res_2;
    struct resource *ppin_res_3;
    preg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    ppin_res_1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    ppin_res_2 = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
    ppin_res_3 = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
    //处理硬件信息
    gpiobase = ioremap(preg_res->start, preg_res->end - preg_res->start);
    gpiocout = (unsigned long *)(gpiobase + 0x00);
    gpiocoutenb = (unsigned long *)(gpiobase + 0x04);
    gpioaltfn0 = (unsigned long *)(gpiobase + 0x20);
    //获取GPIO编号
    pin1 = ppin_res_1->start;
    pin2 = ppin_res_2->start;
    pin3 = ppin_res_3->start;
    //配置GPIO功能为输出并输出1
    //led1
    *gpioaltfn0 &= ~(0x3 << (2 *pin1));
    *gpioaltfn0 |= (1 << (2*pin1));
    *gpiocoutenb |= (1 <<pin1);
    *gpiocout |= (1 << pin1);
    //led2
    *gpioaltfn0 &= ~(0x3 << (2 *pin2));
    *gpioaltfn0 |= (1 << (2*pin2));
    *gpiocoutenb |= (1 <<pin2);
    *gpiocout |= (1 << pin2);
    //led3
    *gpioaltfn0 &= ~(0x3 << (2 *pin3));
    *gpioaltfn0 |= (1 << (2*pin3));
    *gpiocoutenb |= (1 <<pin3);
    *gpiocout |= (1 << pin3);
    printk("register led_misc myled.\n");
    misc_register(&led_misc);
    return 0; //执行成功返回0,执行失败返回负值
}
//删除软件或者硬件节点,内核调用
//pdev:指向匹配成功的硬件节点
//pdev=led_dev.c中的&led_dev
static int led_remove(struct platform_device *pdev)
{
    //1.卸载混杂设备
    misc_deregister(&led_misc);
    printk("unregister led_misc myled.\n");
    *gpiocout |= (1<<pin1);
    *gpiocout |= (1<<pin2);
    *gpiocout |= (1<<pin3);
    //解除地址映射
    iounmap(gpiobase);
    return 0; //执行成功返回0,执行失败返回负值
}
//定义初始化软件节点对象
static struct platform_driver led_drv = {
    .driver = {
        .name = "tarena" //用于匹配
    },
    .probe = led_probe, //匹配成功,内核调用
    .remove = led_remove, //卸载软件或者硬件,内核调用
};
static int led_drv_init(void)
{
    //1.向内核drv链表注册软件节点对象
    //什么遍历,什么匹配,什么调probe,什么传参都是内核完成
    platform_driver_register(&led_drv);
    return 0;
}
static void led_drv_exit(void)
{
    //1.从内核的drv链表删除软件节点对象
    //内核调用remove函数
    platform_driver_unregister(&led_drv);
}
module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");



  • led_test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#define LED_ON  0x100001 //开灯命令
#define LED_OFF 0x100002 //关灯命令
int main(int argc, char *argv[])
{
    int fd;
    int index; //分配用户缓冲区,保存操作灯的编号
    if(argc != 3) {
        printf("用法:%s <on|off> <1|2|3|4>\n", argv[0]);
        return -1;
    }
    //打开设备
    fd = open("/dev/myled", O_RDWR);
    printf("open file /sys/class/misc/myled/dev\n");
    //fd = open("/sys/class/misc/myled/dev", O_RDWR);
    if (fd < 0) {
        printf("open device fail!\n");
        return -1;
    }
    //"1"->1
    index = strtoul(argv[2], NULL, 0);
    //应用ioctl->软中断->内核sys_ioctl->驱动led_ioctl
    if(!strcmp(argv[1], "on"))
        ioctl(fd, LED_ON, &index);
    else if(!strcmp(argv[1], "off"))
        ioctl(fd, LED_OFF, &index);
    //关闭设备
    close(fd);
    return 0;
}



  • Makefile
obj-m += led_drv.o led_dev.o
all:
  make -C /home/ww/ARM/kernel SUBDIRS=$(PWD) modules
test: led_test.c
  arm-cortex_a9-linux-gnueabi-gcc $< -o led_test
clean:
  make -C /home/ww/ARM/kernel SUBDIRS=$(PWD) clean
  rm led_test


  • 执行结果:
#先注册led_dev.ko和先注册led_drv.ko是一样的,没区别,但是使用的时候需要两个模块都存在并且匹配成功,
insmod led_dev.ko
insmod led_drv.ko
ls /sys/class/misc/

20200104224642359.png

相关文章
|
10天前
|
缓存 Linux 开发者
Linux内核中的并发控制机制:深入理解与应用####
【10月更文挑战第21天】 本文旨在为读者提供一个全面的指南,探讨Linux操作系统中用于实现多线程和进程间同步的关键技术——并发控制机制。通过剖析互斥锁、自旋锁、读写锁等核心概念及其在实际场景中的应用,本文将帮助开发者更好地理解和运用这些工具来构建高效且稳定的应用程序。 ####
29 5
|
12天前
|
Linux 数据库
Linux内核中的锁机制:保障并发操作的数据一致性####
【10月更文挑战第29天】 在多线程编程中,确保数据一致性和防止竞争条件是至关重要的。本文将深入探讨Linux操作系统中实现的几种关键锁机制,包括自旋锁、互斥锁和读写锁等。通过分析这些锁的设计原理和使用场景,帮助读者理解如何在实际应用中选择合适的锁机制以优化系统性能和稳定性。 ####
31 6
|
19天前
|
消息中间件 存储 Linux
|
1月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
85 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
2月前
|
存储 Linux 开发工具
如何进行Linux内核开发【ChatGPT】
如何进行Linux内核开发【ChatGPT】
|
3月前
|
Java Linux API
Linux设备驱动开发详解2
Linux设备驱动开发详解
44 6
|
3月前
|
消息中间件 算法 Unix
Linux设备驱动开发详解1
Linux设备驱动开发详解
50 5
|
2月前
|
存储 监控 安全
探究Linux操作系统的进程管理机制及其优化策略
本文旨在深入探讨Linux操作系统中的进程管理机制,包括进程调度、内存管理以及I/O管理等核心内容。通过对这些关键组件的分析,我们将揭示它们如何共同工作以提供稳定、高效的计算环境,并讨论可能的优化策略。
48 0
|
2月前
|
Linux API
Linux里的高精度时间计时器(HPET)驱动 【ChatGPT】
Linux里的高精度时间计时器(HPET)驱动 【ChatGPT】
下一篇
无影云桌面