There is my first device driver in Banana Pro board.
My idea is using this device driver module to control the LED board as below:
Here is the build process and source code:
Setup the build env:
Step 1. Download and rebuild the bsp
git clone https://github.com/LeMaker/lemaker-bsp.git
refer to my another bolg - Banana Pro] Building u-boot, script.bin and linux-kernel
I strong suggest rebuild the BSP on PC, and replace the uboot, kernel and modules to SD card, this is an important process to make sure the version of driver match with kernel. Otherwise, you may got fail when you insert your driver to kernel by insmod command.
Step 2. Copy the linux kernel tree from PC to Banana board(using scp)
PC side -> Banana side
scp -r ~/lemarker-bsp/linux-sunxi/ regis@192.168.0.111:/home/regis/ddv/3.4.103/
Programming:
Source code: led_drv.c
/*
* led_drv:
* LED device driver test program for banana Pro
* Copyright (c) 2015 Regis Hsu
*
* Thanks to code samples from Gordon Henderson
***********************************************************************
*
* led_drv is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* led_drv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with wiringPi.
* If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/spinlock.h>
#include <asm/io.h>
// BananaPro GPIO I/O memory address
#define LED_DRV_MAJOR 31
/*
IOCTL command
*/
#define LED_ON 1
#define LED_OFF 0
static volatile uint32_t *gpio ;
MODULE_LICENSE("Dual BSD/GPL");
/*add for BananaPro by LeMaker team*/
uint32_t readl_1(uint32_t addr)
{
uint32_t val = 0;
uint32_t mmap_base = (addr & ~MAP_MASK);
uint32_t mmap_seek = ((addr - mmap_base) >> 2);
val = ioread32(gpio + mmap_seek);
printk("func:%s phyaddr:0x%x val:0x%x\n",__func__, gpio + mmap_seek, va$
return val;
}
void writel_1(uint32_t val, uint32_t addr)
{
uint32_t mmap_base = (addr & ~MAP_MASK);
uint32_t mmap_seek = ((addr - mmap_base) >> 2);
printk("func:%s phyaddr:0x%x val:0x%x\n",__func__, gpio + mmap_seek, va$
iowrite32(val, gpio + mmap_seek);
}
int get_gpio_mode(int pin)
{
uint32_t regval = 0;
int bank = pin >> 5;
int index = pin - (bank << 5);
int offset = ((index - ((index >> 3) << 3)) << 2);
uint32_t reval=0;
uint32_t phyaddr = SUNXI_GPIO_BASE + (bank * 36) + ((index >> 3) << 2);
printk("func:%s pin:%d, bank:%d index:%d phyaddr:0x%x\n",__func__, pin$
regval = readl_1(phyaddr);
return reval;
}
void set_gpio_mode(int pin,int mode)
{
uint32_t regval = 0;
int bank = pin >> 5;
int index = pin - (bank << 5);
int offset = ((index - ((index >> 3) << 3)) << 2);
uint32_t phyaddr = SUNXI_GPIO_BASE + (bank * 36) + ((index >> 3) << 2);
My idea is using this device driver module to control the LED board as below:
Here is the build process and source code:
Setup the build env:
Step 1. Download and rebuild the bsp
git clone https://github.com/LeMaker/lemaker-bsp.git
refer to my another bolg - Banana Pro] Building u-boot, script.bin and linux-kernel
I strong suggest rebuild the BSP on PC, and replace the uboot, kernel and modules to SD card, this is an important process to make sure the version of driver match with kernel. Otherwise, you may got fail when you insert your driver to kernel by insmod command.
Step 2. Copy the linux kernel tree from PC to Banana board(using scp)
PC side -> Banana side
scp -r ~/lemarker-bsp/linux-sunxi/ regis@192.168.0.111:/home/regis/ddv/3.4.103/
Programming:
Source code: led_drv.c
/*
* led_drv:
* LED device driver test program for banana Pro
* Copyright (c) 2015 Regis Hsu
*
* Thanks to code samples from Gordon Henderson
***********************************************************************
*
* led_drv is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* led_drv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with wiringPi.
* If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/spinlock.h>
#include <asm/io.h>
// BananaPro GPIO I/O memory address
#define GPIO_BASE (0x01C20800)
/*
IOCTL command
*/
#define LED_ON 1
#define LED_OFF 0
static volatile uint32_t *gpio ;
MODULE_LICENSE("Dual BSD/GPL");
/*add for BananaPro by LeMaker team*/
uint32_t readl_1(uint32_t addr)
{
uint32_t val = 0;
uint32_t mmap_base = (addr & ~MAP_MASK);
uint32_t mmap_seek = ((addr - mmap_base) >> 2);
val = ioread32(gpio + mmap_seek);
printk("func:%s phyaddr:0x%x val:0x%x\n",__func__, gpio + mmap_seek, va$
return val;
}
{
uint32_t mmap_base = (addr & ~MAP_MASK);
uint32_t mmap_seek = ((addr - mmap_base) >> 2);
printk("func:%s phyaddr:0x%x val:0x%x\n",__func__, gpio + mmap_seek, va$
iowrite32(val, gpio + mmap_seek);
}
int get_gpio_mode(int pin)
{
uint32_t regval = 0;
int bank = pin >> 5;
int index = pin - (bank << 5);
int offset = ((index - ((index >> 3) << 3)) << 2);
uint32_t reval=0;
uint32_t phyaddr = SUNXI_GPIO_BASE + (bank * 36) + ((index >> 3) << 2);
printk("func:%s pin:%d, bank:%d index:%d phyaddr:0x%x\n",__func__, pin$
regval = readl_1(phyaddr);
return reval;
}
void set_gpio_mode(int pin,int mode)
{
uint32_t regval = 0;
int bank = pin >> 5;
int index = pin - (bank << 5);
int offset = ((index - ((index >> 3) << 3)) << 2);
uint32_t phyaddr = SUNXI_GPIO_BASE + (bank * 36) + ((index >> 3) << 2);
printk("func:%s pin:%d, MODE:%d bank:%d index:%d phyaddr:0x%x\n",__func$
regval = readl_1(phyaddr);
printk("read reg val: 0x%x offset:%d\n",regval,offset);
if(INPUT == mode)
{
regval &= ~(7 << offset);
writel_1(regval, phyaddr);
// for debug
regval = readl_1(phyaddr);
printk("Input mode set over reg val: 0x%x\n",regval);
}
else if(OUTPUT == mode)
{
regval &= ~(7 << offset);
regval |= (1 << offset);
printk("Output mode ready set val: 0x%x\n",regval);
writel_1(regval, phyaddr);
// for debug
regval = readl_1(phyaddr);
printk("Output mode set over reg val: 0x%x\n",regval);
}
else
{
printk("line:%dpin number error\n",__LINE__);
}
return ;
}
void digitalWrite(int pin, int value)
{
uint32_t regval = 0;
int bank = pin >> 5;
int index = pin - (bank << 5);
uint32_t phyaddr = SUNXI_GPIO_BASE + (bank * 36) + 0x10; // +0x10 -> d$
printk("func:%s pin:%d, value:%d bank:%d index:%d phyaddr:0x%x\n",__fun$
regval = readl_1(phyaddr);
printk("befor write reg val: 0x%x,index:%d\n",regval,index);
if(0 == value)
{
regval &= ~(1 << index);
writel_1(regval, phyaddr);
// for debug
regval = readl_1(phyaddr);
printk("LOW val set over reg val: 0x%x\n",regval);
}
else
{
regval |= (1 << index);
writel_1(regval, phyaddr);
// for debug
regval = readl_1(phyaddr);
printk("HIGH val set over reg val: 0x%x\n",regval);
}
}
int digitalRead(int pin)
{
uint32_t regval = 0;
int bank = pin >> 5;
int index = pin - (bank << 5);
uint32_t phyaddr = SUNXI_GPIO_BASE + (bank * 36) + 0x10; // +0x10 -> da$
printk("func:%s pin:%d,bank:%d index:%d phyaddr:0x%x\n",__func__, pin,b$
regval = readl_1(phyaddr);
regval = regval >> index;
regval &= 1;
printk("***** read reg val: 0x%x,bank:%d,index:%d,line:%d\n",regval,ban$
return regval;
}
int led_open (struct inode *pnode, struct file *pfile)
{
printk("enter %s!\n", __FUNCTION__);
// remap the physical address to virtual address
gpio = ioremap(GPIO_BASE, 2*1024);
return 0;
}
ssize_t led_read(struct file *pfile, char __user *buffer, size_t lenght, loff_t$
{
printk("enter %s!\n", __FUNCTION__);
return 0;
}
ssize_t led_write(struct file *pfile, const char __user *buffer, size_t lenght,$
{
printk("enter %s!\n", __FUNCTION__);
return lenght;
}
long led_ioctl(struct file *pfile, unsigned int cmd, unsigned long data)
{
switch (cmd)
{
case LED_ON :
printk ("%s %d!\n", __FUNCTION__, cmd);
set_gpio_mode(data, OUTPUT);
digitalWrite (data, HIGH) ;
break;
case LED_OFF:
printk ("%s %d!\n", __FUNCTION__, cmd);
set_gpio_mode(data, OUTPUT);
digitalWrite (data, LOW) ;
break;
default :
printk ("%s CMD Error!\n", __FUNCTION__);
break;
}
return 0;
}
static struct file_operations io_dev_fops = {
.owner = THIS_MODULE,
.read = led_read,
.write = led_write,
.open = led_open,
.release = led_close,
.unlocked_ioctl = led_ioctl,
};
int __init led_init(void)
{
register_chrdev(LED_DRV_MAJOR, "led",&io_dev_fops);
printk("enter %s!\n", __FUNCTION__);
return 0;
}
void __exit led_exit(void)
{
unregister_chrdev(LED_DRV_MAJOR, "led");
printk("enter %s!\n", __FUNCTION__);
}
module_init(led_init);
module_exit(led_exit);
And, create a make file names "Makefile"
Makefile
obj-m := led_drv.o
It is almost done for the coding!!!
Let's start build the device driver module~~~
It is almost done for the coding!!!
Let's start build the device driver module~~~
regis@lemaker:~/ddr/led$ make -C /home/regis/ddv/3.4.103 M=$PWD modules
make: Entering directory `/home/regis/ddv/3.4.103'
Building modules, stage 2.
MODPOST 1 modules
make: Leaving directory `/home/regis/ddv/3.4.103'
regis@lemaker:~/ddr/led$
ok, now, write a test program to test this device driver:
ddr_test.c
/*
* ddr_test:
* LED device driver test program for banana Pro
* Copyright (c) 2015 Regis Hsu
*
* Thanks to code samples from Gordon Henderson
***********************************************************************
*
* led_drv is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* led_drv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with wiringPi.
* If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#define DEVICE_NAME "/dev/led_drv"
#define LED_ON 1
#define LED_OFF 0
// the PIN7 of BananaPro J6 output is related
// the port PH2 of Allwinner A20 GPIO (Port Group"H")
// it is 32 x 7 + 2 = 226
#define PIN_NO 226
int main(void)
{
int fd;
int ret;
int i;
printf("\nstart led driver test\n\n");
fd = open(DEVICE_NAME, O_RDWR);
printf("fd = %d\n",fd);
if (fd == -1)
{
printf("open device %s error\n",DEVICE_NAME);
}
else
{
//while(1)
for (i=0; i<128; i++)
{
printf("i=%d _ON\n", i);
//fgetc(stdin);
ioctl(fd,LED_ON, PIN_NO);
sleep(.8);
printf("i=%d _OFF\n", i);
//fgetc(stdin);
ioctl(fd,LED_OFF, PIN_NO);
sleep(.8);
}
ret = close(fd);
printf ("ret=%d\n",ret);
printf ("close led driver test\n");
}
return 0;
}// end main
Finally, finish the test code and compile it.
regis@lemaker:~/ddr/led$ gcc ddr_test.c -o ddr_test
It is the show time!!!!!
How to test the device driver?
Step 1:
create a device node:
regis@lemaker:~/ddr/led$ sudo mknod -m 666 /dev/led_drv c 31 0
step 2:
load the driver to system to link with the device node
regis@lemaker:~/ddr/led$ sudo insmod led_drv.ko
check where is the led_drv
regis@lemaker:~/ddr/led$ lsmod
Module Size Used by
led_drv 5049 0
dm_crypt 17240 0
rfcomm 58954 0
bnep 14608 2
bluetooth 266122 10 bnep,rfcomm
ap6210 624941 0
mali_drm 2607 0
drm 215174 1 mali_drm
mali 114752 0
ump 58497 1 mali
step 3:
regis@lemaker:~/ddr/led$ ./ddr_test
start led driver test
fd = 3
i=0 _ON
i=0 _OFF
i=1 _ON
i=1 _OFF
.......
i=126 _ON
i=126 _OFF
i=127 _ON
i=127 _OFF
ret=0
close led driver test
regis@lemaker:~/ddr/led$
You will see the LED flash 128 times.
/////////////////////////////////////////////////////////////////
Some information for reference:
Find an available device node number by this way,
1. Install the Code::Blocks IDE toolsFind an available device node number by this way,
regis@lemaker:~/ddr/led$ sudo apt-get install codeblocks
2. List down the device node
regis@lemaker:~/ddr/led$ cat /proc/devices
Character devices:
1 mem
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
14 sound
29 fb
81 video4linux
89 i2c
108 ppp
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
216 rfcomm
226 drm
241 mali
242 ump
243 hdmi
244 lcd
245 roccat
246 hidraw
247 pa_chrdev
248 ace_chrdev
249 usbmon
250 g2d_chrdev
251 disp
252 bsg
253 media
254 rtc
Block devices:
1 ramdisk
259 blkext
7 loop
8 sd
9 md
11 sr
65 sd
66 sd
67 sd
68 sd
69 sd
70 sd
71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc
253 device-mapper
254 mdp
沒有留言:
張貼留言