linux设备驱动加载失败,深入理解linux设备驱动的CMOS驱动编译加载驱动

在2.6.32出现各种错误,自己调试修正了一下,ioctl除外,欢迎大家拍砖

cmos.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define NUM_CMOS_BANKS 2

struct cmos_dev {

unsigned

short current_pointer;

unsigned int

size; int

bank_number; struct cdev

cdev; char

name[10]; } *cmos_devp[NUM_CMOS_BANKS];

int cmos_open(struct inode *inode, struct file *file);

int cmos_release(struct inode *inode, struct file *file);

ssize_t cmos_read(struct file *file, char *buf, size_t count,

loff_t *ppos);

ssize_t cmos_write(struct file *file, const char *buf, size_t

count, loff_t *ppos);

static loff_t cmos_llseek(struct file *file, loff_t offset, int

orig);

static int cmos_ioctl(struct inode *inode, struct file *file,

unsigned int cmd, unsigned long arg);

unsigned char port_data_in(unsigned char offset, int bank);

void port_data_out(unsigned char offset, unsigned char data,int

bank);

static struct file_operations cmos_fops = {

.owner =

THIS_MODULE, .open =

cmos_open, .release =

cmos_release, .read =

cmos_read, .write =

cmos_write, .llseek =

cmos_llseek, .ioctl =

cmos_ioctl, };

static dev_t

cmos_dev_number; struct class

*cmos_class;

#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,};

int

cmos_open(struct inode *inode, struct file *file)

{

struct

cmos_dev *cmos_devp;

cmos_devp =

container_of(inode->i_cdev, struct cmos_dev, cdev);

file->private_data = cmos_devp;

cmos_devp->size = CMOS_BANK_SIZE;

cmos_devp->current_pointer = 0;

return

0;

}

int

cmos_release(struct inode *inode, struct file *file)

{

struct

cmos_dev *cmos_devp = file->private_data;

cmos_devp->current_pointer = 0;

return

0;

}

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;

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;

}

if

(cmos_devp->current_pointer + count > cmos_devp->size)

{

count = cmos_devp->size - cmos_devp->current_pointer;

}

data =

(char *)kmalloc(CMOS_BANK_SIZE, GFP_ATOMIC);

if (data ==

NULL) {

printk("cmos_read kmalloc fail\n");

return 0;

}

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;

mask = 1 << (8 - zero_out);

for (l=0; l < zero_out; l++) {

data[i-1] &= ~mask; mask <<= 1;

}

xferred = count;

}

if

(!xferred) {

kfree(data);

data = NULL;

return -EIO;

}

if

(copy_to_user(buf, (void *)data, ((xferred/8)+1)) != 0) {

kfree(data);

data = NULL;

return -EIO;

}

cmos_devp->current_pointer += xferred;

kfree(data);

data =

NULL;

return

xferred;

}

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;

}

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;

if

(copy_from_user(kbuf,buf,(count/8)+1)) {

kfree(kbuf);

return -EFAULT;

}

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;

cmos_devp->current_pointer += xferred;

return

xferred;

}

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]);

data = inb(dataports[bank]);

}

return

data;

}

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]);

outb(data, dataports[bank]);

}

return;

}

static loff_t

cmos_llseek(struct file *file, loff_t offset,

int orig)

{

struct

cmos_dev *cmos_devp = file->private_data;

switch

(orig) {

case

0:

if (offset >= cmos_devp->size) {

return -EINVAL;

}

cmos_devp->current_pointer = offset;

break;

case

1:

if ((cmos_devp->current_pointer + offset) >=

cmos_devp->size) {

return -EINVAL;

}

cmos_devp->current_pointer = offset;

break;

case

2:

return -EINVAL;

default:

return -EINVAL;

}

return(cmos_devp->current_pointer);

}

#define CMOS_ADJUST_CHECKSUM 1

#define CMOS_VERIFY_CHECKSUM 2

#define CMOS_BANK1_CRC_OFFSET 0x1E

static int

cmos_ioctl(struct inode *inode, struct file *file,

unsigned int cmd, unsigned long arg)

{

unsigned

short crc = 0;

unsigned

char buf;

switch

(cmd) {

#if 0

case

CMOS_ADJUST_CHECKSUM:

crc = adjust_cmos_crc(0, 0);

crc = adjust_cmos_crc(1, crc);

port_data_out(CMOS_BANK1_CRC_OFFSET,

(unsigned char)(crc & 0xFF), 1);

port_data_out((CMOS_BANK1_CRC_OFFSET + 1),

(unsigned char) (crc >> 8), 1);

break;

case

CMOS_VERIFY_CHECKSUM:

crc = adjust_cmos_crc(0, 0);

crc = adjust_cmos_crc(1, crc);

buf = port_data_in(CMOS_BANK1_CRC_OFFSET, 1);

if (buf != (unsigned char) (crc & 0xFF)) return -EINVAL;

buf = port_data_in((CMOS_BANK1_CRC_OFFSET+1), 1);

if (buf != (unsigned char)(crc >> 8)) return -EINVAL;

break;

#endif default:

return -EIO;

}

return

0;

}

