Char Device Driver Example for Kernel 2.6

Source: Internet
Author: User

There are still questions,

1. How do I know which file name is displayed in the/dev directory after the device is registered?

Generate the file in class_device_create. Research is still pending.

 

 

The process of registering a character device

1. alloc_chrdev_region dynamically allocates device numbers

2. cdev_init initializes cdev and registers the fops

3. cdev_add register this character device to the kernel

After cdev_add, the specified file is not generated in the/dev directory.

Use mknod for Example

Mknod/dev/yw_device c 251 0

To generate a file under/dev, you can use this character device.



Generate a node under the/dev/File

1. class_create

2. class_device_create

In this way, you can generate a device file in the/dev directory.

 

Main. c

-------------------------------------------------------------------

 

# Include <linux/fs. h>
# Include <linux/module. h>
# Include <linux/cdev. h>
# Include <linux/device. h>
# Include <asm/uaccess. h>
# Include <asm/io. h>

/* Per-device (per-bank) structure */
Struct cmos_dev {
Unsigned short current_pointer;/* Current pointer within the bank */
Unsigned int size;/* Size of the bank */
Int bank_number;/* CMOS bank number */
S
Truct cdev

Cdev;/* The cdev structure is usually embedded in its own structure */
Char name [10];/* Name of I/O region */
/*... * // * Mutexes, spinlocks, wait queues ,..*/
} * Cmos_devp;

/* File operations structure. Defined in linux/fs. h */
Static struct file_operations cmos_fops = {
. Owner = THIS_MODULE,/* Owner */
//. Open = cmos_open,/* Open method */
//. Release = cmos_release,/* Release method */
//. Read = cmos_read,/* Read method */
//. Write = cmos_write,/* Write method */
//. Llseek = cmos_llseek,/* Seek method */
//. Ioctl = cmos_ioctl,/* Ioctl method */
};

Static dev_t cmos_dev_number;/* Allotted device number */
Struct class * cmos_class;/* Tie with the device model */

# Define NUM_CMOS_BANKS 2
# Define CMOS_BANK_SIZE (0xFF * 8)
# Define DEVICE_NAME "cmos"
# Define CMOS_BANK0_INDEX_PORT 0x70
# Define cmos_bank0_data_port 0x71
# Define cmos_bank1_index_port 0x72
# Define cmos_bank1_data_port 0x73
Unsigned char addrports [num_cmos_banks] = {cmos_bank0_index_port,
Cmos_bank1_index_port ,};
Unsigned char dataports [num_cmos_banks] = {cmos_bank0_data_port,
Cmos_bank1_data_port ,};

/*
* Open CMOS bank
*
*/
Int cmos_open (struct inode * inode, struct file * file)
{
Struct cmos_dev * cmos_devp;

/* Get the per-device structure that contains this cdev */
Cmos_devp = container_of (inode-> I _cdev, struct cmos_dev, cdev );

/* Easy access to cmose_devp from rest of the entry points */

/*When it is enabled, point private_data to cmos_devp.

*/
File-> private_data = cmos_devp;

/* Initialize some fields */
Cmos_devp-> size = CMOS_BANK_SIZE;
Cmos_devp-> current_pointer = 0;

Return 0;
}

/*
* Release CMOS bank
*/
Int cmos_release (struct inode * inode, struct file * file)
{
Struct cmos_dev * cmos_devp = file-> private_data;

/* Release file pointer */
Cmos_devp-> current_pointer = 0;

Return 0;
}

/*
* Read data from specified CMOS bank
*/
Unsigned char port_data_in (unsigned char offset, int Bank)
{
Unsigned char data;
If (unlikely (bank> = num_cmos_banks )){
Printk ("unknown CMOS bank/N ");
Return 0;
} Else {
Outb (offset, addrports [Bank]);/* read a byte */
Data = INB (dataports [Bank]);
}
Return data;
}

