两个相同的设备(只有基地址不同)怎么共用一个驱动啊?

freetime-wxj 2012-12-15 03:50:47
两个字符设备或者混杂设备,只有基地址不同。
要是按照字符设备去注册,要调用class_create函数,这样的话第二个设备初始化时就会再次调用class_create,这样就报错了 就是无法创建相同名字的类。
要是按照misc设备注册,miscdevice结构体里的.name = DEVICE_NAME,又会重名,又会导致失败。
到底怎么办才可以呀???[/size]
...全文
1392 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
wfy1008 2013-01-24
  • 打赏
  • 举报
回复
我的理解是不能两个硬件使用同一个驱动,因为每一个都是一个实例,系统一次装一个,怎么可能装两个呢,但是这个与两个设备共用一份驱动程序并不矛盾,就像一个可执行文件可以同时在主机内运行是一样的。 另外我对这个问题的理解是,如果两个设备的地址不同,就不应该使用同一个驱动,也不应该使用同样的设备ID,只有同样功能的设备才应该用同一个驱动。
li32768 2013-01-20
  • 打赏
  • 举报
回复
13楼,uart是只有一个驱动啊,一个驱动并不意味着只有一个节点,就跟网卡一样,usbstorage 驱动也是一个,并且有些平台底层硬件有多个控制器不同地址
kickxxx 2013-01-18
  • 打赏
  • 举报
回复
引用 11 楼 budongjiuwenha 的回复:
引用 5 楼 guomeng198613 的回复:创建一个字符设备数组,两个设备注册时使用相同的主设备号,不同的从设备号。 能举个例子么,比如驱动两个led??
uart mmc 都是啊
kickxxx 2013-01-18
  • 打赏
  • 举报
回复
引用 3 楼 li32768 的回复:
我理解是,仅注册一个,内部包含一个分支,可用id标记,上层调用对应传递id,这样维护方便简洁
我的理解是,必须注册两个,因为物理设备存在两个啊,如果这里值注册一个,那么上层应用的逻辑就不对了,因为从上层应用角度看到两个设备,但是只能打开相同的设备;另外还要为上层提供接口区分这个设备(传入id);使用两个不同id打开设备后,导致这个设备节点被打开了两次,由此带来很多问题。逻辑更混乱。 很明显的两个设备,系统的uart设备和楼主的情况不是完全一样吗,都是reg地址不同
RedWolf1999 2013-01-18
  • 打赏
  • 举报
回复
共用一个驱动的话,两个设备就不能同时使用了
zhoujiawen 2013-01-17
  • 打赏
  • 举报
回复

