在linux源码树下,编译arm驱动

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]# 


你可能感兴趣的:(arm)