将前面的三篇中的代码整合起来代码如下:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/platform_device.h>

#include <asm/io.h>
#include <asm/uaccess.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhanglong");

/*
 *板子上的led1,2,4,8分别对应连在GPF4,5,6,7上
 *
 *GPFCON ==> 0x56000050
 *GPFDAT ==> 0x56000054
 *GPFUP ==> 0x56000058
 *
 */

#define IO_PHYS 0x56000000
#define GPFCON_OFFSET 0x50
#define GPFDAT_OFFSET 0x54
#define GPFUP_OFFSET 0x58

struct led_device_s {
    struct cdev dev;
    dev_t no; 
    struct class_device *led_classdev;

    short *io_gpfcon;
    char *io_gpfdat;
    char *io_gpfup;
};

struct led_device_s my_led;

void zl_release(struct device *dev)
{
    printk("device release.\n");
}

struct resource zl_res[] = {
    {
        .start = IO_PHYS,
        .end = IO_PHYS + SZ_4K,
        .flags = IORESOURCE_IO,
    },
#if 0
    {
        .start = IRQ_EINT2,
        .end = IRQ_EINT2,
        .flags = IORESOURCE_IRQ,
    },
#endif
};

struct platform_device zl_dev = {
    .name = "zl_device",        //this string will be show as /sys/devices/platform/zl_device.0

    .dev = {
        .release = zl_release,
        .platform_data = &my_led,
    },
    .num_resources = ARRAY_SIZE(zl_res),
    .resource = zl_res,
};

unsigned int devnum = 0;
struct class *my_class;

ssize_t my_read(struct file *fp, char __user *buf, size_t count, loff_t *off)
{
    return 4; //不能返回0, 否则读相关设备时会卡住.

}


ssize_t my_write(struct file *fp, const char __user *buf, size_t count, loff_t *off)
{
    struct led_device_s *get = fp->private_data;
    unsigned int minor;
    char value;

    copy_from_user(&value, buf, 1);

#if 0
    minor = MINOR(get->no);

    *(get->io_gpfcon) &= ~(<< ((minor * 2) + 8));
    *(get->io_gpfcon) |= (<< ((minor * 2) + 8));
    *(get->io_gpfup) &= ~(<< (minor + 4));

    if((*buf == 0) || (*buf == 48)) {
        *(get->io_gpfdat) &= ~(<< (minor + 4));
    } else {
        *(get->io_gpfdat) |= (<< (minor + 4));
    }
#else
    *(get->io_gpfcon) &= ~(0xff << 8);
    *(get->io_gpfcon) |= (0x55 << 8);
    *(get->io_gpfup) &= ~(0xf0);

    if((value >= 0) && (value <= 15)) {
        *(get->io_gpfdat) = ((value & 0xf) << 4);
    } else if((value >= '0') && (value <= '9')){
        *(get->io_gpfdat) = ((value & 0xf) << 4);
    } else if((value >= 'a') && (value <= 'f')){
        *(get->io_gpfdat) = ((value - 97 + 10) << 4);
    } else if((value >= 'A') && (value <= 'F')){
        *(get->io_gpfdat) = ((value - 65 + 10) << 4);
    } else {

    }
#endif

    return 4;
} 

int my_open(struct inode *no, struct file *fp)
{ 
    fp->private_data = container_of(no->i_cdev, struct led_device_s, dev);
    //printk(" kernel: open.\n");

    return 0;
}


int my_release(struct inode *no, struct file *fp)
{ 
    //printk(" kernel: release.\n");

    return 0;
}

struct file_operations my_ops = {
    .open = my_open,
    .release = my_release,
    .read = my_read,
    .write = my_write,
};

int zl_probe(struct device * dev)
{
    struct platform_device *pdev = container_of(dev, struct platform_device, dev);
    struct resource *res = pdev->resource;
    struct led_device_s *pled = pdev->dev.platform_data; 

    int ret = 0;
    char *virt = NULL;
    u32 i; 

    for(= 0; i < pdev->num_resources; i++) {
        if(IORESOURCE_IO & res[i].flags) {
            virt = ioremap(res[i].start, (res[i].end - res[i].start));
            break;
        }
    }
    if(virt == NULL){
        printk("[%s-L%d]:virt == NULL\n", __func__, __LINE__);
        return -1;
    }

    pled->io_gpfcon = virt + GPFCON_OFFSET;
    pled->io_gpfdat = virt + GPFDAT_OFFSET;
    pled->io_gpfup = virt + GPFUP_OFFSET;
    pled->no = MKDEV(52, devnum);
  
    cdev_init(&pled->dev, &my_ops);
    cdev_add(&pled->dev, pled->no, 1); 

    pled->led_classdev = device_create(my_class, NULL, pled->no, &(pled->dev),"mydev_led.%d", devnum); 
    if(IS_ERR(pled->led_classdev)) {
        printk("[%s-L%d]: device_create.\n", __func__, __LINE__);
        return PTR_ERR(pled->led_classdev);
    }

    devnum++;

    printk("driver zl_probe.\n");

    return ret;
}

