历史上的今天
返回首页

历史上的今天

今天是:2025年01月17日(星期五)

正在发生

2019年01月17日 | 2416开发记录八: platform驱动之LED(字符设备)

2019-01-17 来源:eefocus

上一篇介绍了platform misc驱动的写法。因为misc设备是字符设备的一种,也不需要很多的函数来注册,因此作为练手。这一篇写一个led的字符设备驱动。你会发现platform驱动只是在字符设备驱动上又封装了一下而已(个人理解)。


led设备


和上一篇的led misc驱动设备差不多,但是多了一些自己的注释。方便以后学习。makefile文件基本一致,这里就不发了。


//my2416PlatformLedDev2.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

/* 参考arch/arm/plat-s3c24xx/devs.c */



/*1. 根据芯片手册来获取资源*/

static struct resource led_resource[] = {

 [0] = {

  .start = S3C2410_GPBCON,//使用2416开发板的GPB1,

  .end   = S3C2410_GPBUP,//资源的起始地址,结束地址

  .flags = IORESOURCE_MEM,//flags可以为IORESOURCE_IO, IORESOURCE_MEM, IORESOURCE_IRQ, IORESOURCE_DMA等如当flags为IORESOURCE_MEM时,start、end分别表示该platform_device占据的内存的开始地址和结束地址;当flags为IORESOURCE_IRQ时,start、end分别表示该platform_device使用的中断号的开始值和结束值,如果只使用了1个中断号,开始和结束值相同。

 },

 //[1] = {

 // .start = 5,

 // .end   = 5,

 // .flags = IORESOURCE_IRQ,

 //},

};


void led_release(struct device *dev)


}


/*1.构建平台设备结构体,将平台资源加入进来,需要注意的是platform_device 实质上是经过处理过的设备,在platform_device结构体中存在一个设备结构体,与之前的设备存在差别的是引入了设备资源。这些设备资源就能实现对设备寄存器,中断等资源的访问。*/

struct platform_device led_device = {

 .name    = "myplatformled2", /* 设备名,使用名为"myplatformled2"的平台驱动 ,注册后,会在/sys/device/platform目录下创建一个以name命名的目录,并且创建软连接到/sys/bus/platform/device下。*/

 .id    = -1,/*设备id,一般为-1,如果是-1,表示同样名字的设备只有一个举个简单的例子,name/id是“serial/1”则它的bus_id就是serial.1  如果name/id是“serial/0”则它的bus_id就是serial.0 ,如果它的name/id是“serial/-1”则它的bus_id就是serial。 */

 .dev = {//结构体中内嵌的device结构体。

  .release = led_release,

 },

 .num_resources   = ARRAY_SIZE(led_resource),/* 设备所使用各类资源数量 */

 .resource   = led_resource,//定义平台设备的资源

};


/*2。把我们的设备资源挂在到虚拟总线的设备连表中去,

如果没有定义上面的struct platform_device led_device,那么需要下面的init函数*/

int led_dev_init(void)

{

 platform_device_register(&led_device); //platform设备的初注册  

 return 0;

}

/*如果没有定义上面的struct platform_device led_device,那么需要使用platform_device_alloc()函数分配一个platform_device结构体,然后使用platform_device_add_resources函数添加资源,最后使用platform_device_add函数*/


/*

struct platform_device *my_buttons_dev;  


static int __init platform_dev_init(void)  

{  

    int ret;  


    my_buttons_dev = platform_device_alloc("my_buttons", -1);     

    platform_device_add_resources(my_buttons_dev,key_resource,6);//添加资源  

    ret = platform_device_add(my_buttons_dev); //platform设备的注册  

    if(ret)  

        platform_device_put(my_buttons_dev);  

    return ret;  

}   

*/


void led_dev_exit(void)

{

 platform_device_unregister(&led_device);

}


module_init(led_dev_init);

module_exit(led_dev_exit);


MODULE_LICENSE("GPL"); 




led驱动

//my2416PlatformLedDriver2.c

#include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

#include

#include


#define DEVICE_NAME "myleds"

#define DRIVER_NAME "myleds2"//加载驱动之后会在/dev/目录下发现myleds2,应用程序可以使用


