精华内容
下载资源
问答
  • 硬件平台:TI AM335X Starter ... 这次写《Android 从硬件到应用》是想尝试从底层的最简单的GPIO硬件驱动开始,一步一步的向上走,经过硬件抽象层HAL、JNI方法等,最终编写出APP,达到硬件调用的目的,期间会增加一些

    硬件平台:TI AM335X Starter Kit

    开发源码:TI-Android-ICS-4.0.3-DevKit-EVM-SK-3.0.1.bin

    主机系统:Ubuntu 10.04

           这次写《Android 从硬件到应用》是想尝试从底层的最简单的GPIO硬件驱动开始,一步一步的向上走,经过硬件抽象层HAL、JNI方法等,最终编写出APP,达到硬件调用的目的,期间会增加一些Android下C程序测试底层驱动的细节。既然是从零编写驱动,那就要脱离源码包里已有的一些api函数,从硬件电路开始。找到EVM板GPIO处原理图:

           我要控制LED D1的状态,如上图所示,D1接了Q4,也就是BSS138,N沟道的MOS器件,AM335X_GPIO_LED4为高电平时,Q4的栅极漏极导通,D1为亮,反之,灭。首先设置GPIO时钟:

    一、CM_PER_GPIO1_CLKCTRL:地址0x44E000AC 要装载的值为 0x00040002

    接着设置GPIO1输出使能:

    二、GPIO_OE:地址0x4804C134 要装载的值为 0x0

    然后设置输出GPIO1的输出:

    三、GPIO_DATAOUT:地址0x4804C13C 要装载的值为 0x00000010或者是0x00000000,让AM335X_GPIO_LED4引脚为高或低,这样D1就可以亮灭

    编写驱动程序 android_gpio.c:移到drivers/char目录下

    #include <linux/module.h>  
    #include <linux/kernel.h>  
    #include <linux/fs.h>  
    #include <linux/uaccess.h> /* copy_to_user,copy_from_user */  
    #include <linux/miscdevice.h>  
    #include <linux/device.h>  
    #include <asm/io.h>  
      
    static struct class  *gpio_class;  
      
    volatile unsigned long *DIR;  
    volatile unsigned long *DAT; 
    volatile unsigned long *CLK; 
      
    int gpio_open (struct inode *inode,struct file *filp)  
      
    {  
        *CLK = 0x00040002; //Enable
        *DIR = (*DIR)&0xffffffef;  //output  
        return 0;  
    }  
      
    ssize_t gpio_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos)  
    {  
        return 0;  
    }  
      
    ssize_t gpio_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)  
    {  
        char val_buf[2];  
        int ret;  
        ret = copy_from_user(val_buf,buf,count);  
              
        switch(val_buf[0])  
        {  
            case 0x31 :  
                *DAT = (*DAT)|0x00000010;  
                break;  
            case 0x30 :  
                *DAT = (*DAT)&0xffffffef;         
                break;  
            default :  
                break;  
        }  
        return count;  
    }  
      
    struct file_operations gpio_fops =  
    {  
        .owner   = THIS_MODULE,  
        .open    = gpio_open,  
        .read    = gpio_read,  
        .write   = gpio_write,  
    } ;  
      
    int major;  
    int gpio_init (void)  
    {     
          
        major = register_chrdev(0,"Android_gpio",&gpio_fops);  
        gpio_class = class_create(THIS_MODULE, "Android_gpio");  
        device_create(gpio_class,NULL,MKDEV(major,0),NULL,"AdrIO");  
      
        DIR = (volatile unsigned long *)ioremap(0x4804C134,4);  
        DAT = (volatile unsigned long *)ioremap(0x4804C13C,4);  
        CLK = (volatile unsigned long *)ioremap(0x44E000AC,4);
    
        printk ("gpio is ready\n");  
        return 0;  
    }  
      
    void gpio_exit (void)  
    {  
        unregister_chrdev(major,"Android_gpio");  
        device_destroy(gpio_class,MKDEV(major,0));  
        class_destroy(gpio_class);  
      
        iounmap(DIR);  
        iounmap(DAT);  
        iounmap(CLK);
      
        printk ("module exit\n");  
        return ;  
    }  
      
    MODULE_LICENSE("GPL");  
    module_init(gpio_init);  
    module_exit(gpio_exit); 
    打开drivers/char目录下的Makefile,增加:

    obj-$(CONFIG_ANDROID_GPIO)	+= android_gpio.o
    打开drivers/char目录下的Kconfig,增加:

    config ANDROID_GPIO
           tristate "android gpio enable"
           default y
    
    源码目录下执行:

    make ARCH=arm CROSS_COMPILE=arm-eabi- uImage

    生成uImage,重新启动新系统,ls /dev 查看设备:

    # ls /dev                                                      
    AdrIO                                                                         
    alarm                                                                          
    android_adb                                                                
    ashmem                                                                      
    binder                                                                         
    block                                                                           
    bus 

    发现AdrIO设备,第一步完成,注意在操作物理地址时一定要对位进行操作,不然

    GPIO1会影响到AM335X Starter Kit的LCD显示,下一步就要执行C程序测试该驱动。

    展开全文
  • Linux系统的硬件驱动程序编写原理

    千次阅读 2009-12-28 18:09:00
    Linux系统的硬件驱动程序编写原理http://www.yesky.com/161/1874161.shtml本文详细地介绍如何Linux系统的硬件驱动程序的编写原理,指出哪些内核例程将会被调用、如何初始化驱动程序及如何分配内存等等。大家一定对...
    Linux系统的硬件驱动程序编写原理

    http://www.yesky.com/161/1874161.shtml

    本文详细地介绍如何Linux系统的硬件驱动程序的编写原理,指出哪些内核例程将会被调用、如何初始化驱动程序及如何分配内存等等。大家一定对Linux操作系统有所了解了,在此本人也不再赘述了。好吧,下面简单地介绍一下设备驱动程序。顾名思义,驱动程序是用来控制计算机外围设备的,Linux系统将所有的外围设备都高度地抽象成一些字节的序列,并且以文件的形式来表示这些设备。我们可以来看一下Linux的I/O子系统(图1)。


        图1 Linux的I/O子系统

      从图上我们可以看出,内核紧紧地包围在硬件周围,内核是一些软件包的组合,它们可以直接访问系统的硬件,包括处理器、内存和I/O设备。而用户进程则通过内核提供的用户服务来和内核通讯,从而间接地控制系统硬件。

    我们可以通过图2来了解这些动作的具体情况。


           图2 用户级、内核级和硬件级三者之间的通讯

      图上显示了用户级的程序使用内核提供的标准系统调用来与内核通讯,这些系统调用有:open(), read(), write(), ioctl(), close() 等等。
    Linux的内核是一个有机的整体。每一个用户进程运行时都好像有一份内核的拷贝,每当用户进程使用系统调用时,都自动地将运行模式从用户级转为内核级,此时进程在内核的地址空间中运行。


              图3 Linux的I/O子系统

      Linux内核使用"设备无关"的I/O子系统来为所有的设备服务。每个设备都提供标准接口给内核,从而尽可能地隐藏了自己的特性。图3展示了用户程序使用一些基本的系统调用从设备读取数据并且将它们存入缓冲的例子。我们可以看到,每当一个系统调用被使用时,内核就转到相应的设备驱动例程来操纵硬件。

      每个设备在Linux系统上看起来都像一个文件,它们存放在/dev目录中并被称为"特殊文件"或是"设备节点"。大家可以使用ls -l /dev/lp* 来得到以下的输出:

      crw-rw-rw 1 root root 6, 0 April 23 1994 /dev/lp0

      这行输出表示lp0是一个字符设备(属性字段的第一个字符是'c'),主设备号是6,次设备号是0。主设备号用来向内核表明这一设备节点所代表的驱动程序的类型(比如:主设备号是3的块设备是IDE磁盘驱动程序,而主设备号为8的块设备是SCSI磁盘驱动程序);每个驱动程序负责管理它所驱动的几个硬件实例,这些硬件实例则由次设备号来表示(例如:次设备号为0的SCSI磁盘代表整个也可以说是"第一个"SCSI磁盘,而次设备号为1到15的磁盘代表此SCSI磁盘上的15个分区)。

      到此大家应该对Linux的设备有所了解了吧,下面就可以开始我们的正题"设备驱动程序"。

    设备驱动程序是一组由内核中的相关子例程和数据组成的I/O设备软件接口。每当内核意识到要对某个设备进行特殊的操作时,它就调用相应的驱动例程。这就使得控制从用户进程转移到了驱动例程,当驱动例程完成后,控制又被返回至用户进程。图5就显示了以上的过程。



    图5 设备驱动程序的作用

      每个设备驱动程序都具有以下几个特性:

      l 具有一整套的和硬件设备通讯的例程,并且提供给操作系统一套标准的软件接口;

      l 具有一个可以被操作系统动态地调用和移除的自包含组件;

      l 可以控制和管理用户程序和物理设备之间的数据流。

      接下来我们来了解一下字符设备和块设备,它们是Linux系统中两种主要的外围设备。我们常见的磁盘是块设备,而终端和打印机是字符设备。块设备被用户程序通过系统缓冲来访问。特别是系统内存分配和管理进程就没有必要来充当从外设读写的数据传输者了。正好与之相反的是,字符设备直接与用户程序进行通讯,而且两者似乎没有缓冲区。Linux的传输控制机制会根据用户程序的需要来正确地操纵内存和磁盘等外设来取得数据。在Linux系统中字符设备驱动器被保存为/usr/src/linux/drivers/char目录中。下面我们重点介绍字符设备驱动程序的开发方法。

    首先了解一下Linux的内核编程环境。我们知道每个Linux用户进程都在一个独立的系统空间中运行着,与系统区和其他用户进程相隔离。这样就保护了一个用户进程的运行环境,以免被其他用户进程所破坏。与这种情况正相反的是,设备驱动程序运行在内核模式,它们具有很大的自由度。这些设备驱动程序都是被假设为正确和可靠的,它们是内核的一部分,可以处理系统中断请求和访问外围设备,同时它们有效地处理中断请求以便系统调度程序保持系统需求的平衡。所以设备驱动程序可以脱离系统的限制来使用系统区,比如系统的缓冲区等等。

      一个设备驱动程序同时包括中断和同步区域。其中中断区域处理实时事件并且被设备的中断所驱动;而同步区域则组成了设备的剩余部分,处理进程的同步事件。所以,当一个设备需要一些软件服务时,就发出一个"中断",然后中断处理器得到产生中断的原因同时进行相应的动作。

      一个Linux进程可能会在事件发生之前一直等待下去。例如,一个进程可能会在运行中等待一些写入硬件设备的信息的到来。其中一种方式是进程可以使用sleep()和wakeup()这两个系统调用,进程先使自己处于睡眠状态,等待事件的到来,一旦事件发生,进程即可被唤醒。举个例子来说:interruptible_sleep_on(&dev_wait_queue)函数使进程睡眠并且将此进程的进程号加到进程睡眠列表dev_wait_queue中,一旦设备准备好后,设备发出一个中断,从而导致设备驱动程序中相应的例程被调用,这个驱动程序例程处理完一些设备要求的事宜后会发出一个唤醒进程的信号,通常使用wake_up_interruptible(&dev_wait_queue)函数,它可以唤醒dev_wait_queue所示列表中的所有进程。

      特别要注意的是,如果两个和两个以上的进程共享一些公共数据区时,我们必须将之视为临界区,临界区保证了进程间互斥地访问公共数据。在Linux系统中我们可以使用cli()和sti()两个内核例程来处理这种互斥,当一个进程在访问临界区时可以使用cli()来关闭中断,离开时则使用sti()再将中断打开,就像下面的写法:

      cli()

       临界区

      sti()

    除了以上这些,我们还得了解一下虚拟文件系统交换(VFS)的概念。


              图6 虚拟文件系统交换

    图6中的"文件操作结构"在/usr/include/linux/fs.h文件中定义,此结构包含了驱动程序中的函数列表。图上的初始化例程xxx_init()根据VFS和设备的主设备号来注册"文件操作结构"。
    下面是一些设备驱动程序的支撑函数(具体使用方法详见Linux编程手册,使用man命令):

      add_timer()

      定时间一过,可以引发函数的执行;

      cli()

      关闭中断,阻止中断的捕获;

      end_request()

      当一个请求被完成或被撤销时被执行;

      free_irq()

      释放一个先前被request_irq()和irqaction()捕获的的中断请求;

      get_fs*()

      允许一个设备驱动程序访问用户区数据(一块不属于内核的内存区);

      inb(), inb_p()

      从一个端口读取一个字节,其中inb_p() 会一直阻塞直到从端口得到字节为止;

      irqaction()

      注册一个中断;

      IS_*(inode)

      测试inode是否在一个被mount了的文件系统上;

      kfree*()

      放先前被kmalloc()分配的内存区;

      kmalloc()

      分配大于4096个字节的大块内存区;

      MAJOR()

      返回设备的主设备号;

      MINOR()

      返回设备的次设备号;

      memcpy_*fs()

      在用户区和内核区之间复制大块的内存;

      outb(), outb_p()

      向一个端口写一个字节,其中outb_p()一直阻塞直到写字节成功为止;

      printk()

      内核使用的printf()版本;

      put_fs*()

      允许设备驱动程序将数据写入用户区;

      register_*dev()

      在内核中注册一个设备;

      request_irq()

      向内核申请一个中断请求IRQ,如果成功则安装一个中断请求处理器;

      select_wait()

      将一个进程加到相应select_wait队列中;

      *sleep_on()

      使进程睡眠以等待事件的到来,并且将wait_queue 入口点加到列表中以便事件到来时将进程唤醒;

      sti()

      和cti()相对应,恢复中断捕获;

      sys_get*()

      系统调用,得到进程的有关信息;

      wake_up*()

      唤醒先前被*sleep_on() 睡眠的进程;
    Linux的用户进程不能直接访问系统物理内存。每个用户进程都有自己的内存空间(用户虚拟地址空间,开始于虚拟0地址)。同样内核也具有自己特定的内存空间--系统虚拟地址空间。每当用户使用系统调用read()或write()时,设备驱动程序就在内核地址空间和用户程序地址空间之间拷贝数据。许多Linux例程,比如memcpy_*fs() 和 put_fs*()可以使设备驱动程序穿越"用户-系统"边界来传输数据。而且数据可以是字节、字或任意长度的数据块。例如,memcpy_fromfs()可以从用户内存空间传输任意长度的数据块到设备,而get_fs_byte()则只从用户内存空间传输一个字节;相同的memcpy_tofs()和 put_fs_byte()也是如此,只不过它们是写数据到用户内存空间。

      然而,在内核可访问内存空间和设备本身之间传输数据则要视不同的计算机而定。一些计算机需要使用一些特殊CPU输入输出指令来完成这项工作,这通常被称为DMA(直接内存访问)。而另一种方案则是使用内存映射I/O来解决,通常使用系统提供的I/O函数,比如inb()和outb()来分别地从I/O地址(即端口)读取和向I/O地址输出一单字节,可以使用以下的语句:

      unsigned char inb(int port)

      outb(char data, int port)

    好,下面就可以来看看字符设备驱动程序的基本结构。如图6所示xxx_write()例程轮询设备是否已经准备好接收数据,如果准备好了,则将指定长度的字符串从用户内存空间发送到字符设备。另外还可以使用中断来通知设备是否准备好,这样就不需要程序为了轮询而等待,从而提高CPU的利用率。xxx_table[]是一个结构的数组,它包含很多成员变量,包括xxx_wait_queue和bytes_xfered(两者都被用于读写操作)。xxx_open()使用request_irq()或irqaction()来调用xxx_interrupt()例程。

      为了使设备驱动程序被正确地初始化,每当系统启动时,xxx_init() 例程必须被调用。为了确保这一操作,需要将语句mem_start = xxx_init(mem_start); 加到/usr/src/linux/driver/char/mem.c文件的chr_drv_init()函数末。接下来的工作就是将驱动设备安装到内核中去了(注意:字符设备驱动程序只能被安装在/usr/src/linux/drivers/char/char.a库文件中)。

    展开全文
  • Android 标准的硬件驱动分为两个部分,一个是运行在linux内核里的硬件驱动,而另外一部分是...中已经有了编写硬件驱动到linux内核里的步骤,下面就要接着这个工程去看看怎么在硬件抽象层增加硬件模块和我们的内核驱动

           Android 标准的硬件驱动分为两个部分,一个是运行在linux内核里的硬件驱动,而另外一部分是运行在用户空间的硬件抽象层。采用这种方法,就可以使系统具有硬件无关性,也保护了部分厂商的利益。在 Android 从硬件到应用:一步一步向上爬 1 -- 从零编写底层硬件驱动程序 中已经有了编写硬件驱动到linux内核里的步骤,下面就要接着这个工程去看看怎么在硬件抽象层增加硬件模块和我们的内核驱动程序进行交互,完成硬件控制。

    进入hardware/libhardware/include/hardware目录,新建gpio.h:

    #ifndef ANDROID_GPIO_INTERFACE_H  
    #define ANDROID_GPIO_INTERFACE_H  
    #include <hardware/hardware.h>  
          
    __BEGIN_DECLS  
          
    /*module ID*/  
    #define GPIO_HARDWARE_MODULE_ID "gpio"  
    /*module struct*/  
    struct gpio_module_t {
    	struct hw_module_t common;  
    };       
    /*interface struct*/  
    struct gpio_device_t {
    	struct hw_device_t common;  
    	int fd;  
    	int (*set_val)(struct gpio_device_t* dev, int val);  
    	int (*get_val)(struct gpio_device_t* dev, int* val);  
    }; 
    __END_DECLS
    #endif  
    其中set_val和get_val是HAL层向上层应用提供的API接口。

    cd到hardware/libhardware/modules目录,新建gpio目录,在里面新建gpio.c文件:

    #include <hardware/hardware.h>  
    #include <hardware/gpio.h>  
    #include <fcntl.h>  
    #include <errno.h>  
    #include <cutils/log.h>  
    #include <cutils/atomic.h>  
    #define DEVICE_NAME "/dev/AdrIO"  
    #define MODULE_NAME "Gpio"  
    
    //open and close
    static int gpio_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);  
    static int gpio_device_close(struct hw_device_t* device);  
    //device access
    static int gpio_set_val(struct gpio_device_t* dev, int val);  
    static int gpio_get_val(struct gpio_device_t* dev, int* val);  
    
    static struct hw_module_methods_t gpio_module_methods = {  
        open: gpio_device_open  
    };  
    
    struct gpio_module_t HAL_MODULE_INFO_SYM = {  
        common: {  
            tag: HARDWARE_MODULE_TAG,  
            version_major: 1,  
            version_minor: 0,  
            id: GPIO_HARDWARE_MODULE_ID,  
            name: MODULE_NAME,  
            author: "HAL",  
            methods: &gpio_module_methods, }  
    }; 
    
    static int gpio_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) 
    {  
    	struct gpio_device_t* dev;
    	dev = (struct gpio_device_t*)malloc(sizeof(struct gpio_device_t));  
    	memset(dev, 0, sizeof(struct gpio_device_t));  
    	dev->common.tag = HARDWARE_DEVICE_TAG;  
    	dev->common.version = 0;  
    	dev->common.module = (hw_module_t*)module;  
    	dev->common.close = gpio_device_close;  
    	dev->set_val = gpio_set_val;
    	dev->get_val = gpio_get_val;  
    	if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {  
    		LOGE("gpio: failed to open /dev/AdrIO -- %s.", strerror(errno));
    		free(dev);  
    		return -EFAULT;  
    	}  
    	*device = &(dev->common);  
    	return 0;  
    }  
    
    static int gpio_device_close(struct hw_device_t* device) 
    {  
    	struct gpio_device_t* gpio_device = (struct gpio_device_t*)device;  
    
    	if(gpio_device) {  
    	    close(gpio_device->fd);  
    	    free(gpio_device);  
    	}    
    	return 0;  
    }  
    
    static int gpio_set_val(struct gpio_device_t* dev, int val) 
    {  
    	LOGI("gpio: set value %d to device.", val);  
    	write(dev->fd, &val, sizeof(val));  
    	return 0;  
    }  
    
    static int gpio_get_val(struct gpio_device_t* dev, int* val) 
    {  
    	return 0;
    }
    为了防止调用时出现 Permission denied的情况:

    打开am335xevm文件系统根目录rootfs,打开ueventd.rc添加:

    /dev/AdrIO  0666 root root

    该文件并不会创建设备节点,而是当有设备节点产生的时候,eventd 会根据这个数据库设置设备的权限。

    修改hardware/libhardware/modules目录下Android.mk在harware_modules :=后面加上“gpio”

    在gpio目录中继续添加Android.mk文件:

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE_TAGS := optional
    LOCAL_PRELINK_MODULE := false
    LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
    LOCAL_SHARED_LIBRARIES := liblog
    LOCAL_SRC_FILES := gpio.c
    LOCAL_MODULE := gpio.default
    include $(BUILD_SHARED_LIBRARY)

    编译HAL层:

    make TARGET_PRODUCT=am335xevm_sk -j8 OMAPES=4.x

    如果出现错误,参考:

    没有规则可以创建 /lib/liblog.so 

    如果成功,就可以生成 gpio.default.so

    out/target/product/am335xevm_sk/obj/lib/gpio.default.so
    
    这个就是我们需要的硬件抽象层模块,这一步完成之后,还要接着向上走,最终完成硬件调用。

    展开全文
  • 一些硬件厂商(比如条码枪)有使用java编写驱动程序吗?如果没有,java如何调用它们?
  • Linux 驱动编写

    千次阅读 2019-03-12 20:57:43
    驱动程序(Device Driver)全称为“设备驱动程序”,是一种负责操作系统中的设备操作和通信,相当于硬件的接口,操作系统只能通过这个接口,才能控制硬件设备工作,否则不能正常工作。本博文主要讲解如何编写编译...

    驱动程序(Device Driver)全称为“设备驱动程序”,是一种负责操作系统中的设备操作和通信,相当于硬件的接口,操作系统只能通过这个接口,才能控制硬件设备工作,否则不能正常工作。本博文主要讲解如何编写编译驱动程序、加载驱动模块、移除驱动模块等。

     

    前提条件:

    安装好Linux环境,这里选用Ubuntu16.04

     

    步骤:

    1、新建一个用于存放驱动文件的目录

    $ mkdir ~/driver
    $ cd ~/driver

    2、编写hello.c文件

    $ nano hello.c

    内容如下:

    #include <linux/init.h>
    #include <linux/module.h>
     
    MODULE_LICENSE("Dual BSD/GPL");
     
    static int hello_init(void)
    {
        printk(KERN_ALERT "hello module!\n");
        return 0;
    }
     
    static void hello_exit(void)
    {
        printk(KERN_ALERT "bye module!\n");
    }
     
    module_init(hello_init);
    module_exit(hello_exit);

     保存退出。

    3、编写Makefile(注意:Makefile名称不要随意改变)

    $ nano Makefile

    内容如下:

    obj-m := hello.o
    KERNEL_DIR := /lib/modules/$(shell uname -r)/build
    PWD := $(shell pwd)
    all:
    	make -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules
    clean:
    	rm *.o *.ko *.mod.c
    
    .PHONY:clean

    保存退出。

     ls查看有刚新建好的两个文件

    $ ls
    hello.c  Makefile

    4、编译

    输入make命令编译

    $ make
    make -C /lib/modules/4.4.0-93-generic/build SUBDIRS=/home/hadoop/driver modules
    make[1]: Entering directory '/usr/src/linux-headers-4.4.0-93-generic'
      CC [M]  /home/hadoop/driver/hello.o
      Building modules, stage 2.
      MODPOST 1 modules
      CC      /home/hadoop/driver/hello.mod.o
      LD [M]  /home/hadoop/driver/hello.ko
    make[1]: Leaving directory '/usr/src/linux-headers-4.4.0-93-generic'

    再次用ls命令查看,发现编译之后多个6个文件

    $ ls
    hello.c   hello.mod.c  hello.o   modules.order
    hello.ko  hello.mod.o  Makefile  Module.symvers

    5、安装模块:

    $ sudo insmod hello.ko

      查看信息:

    $ dmesg

    此时输出了大量的日志,在输入日志的最后一行有

     hello module!

    6、移除模块

    $ sudo rmmod hello

      再次查看信息:

    $ dmesg

     此时输出了大量的日志,在输入日志的最后一行有

      bye module!


    可以重复步骤5、步骤6能看到如下信息

    重复步骤5,重新加载模块,查看信息如下:

     

    重复步骤6,再次移除模块,查看信息如下:

    说明:

    每次加载模块(insmod),运行一次hello.c的module_init(hello_init)方法;

    每次卸载模块(rmmod),运行一次hello.c的module_exit(hello_exit)方法。

     

     

    完成!enjoy it!

    展开全文
  • 标准触摸屏接口硬件编写驱动程序

    千次阅读 2007-12-02 13:25:00
     我们在开始编写触摸屏驱动程序之前,必须对硬件的工作原理有个基本的了解。许多不同的触摸技术会把屏幕某个位置的压力或接触转换成有意义的数字坐标。典型的触摸技术包括电阻触摸屏、声表面波触摸屏、红外线触摸屏...
  • 如何编写显卡驱动

    千次阅读 2015-11-02 20:34:41
    题主是一位图形引擎开发者,主要从事OpenGL,目前对GPU底层的详细架构和工作原理还未掌握,希望可以通过编写显卡驱动的过程对GPU工作的各个阶段有深入的理解,题主有看到一本讲解CUDA的书,大致看了一下感觉还是不能...
  • 编写与一个USB设备驱动程序的方法和其他总线驱动方式类似,驱动程序把驱动程序对象注册到USB子系统中,稍后再使用制造商和设备标识来判断是否安装了硬件。当然,这些制造商和设备标识需要我们编写进USB 驱动程序中...
  • vc编写驱动

    千次阅读 2012-12-17 12:33:47
    这篇教程将用于说明如何在Windows NT上编写一个简单的设备驱动程序。现在互联网上有很多关于编写设备驱动的资源和教程。但是,相对教你在Windows上编写一个“hello world”的GUI程序的要少得多。这使得搜索如何开始...
  • 嵌入式驱动编写-点亮LED驱动程序

    万次阅读 2016-11-05 22:51:50
    如何通过应用程序点亮这三个灯如何编写驱动程序 操作硬件的时候,我们需要准备开发板的原理图和开发手册,,根据这两个文档来进行配置  在source insight 编写代码 1 第一个led驱动程序 #...
  • 利用Qt creator编写linux驱动

    千次阅读 2012-11-14 13:55:15
    利用Qt creator编写linux驱动  最近在潜心研究linux驱动开发,个人在这几天驱动开发中的遇到的几个难点: 开发工具不够智能 驱动代码庞大不知如何入手 硬件方面主要是电路方面知识欠缺    从这几个方面...
  • Linux USB 驱动开发(三)—— 编写USB 驱动程序

    万次阅读 多人点赞 2016-03-26 15:10:13
    Linux的设备驱动都遵循一个惯例——表征驱动程序(用driver更贴切一些,应该称为驱动器比较好吧)的结构体,结构体里面应该包含了驱动程序所需要的所有资源。用术语来说,就是这个驱动器对象所拥有的属性及成员。 ...
  • 上层APP调用底层硬件驱动过程解析

    千次阅读 2017-12-07 13:12:30
    APP应用程序->应用框架层->硬件抽象层-> 硬件驱动程序 一、硬件驱动层  进入kernel/drivers文件夹中,创建一文件夹,放入驱动程序。包括头文件,C文件,Makefile,Kconfig。同时对drivers下的Makefile跟...
  • 如何编写驱动程序

    千次阅读 2020-04-16 22:29:41
    编写驱动程序的步骤 1.确定主设备号 2.定义file_operation结构体 3.实现open,close,read,write等函数,填入file_operation结构体 4.把file_operation结构体告诉内核:注册驱动程序 5.谁来注册驱动程序,需要入口函数...
  • LCD驱动编写(PCF8545驱动芯片)

    千次阅读 2020-04-02 10:07:16
    不管编写什么驱动第一件事都是查阅数据手册,这里记录一下我编写LCD驱动的过程 硬件环境: 主板: PIC24FJ64GA306 LCD驱动芯片:PCF8542ATT 这款LCD驱动芯片支持1:8的输出可以驱动8*40的段码 可以通过这里了解...
  • 升级Linux硬件驱动结构作者:冯立功编译 2005-01-18 10:55:19 来自:开发系统世界 硬件驱动程序是界于硬件和Linux内核之间的软件接口,是一种低级的、专用于某一硬件的软件组件。这种软件组件可以使硬件与更普遍的...
  • Android架构实例分析之编写hello驱动的HAL层代码摘要:HAL层中文名称又叫硬件抽象层,可以理解我Linux驱动的应用层。本文实现了一个简单的hello HAL的代码,衔接hello驱动和hello JNI:...
  • VS2013+WDK8.1编写window驱动

    千次阅读 2014-03-04 19:59:55
    不仅仅要克服注册表,inf文件编写,驱动编写.还涉及windows的原理性东西. 我的项目环境是vs2013和wdk8.1. vs2013不需要任何的设置,编写好文件后,点击F7编译生成,就会自动生成一个inf文件和sys文件. vs2013和WDK8.1...
  • 嵌入式驱动编写-LCD驱动程序

    千次阅读 2016-11-08 22:14:23
    如何来写LCD的驱动程序,首先 看芯片开发手册和原理图 根据原理图,找到s3c2440的GPIO控制管脚,gpb gpc gpd gpg管脚控制 需要设置寄存器 以及...
  • 需求:在menuconfig 菜单中添加自己编写驱动选项 环境:ubuntu14.04 硬件平台:am335x  Linux内核版本:3.2.0 1 需要修改的文件 linux3.2.0/drivers 目录下的    Kconfig   Makefile文件 ...
  • 在前面3篇博客的前提下,已经成功将硬件IP添加到了系统。...(1)硬件驱动编写 主要是makefile的编写,每个人的电脑配置都不一样,需要根据自己交叉编译器安装的具体情况,修改makefile, 然后使用make
  • PWM驱动编写心路

    千次阅读 2019-08-30 16:49:49
    记录一个PWM驱动编写过程 笔者从零入门编写一个PWM驱动的心路历程。 本科阶段的知识大多停留在知其然但不知其所以然的层次,大三做智能车时使用的K60芯片,通过PWM模块的输出模式控制电机输出和输入捕捉模式获取...
  • Android下,java应用程序通过JNI方法调用硬件抽象层模块,在Android 从硬件到应用:一步一步向上爬 3 -- 硬件抽象层访问硬件驱动 中我们已经编译好了硬件抽象层模块,下面就要开始为HAL层编写JNI方法,为上层提供...
  • 最近项目中用到了AD7793读取铂电阻值来得到相应的温度,编写了基于MSP430的硬件驱动程序和模拟驱动程序,并且能成功运行,现在记录一下分享给大家。 AD7793硬件IIC驱动完整版下载链接:...
  • 【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 Linux下面的声卡驱动很复杂,根本不是一篇...1、linux声卡驱动在哪个目录sound/2、oss、alsa、asoc是什么关系oss是最老的声卡...
  • linux驱动编写(其他的驱动代码)

    千次阅读 2018-04-11 22:03:39
    在实际工作中,我们基本上需要什么驱动,就移植什么驱动。linux系统下bus-host-device模式一直没有变过,大家只要抓住这个基本原则就可以了。1、其他还有什么重要的驱动gpio驱动,位于drivers/gpio,主要用作键盘...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 116,969
精华内容 46,787
关键字:

编写硬件驱动