#include <linux/delay.h>
#include <linux/device.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
//#define DEVICE_NAME "leds" /* 驅動名稱 */
//#define LEDS_MAJOR 231 /* 次設備號 */
//-------------------------------------------------------------------------
#define CHAR_DEV_DEVICE_NAME "cdev_leds" // 設備名
struct class *char_dev_class; // class結構用於自動創建設備結點
static int major = 0;
static struct cdev char_dev_devs;// 定義一個cdev結構
static unsigned long led_table [] = {
S3C2410_GPB(5),
S3C2410_GPB(6),
S3C2410_GPB(7),
S3C2410_GPB(8),
};
static unsigned int led_cfg_table [] = {
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
};
/*驅動程序,提供這個接口*/
static int sbc2440_leds_ioctl(
struct inode *inode, /*內核裏面的兩個結構體*/
struct file *file,
unsigned int cmd, /*開關燈*/
unsigned long arg)/*第幾個燈*/
{
switch (cmd) {
case 0: /*空,不執行*/
case 1:
if (arg >=4) {
return -EINVAL;/*返回錯誤*/
}
s3c2410_gpio_setpin(led_table[arg], !cmd);/*條件具備(arg小於4時候執行本函數)把第幾個腳設置低電平,燈亮*/
return 0;
default:
return -EINVAL;
}
}
// 設備建立子函數,被char_dev_init函數調用
static void char_dev_setup_cdev(struct cdev *dev, int minor, struct file_operations *fops)
{
int err, devno = MKDEV(major, minor);
cdev_init(dev, fops);
dev->owner = THIS_MODULE;
dev->ops = fops;//這句可以不寫,已經在cdev_init()函數裏實現了。
err = cdev_add(dev, devno, 1); //註冊設備
if ( err )
{
printk(KERN_NOTICE "Error %d adding char_dev %d\n", err, minor);
}
}
// file_operations 結構體設置,該設備的所有對外接口在這裏明確,此處只寫出了幾常用的
static struct file_operations char_dev_fops =
{
.owner = THIS_MODULE,
/* .open = char_dev_open, // 打開設備
.release = char_dev_release, // 關閉設備
.read = char_dev_read, // 實現設備讀功能
.write = char_dev_write, // 實現設備寫功能 */
.ioctl = sbc2440_leds_ioctl, //實現設備控制功能
};
// 設備初始化
static int char_dev_init(void)
{
int result;
dev_t dev = MKDEV(major, 0);
if ( major )
{
// 給定設備號註冊
result =DEV_DEV register_chrdev_region(dev, 1, CHAR_ICE_NAME);
else
{
// 動態分配設備號並註冊
result = alloc_chrdev_region(&dev, 0, 1, CHAR_DEV_DEVICE_NAME);
major = MAJOR(dev);
}
char_dev_setup_cdev(&char_dev_devs, 0, &char_dev_fops);
printk("The major of the char_dev device is %d\n", major);
//==== 有中斷的可以在此註冊中斷:request_irq,並要實現中斷服務程序 ===//
// 創建設備結點
char_dev_class = class_create(THIS_MODULE,CHAR_DEV_DEVICE_NAME);
if (IS_ERR(char_dev_class))
{
printk("Err: failed in creating class.\n");
return 0;
}
device_create(char_dev_class, NULL, dev, NULL, CHAR_DEV_DEVICE_NAME);
return 0;
}
// 設備註銷
static void char_dev_cleanup(void)
{
cdev_del(&char_dev_devs);//字符設備的註銷*/
unregister_chrdev_region(MKDEV(major, 0), 1);//設備號的註銷
device_destroy(char_dev_class,MKDEV(major,0));
class_destroy(char_dev_class);
//======== 有中斷的可以在此註銷中斷:free_irq ======//
printk("char_dev device uninstalled\n");
}
module_init(char_dev_init); //模塊初始化接口
module_exit(char_dev_cleanup);//模塊註銷接口
// 以下兩句不能省略,否則編譯不通過
MODULE_AUTHOR("www.arm.com");
MODULE_LICENSE("GPL");
#include <linux/module.h>
/* register_chrdev(),unregister_chrdev(),struct file_operations */
#include <linux/fs.h>
/*定義設備名*/
#define DEV_NAME "first_chardev"
int major = 0;
int first_chardev_open (struct inode *inode, struct file *file)
{
printk(KERN_EMERG"open() call\r\n");
return 0 ;
}
ssize_t first_chardev_read (struct file *file, char __user *buf, size_t size, loff_t * off)
{
printk(KERN_EMERG"read() call\r\n");
return size;
}
ssize_t first_chardev_write (struct file *file, const char __user *buf, size_t size, loff_t *off)
{
printk(KERN_EMERG"write() call\r\n");
return size;
}
int first_chardev_ioctrl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
printk(KERN_EMERG"ioctl() call\r\n");
return 0;
}
int first_chardev_close (struct inode *inode, struct file *file)
{
printk(KERN_EMERG"release() call\r\n");
return 0;
}
loff_t first_chardev_llseek(struct file *file, loff_t loff, int origin )
{
printk(KERN_EMERG"llseek() call\r\n");
printk(KERN_EMERG"loff:%d; origin:%d\r\n",loff,origin);
return loff;
}
static const struct file_operations first_chardev_fops=
{
.open = first_chardev_open,
.release = first_chardev_close,
.read = first_chardev_read,
.write = first_chardev_write,
.ioctl = first_chardev_ioctrl,
.llseek = first_chardev_llseek,
};
static int __init first_chardev_init(void)
{
printk(KERN_EMERG"module init now!\r\n");
major = register_chrdev(major,DEV_NAME,&first_chardev_fops); //註冊設備 printk(KERN_EMERG"major:%d\r\n",major);
return 0;
}
static __exit void first_chardev_exit(void)
{
printk(KERN_EMERG"module remove now!\r\n");
unregister_chrdev(major,DEV_NAME); //註銷設備
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ARM Inc.");
module_init(first_chardev_init);
module_exit(first_chardev_exit);
MODULE_DESCRIPTION("this is simlpe fist driver test!\r\n");
/*提供接口函數給內核,在dev目錄下生成設備節點*/
static struct file_operations dev_fops = {
.owner = THIS_MODULE,/*初始化加載模式 就是個聲明,模塊加1*/
.ioctl = sbc2440_leds_ioctl,/*控制函數*/
};
/*註冊(報到)*/
static struct miscdevice misc = {
.minor = LEDS_MAJOR, /*次設備號 .minor是結構題裏面的一個元素(變量) */
.name = DEVICE_NAME,/*設備號*/
.fops = &dev_fops,/*功能函數 &取地址*/
};
/*初始化,內存優化*/
static int __init dev_init(void)//(開機運行一次)
{
int ret;
int i;
for (i = 0; i < 4; i++) {
s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);/*gpio口配置,設置輸入輸出 內核自帶函數 ,四個I/O設置輸出 */
s3c2410_gpio_setpin(led_table[i], 1);/*設爲高電平,所有燈關掉*/
}
ret = misc_register(&misc);/*雜選設備註冊,主設備號固定,註冊函數*/
printk (DEVICE_NAME"\tinitialized\n");
return ret;
}
/*退出函數*/
static void __exit dev_exit(void)/*__編譯器用的 __exit編譯器規定要加的*/
{
misc_deregister(&misc);/*釋放註冊*/
}
module_init(dev_init);/*聲明初始化函數(從哪裏進來)初始化加載用的*/
module_exit(dev_exit);/*聲明退出函數*/
MODULE_LICENSE("GPL");/*聲明遵循GPL協議(開源協議)*/