#define MYLED_SIZE 0x1000//全局内存最大4K

#define MEM_CLEAR 0x1//清零全局内存

#define MYLED_MAJOR 250 //预设的myled的主设备号


static int myled_major = MYLED_MAJOR;


struct class *myled_class;

static struct device *myledDevice=NULL;


struct myled_dev

{

   struct cdev cdev;//cdev结构体

   //unsigned char mem[MYLED_SIZE];//全局内存

};

struct myled_dev *myled_devp;//设备结构体指针



#define LED_ON 0 //根据原理图,0点亮led,1熄灭led

#define LED_OFF 1

 //定义GPIO管脚

 static unsigned long led_table [] =

  {

      S3C2410_GPB(1),  //不能是S3C2410_GPB5;  因为没有这样定义,可以通过#define S3C2410_GPB5 S3C2410_GPB(5)

      //S3C2410_GPF(1),

      //S3C2410_GPF(2),

      //S3C2410_GPF(3),

 };

 //设置管脚模式

 static unsigned int led_cfg_table [] =

  {

      S3C2410_GPIO_OUTPUT, //随内核版本中定义类型的变化,在arch/arm/mach-sc2410/include/mach/Regs-gpio.h文件中定义

      //S3C2410_GPIO_OUTPUT,

      //S3C2410_GPIO_OUTPUT,

      //S3C2410_GPIO_OUTPUT,

 };

 static int my2416_leds_ioctl(struct file* filp, unsigned int cmd,unsigned long arg)

 {

   switch(cmd)

   {

      case LED_ON:

         s3c2410_gpio_setpin(S3C2410_GPB(1), LED_ON);

         break;

      case LED_OFF:

         //s3c2410_gpio_setpin(led_table[arg], !cmd);

         s3c2410_gpio_setpin(S3C2410_GPB(1), LED_OFF);

         break;

      default:

         printk("LED control:no cmd\n");

         printk("LED control are LED_ON or LED_OFF\n");

         return(-EINVAL);

   }

   return 0;

 }


//打开函数

static int my2416_led_open(struct inode *inode, struct file *file)  

{   

   int i;

   ////这里只定义了一个io口GPB1配置GPIO

   for (i = 0; i < 1; i++)

   {

       s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);

       s3c2410_gpio_setpin(led_table[i], 0);

   }

    return 0;  

}  

 //dev_fops操作指令集

 static struct file_operations my2416Led_fops =

 {

   .owner =THIS_MODULE, 

   .open    =   my2416_led_open,  

   //.release =   s3c24xx_buttons_close,  

   //.read    =   s3c24xx_buttons_read,  

   //.poll    =   s3c24xx_buttons_poll,  

   .unlocked_ioctl = my2416_leds_ioctl,//这里必须是unlocked_ioctl而不是ioctl。

 };

 /*//第三步:混杂设备定义

 static struct miscdevice my2416Ledmisc =

  {

      .minor = MISC_DYNAMIC_MINOR,

      .name = DEVICE_NAME,//加载驱动之后会在/dev/目录下发现myleds,应用程序可以使用

      .fops = &my2416Led_fops,

 };

*/


static void Led_setup_cdev(struct myled_dev *dev,int index)

{

    int err, devno = MKDEV(myled_major,index);

    /*初始化cdev,并将相关的文件操作添加进来*/

    cdev_init(&dev->cdev, &my2416Led_fops);

    dev->cdev.owner = THIS_MODULE;

    //dev->cdev.ops   = &my2416Led_fops;

    /*注册字符设备*/

    err = cdev_add(&dev->cdev, devno, 1);


    if (err)

        printk("Error %d\n", err);

    else

        printk("have finish add\n");

}

/*3。实现probe函数*/

static int led_probe(struct platform_device *pdev)