/*
* Read from a CMOS bank at bit-level Granularity
*/
Ssize_t cmos_read (struct file * file, char * Buf,
Size_t count, loff_t * PPOs)
{
Struct cmos_dev * cmos_devp = file-> private_data;


Char data [CMOS_BANK_SIZE];
Unsigned char mask;
Int xferred = 0, I = 0, l, zero_out;
Int start_byte = cmos_devp-> current_pointer/8;
Int start_bit = cmos_devp-> current_pointer % 8;

If (cmos_devp-> current_pointer> = cmos_devp-> size ){
Return 0;/* EOF */
}

/* Adjust count if it edges past the end of the CMOS bank */
If (cmos_devp-> current_pointer + count> cmos_devp-> size ){
Count = cmos_devp-> size-cmos_devp-> current_pointer;
}

/* Get the specified number of bits from the CMOS */
While (xferred <count ){
Data [I] = port_data_in (start_byte, cmos_devp-> bank_number)> start_bit;
Xferred + = (8-start_bit );
If (start_bit) & (count + start_bit> 8 )){
Data [I] | = (port_data_in (start_byte + 1,
Cmos_devp-> bank_number) <(8-start_bit ));
Xferred + = start_bit;
}
Start_byte ++;
I ++;
}
If (xferred> count ){
/* Zero out (xferred-count) bits from the MSB
Of the last data byte */
Zero_out = xferred-count;
Mask = 1 <(8-zero_out );
For (L = 0; L <zero_out; l ++ ){
Data [I-1 ~ Mask; mask <= 1;
}
Xferred = count;
}

If (! Xferred) Return-EIO;

/* Copy the read bits to the user buffer */
If (copy_to_user (BUF, (void *) data, (xferred/8) + 1 ))! = 0 ){
Return-EIO;
}

/* Increment the file pointer by the number of xferred bits */
Cmos_devp-> current_pointer + = xferred;
Return xferred;
}

/*
* Write data to specified CMOS bank
*/
Void port_data_out (unsigned char offset, unsigned char data, int bank)
{
If (unlikely (bank> = NUM_CMOS_BANKS )){
Printk ("Unknown CMOS Bank/n ");
Return;
} Else {
Outb (offset, addrports [bank]);/* Output a byte */
Outb (data, dataports [bank]);
}
Return;
}

/*
* Write to a CMOS bank at bit-level granularity. 'Count' holds
* Number of bits to be written.
*/
Ssize_t cmos_write (struct file * file, const char * buf, size_t count, loff_t * ppos)
{
Struct cmos_dev * cmos_devp = file-> private_data;


Int xferred = 0, I = 0, l, end_l, start_l;
Char * kbuf, tmp_kbuf;
Unsigned char tmp_data = 0, mask;
Int start_byte = cmos_devp-> current_pointer/8;
Int start_bit = cmos_devp-> current_pointer % 8;

If (cmos_devp-> current_pointer> = cmos_devp-> size ){
Return 0;/* EOF */
}
/* Adjust count if it edges past the end of the CMOS bank */
If (cmos_devp-> current_pointer + count> cmos_devp-> size ){
Count = cmos_devp-> size-cmos_devp-> current_pointer;
}

Kbuf = kmalloc (count/8) + 1, GFP_KERNEL );
If (kbuf = NULL)
Return-ENOMEM;

/* Get the bits from the user buffer */
If (copy_from_user (kbuf, buf, (count/8) + 1 )){
Kfree (kbuf );
Return-EFAULT;
}

/* Write the specified number of bits to the CMOS bank */
While (xferred <count ){
Tmp_data = port_data_in (start_byte, cmos_devp-> bank_number );
Mask = 1 <start_bit;
End_l = 8;
If (count-xferred) <(8-start_bit )){
End_l = (count-xferred) + start_bit;
}
For (l = start_bit; l <end_l; l ++ ){
Tmp_data & = ~ Mask; mask <= 1;
}
Tmp_kbuf = kbuf [I];
Mask = 1 <end_l;
For (l = end_l; l <8; l ++ ){
Tmp_kbuf & = ~ Mask;
Mask <= 1;
}

