android can驱动程序,can设备驱动-程序员宅基地

技术标签: android can驱动程序  

拿到一个设备驱动,首先要看的是设备初始化函数。

static int __init mcp251x_init(void)

{

int ret;

can_class = class_create(THIS_MODULE, "can");

if (IS_ERR(can_class))

return PTR_ERR(can_class);

ret = alloc_chrdev_region(&devid, 0, CAN_DEV_MAX, DRIVER_NAME);

if (ret < 0)

{

printk(KERN_ERR "%s: failed to allocate char dev region\n", __FILE__);

class_destroy(can_class);

return ret;

}

return spi_register_driver(&mcp251x_driver);

}

class_create()用于自动创建设备节点,我们可以暂时不看,有兴趣的可以看看Linux源码。alloc_chrdev_region()自动为DRIVER_NAME分配设备号。在这里,我们真正关心的是spi_register_driver()函数和mcp251x_driver结构体的内容。

我们先看spi_register_driver()的内容。

/**

* spi_register_driver - register a SPI driver

* @sdrv: the driver to register

* Context: can sleep

*/

int spi_register_driver(struct spi_driver *sdrv)

{

sdrv->driver.bus = &spi_bus_type;

if (sdrv->probe)

sdrv->driver.probe = spi_drv_probe;

if (sdrv->remove)

sdrv->driver.remove = spi_drv_remove;

if (sdrv->shutdown)

sdrv->driver.shutdown = spi_drv_shutdown;

return driver_register(&sdrv->driver);

}

spi_register_driver()完成了驱动在总线的挂载以及spi驱动函数probe, remove, shutdown的赋值。那mcp251x_driver是什么样的结构体,里面又存储了什么内容呢?

static struct spi_driver mcp251x_driver = {

.driver = {

.name = DRIVER_NAME,

.bus = &spi_bus_type,

.owner = THIS_MODULE,

},

.probe = mcp251x_probe,

.remove = __devexit_p(mcp251x_remove),

#ifdef CONFIG_PM

.suspend = mcp251x_suspend,

.resume = mcp251x_resume,

#endif

};

mcp251x_driver是结构体spi_driver的实例,在mcp251x_driver里面完成了mcp251x驱动函数probe, remove, suspend, resume的赋值。

在进入mcp251x的驱动函数之前,我们还是先看看mcp251x的结构吧!

struct mcp251x

{

struct cdev cdev;

struct class_device *class_dev;

struct semaphore lock;      /* semaphore for spi bus share. */

struct semaphore rxblock;   /* semaphore for ring buffer of receive. */

struct semaphore txblock;   /* semaphore for ring buffer of send. */

uint8_t *spi_transfer_buf;  /* temp buffer for spi bus transfer. */

struct can_frame rxb[MCP251X_BUF_LEN];  /* ring buffer for receive. */

struct can_frame txb[MCP251X_BUF_LEN];  /* ring buffer for send. */

int txbin;                  /* pos of in for ring buffer of sned. */

int txbout;                 /* pos of out for ring buffer of send. */

int rxbin;                  /* pos of in for ring buffer of receive. */

int rxbout;                 /* pos of out for ring buffer of receive. */

int bit_rate;               /* save bit rate of current set. */

int count;                  /* count of the device opened. */

wait_queue_head_t wq;       /* queue for read process. */

struct work_struct irq_work;    /* bottom half of interrupt task. */

struct spi_device *spi;     /* save the point of struce spi_device. */

struct can_filter filter;   /* save the filter data of current set. */

};

其中的很多结构体,我们暂时不管。下面开始进入正题。

static int __devinit mcp251x_probe(struct spi_device *spi)

{

struct mcp251x *chip;

int ret = 0;

dev_dbg(&spi->dev, "%s: start\n", __FUNCTION__);

/* 申请内存资源 */

chip = kmalloc(sizeof(struct mcp251x), GFP_KERNEL);

if (!chip)

{

ret = -ENOMEM;

goto error_alloc;

}

/* 将mcp251x的设备信息保存到spi的设备结构体中 */

dev_set_drvdata(&spi->dev, chip);

/* mcp251x结构体初始化 */

chip->txbin = chip->txbout = 0;

chip->rxbin = chip->rxbout = 0;

chip->count = 0;

chip->spi = spi;

init_MUTEX(&chip->lock);

init_MUTEX(&chip->txblock);

init_MUTEX(&chip->rxblock);

init_waitqueue_head(&chip->wq);

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))