/*
仅做参考:原是一个SPI口扩展了两路mcp2515,一个驱动注册两个设备,mcp251x_count=2
*/
static int __init mcp251x_init(void)
{
    int ret,i;
    struct mcp251x *chip=NULL;
    
    DEBUGMSG(DRIVER_NAME" init\n");
    
    mcp251x_dev = kmalloc(sizeof(struct mcp251x)*mcp251x_count,GFP_KERNEL);
    if (!mcp251x_dev) {
        printk(KERN_WARNING "mcp251x_CAN: cannot allocate memmory for mcp251x_dev");
        ret = -1;
        goto err_kmalloc_mcp251x_dev;
    }

	alloc_chrdev_region(&mcp251x_dev_major,0, mcp251x_count, DRIVER_NAME);
	cclass = class_create(THIS_MODULE, DRIVER_NAME);
	
    for (i=0; i< mcp251x_count; i++) {
        chip = &mcp251x_dev[i];
        chip->dev = i;//minor device number
        chip->f_osc = CANFOSC;

    	cdev_init(&chip->cdev, &mcp251x_fops);
    	chip->cdev.owner = THIS_MODULE;
    	chip->cdev.ops = &mcp251x_fops;
    	ret = cdev_add (&chip->cdev, MKDEV(MAJOR(mcp251x_dev_major), i), 1);
    	if (ret)
    		printk (KERN_NOTICE "Error %d adding can_lpc2xxx\n", ret);

		sprintf(chip->name, DRIVER_NAME"%d", i+1);
		if (device_create(cclass, NULL,	MKDEV(MAJOR(mcp251x_dev_major), i),
							chip, DRIVER_NAME"%d",i+1) == NULL) {
			printk(KERN_WARNING "fail to create device %s %d \n",__FILE__,__LINE__);
		}

        chip->can_available = (atomic_t)ATOMIC_INIT(1);
        chip->spi_transfer_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);
        if (!chip->spi_transfer_buf) {
            ret = -ENOMEM;
            goto error_buf;
        }
        
        /*init receive FIFO*/
        //chip->RxFIFO.fadd    = 0;
        //chip->RxFIFO.fremove = 0;
        (chip->RxFIFO).count = 0;
        (chip->RxFIFO).wp = 0;
        (chip->RxFIFO).rp = 0;
        (chip->RxFIFO).buf = kmalloc(sizeof(struct canmsg_t)*CAN_CIRBUF_SIZE,GFP_KERNEL);
        
        spin_lock_init(&chip->RxFIFO.flock);
        if ( !(chip->RxFIFO).buf) {
            printk(KERN_WARNING "mcp251x_CAN: cannot allocate memmory for receive FIFO buffer");
            ret = -1;
            goto err_kmalloc_buf;
        }
        
        /*init Transimit FIFO*/
        //chip->TxFIFO.fadd    = 0;
        //chip->TxFIFO.fremove = 0;
        (chip->TxFIFO).count = 0;
        (chip->TxFIFO).wp = 0;
        (chip->TxFIFO).rp = 0;
        (chip->TxFIFO).buf = kmalloc(sizeof(struct canmsg_t)*CAN_TXDBUF_SIZE,GFP_KERNEL);
        spin_lock_init(&chip->lock);
        spin_lock_init(&chip->TxFIFO.flock);
        if ( !(chip->TxFIFO).buf) {
            printk(KERN_WARNING "mcp251x_CAN: cannot allocate memmory for transimit FIFO buffer");
            ret = -1;
            goto err_kmalloc_buf;
        }
        
        if (i == 0) {
            set_irq_type(IRQ0_GPIO_NAME, IRQ_TYPE_EDGE_FALLING);
            __raw_writel(PIO_DIR_GPIO(IRQ0_GPIO), GPIO_P2_DIR_CLR(GPIO_IOBASE));//GPIO_00 as input
            chip->irq=IRQ0_GPIO_NAME;
            
            ret = request_irq(chip->irq, mcp251x_can1_irq, IRQF_DISABLED|IRQF_TRIGGER_FALLING,DRIVER_NAME, NULL);
            if (ret < 0) {
                dev_err(&chip->sdev, "request irq %d failed (ret = %d)\n", chip->irq, ret);
                goto error_irq;
            }
        } else if (i ==  1) {
            set_irq_type(IRQ1_GPIO_NAME, IRQ_TYPE_EDGE_FALLING);
            __raw_writel(PIO_DIR_GPIO(IRQ1_GPIO), GPIO_P2_DIR_CLR(GPIO_IOBASE));//GPIO_01 as input
            chip->irq=IRQ1_GPIO_NAME;
            
            ret = request_irq(chip->irq, mcp251x_can2_irq, IRQF_DISABLED|IRQF_TRIGGER_FALLING,DRIVER_NAME, NULL);
            if (ret < 0) {
                dev_err(&chip->sdev, "request irq %d failed (ret = %d)\n", chip->irq, ret);
                goto error_irq;
            }
        } else {
            goto error_irq;
        }
        
        lpc32xx_gpio_irq_set(i,Disable);
    }
	

    mcp251x_hw_init();
    for (i=0; i<mcp251x_count; i++) {
        mcp251x_set_bit_rate(i, 20000);
    }
    DEBUGMSG("%s init sucess", DRIVER_NAME);
    return 0;

error_irq:
DEBUGMSG("error_irq");
error_buf:
DEBUGMSG("error_buf");
err_kmalloc_buf:
DEBUGMSG("err_kmalloc_buf");
    while (i > 0) {
    	i--;
    	kfree((mcp251x_dev[i].RxFIFO).buf);
    	kfree((mcp251x_dev[i].TxFIFO).buf);
    }
    kfree(mcp251x_dev);
