iny6410 simple LED character device driver io driver

Publisher:oplkjjjLatest update time:2019-10-30 Source: 51heiKeywords:iny6410 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

        return ;    

    }    

        

    module_init(led_init);    

    module_exit(led_exit);    



Makefile



[cpp] view plain copy

print?


    obj-m := led_driver.o    

    KDIR :=/home/workdir/kernel/linux-2.6.38  

    all:    

        make -C $(KDIR) M=$(shell pwd) modules    

    install:    

        cp driver_led.ko /tftpboot/    

    clean:    

        make -C $(KDIR) M=$(shell pwd) clean   





Test Files



test_led.c


[cpp] view plain copy

print?


    #include     

    #include     

    #include     

    #include     

      

      

    #define LED_OFF 0  

    #define LED_ON 1  

    #define LED_1_ON 2  

    #define LED_1_OFF 3  

    #define LED_2_ON 4  

    #define LED_2_OFF 5  

    #define LED_3_ON 6  

    #define LED_3_OFF 7  

    #define LED_4_ON 8  

    #define LED_4_OFF 9  

      

    int main (void)    

    {    

        int i=0;  

        int fd;    

        char buf[10]={  

                LED_ON , LED_OFF ,  

                LED_1_ON, LED_1_OFF,  

                LED_2_ON, LED_2_OFF,  

                LED_3_ON, LED_3_OFF,  

                LED_4_ON, LED_4_OFF,             

             };    

      

        fd = open("/dev/led",O_RDWR);    

        if (fd < 0)    

        {    

            printf ("Open /dev/led file errorn");    

            return -1;    

        }       

      

        while(i<10)    

        {    

            write(fd,&buf[i],4);    

            sleep(1);    

            i++;  

        }    

        close (fd);    

        return 0;    

        

    }   


If the above compilation is OK, you can download it to the board for testing.

Load the driver insmod led_driver.ko
Create the device file mknod /dev/led c 243 0 Where 243 should be consistent with the device number in the driver file

Run the test file ./test_led
to complete.


------------------------------------------------------------------------------------------
References:

#include /*It defines the module's API, type and macros (MODULE_LICENSE, MODULE_AUTHOR, etc.). All kernel modules must include this header file. /

#include /*This file should be included when using kernel information priority. Priority information is generally used when using the printk function*/

#include //Header file: macro definitions such as module_init and module_exit.

#include ////struct file_operations

#include

#include // S3C2410 GPIO register definition

#include // s3c2410_gpio_setpin, s3c2410_gpio_cfgpin, etc.

#include //class_create device_create (note that some 2.6.27 and earlier may be class_device_create. If an implicate error occurs, check which one is in this header problem), udev, automatically creates a device node under /dev

#include //Character device node registration, functions include cdev_init, cdev_add, cdev_del, etc. The early method is register_chrdev, unregister_chrdev. This method should be avoided.

#define DEVICE_NAME "leds" /* After loading mode, execute the "cat /proc/devices" command to see the device name*/

#define LED_MAJOR 231 /* Main device number*/

/* The second parameter when the application executes ioctl(fd, cmd, arg)*/

#define IOCTL_LED_ON 1

#define IOCTL_LED_OFF 0

/* Used to specify the GPIO pin used by the LED */

static unsigned long led_table[] =

{

S3C2410_GPB5,

S3C2410_GPB6,

S3C2410_GPB7,

S3C2410_GPB8,

};

/* Used to specify the function of the GPIO pin: output*/

static unsigned int led_cfg_table[] =

{

S3C2410_GPB5_OUTP,

S3C2410_GPB6_OUTP,

S3C2410_GPB7_OUTP,

S3C2410_GPB8_OUTP,

};

struct leds_type

{

struct cdev cdev;

};

struct leds_type *my_leds_dev;

/* When the application executes open(...) on the device file /dev/EmbedSky-leds,

* The EmbedSky_leds_open function will be called

*/

static int EmbedSky_leds_open(struct inode *inode, struct file *file)

{

int i;

for (i = 0; i < 4; i++)

{

// Set the function of the GPIO pin: The GPIO pin involved in the LED in this driver is set to output function

s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);

}

return 0;

}

/* When the application executes ioclt(...) on the device file /dev/EmbedSky-leds,

* The EmbedSky_leds_ioctl function will be called

*/

static int EmbedSky_leds_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)

{

if (arg > 4)

{

return -EINVAL;

}

switch(cmd)

{

case IOCTL_LED_ON:

// Set the output level of the specified pin to 0

s3c2410_gpio_setpin(led_table[arg], 0);

return 0;

case IOCTL_LED_OFF:

// Set the output level of the specified pin to 1

s3c2410_gpio_setpin(led_table[arg], 1);

return 0;

default:

return -EINVAL;

}

}

/* This structure is the core of the character device driver

* The open, read, write and other functions called when the application operates the device file.

* The corresponding function specified in this structure will eventually be called

*/

static struct file_operations EmbedSky_leds_fops =

{

.owner = THIS_MODULE, /* This is a macro that pushes to the __this_module variable that is automatically created when compiling the module*/

.open = EmbedSky_leds_open,

.ioctl = EmbedSky_leds_ioctl,

};

static char __initdata banner[] = "TQ2440/SKY2440 LEDS, (c) 2008,2009 www.embedsky.net/n";

static struct class *led_class;