Port_data_out (start_byte, tmp_data | (tmp_kbuf <start_bit), cmos_devp-> bank_number );
Xferred + = (end_l-start_bit );
If (xferred <count) & (start_bit) & (count + start_bit> 8 )){
Tmp_data = port_data_in (start_byte + 1, cmos_devp-> bank_number );
Start_l = (start_bit + count) % 8 );
Mask = 1 <start_l;
For (l = 0; l <start_l; l ++ ){
Mask> = 1;
Tmp_data & = ~ Mask;
}
Port_data_out (start_byte + 1 ),
Tmp_data | (kbuf [I]> (8-start_bit )),
Cmos_devp-> bank_number );
Xferred + = start_l;
}
Start_byte ++;
I ++;
}

If (! Xferred) return-EIO;
/* Push the offset pointer forward */
Cmos_devp-> current_pointer + = xferred;
Return xferred;/* Return the number of written bits */
}

/*
* Driver Initialization
*/
Int _ init cmos_init (void)
{
Int I;

/* Request dynamic allocation of a device major number */

/* This function only assigns a device number and has no specific action */
/* This will create an enty in/Proc/devices

*/
If (Alloc_chrdev_region

(& Cmos_dev_number, 0,
NUM_CMOS_BANKS, DEVICE_NAME) <0 ){
Printk ("Can't register/n ");
}
Printk ("Major % d, Minor % d/n", MAJOR (cmos_dev_number), MINOR (cmos_dev_number ));

/* Populate sysfs entries, but don't see it */
Cmos_class =Class_create

(THIS_MODULE, DEVICE_NAME );

For (I = 0; I <num_cmos_banks; I ++ ){
/* Allocate memory for the per-device structure dynamic allocation */
Cmos_devp = kmalloc (sizeof (struct cmos_dev), gfp_kernel );
If (! Cmos_devp ){
Printk ("Bad kmalloc/N ");
Return 1;
}

/* Request I/O region */
/* The I/O region is displayed in/Proc/ioports

*/
Sprintf (cmos_devp-> name, "cmos % d", I );
If (! (Request_region (addrports [I], 2, cmos_devp-> name ))){
Printk ("cmos: I/O port 0x % x is not free./n", addrports [I]);
Return-EIO;
}

/* Fill in the bank number to correlate this
* Device with the corresponding CMOS bank */
Cmos_devp-> bank_number = I;

/* Connect the file operations with the cdev to initialize an important cdev Structure
*/
Cdev_init

(& Cmos_devp-> cdev, & cmos_fops );
Cmos_devp-> cdev. owner = THIS_MODULE;

/* Connect the major/minor number to the cdevIn this way, the device is added.

*/
If (Cdev_add

(& Cmos_devp-> cdev, (cmos_dev_number + I), 1 )){
Printk ("Bad cdev/n ");
Return 1;
}

/* Send uevents to udev, so it'll create/dev nodes */

/*After this command, the corresponding file named "CMOS % d" will be created in the/dev directory.

*/

/*However, the book says that rules should be added to/etc/udev/rules. D, but it seems that they can be generated without adding

*/
Class_device_create

(Cmos_class, null, (cmos_dev_number + I ),
Null, "CMOS % d", I );
}
Printk ("CMOS driver initialized./N ");

Return 0;
}

/* Driver exit */
Void _ exit
Cmos_cleanup (void)
{
Int I;

/* Remove the cdev created by cdev_add
*/
Cdev_del

(& Cmos_devp-> cdev );

/* Release the major number */
/* This is used to release the device major number required by alloc_chrdev_region
*/
Unregister_chrdev_region

(Cmos_dev_number, NUM_CMOS_BANKS );

/* Release I/O region */
For (I = 0; I <NUM_CMOS_BANKS; I ++ ){
Class_device_destroy (cmos_class, MKDEV (MAJOR (cmos_dev_number), I ));
Release_region (addrports [I], 2 );
}

/* Destroy cmos_class created by class_create
*/
Class_destroy (cmos_class );
Return;
}

Module_init (cmos_init );
Module_exit (cmos_cleanup );
MODULE_LICENSE ("GPL ");

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.