INIT_WORK(&chip->irq_work, mcp251x_irq_handler);

#else

INIT_WORK(&chip->irq_work, mcp251x_irq_handler, spi);

#endif

/* 为spi的buf分配空间 */

chip->spi_transfer_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);

if (!chip->spi_transfer_buf)

{

ret = -ENOMEM;

goto error_buf;

}

/* 输入模式,不使用内部上拉电阻 */

at91_set_gpio_input(spi->irq, 0);

/* 绑定输入函数mcp251x_irq,传递参数spi */

/* mcp251x_irq函数我们等下再看,先放一放 */

ret = request_irq(spi->irq, mcp251x_irq, IRQF_SAMPLE_RANDOM, DRIVER_NAME, spi);

if (ret < 0)

{

dev_err(&spi->dev, "request irq %d failed (ret = %d)\n", spi->irq, ret);

goto error_irq;

}

if (can_minor > CAN_DEV_MAX)

goto error_register;

if (can_major)

{

devid = MKDEV(can_major, can_minor++);

ret = register_chrdev_region(devid, 0, DRIVER_NAME);

}

else

{

ret = alloc_chrdev_region(&devid, can_minor, 0, DRIVER_NAME);

can_major = MAJOR(devid);

}

if (ret < 0)

{

dev_err(&spi->dev, "register char device region (%d:%d) failed (ret = %d)\n", MAJOR(devid),

MINOR(devid), ret);

goto error_register;

}

/* 字符设备的初始化以及添加到内核 */

cdev_init(&chip->cdev, &mcp251x_fops);

chip->cdev.owner = THIS_MODULE;

ret = cdev_add(&chip->cdev, devid, 1);

if (ret < 0)

{

dev_err(&spi->dev, "register char device failed (ret = %d)\n", ret);

goto error_devadd;

}

dev_info(&spi->dev, "device register at dev(%d:%d)\n", MAJOR(devid), MINOR(devid));

/* 自动创建设备文件 */

chip->class_dev = device_create(can_class, NULL,

MKDEV(MAJOR(devid), can_minor), &spi->dev, "can%d", can_minor);

if (IS_ERR(chip->class_dev))

{

dev_err(&spi->dev, "cannot create CAN class device\n");

ret = PTR_ERR(chip->class_dev);

goto error_class_reg;

}

/* mcp251x初始化设置 */

mcp251x_hw_init(spi);

mcp251x_set_bit_rate(spi, 125000);  /* A reasonable default */

mcp251x_hw_sleep(spi);

return 0;

error_class_reg:

cdev_del(&chip->cdev);

error_devadd:

unregister_chrdev_region(devid, 0);

error_register:

free_irq(spi->irq, spi);

error_irq:

kfree(chip->spi_transfer_buf);

error_buf:

kfree(chip);

error_alloc:

return ret;

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_42501850/article/details/117557700

智能推荐

matlab 提取struct结构体中某个字段所有变量的值_matlab读取struct类型数据中的值-程序员宅基地

文章浏览阅读7.5k次,点赞5次,收藏19次。matlab结构体struct字段变量值提取_matlab读取struct类型数据中的值

Android fragment的用法_android reader fragment-程序员宅基地

文章浏览阅读4.8k次。1,什么情况下使用fragment通常用来作为一个activity的用户界面的一部分例如, 一个新闻应用可以在屏幕左侧使用一个fragment来展示一个文章的列表,然后在屏幕右侧使用另一个fragment来展示一篇文章 – 2个fragment并排显示在相同的一个activity中,并且每一个fragment拥有它自己的一套生命周期回调方法,并且处理它们自己的用户输_android reader fragment

FFT of waveIn audio signals-程序员宅基地

文章浏览阅读2.8k次。FFT of waveIn audio signalsBy Aqiruse An article on using the Fast Fourier Transform on audio signals. IntroductionThe Fast Fourier Transform (FFT) allows users to view the spectrum content of _fft of wavein audio signals

AndroidStudio无法下载远程依赖问题_android studio 无法x下载远程依赖,浏览器能下载-程序员宅基地

