当前位置: 技术问答>linux和unix
根据LDD3 编写一个简单LED控制灯的驱动
来源: 互联网 发布时间:2016-08-08
本文导语: 本帖最后由 xiaopei1982 于 2010-03-03 18:00:40 编辑 第一个自己写的驱动,请大家帮忙,谢谢: 想法:(无实际意义,只是练习驱动编写) 1 不使用静态映射(通用IO口),改用动态映射 2 不使用ioctrl,...
想法:(无实际意义,只是练习驱动编写)
1 不使用静态映射(通用IO口),改用动态映射
2 不使用ioctrl,使用read write分别读取写入IO口
问题:1 写入时候IO口无反应
#define led_phy_address 0x56000070
#define led_size 0x100
int led_major = 0;
int led_minor = 0;
struct cdev *led_cdev;
unsigned long led_base_addr = 0;
//////////////////////////////////////////////////
static int led_open(struct inode *inode, struct file *file)
{
int ret;
led_base_addr = (unsigned long)ioremap_nocache(led_phy_address, led_size);
if ( (unsigned long)NULL == led_base_addr)
{
ret = -EBUSY;
goto fail;
}
printk(" led io remap successn");
//init IO
*(volatile unsigned *)led_base_addr = *(volatile unsigned *)led_base_addr| 0x00010000;//GPH8 set as output
*(volatile unsigned *)(led_base_addr+8) = *(volatile unsigned *)(led_base_addr+8)&0x00000000;//GPH8 pull up
return 0;
fail:
release_mem_region((unsigned long)led_phy_address, led_size);
return -1;
}
//////////////////////////////////////////////////
static ssize_t led_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
int ret = 0;
int IO_read = *(volatile unsigned *)(led_base_addr+4);//read IO
ret = copy_to_user (buf, &IO_read, sizeof(IO_read));
if (0 == ret)
{
printk(" led kernel copy to user successn");
}
else
{
return ret;
}
return 0;
}
//////////////////////////////////////////////////
static ssize_t led_write (struct file *filp, const char __user *buf, size_t count,loff_t *pos)
{
int ret = 0;
int IO_write = *(volatile unsigned *)(led_base_addr+4);//write IO
ret = copy_from_user (&IO_write,buf,sizeof(IO_write));
if (0 == ret)
{
printk(" led kernel copy from user successn");
}
else
{
return ret;
}
return 0;
}
//////////////////////////////////////////////////
|
首先确保lz在无OS的情况下能够正常点亮灯,不会搞错寄存器
led_base_addr = (unsigned long)ioremap_nocache(led_phy_address, led_size);
----------------------
lz用的是arm吧,这么一下子很有魄力,不过也太容易出错了,算偏移头大啊
不如这样
#define ADCCON 0x58000000
ioremap(ADCCON,0x4);
无非是如GPFCON GPFDAT 这么几个寄存器,分开ioremap几次编程会容易些
ret = copy_to_user (buf, &IO_read, sizeof(IO_read));
ret = copy_from_user (&IO_write,buf,sizeof(IO_write));
---------------------------------------------------------------
一次就完成了copy+读/写,还真是省事
不过我觉得ioremap之后的地址
readl writel 才对
比如
writel((readl(gpfcon) | 0x33) & 0xffffffcc, gpfcon);
led_base_addr = (unsigned long)ioremap_nocache(led_phy_address, led_size);
----------------------
lz用的是arm吧,这么一下子很有魄力,不过也太容易出错了,算偏移头大啊
不如这样
#define ADCCON 0x58000000
ioremap(ADCCON,0x4);
无非是如GPFCON GPFDAT 这么几个寄存器,分开ioremap几次编程会容易些
ret = copy_to_user (buf, &IO_read, sizeof(IO_read));
ret = copy_from_user (&IO_write,buf,sizeof(IO_write));
---------------------------------------------------------------
一次就完成了copy+读/写,还真是省事
不过我觉得ioremap之后的地址
readl writel 才对
比如
writel((readl(gpfcon) | 0x33) & 0xffffffcc, gpfcon);
|
你可以参考 《linux设备驱动开发详解》,里面有这个。
|
没关系阿
readl(b+0x100)
readl(b+0x100)
|
ioread32 != readl
试试readl啊
试试readl啊
|
回去慢慢研究一下
回复内容太短了!
回复内容太短了!
|
不清楚,我得到的例子都是readl 和 writel
|
你看 http://topic.csdn.net/u/20100304/11/a24a3b44-c510-43d8-badb-ec6a50bcad4f.html?seed=734201168&r=63701098#r_63701098
我就觉得ioread32是被2.6抛弃的方法
此外还可以
#define INTPND *(volatile unsigned int *)S3C2410_INTPND
__raw_readl(S3C2410_INTPND);
我就觉得ioread32是被2.6抛弃的方法
此外还可以
#define INTPND *(volatile unsigned int *)S3C2410_INTPND
__raw_readl(S3C2410_INTPND);
|
ret = copy_from_user (&IO_write,buf,sizeof(IO_write));
把ret 打出来
去include/asm-generic/errno-base.h查
你就不能分2步完成吗?
这么关键的步骤
把ret 打出来
去include/asm-generic/errno-base.h查
你就不能分2步完成吗?
这么关键的步骤