Linux driver learning (2) - beep driver

Publisher:心满愿望Latest update time:2024-08-14 Source: cnblogsKeywords:linux Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

// >0 sets the value in down_counter (beeping frequency)

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

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

{

unsigned long temp;

if(cmd <= 0)

{

//set as gpb0,output

temp = __raw_readl(S3C2410_GPBCON);        //GPBCON IO Control

temp &= ~3;        //just select the GPBCON[1:0]bits for gpb0

temp |= 1;        //set gpb[0] as output

__raw_writel(temp, S3C2410_GPBCON);

//set gpbdata[0](beep value) as 0

temp = __raw_readl(S3C2410_GPBDAT);        //GPBDAT

temp &= ~1;

__raw_writel(temp, S3C2410_GPBDAT);

}

else

{

//set as TOUT0

temp = __raw_readl(S3C2410_GPBCON);        //GPBCON

temp &= ~3;

temp |= 2;                //using TOUT0(pwm timer)

__raw_writel(temp, S3C2410_GPBCON);

//using pwm timer TOUT0

temp = __raw_readl(S3C2410_TCFG0);        //TCFG0

temp &= ~0xff;        //select Timer0

temp |= 15;                //FCLK/(15+1)/(devided value),prescaler value!

__raw_writel(temp, S3C2410_TCFG0);

temp = __raw_readl(S3C2410_TCFG1);        //TCFG1

temp &= ~0xf;        //select MUX0

temp |= 1;                //1/4 diveder

__raw_writel(temp, S3C2410_TCFG1);

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

//        now set TCNTB and TCMPB,generate 1:1 diveded timer

//TCNTB register sets the initial value loaded into the down counter and decrements it in sequence

//TCMPB register is used to load the value to be compared with the down counter

// So when TCMPB = TCNTB/2 is set, it means 1:1 time division

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

temp = (50000000/64)/cmd;//set timer count buffer rgister ,50MHZ/(16*4*cmd)

__raw_writel(temp, S3C2410_TCNTB(0));

temp >>= 1;

__raw_writel(temp, S3C2410_TCMPB(0));

//setup timer0

temp = __raw_readl(S3C2410_TCON); //TCON

temp &= ~0x1f;

temp |= 0xb;//disable deadzone,auto-reload,interval-off,update TCNTB and TCMPB,start timer0

__raw_writel(temp, S3C2410_TCON);

temp &= ~2;//set bit[0] as 0,clear manual update-setting bit

__raw_writel(temp, S3C2410_TCON);

}

return 0;

}

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

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

// The open, read, write, ioctl 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 xiaoyang_beep_fops = {

.owner        =        THIS_MODULE,

.ioctl        =        xiaoyang_beep_ioctl,

};

static char __initdata banner[] = "TQ2440 Beep, 2010-xiaoyang yin";

static struct class *beep_class;

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

// This function will be called when the "insmod xiaoyang_beep.ko" command is executed

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

static int __init xiaoyang_beep_init(void)

{

int ret;

printk(banner);

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

// Register character device driver

// The parameters are the main 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 a device file whose main device is BEEP_MAJOR, the relevant member function in xiaoyang_beep_fops will be called

// BEEP_MAJOR can be set to 0, indicating that the kernel automatically assigns the major device number

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

ret = register_chrdev(BEEP_MAJOR, DEVICE_NAME, &xiaoyang_beep_fops);//Assign device number

if (ret < 0) {

printk(DEVICE_NAME " can't register major numbern");

return ret;

}

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

beep_class = class_create(THIS_MODULE, DEVICE_NAME);

if(IS_ERR(beep_class))

{

printk("Err: failed in xiaoyang-Beep class. n");

return -1;

}

//Create a device node named DEVICE_NAME

device_create(beep_class, NULL, MKDEV(BEEP_MAJOR, 0), NULL, DEVICE_NAME);

printk(DEVICE_NAME " initializedn");

return 0;

}

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

// This function will be called when the "rmmod xiaoyang_beep.ko" command is executed

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

static void __exit xiaoyang_beep_exit(void)

{

/* Uninstall the driver */

unregister_chrdev(BEEP_MAJOR, DEVICE_NAME);

device_destroy(beep_class, MKDEV(BEEP_MAJOR, 0)); //Delete the device node

class_destroy(beep_class); //Deregister class

}

//Specify the driver's initialization function and uninstallation function

module_init(xiaoyang_beep_init);

module_exit(xiaoyang_beep_exit);

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

MODULE_AUTHOR("software-hit"); //Driver author

MODULE_DESCRIPTION("TQ2440 Beep Driver"); //Description information

MODULE_LICENSE("GPL"); //Agreement to follow

Add it to the kernel, configure drivers/char/Kconfig and Makefile, copy config_EmbededSky_W35 in the root directory to .config and run: Make menuconfig to configure.

Beep can be added to the kernel as a module or as a mandatory part of the kernel. Then run

Make oldconfig

Make

After generating zImage and burning it to the development board, there will be a /dev/beep device.

If you want to compile it as a module, just run Make SUBDIR=drivers/char/modules to compile EmbededSky_Beep.ko, copy it to the development board and load it with insmod.

The following problems occurred during the compilation process:

drivers/char/EmbedSky_beep.c: In function 'xiaoyang_beep_init':