err_kmalloc_mcp251x_dev:
DEBUGMSG("err_kmalloc_mcp251x_dev");
    printk(KERN_WARNING "mcp251x_can init FAILURE\n");
    return ret;
}
budongjiuwenha 2013-01-14
  • 打赏
  • 举报
回复
引用 4 楼 gongyf1977 的回复:
你的驱动得要按照能够驱动多个的设备来编写,内部用一个设备数组来保存多个设备对象,应用程序在调用驱动的时候,驱动程序需要判别是对哪个设备进行操作。
您好,我最近也在学习简单的字符设备驱动,但是在设备号这里卡住了。如果两个设备共用一个驱动,网上说是通过次设备号来区分的,但是次设备号又是通过设么来实现的呢?两个设备虽然可以通用一个驱动,但是至少它们的IO端口是不一样的,内核怎么知道你是要操作哪个端口呢?你提到的设备数组是什么意思,能说的详细点么,在编程时怎么体现,这一思路呢,能举个例子么?谢谢啦
budongjiuwenha 2013-01-14
  • 打赏
  • 举报
回复
引用 5 楼 guomeng198613 的回复:
创建一个字符设备数组,两个设备注册时使用相同的主设备号,不同的从设备号。
能举个例子么,比如驱动两个led??
swq1982 2013-01-14
  • 打赏
  • 举报
回复
主次设备号的定义都是内核已经按照一套规则编写好的,你可以参考内核里的代码文档/Documentation/devices.txt里面都有定义的。至少操作时,由于设备注册的时候分配的次设备号不一样的就对应到不同的两个设备来对待了。
HuaiShuShuV 2013-01-13
  • 打赏
  • 举报
回复
注册两个名字不同的,然后上层可以分别调用。
jiangbei_lengyu 2013-01-11
  • 打赏
  • 举报
回复
可以在id_table中定义一个platform_device_id结构体数组,使用不同的name和不同的driver_data。这样你可是尝试一下……
swq1982 2013-01-10
  • 打赏
  • 举报
回复
字符设备本来就是相同的主设备号应用的是相同的驱动,既然两个设备的基址不同,你得区别开,可以参考像i2c设备那样可以在/dev/i2c-x(x=0,1,2...)下建立不同的设备接口。还有就是网卡,例如两个相同的pcie网卡可以使用相同的驱动,但是在注册到内核的eth0和eth1两者是不同的。
大脸猫_Mars 2013-01-10
  • 打赏
  • 举报
回复
创建一个字符设备数组,两个设备注册时使用相同的主设备号,不同的从设备号。
gongyf1977 2013-01-07
  • 打赏
  • 举报
回复
你的驱动得要按照能够驱动多个的设备来编写,内部用一个设备数组来保存多个设备对象,应用程序在调用驱动的时候,驱动程序需要判别是对哪个设备进行操作。
li32768 2012-12-16
  • 打赏
  • 举报
回复
我理解是,仅注册一个,内部包含一个分支,可用id标记,上层调用对应传递id,这样维护方便简洁
freetime-wxj 2012-12-15
  • 打赏
  • 举报
回复
俩设备除了基地址不同其他的都是一模一样的 寄存器也是各自独立的 ,在probe函数里 他们俩资源得每人保存一份吧? 不然后注册的会把先注册的资源覆盖掉???
Wenxy1 2012-12-15
  • 打赏
  • 举报