static int __init cmos_init(void)

{

int i,

ret;

if

(alloc_chrdev_region(&cmos_dev_number, 0,

NUM_CMOS_BANKS, DEVICE_NAME) < 0) {

printk(KERN_DEBUG "CMOS Can't register device\n"); return -1;

}

else {

printk(KERN_DEBUG "CMOS Major dev num = %d\n",

MAJOR(cmos_dev_number));

}

cmos_class =

class_create(THIS_MODULE, DEVICE_NAME);

if

(IS_ERR(cmos_class)) {

printk(KERN_ERR "CMOS %s:

couldn't create class\n", __FILE__);

return

PTR_ERR(cmos_class);

}

else {

printk(KERN_ERR "CMOS %s: create class success\n", __FILE__);

}

for (i=0;

i

cmos_devp[i] = kmalloc(sizeof(struct cmos_dev), GFP_KERNEL);

if (!cmos_devp[i]) {

printk("CMOS Bad Kmalloc\n"); return -ENOMEM;

}

sprintf(cmos_devp[i]->name, "cmos%d", i);

//必须增加,否则报input output error

release_region(addrports[i], 2);

if (!(request_region(addrports[i], 2, cmos_devp[i]->name)))

{

printk("CMOS cmos: I/O port 0x%x is not free.\n",

addrports[i]);

return -EIO;

}

cmos_devp[i]->bank_number = i;

cdev_init(&cmos_devp[i]->cdev, &cmos_fops);

cmos_devp[i]->cdev.owner = THIS_MODULE;

ret = cdev_add(&cmos_devp[i]->cdev, (cmos_dev_number + i),

1);

if (ret) {

printk(KERN_ERR "CMOS %s: Bad cdev %d\n", __FILE__, i);

return ret;

}

else

{ printk(KERN_ERR "CMOS %s: good cdev %d\n", __FILE__, i);

}

//源代码有问题,最新的版本需要增加一个参数,也就是第四个参数

device_create(cmos_class, NULL, MKDEV(MAJOR(cmos_dev_number),

i),

NULL, "cmos%d", i);

}

printk(KERN_ERR "CMOS %s: Driver Initialized.\n", __FILE__);

return 0;

}

module_init(cmos_init);

static void __exit cmos_cleanup(void)

{

int i;

unregister_chrdev_region((cmos_dev_number), NUM_CMOS_BANKS);

for (i=0;

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]);

}

class_destroy(cmos_class);

return;

}

module_exit(cmos_cleanup);

MODULE_AUTHOR("David Brownell");

MODULE_DESCRIPTION("Driver for PC-style RTCs");

MODULE_LICENSE("GPL");

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

Makefile:

# Comment/uncomment the following line to enable/disable

debugging

#DEBUG = y

ifeq ($(DEBUG),y)

DEBFLAGS = -O -g -DSCULLC_DEBUG # "-O" is needed

to expand inlines

else

DEBFLAGS = -O2

endif

EXTRA_CFLAGS += $(DEBFLAGS) -I$(LDDINC)

TARGET = cmos

ifneq ($(KERNELRELEASE),)

scullc-objs := cmos.o

obj-m := cmos.o

else

KERNELDIR ?= /lib/modules/$(shell uname -r)/build

PWD := $(shell pwd)

modules:

$(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD)

modules

endif

install:

install -d $(INSTALLDIR)

install -c $(TARGET).o $(INSTALLDIR)

clean:

rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c

.tmp_versions

depend .depend dep:

$(CC) $(EXTRA_CFLAGS) -M *.c > .depend

ifeq (.depend,$(wildcard .depend))

include .depend

endif

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

编译执行:

$ uname -a

Linux powertree 2.6.32-358.el6.i686 #1 SMP Tue Jan 29 11:48:01 EST

2013 i686 i686 i386 GNU/Linux

make

make -C /lib/modules/2.6.32-358.el6.i686/build M=/elinuxdriver/cmos

LDDINC =elinuxdriver/cmos modules

make[1]: Entering directory

`/usr/src/kernels/2.6.32-358.el6.i686'

Building modules, stage 2.

MODPOST 1 modules

make[1]: Leaving directory

`/usr/src/kernels/2.6.32-358.el6.i686'

$ sudo insmod cmos

$ ls /dev/cmos*

/dev/cmos0 /dev/cmos1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值