drivers/char/EmbedSky_beep.c:134: error: implicit declaration of function 'class_device_create'

drivers/char/EmbedSky_beep.c: In function 'xiaoyang_beep_exit':

drivers/char/EmbedSky_beep.c:148: error: implicit declaration of function 'class_device_destroy'

make[2]: *** [drivers/char/EmbedSky_beep.o] Error 1

make[1]: *** [drivers/char] Error 2

make: *** [drivers] Error 2

[xiaoyang@localhost linux-2.6.3

Solution:

This is mainly caused by interface changes between versions.

In Linux 2.6, there are some modifications in different versions to address the above problem. Before using, you should first check the function declaration in /.../include/linux/device.h. For example, if I use Linux 2.6.30, there is no class_device_create function, and you can directly use device_create. In previous versions such as Linux 2.6.15, you need to use the class_device_create function.

So don't use class_device_create but use device_create instead, and the same goes for the other interface.

Writing an application:

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

// xiaoyang@2011.4.21

// beep driver/module test

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

#include

#include

#include

#include

#include

#include

int main()

{

int fd;

int i = 0;

int m_pwm_val;

fd = open("/dev/xiaoyang-beep",O_RDWR);

if(fd < 0){

perror("open device xiaoyang-beep error!");

exit(1);

}

for(i = 0; i < 1000; i++){

scanf("%d",&m_pwm_val);

printf("your pwm_val is %dn",m_pwm_val);

ioctl(fd,m_pwm_val,4); //The last parameter is useless. ioctl: Linux interface uses a unified interface to operate the device

if(m_pwm_val == 0){

break;

}

}

close(fd);

return 0;

}

Makefile is as follows:

CROSS_COMPILE=arm-linux-

CC=$(CROSS_COMPILE)gcc

obj-m := hello.o

all:beep

beep:beep.c

$(CC) -o beep beep.c

$(CROSS_COMPILE)strip beep

clean:

rm -rf *.o beep

Screenshot of experimental results:

After entering the number, the beep sounds at different frequencies, which is too harsh.


Keywords:linux Reference address:Linux driver learning (2) - beep driver

Previous article:Linux driver learning (3)--synchronization, semaphores and spin locks
Next article:Linux driver learning (1) - environment and hello world program

Recommended ReadingLatest update time:2024-11-16 09:40

ARMv7: Linux Kernel Boot
1. If the kernel image is compressed, it needs to be decompressed. The first step of booting is to start from decompression: archarmbootcompressedhead.S 2. After decompression, the kernel image already exists in ARM. Let's start running. The kernel starts running from /arch/arm/kernel/head.S. The entry code is: 1
[Microcontroller]
LCD touch screen interface circuit in ARM9 Linux development system
1 Basic principles of touch screen Touch screens can be divided into surface acoustic wave screens, capacitive screens, resistive screens and infrared screens according to their working principles. Each type of touch screen has its own advantages and disadvantages. Here we briefly introduce the working principles an
[Microcontroller]
LCD touch screen interface circuit in ARM9 Linux development system
Camera used in embedded Linux system
1) Currently, more and more embedded systems use camera applications, mainly in the following ways Remote monitoring: such as closed-circuit television systems, operators use cameras to remotely monitor a specific area, which can be as small as a community or as large as a municipal public place. Surveillance vide
[Microcontroller]
Camera used in embedded Linux system
Overview and features of ALSA, an advanced Linux sound card architecture
ALSA Introduction ALSA Overview ALSA (Advanced Linux Sound Architecture) is the abbreviation of Advanced Linux Sound Card Architecture. It is the current mainstream audio architecture of Linux and provides support for audio and MIDI. In addition to the sound device drivers, ALSA also bundles a u
[Embedded]
Overview and features of ALSA, an advanced Linux sound card architecture
OK6410A Development Board (VIII) 107 linux-5.11 OK6410A devtmpfs file system
drivers/base/devtmpfs.c devtmpfs is divided into two implementations 1. CONFIG_TMPFS is not defined 2. Define CONFIG_TMPFS  67 static struct file_system_type internal_fs_type = {                                68     .name = "devtmpfs",                                                            69 #ifdef CONFI
[Microcontroller]
Several key addresses when the ARM Linux kernel starts
1. Kernel boot address 1.1. Glossary ZTEXTADDR The start address of the decompressed code. There is no distinction between physical address and virtual address because the MMU is turned off at this time. This address is not necessarily the address of RAM, but can be a storage medium such as flash that supports read an
[Microcontroller]
Advantech launches AIM-Linux community and invites users to join
In June 2022, Advantech announced the launch of a technical support forum, the AIM-Linux Community . This is an online community that aims to provide a communication platform for Advantech and users, where Arm and Linux-based developers can stay in touch with engineers from Advantech and its partners.
[Industrial Control]
Advantech launches AIM-Linux community and invites users to join
Linux 6.1 continues to bring new CPU features to LoongArch architecture
Although the Linux community has long since introduced preliminary support for LoongArch CPUs through the 5.19 merge, it has not yet reached the stage of maturity where it can be pushed to the public. In the meantime, developers have insisted on filling in feature gaps -- such as LoongArch PCI support and other change
[Embedded]
Linux 6.1 continues to bring new CPU features to LoongArch architecture
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号