回复
注册两个设备就OK。
目录 1 总体方案设计 2 AT89S51单片机简介 3 硬件部分设计 3.1单片机系统 3.2电路原理图 3.3 仿真电路图 4 软件部分设计 4.1 程序设计方法 4.2主程序框图 4.3 T0中断程序框图 4.4汇编源程序 5 调试分析 5.1硬件调试 5.2软件调试 5.3软、硬件联调 结论 参考文献 附录1 1 总体方案设计 针对本课题的设计任务,进行分析得到:本次设计是利用单片机实 现对扬声器发声的,控制采用按钮操作,AT89S51单片机进行控制,由 音频功率放大器进行放大,最后使扬声器发出"叮咚"声音。 单片机AT89S51 按钮 晶振电路 音频放大器 扬声器 图1 "叮咚"门铃总体设计框图 2 AT89S51单片机简介 AT89S51 为 ATMEL 所生产的可电气烧录清洗的 8051 相容单芯 片,其内部程序代码容量为4KB 图2 AT89S51单片机引脚图 (一)AT89S51主要功能列举如下: 1、为一般控制应用的 8 位单芯片 2、晶片内部具时钟振荡器(传统最高工作频率可至 12MHz) 3、内部程式存储器(ROM)为 4KB 4、内部数据存储器(RAM)为 128B 5、外部程序存储器可扩充至 64KB 6、外部数据存储器可扩充至 64KB 7、32 条双向输入输出线,且每条均可以单独做 I/O 的控制 8、5 个中断向量源 9、2 组独立的 16 位定时器 10、1 个全多工串行通信端口 11、8751 及 8752 单芯片具有数据保密的功能 12、单芯片提供位逻辑运算指令 (二)AT89S51各引脚功能介绍: VCC: AT89S51 电源正端输入,接+5V。 VSS: 电源地端。 XTAL1: 单芯片系统时钟的反相放大器输入端。 XTAL2: 系统时钟的反相放大器输出端,一般在设计上只要在 XTAL1 和 XTAL2 上接上一只石英振荡晶体系统就可以动作了,此外可以在两引脚 与地之间加入一 20PF 的小电容,可以使系统更稳定,避免噪声干扰而 死机。 RESET: AT89S51的重置引脚,高电平动作,当要对晶片重置时,只要对此 引脚电平提升至高电平并保持两个机器周期以上的时间,AT89S51便能 完成系统重置的各项动作,使得内部特殊功能寄存器之内容均被设成已 知状态,并且至地0000H处开始读入程序代码而执行程序。 EA/Vpp: "EA"为英文"External Access"的缩写,表示存取外部程序代码之 意,低电平动作,也就是说当此引脚接低电平后,系统会取用外部的程 序代码(存于外部EPROM中)来执行程序。因此在8031及8032中,EA引 脚必须接低电平,因为其内部无程序存储器空间。如果是使用 8751 内 部程序空间时,此引脚要接成高电平。此外,在将程序代码烧录至8751 内部EPROM时,可以利用此引脚来输入21V的烧录高压(Vpp)。 ALE/PROG: ALE是英文"Address Latch Enable"的缩写,表示地锁存器启用 信号。AT89S51可以利用这支引脚来触发外部的8位锁存器(如 74LS373),将端口0的地总线(A0~A7)锁进锁存器中,因为 AT89S51是以多工的方式送出地及数据。平时在程序执行时ALE引脚的 输出频率约是系统工作频率的1/6,因此可以用来驱动其他周边晶片的 时基输入。此外在烧录8751程序代码时,此引脚会被当成程序规划的特 殊功能来使用。 PSEN: 此为"Program Store Enable"的缩写,其意为程序储存启用,当 8051被设成为读取外部程序代码工作模式时(EA=0),会送出此信号以 便取得程序代码,通常这支脚是接到EPROM的OE脚。AT89S51可以利用 PSEN及RD引脚分别启用存在外部的RAM与EPROM,使得数据存储器与程序 存储器可以合并在一起而共用64K的定范围。 PORT0(P0.0~P0.7): 端口0是一个8位宽的开路汲极(Open Drain)双向输出入端口,共 有8个位,P0.0表示位0,P0.1表示位1,依此类推。其他三个I/O端口 (P1、P2、P3)则不具有此电路组态,而是内部有一提升电路,P0在当 做I/O用时可以推动8个LS的TTL负载。如果当EA引脚为低电平时(即取 用外部程序代码或数据存储器),P0就以多工方式提供地总线(A0~ A7)及数据总线(D0~D7)。设计者必须外加一锁存器将端口0送出的 地栓锁住成为A0~A7,再配合端口2所送出的A8~A15合成一完整的16 位地总线,而定到64K的外部存储器空间。 PORT2(P2.0~P2.7): 端口2是具有内部提升电路的双向I/O端口,每一个引脚可以推动4 个LS的TTL负载,若将端口2的输出设为高电平时,此端

1,318

社区成员

发帖
与我相关
我的任务
社区描述
主要是开发驱动技术
社区管理员
  • 驱动程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