文章浏览阅读6.8k次。这2天是日了狗,重装了下系统,竟然studio连远程库都下不到了。各种尴尬啊,搞了2天的环境,还被组长看在眼里。。。。先给出我的问题是,基本都会提示了下面这句。failed to resolve 。。。当时,直接百度 ,谷歌后,也使用了大量解决方法,设代理,更改gradle配置,但都没鸟用。后面发现所有远程依赖都是这个提示,或者有时候会提示: Server sent an_android studio 无法x下载远程依赖,浏览器能下载

百度地图lib/libgnustl_shared.so" not found_gnustl_shared.so 下载-程序员宅基地

文章浏览阅读2.1k次。1.在项目的根目录的 gradle.properties 里面添加一行代码 Android.useDeprecatedNdk=true. 2.在 build.gradle 文件里添加以下代码 defaultConfig { ndk { abiFilters "armeabi" } packagingOptions {_gnustl_shared.so 下载

100G波分复用(WDM)宽带传输设备_wdm单跨段-程序员宅基地

文章浏览阅读6.2k次。eWAVE5101100G波分复用(WDM)宽带传输设备 eWAVE5101 40G/100G传输设备是为满足大容量和长距离数据传输而开发的一款小型化且高性价比的设备。它支持包括 100GBASE-LR4、100GBASE-ER4和100GBASE-SR10的各种 100G用户接口,能与任何第三方 100G设备无缝连接。它也能支持包括 40GBASE-LR4_wdm单跨段

随便推点

java前端技术---jquery基础详解_简介java中jquery技术-程序员宅基地

文章浏览阅读616次。一.jquery简介 jQuery是一个快速的,简洁的javaScript库,使用户能更方便地处理HTML documents、events、实现动画效果,并且方便地为网站提供AJAX交互 jQuery 的功能概括1、html 的元素选取2、html的元素操作3、html dom遍历和修改4、js特效和动画效果5、css操作6、html事件操作7、ajax_简介java中jquery技术

Ant Design Table换滚动条的样式_ant design ::-webkit-scrollbar-corner-程序员宅基地

文章浏览阅读1.6w次,点赞5次,收藏19次。我修改的是表格的固定列滚动而产生的滚动条引用Table的组件的css文件中加入下面的样式:.ant-table-body{ &amp;amp;::-webkit-scrollbar { height: 5px; } &amp;amp;::-webkit-scrollbar-thumb { border-radius: 5px; -webkit-box..._ant design ::-webkit-scrollbar-corner

javaWeb毕设分享 健身俱乐部会员管理系统【源码+论文】-程序员宅基地

文章浏览阅读269次。基于JSP的健身俱乐部会员管理系统项目分享:见文末!

论文开题报告怎么写?_开题报告研究难点-程序员宅基地

文章浏览阅读1.8k次,点赞2次,收藏15次。同学们,是不是又到了一年一度写开题报告的时候呀?是不是还在为不知道论文的开题报告怎么写而苦恼?Take it easy!我带着倾尽我所有开题报告写作经验总结出来的最强保姆级开题报告解说来啦,一定让你脱胎换骨,顺利拿下开题报告这个高塔,你确定还不赶快点赞收藏学起来吗?_开题报告研究难点

原生JS 与 VUE获取父级、子级、兄弟节点的方法 及一些DOM对象的获取_获取子节点的路径 vue-程序员宅基地

文章浏览阅读6k次,点赞4次,收藏17次。原生先获取对象var a = document.getElementById("dom");vue先添加ref <div class="" ref="divBox">获取对象let a = this.$refs.divBox获取父、子、兄弟节点方法var b = a.childNodes; 获取a的全部子节点 var c = a.parentNode; 获取a的父节点var d = a.nextSbiling; 获取a的下一个兄弟节点 var e = a.previ_获取子节点的路径 vue

UIToolkit下一代UI系统_uitookit-程序员宅基地

文章浏览阅读7k次,点赞2次,收藏14次。1. UIToolkit运行时――下一代UI系统UIToolkit的前身是UIElement,发布于Unity 2018。起初它用于开发Editor编辑面板中的UI,自Unity 2019、Unity 2020起正式支持运行时UI并且更名为UIToolkit,它以Package包的形式存在。自Unity 2021.2起,UIToolkit被官方内置在Unity中和UGUI的地位一致,UIToolkit作为下一代UI系统,设计之初目标就很明确,就是替换掉现有的UGUI系统。现有的UGUI系统从2014_uitookit