int zl_remove(struct device * dev)
{
    struct platform_device *pdev = container_of(dev, struct platform_device, dev);
    struct led_device_s *pled = pdev->dev.platform_data; 

    device_destroy(my_class, pled->no);
    cdev_del(&pled->dev); 
    printk("driver zl_remove.\n");
    return 0;
}

struct device_driver zl_driver_struct = {
        .name = "zl_device", //this string will be show as /sys/bus/platform/drivers/zl_device

        .bus = &platform_bus_type,
        .probe = zl_probe,
        .remove = zl_remove,
};

int test_init(void)
{
    int ret = 0;

    driver_register(&zl_driver_struct);
    my_class = class_create(THIS_MODULE, "myclass_led");
    if (IS_ERR(my_class)) {
        printk("[%s-%d]: class_create.\n", __func__, __LINE__);
        return PTR_ERR(my_class);
    }
 
    ret = register_chrdev_region(MKDEV(52,0), 4, "my_led");
    if (ret) {
        printk("[%s-L%d]: register_chrdev_region.\n", __func__, __LINE__);
        return ret;
    }
    platform_device_register(&zl_dev);

    return ret;
}

void test_exit(void)
{
    platform_device_unregister(&zl_dev);
    class_destroy(my_class);
    driver_unregister(&zl_driver_struct);
}

module_init(test_init);
module_exit(test_exit);

丘猴子 發表在 痞客邦 留言(0) 人氣()

一个简单的platform设备驱动
硬/软件环境:s3c2440/linux-2.6.36/busybox-1.18.4/arm-linux-gcc 4.4.3

下面是模块的c代码:

#include <linux/module.h>
#include <linux/init.h>

#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/platform_device.h>

#include <asm/io.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zl");

int zl_probe(struct device * dev)
{
    struct platform_device *pdev = container_of(dev, struct platform_device, dev);
    struct resource *res = pdev->resource;

    printk("driver zl_probe.\n");

    return 0;
}

int zl_remove(struct device * dev)
{
    printk("driver zl_remove.\n");
    return 0;
}

struct device_driver zl_driver_struct = {
        .name = "zl_device", //this string will be show as /sys/bus/platform/drivers/zl_device

        .bus = &platform_bus_type,
        .probe = zl_probe,
        .remove = zl_remove,
};

void zl_release(struct device *dev)
{
    printk("device release.\n");
}

struct resource zl_res[] = {
    {
        .name = "zl_res_name",
        .start = 0x56000000,
        .end = 0x57000000,
        .flags = IORESOURCE_IO,
    },

    {
        .start = IRQ_EINT2,
        .end = IRQ_EINT2,
        .flags = IORESOURCE_IRQ,
    },
};

struct platform_device zl_dev = {
    .name = "zl_device",        //this string will be show as /sys/devices/platform/zl_device.0

    .dev = {
        .release = zl_release,
    },
    .num_resources = ARRAY_SIZE(zl_res),
    .resource = zl_res,
};

int test_init(void)
{
    int ret = 0;

    platform_device_register(&zl_dev);
    driver_register(&zl_driver_struct);
    return ret;
}

void test_exit(void)
{
    driver_unregister(&zl_driver_struct);
    platform_device_unregister(&zl_dev);
}

module_init(test_init);
module_exit(test_exit);

丘猴子 發表在 痞客邦 留言(0) 人氣()

在linux下使用class的功能

硬/软件环境:s3c2440/linux-2.6.36/busybox-1.18.4/arm-linux-gcc 4.4.3

下面是模块的c代码:

#include <linux/module.h>
#include <linux/init.h>

#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/platform_device.h>

#include <asm/io.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhanglong");

//----------------------------

struct class *zl_class;
struct class_device *test_cla_dev;

struct zl_device {
    struct device dev;
    dev_t no;
};

struct zl_device zl_dev = {
    .no = MKDEV(52,0),
};

int test_init(void)
{
    int ret = 0;

    zl_class = class_create(THIS_MODULE, "zl_class");
    test_cla_dev = device_create(zl_class, NULL, zl_dev.no, &(zl_dev.dev),"zldev_name");        
    return ret;
}

void test_exit(void)
{
    class_destroy(zl_class);
}

module_init(test_init);
module_exit(test_exit);

