#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/pci.h>
#define NUM_CMOS_BANKS 2
/* 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 */
struct cdev cdev; /* The cdev structure */
char name[10]; /* Name of I/O region */
/* ... */ /* Mutexes, spinlocks, wait
queues, .. */
} *cmos_devp[NUM_CMOS_BANKS];
/* 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 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,};
/*
* Driver Initialization
*/
int __init
cmos_init(void)
{
int i, ret;
/* Request dynamic allocation of a device major number */
if (alloc_chrdev_region(&cmos_dev_number, 0,
NUM_CMOS_BANKS, DEVICE_NAME) < 0) {
printk(KERN_DEBUG "Can't register device\n"); return -1;
}
/* Populate sysfs entries */
cmos_class = class_create(THIS_MODULE, DEVICE_NAME);
for (i=0; i<NUM_CMOS_BANKS; i++) {
/* Allocate memory for the per-device structure */
cmos_devp[i] = kmalloc(sizeof(struct cmos_dev), GFP_KERNEL);
if (!cmos_devp[i]) {
printk("Bad Kmalloc\n"); return -ENOMEM;
}
/* Request I/O region */
sprintf(cmos_devp[i]->name, "cmos%d", i);
if (!(request_region(addrports[i], 2, cmos_devp[i]->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[i]->bank_number = i;
/* Connect the file operations with the cdev */
cdev_init(&cmos_devp[i]->cdev, &cmos_fops);
cmos_devp[i]->cdev.owner = THIS_MODULE;
/* Connect the major/minor number to the cdev */
ret = cdev_add(&cmos_devp[i]->cdev, (cmos_dev_number + i), 1);
if (ret) {
printk("Bad cdev\n");
return ret;
}
/* Send uevents to udev, so it'll create /dev nodes */
device_create(cmos_class, NULL, MKDEV(MAJOR(cmos_dev_number), i),
"cmos%d", i);
}
printk("CMOS Driver Initialized.\n");
return 0;
}
/* Driver Exit */
void __exit
cmos_cleanup(void)
{
int i;
/* Release the major number */
unregister_chrdev_region((cmos_dev_number), NUM_CMOS_BANKS);
/* Release I/O region */
for (i=0; i<NUM_CMOS_BANKS; i++) {
device_destroy (cmos_class, MKDEV(MAJOR(cmos_dev_number), i));
release_region(addrports[i], 2);
cdev_del(&cmos_devp[i]->cdev);
kfree(cmos_devp[i]);
}
/* Destroy cmos_class */
class_destroy(cmos_class);
return();
}
module_init(cmos_init);
module_exit(cmos_cleanup);
syntax highlighted by Code2HTML, v. 0.9.1