kernel版本:linux3.2.0
关于app调试,驱动调试使用nfs挂载目标板是个不错的选择。
1、编写驱动模块
/*
* linux/arch/arm/mach-omap2/gpmc-bus.c
*
* Copyright (C) 2017 WLS
* Contact: ranruoyu
* Version: 1.0
*
* 2017.11.29
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define USER_BUFF_SIZE 128
struct extgpmc_dev {
dev_t devt; //device id
struct cdev icdev; // char device
struct semaphore sem;
struct class *class; //??
char *user_buff;
};
static struct extgpmc_dev extgpmc_dev;
unsigned long mem_base;
static void __iomem *extgpmc_base;
//static void __iomem *gpmc_base;
/* GPMC register offsets */
#define GPMC_REVISION 0x00
#define GPMC_SYSCONFIG 0x10
#define GPMC_SYSSTATUS 0x14
#define GPMC_IRQSTATUS 0x18
#define GPMC_IRQENABLE 0x1c
#define GPMC_TIMEOUT_CONTROL 0x40
#define GPMC_ERR_ADDRESS 0x44
#define GPMC_ERR_TYPE 0x48
#define GPMC_CONFIG 0x50
#define GPMC_STATUS 0x54
#define GPMC_PREFETCH_CONFIG1 0x1e0
#define GPMC_PREFETCH_CONFIG2 0x1e4
#define GPMC_PREFETCH_CONTROL 0x1ec
#define GPMC_PREFETCH_STATUS 0x1f0
#define GPMC_ECC_CONFIG 0x1f4
#define GPMC_ECC_CONTROL 0x1f8
#define GPMC_ECC_SIZE_CONFIG 0x1fc
#define GPMC_ECC1_RESULT 0x200
#define GPMC_ECC_BCH_RESULT_0 0x240
#define GPMC_BASE_ADDR 0x50000000
#define GPMC_CS 2
#define GPMC_CS0 0x60
#define GPMC_CS_SIZE 0x30
#define STNOR_GPMC_CONFIG1 0x28601000
#define STNOR_GPMC_CONFIG2 0x00011001
#define STNOR_GPMC_CONFIG3 0x00020201
#define STNOR_GPMC_CONFIG4 0x08031003
#define STNOR_GPMC_CONFIG5 0x000f1111
#define STNOR_GPMC_CONFIG6 0x0f030080
static const u32 gpmc_nor[7] = {
STNOR_GPMC_CONFIG1,
STNOR_GPMC_CONFIG2,
STNOR_GPMC_CONFIG3,
STNOR_GPMC_CONFIG4,
STNOR_GPMC_CONFIG5,
STNOR_GPMC_CONFIG6, 0
};
static ssize_t extgpmc_write(struct file *filp, const char __user *buff,
size_t count, loff_t *f_pos)
{
ssize_t status;
size_t len = USER_BUFF_SIZE - 1;
int i,tmp;
printk(KERN_ALERT "extgpmc_write\n");
if (count == 0)
return 0;
printk(KERN_ALERT "check down_interruptible(&extgpmc_dev.sem) extgpmc_write\n");
if (down_interruptible(&extgpmc_dev.sem))
return -ERESTARTSYS;
if (len > count)
len = count;
memset(extgpmc_dev.user_buff, 0, USER_BUFF_SIZE);
if (copy_from_user(extgpmc_dev.user_buff, buff, len)) {
status = -EFAULT;
printk(KERN_ALERT "status = -EFAULT extgpmc_write\n");
goto extgpmc_write_done;
}
/* do something with the user data */
printk("extgpmc_write \n");
/*write 8 bit once mode ,test io out ;CPLD is 16bit */
//for (i = 0; i < len; i++) {
// tmp = extgpmc_dev.user_buff | (extgpmc_dev.user_buff[i+1]<<8);
// writew(tmp,extgpmc_base+i);
//}
//for (i = 0; i < len; i++) {
// printk("0x%x ",extgpmc_dev.user_buff);
//}
tmp = extgpmc_dev.user_buff;
writeb(tmp,extgpmc_base);
printk("0x%x ",tmp);
printk("\n");
extgpmc_write_done:
up(&extgpmc_dev.sem);
return status;
}
static ssize_t extgpmc_read(struct file *filp, char __user *buff,
size_t count, loff_t *offp)
{
ssize_t status;
size_t len;
// int i,tmp;
/*
Generic user progs like cat will continue calling until we
return zero. So if *offp != 0, we know this is at least the
second call.
*/
printk(KERN_ALERT "extgpmc_read\n");
if (*offp > 0)
return 0;
printk(KERN_ALERT "check down_interruptible(&extgpmc_dev.sem)..\n");
if (down_interruptible(&extgpmc_dev.sem))
return -ERESTARTSYS;
strcpy(extgpmc_dev.user_buff, "extgpmc driver data goes here\n");
len = strlen(extgpmc_dev.user_buff);
if (len > count)
len = count;
if (copy_to_user(buff, extgpmc_dev.user_buff, len)) {
status = -EFAULT;
printk(KERN_ALERT "status = -EFAULT..\n");
goto extgpmc_read_done;
}
printk(KERN_ALERT "read ok\n");
extgpmc_read_done:
up(&extgpmc_dev.sem);
return status;
}
static int extgpmc_open(struct inode *inode, struct file *filp)
{
int status = 0;
printk(KERN_ALERT "extgpmc_open(struct inode *inode, struct file *filp)");
if (down_interruptible(&extgpmc_dev.sem))
return -ERESTARTSYS;
if (!extgpmc_dev.user_buff) {
extgpmc_dev.user_buff = kmalloc(USER_BUFF_SIZE, GFP_KERNEL);
//kzalloc
if (!extgpmc_dev.user_buff) {
printk(KERN_ALERT "extgpmc_open: user_buff alloc failed\n");
status = -ENOMEM;
}else
printk(KERN_ALERT "extgpmc_dev.user_buff kmalloc OK \n");
}else
printk(KERN_ALERT "extgpmc_dev.user_buff is true \n");
up(&extgpmc_dev.sem);
return status;
}
static const struct file_operations extgpmc_fops = {
.owner = THIS_MODULE,
.open = extgpmc_open,
.read = extgpmc_read,
.write = extgpmc_write,
};
static int __init extgpmc_init_cdev(void)
{
int error;
u32 val;
printk(KERN_ALERT "extgpmc_init_cdev");
extgpmc_dev.devt = MKDEV(0, 0);
error = alloc_chrdev_region(&extgpmc_dev.devt, 0, 1, "extgpmc");
if (error) {
printk(KERN_ALERT "extgpmc alloc_chrdev_region() failed: %d\n", error);
return error;
}
cdev_init(&extgpmc_dev.icdev, &extgpmc_fops);
extgpmc_dev.icdev.owner = THIS_MODULE;
error = cdev_add(&extgpmc_dev.icdev, extgpmc_dev.devt, 1);
if (error) {
printk(KERN_ALERT "extgpmc cdev_add() failed: %d\n", error);
unregister_chrdev_region(extgpmc_dev.devt, 1);
return error;
}
printk("extgpmc Getting Chip Select\n");
// val = 0xf64;
// gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG7, val);
//gpmc_base = ioremap(GPMC_BASE_ADDR, SZ_4K);
val = gpmc_read_reg(GPMC_REVISION);
printk("extgpmc GPMC revision %d.%d\n", (val >> 4) & 0x0f, val & 0x0f);
gpmc_write_reg(GPMC_IRQENABLE, 0);
gpmc_write_reg(GPMC_TIMEOUT_CONTROL, 0);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG1, gpmc_nor[0]);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG2, gpmc_nor[1]);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG3, gpmc_nor[2]);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG4, gpmc_nor[3]);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG5, gpmc_nor[4]);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG6, gpmc_nor[5]);
val = gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG7);
printk("Gextgpmc PMC_CS_CONFIG7 value 0x%x\n", val);
if (gpmc_cs_request(GPMC_CS, SZ_2K, (unsigned long *)&mem_base) < 0){
printk(KERN_ERR "extgpmc Failed request for GPMC mem for usrp_e\n");
return -1;
}
printk("extgpmc Got CS0, address = %lx\n", mem_base);
if (!request_mem_region(mem_base, SZ_2K, "mem_extgpmc")) {
printk(KERN_ERR "extgpmc Request_mem_region failed.\n");
gpmc_cs_free(GPMC_CS);
return -1;
}
printk(KERN_ERR "extgpmc Request_mem_region OK.\n");
extgpmc_base = ioremap(mem_base, SZ_2K);
return 0;
}
static int __init extgpmc_init_class(void)
{
struct device *device;
extgpmc_dev.class = class_create(THIS_MODULE, "extgpmc");
if (IS_ERR(extgpmc_dev.class)) {
printk(KERN_ALERT "extgpmc class_create(extgpmc) failed\n");
return PTR_ERR(extgpmc_dev.class);
}
device = device_create(extgpmc_dev.class, NULL, extgpmc_dev.devt, NULL, "extgpmc");
if (IS_ERR(device)) {
class_destroy(extgpmc_dev.class);
printk(KERN_ALERT "extgpmc class_create(extgpmc) IS_ERR(device)\n");
return PTR_ERR(device);
}
printk(KERN_ALERT "extgpmc class_create(extgpmc) OK \n");
return 0;
}
static int __init extgpmc_init(void)
{
printk(KERN_INFO "extgpmc_init()\n");
memset(&extgpmc_dev, 0, sizeof(struct extgpmc_dev));
sema_init(&extgpmc_dev.sem, 1);
if (extgpmc_init_cdev())
goto init_fail_1;
if (extgpmc_init_class())
goto init_fail_2;
printk(KERN_INFO "extgpmc_init() OK \n");
return 0;
init_fail_2:
cdev_del(&extgpmc_dev.icdev);
unregister_chrdev_region(extgpmc_dev.devt, 1);
printk(KERN_INFO "extgpmc_init() init_fail_2 \n");
init_fail_1:
printk(KERN_INFO "extgpmc_init() init_fail_1 \n");
return -1;
}
module_init(extgpmc_init);
static void __exit extgpmc_exit(void)
{
printk(KERN_INFO "extgpmc_exit()\n");
device_destroy(extgpmc_dev.class, extgpmc_dev.devt);
class_destroy(extgpmc_dev.class);
cdev_del(&extgpmc_dev.icdev);
unregister_chrdev_region(extgpmc_dev.devt, 1);
release_mem_region(mem_base, SZ_2K);
gpmc_cs_free(GPMC_CS);
iounmap(extgpmc_base);
if (extgpmc_dev.user_buff)
kfree(extgpmc_dev.user_buff);
}
module_exit(extgpmc_exit);
MODULE_AUTHOR("ranruoyu");
MODULE_DESCRIPTION("extgpmc driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION("0.1");
2、编写Makefile
ARCH=arm
obj-m += extgpmc.o
KDIR := /opt/EmbedSky/TQ3358/Kernel_3.2_TQ3358_for_Linux_v2.0
PWD = $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -rf *.o
3、make 并查看
4、将文件拷贝到nfs挂载文件系统下,再测试
[root@EmbedSky /opt]# chmod 777 extgpmc.ko
[root@EmbedSky /opt]# insmod extgpmc.ko
extgpmc_init()
extgpmc_init_cdevextgpmc Getting Chip Select
extgpmc GPMC revision 6.0
Gextgpmc PMC_CS_CONFIG7 value 0xf00
extgpmc Got CS0, address = 1000000
extgpmc Request_mem_region OK.
extgpmc class_create(extgpmc) OK
extgpmc_init() OK
[root@EmbedSky /opt]# rmmod extgpmc.ko
[root@EmbedSky /opt]# dmesg | tail -3
extgpmc Request_mem_region OK.
extgpmc class_create(extgpmc) OK
extgpmc_init() OK
[root@EmbedSky /opt]#