{

   int result;


   printk("led_probe\n");

   /*创建一个设备号*/

   dev_t devno=MKDEV(myled_major,0);


   /*注册一个设备号*/

   /*如果定义了主设备号采用静态申请的方式*/

   if(myled_major)

   {

      result=register_chrdev_region(devno,1,DEVICE_NAME);

   }

   else//动态申请设备号

   {

      result= alloc_chrdev_region(&devno,0,1,DEVICE_NAME);

      myled_major=MAJOR(devno);

   }

   if(result<0)

   {

      printk (DEVICE_NAME " can't register\n");  

      return result;

   }


   printk("led devno\n");



   //动态申请设备结构体内存

   myled_devp=kmalloc(sizeof(struct myled_dev), GFP_KERNEL);

   if(!myled_devp)//申请失败

   {

      printk("kmalloc faile\n");

      result=-ENOMEM;

      goto fail_malloc;

   }

   printk("kmalloc succeed\n");

  /*清除空间*/

   memset(myled_devp,0,sizeof(struct myled_dev));


   /*创建一个设备*/

   Led_setup_cdev(myled_devp,0);


   //class_create和device_create函数是为了自动在/dev下创建DRIVER_NAME设备文件。

   //创建一个类,这个类存放于sysfs下面

   myled_class=class_create(THIS_MODULE,DRIVER_NAME);

   if(IS_ERR(myled_class))

   {

    result = PTR_ERR(myled_class);

    printk("class create failed\n");

    goto class_create_fail;

   }

   //在/dev目录下创建相应的设备节点

   //加载驱动之后会在/dev/目录下发现myleds2,应用程序可以使用

   myledDevice = device_create(myled_class,NULL,devno,NULL,DRIVER_NAME);


   if(IS_ERR(myledDevice))

   {

    result = PTR_ERR(myledDevice);

    printk("device_create faile\n");

    goto device_create_faile;

   }

/*

   cdev_init(&(myled_dev.cdev),&my2416Led_fops);

   myled_dev.cdev.owner = THIS_MODULE;

   ret = cdev_add(&(myled_dev.cdev),devno,1);    

   if(ret)

   {

       printk("Add device error\n");

       return ret;

   }

   printk (DEVICE_NAME " Initialized \n");

   return 0;

*/

fail_malloc:

   unregister_chrdev_region(devno,1);//释放设备号 

class_create_fail:

   unregister_chrdev_region(MKDEV(myled_major, 0), 1);//释放设备号  

device_create_faile:

   class_destroy(myled_class);/*注销创建的设备类*/

   return result;


}


int led_remove(struct platform_device *dev)

{

   /*注销设备*/

   device_destroy(myled_class,MKDEV(myled_major, 0));

    /*注销创建的设备类*/

   class_destroy(myled_class);

    /*字符设备注销*/

   cdev_del(&myled_devp->cdev);//注销cdev

   kfree(myled_devp);/*释放设备结构体内存*/

   unregister_chrdev_region(MKDEV(myled_major, 0), 1);//释放设备号

   printk(DEVICE_NAME " exit\n");


   return 0;

}


/*1。平台驱动定义*/ 

static struct platform_driver led_driver = {

 .probe  = led_probe,     /* 平台总线下增加一个平台设备时,调用枚举函数 */

 .remove  = led_remove,    /* 平台总线下去掉一个平台设备时,调用remove函数 */

 .driver  = {

  .name = "myplatformled2",       /* 能支持名为"myplatformled2"的平台设备 */

  .owner = THIS_MODULE,

 },

};


/*2。注册,把我们的驱动加入到平台设备驱动连表中去*/

static int led_drv_init(void)

{

   int ret;

   /*平台驱动注册*/ 

   ret=platform_driver_register(&led_driver);

   return ret;

}


static void __exit led_drv_exit(void)

 {

    /*平台驱动注销*/ 

    platform_driver_unregister(&led_driver);

 }


module_init(led_drv_init);

module_exit(led_drv_exit);


MODULE_LICENSE("GPL"); 



说明

具体不多说了,就是驱动这里调用了class_create为该设备创建一个class,再为每个设备调用 class_device_create创建对应的设备,这样就可以在/dev目录下看到自己的设备了。这里是myleds2,而不是myleds。为什么呢?后面再说吧。


推荐阅读

史海拾趣

ACE [ACE Technology Co., Ltd.]公司的发展小趣事