丘猴子 發表在 痞客邦 留言(0) 人氣()

一个led驱动,做个记号

硬软件环境:s3c2440/linux-2.6.36/busybox-1.18.4/arm-linux-gcc 4.4.3

下面是模块c代码:


#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/io.h>

#include <asm/uaccess.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhanglong");

/*
 * 板子上的led1,2,4,8分别对应连在GPF4,5,6,7上
 *
 *GPFCON ==> 0x56000050
 *GPFDAT ==> 0x56000054
 *GPFUP ==> 0x56000058
 *
 */
#define IO_PHYS 0x56000000
#define GPFCON_OFFSET   0x50
#define GPFDAT_OFFSET   0x54
#define GPFUP_OFFSET   0x58

struct led_device_s {
    struct cdev dev;
    dev_t  no;

    short *io_gpfcon;   //注意数据类型, 前面因为错误声明为char型指针,造成结果与预期的不同,郁闷了很久.
    char *io_gpfdat;
    char *io_gpfup;
};

struct led_device_s  my_led[4];

ssize_t my_write(struct file *fp, const char __user *buf, size_t count, loff_t *off)
{
    struct led_device_s *get = fp->private_data;
    unsigned int    minor;

    minor = MINOR(get->no);
    
    *(get->io_gpfcon) &= ~(3 << ((minor * 2) + 8));
    *(get->io_gpfcon) |= (1 << ((minor * 2) + 8));
    *(get->io_gpfup) &= ~(1 << (minor + 4));

    if((*buf == 0) || (*buf == 48)) {
        *(get->io_gpfdat) &= ~(1 << (minor + 4));
    } else {
        *(get->io_gpfdat) |= (1 << (minor + 4));
    }

    return  4;
}

ssize_t my_read(struct file *fp, char __user *buf, size_t count, loff_t *off)
{
    return  4;  //不能返回0, 否则读相关设备时会卡住.
}


int my_open(struct inode *no, struct file *fp)
{
    fp->private_data = container_of(no->i_cdev, struct led_device_s, dev);
    //printk(" kernel: open.\n");

    return 0;
}

int my_release(struct inode *no, struct file *fp)
{
    //printk(" kernel: release.\n");

    return 0;
}

struct file_operations my_ops = {
    .open = my_open,
    .release = my_release,
    .read = my_read,
    .write = my_write,
};

int test_init(void)
{
    int ret = 0;
    char *virt;
    int i;    

    virt = ioremap(IO_PHYS, SZ_4K);

    for (i = 0; i < 4; i ++) {
        my_led[i].no = MKDEV(52, i);
        cdev_init(&my_led[i].dev, &my_ops);

        my_led[i].io_gpfcon = virt + GPFCON_OFFSET;
        my_led[i].io_gpfdat = virt + GPFDAT_OFFSET;
        my_led[i].io_gpfup = virt + GPFUP_OFFSET;
    }

    ret = register_chrdev_region(my_led[0].no, 4, "my dev");
    if (ret) {
        printk(" register device number failed.\n");
        return ret;
    }

    for (i = 0; i < 4; i ++) {
        cdev_add(&my_led[i].dev, my_led[i].no, 1);
    }

    return ret;
}

void test_exit(void)
{
    int i ;
    for (i = 0; i < 4; i ++) {
        cdev_del(&my_led[i].dev);
    }
    unregister_chrdev_region(my_led[0].no, 4);    
}

module_init(test_init);
module_exit(test_exit);


下面是Makefile文件内容

丘猴子 發表在 痞客邦 留言(0) 人氣()

在 u-boot shell 中 可以吃的 kernel image 是 uImage, 剛好綱哥他們那一個平台的 可以吃 zImage 因為好奇 所以稍微 trace 一下.

丘猴子 發表在 痞客邦 留言(0) 人氣()

其實這個問題困擾我很久 在 grub 裡會我們會填一個 initrd 的東西, 這個東西就是在 /boot 下面的 initrd.img* 這個檔案 是 ramdisk 但是問題來了 grub 到底是如何跟 kernel 互動的呢?

丘猴子 發表在 痞客邦 留言(0) 人氣()


CF/SD 卡上用 JFFS2 好嗎?

丘猴子 發表在 痞客邦 留言(0) 人氣()

報告名稱:JFFS2 書面報告

製作學生:鄭家明

丘猴子 發表在 痞客邦 留言(0) 人氣()

分享: MURMUR facebook PLURK twitter Del.icio.us  

動機

丘猴子 發表在 痞客邦 留言(0) 人氣()

分享: MURMUR facebook PLURK twitter Del.icio.us  

Character or block device?

丘猴子 發表在 痞客邦 留言(0) 人氣()