/*

* This function will be called when executing the "insmod EmbedSky_leds.ko" command

*/

static int __init EmbedSky_leds_init(void)

{

int ret;

dev_t devno=MKDEV(LED_MAJOR,0);

printk("init led/n");

printk(banner);

/* Register character device driver

* The parameters are the major device number, device name, and file_operations structure;

* In this way, the major device number is associated with the specific file_operations structure.

* When operating the device file whose main device is LED_MAJOR, the relevant member functions in EmbedSky_leds_fops will be called

ret = register_chrdev_region(devno, 1,DEVICE_NAME); //Get the device number

my_leds_dev = kmalloc(sizeof(struct leds_type),GFP_KERNEL);

/*This must be present, otherwise the error "Unable to handle kernel NULL pointer dereference at virtual addres 00000000" will appear when loading the module. This is because my_leds_dev is just a pointer here, and there is no allocated memory of the corresponding size, so an error will occur when using it. It is quite troublesome to find this error*/

if(!my_leds_dev)

{

ret=-ENOMEM;

goto fail_malloc;

}

memset(my_leds_dev,0,sizeof(struct leds_type));

cdev_init(&(my_leds_dev->cdev),&EmbedSky_leds_fops);

ret = cdev_add(&(my_leds_dev->cdev),devno,1);

/*Note: Different from the earlier device registration method, the earlier direct register_chrdev() method was sufficient. */

if(ret)printk(KERN_NOTICE"ERROR %d",ret);

//Register a class so that mdev can create device nodes under the "/dev/" directory

led_class = class_create(THIS_MODULE, DEVICE_NAME);

if(IS_ERR(led_class))

{

printk("Err: failed in EmbedSky-leds class. /n");

return -1;

}

//Create a device node named DEVICE_NAME

device_create(led_class, NULL, MKDEV(LED_MAJOR, 0), NULL, DEVICE_NAME);

printk(DEVICE_NAME " initialized/n");

return 0;

fail_malloc: unregister_chrdev_region(devno,1);

return ret;

}

/*

* This function will be called when executing the "rmmod EmbedSky_leds.ko" command

*/

static void __exit EmbedSky_leds_exit(void)

{

/* Uninstall the driver */

unregister_chrdev(LED_MAJOR, DEVICE_NAME);

device_destroy(led_class, MKDEV(LED_MAJOR, 0)); //Delete the device node

class_destroy(led_class); //Deregister class

}

/* These two lines specify the initialization function and uninstallation function of the driver */

module_init(EmbedSky_leds_init);

module_exit(EmbedSky_leds_exit);

/* Describe some information about the driver, not required */

MODULE_AUTHOR("http://www.embedsky.net"); // Driver author

MODULE_DESCRIPTION("TQ2440/SKY2440 LED Driver"); // Some description information

MODULE_LICENSE("GPL"); // Comply with the agreement

In the above code, the led_table array is equivalent to the index of the four IO ports of GPB. Through these four values, relevant operations are performed on these four IO ports. For example:

S3C2410_GPB5 = S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5)

= S3C2410_GPIO_BANKB + 5

= 32*1 + 5

In s3c2410_gpio_setpin(S3C2410_GPB5,0), the function first obtains the virtual address and offset address of GPB through S3C2410_GPB5, and then operates the GPBDAT register of GPB5.

void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)

{

void __iomem *base = S3C2410_GPIO_BASE(pin);

unsigned long offs = S3C2410_GPIO_OFFSET(pin);

unsigned long flags;

unsigned long dat;

local_irq_save(flags);

dat = __raw_readl(base + 0x04); //Read GPIO DAT data to dat

dat &= ~(1 << offs); //First pull the IO port to be set low

dat |= to << offs; //Assign the to value of the parameter to dat

__raw_writel(dat, base + 0x04); //Finally write the DAT value into GPIO's DAT

local_irq_restore(flags);

}


The above function calls two sub-functions, which are defined as follows


#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)

#define S3C2410_GPIO_OFFSET(pin) ((pin) & 31)

The definition of S3C24XX_VA_GPIO is as follows:


#define S3C24XX_VA_GPIO S3C2410_ADDR(0x00E00000)

#define S3C2410_ADDR(x) (0xF0000000 + (x))

Here, the base address of S3C2410_ADDR is 0xF0000000(??), which is the base address of the virtual addresses of all registers of 2440. 0x00E00000 indicates the offset address of GPIO of 2440, which means that the first address of the virtual address of its GPIO is 0xF0E00000.


Let's look at the definition of S3C2410_GPIO_BASE(pin). We can put the value of S3C2410_GPB5 into the calculation, and we can get (S3C2410_GPB5&~31)=32. The purpose is to remove the offset value of GPB, and then shift it right by one bit, and add it to the first address of the GPIO virtual address. Therefore, S3C2410_GPIO_BASE(pin) only represents the virtual address of the corresponding GPIO group. For example, the virtual address of GPB is 10000(B)+0xF0E00000=0xF0E00010. By analogy, the offset addresses of all GPIOs can be obtained, as shown in the following table:



BANK

(pin&~31)

(pin&~31)>>1

[1] [2] [3]
Keywords:iny6410 Reference address:iny6410 simple LED character device driver io driver

Previous article:Tips for getting started with ARM and embedded systems
Next article:Samsung S3C2440 ARM920T core processor register arrangement-very useful information

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号