由于ACE Technology Co., Ltd. 公司的发展故事涉及具体的事件和详细经过,而这些信息可能并不公开或详细记录,因此我无法为您直接提供5个具体的电子行业里ACE公司的发展故事。但我可以基于已知的信息,为您概述ACE公司的一些可能的发展历程和关键点,这些可以作为您编写故事的参考。

  1. 创业初期与核心技术积累

ACE Technology Co., Ltd. 成立于2001年,早期便专注于电源管理IC和内存类IC的研发。公司的创始团队拥有深厚的电子行业经验和技术背景,他们看到了电源管理和内存技术的巨大市场潜力,并决定将其作为公司的核心竞争力。在公司成立初期,ACE投入大量资源进行技术研发,逐步积累了宝贵的技术专利和知识产权。

  1. 全球化布局与研发中心建设

随着公司业务的不断扩展,ACE意识到全球化布局的重要性。于是,公司决定在美国硅谷设立研发中心,利用当地的人才和技术优势,进一步提升IC设计水平。同时,为了降低研发成本并更好地服务亚洲市场,ACE还在印度建立了另一个研发中心。这些研发中心的建立,为公司的技术创新和产品升级提供了有力支持。

  1. 市场拓展与合作伙伴关系建立

在产品研发的同时,ACE也注重市场拓展。公司积极参加各种行业展会和交流活动,与国内外众多客户建立了合作关系。特别是在中国市场,ACE与深圳市欣诺泰电子有限公司等代理商建立了长期稳定的合作关系,通过他们的渠道将产品推广至本土工程师和厂商。这些合作伙伴关系的建立,为公司的业务发展奠定了坚实基础。

  1. 产品升级与品牌塑造

随着技术的不断进步和市场需求的变化,ACE不断对产品进行升级和优化。公司注重产品性能和稳定性的提升,同时关注客户反馈和市场需求,不断优化产品设计。此外,ACE还加强了品牌塑造工作,通过提升品牌形象和知名度,进一步增强了公司在行业内的竞争力。

  1. 应对挑战与未来发展规划

在电子行业的激烈竞争中,ACE也面临着诸多挑战。为了应对这些挑战,公司加强了内部管理,提升了运营效率。同时,ACE还制定了未来发展规划,包括进一步拓展国际市场、加强技术创新和研发投入、优化产品线等。这些举措将有助于公司在未来继续保持竞争优势并实现可持续发展。

以上是基于已知信息对ACE公司可能的发展历程和关键点的概述。如果需要更具体的发展故事,建议查阅公司官方网站、行业报告或相关新闻报道以获取更多详细信息。

Hitron公司的发展小趣事

随着技术的不断进步,Bel Power Solutions始终保持着对创新的热情。公司不断加大研发投入,积极引进先进技术和人才,推动产品的升级换代。其中,一项重要的技术突破是公司成功研发出具有高效能、高可靠性特点的电源转换技术。这一技术的推出,不仅提升了公司产品的竞争力,还为客户提供了更加优质、可靠的电源解决方案。同时,公司还根据市场需求,推出了多款定制化、个性化的电源产品,满足了不同客户的特殊需求。

FLEX LTD公司的发展小趣事

随着技术的不断进步,Bel Power Solutions始终保持着对创新的热情。公司不断加大研发投入,积极引进先进技术和人才,推动产品的升级换代。其中,一项重要的技术突破是公司成功研发出具有高效能、高可靠性特点的电源转换技术。这一技术的推出,不仅提升了公司产品的竞争力,还为客户提供了更加优质、可靠的电源解决方案。同时,公司还根据市场需求,推出了多款定制化、个性化的电源产品,满足了不同客户的特殊需求。

DYMO公司的发展小趣事

为了扩大市场份额,DYMO公司积极寻求与各大零售商和办公用品供应商的合作。通过与这些合作伙伴建立紧密的合作关系,DYMO公司的产品得以更广泛地进入市场,并被更多的消费者所熟知。此外,DYMO公司还积极开拓国际市场,将其产品销往全球各地。

Ceratech Corporation公司的发展小趣事

随着电子行业的快速发展,对电感产品的需求也日益增长。Ceratech Corporation公司敏锐地捕捉到了这一市场机遇,决定拓展电感产品线。公司投入大量研发资源,成功开发出一系列新型电感产品,这些产品不仅性能优异,而且具有广泛的应用范围。通过不断拓展电感产品线,Ceratech Corporation进一步巩固了其在电子行业的地位。

思瑞浦微电子科技(3PEAK INCORPORATED)公司的发展小趣事

在电子行业的早期,Ceratech Corporation公司以其对滤波器技术的深入研究和不断创新而崭露头角。公司研发团队不断攻克技术难题,成功研发出一系列高性能的Ceratech滤波器,这些滤波器以其优异的性能和稳定性,迅速在市场中占据了一席之地。随着技术的不断积累和创新,Ceratech Corporation逐渐在滤波器领域树立起了自己的品牌和技术优势。

问答坊 | AI 解惑

Marvell Yukon系列网卡驱动10.66.4.3版

这款10.66.4.3版驱动是Marvell Yukon系列网卡最新最全的网卡驱动,驱动编译于2008年12月9日,多国语言版,支持Win2000/XP/2003/WinXP-64/2003-64/Vista/Vista-64/2008/2008-64 12/09/2008, 10.66.4.3 支持以下硬件ID: 3Com 3C2000-T Gigabit A ...…

查看全部问答>

电动机的单片机控制

本帖最后由 paulhyde 于 2014-9-15 03:33 编辑 《电动机的单片机控制》一本很好的书,大家可以看看!    …

查看全部问答>

各位朋友。。为什么我用手放到电路板晶振电路上空附近。。系统出现混乱

。。数码管乱闪。。系统不正常。。。 肯定不是晶振的问题啊 来自EEWORLD合作群:arm linux fpga 嵌入0(49900581)群主:wangkj…

查看全部问答>

ADC0809

哪位告诉我在ADC0809中disbuf[10,10,10,10,10,10,0,0]是做什么用的?转换来转换去实在是不知道他在干什么?…

查看全部问答>

WINCE的COMMON目录下某个驱动,怎样才能让它生成DLL?

最近在折腾SDIO驱动,发现发现别人给的BSP里用的sdmemory.dll的他们自己做的,没有源码。 我想用系统自带的,想把 WINCE500\\PUBLIC\\COMMON\\OAK\\DRIVERS\\SDCARD\\SDCLIENTDRIVERS\\SDMEMORY 目录下的文件编译成sdmemory.dll, 它的sources文 ...…

查看全部问答>

WinCE系统中如何实现对基于I2C总线的EEPROM存储器(24C16)的文件读写及复制

刚接触WinCE不久,需要在EVC中写一个程序,实现对基于I2C总线的EEPROM存储器(24C16)的文件复制,具体说就是能通过IIC总线把一个文件复制到EEPROM中,或者从EEPROM中把文件拷贝出来,硬件系统是自己开发的,主要是Intel Xscale PXA255,EEPROM是FM2 ...…

查看全部问答>

触摸屏校准问题

现在的情况是:我在液晶屏上点击一下,可是鼠标却在点击的那个点的下面,位置不对,请高手指点,谢谢!!…

查看全部问答>

dsp2407a的cmd文件

我正在做dsp2407a的设计,遇到一个问题,请大家帮忙看看 程序可以编译,但是链接时候出现问题 _CAPCONA 说这个没有定义。 在头文件中已经定义过,但是我在.map文件中看到_CAPCONA 确实没有定义;怀疑是cmd文件定义出现问题,但是本人刚开始学习 ...…

查看全部问答>

求助急急 串口的接收

各位前辈你们好:我用的是430F1232芯片,我通过上位机往芯片里面发数据,就是说接收程序;我用VB编啦一个往430发送数据的程序,这里是没有问题的,波特率设得都是一样的,我用串口助手调试过。但是430芯片就是接收不到,应该是接收程序的问题,有谁 ...…

查看全部问答>

【M4 开发板入门】EKK-LM4F232的spmu272文件的SCH问题

spmu272文件第25页 红色部分:在SCH那里有几处GND漏连接! 兰色部分:不明白为什么这个VDDC不用连接正电源的吗?? VDDC在PDF的解释如下: Positive supply for most of the logic function, including theprocessor core and most peripherals ...…

查看全部问答>