linux device driver 2009/04/08. reference book another reference book embedded linux primer: a...

Click here to load reader

Upload: henry-lewis

Post on 17-Jan-2016

227 views

Category:

Documents


0 download

TRANSCRIPT

  • Linux Device Driver2009/04/08

  • Reference Book

  • Another Reference BookEmbedded Linux Primer: A Practical, Real-World Approach By ChristopherHallinan Publisher: Prentice Hall Pub Date: September 18, 2006 Print ISBN-10: 0-13-167984-8 Print ISBN-13: 978-0-13-167984-9 Pages: 576

  • Websitehttp://wiki.openwrt.orghttp://www.linuxsir.orghttp://www-128.ibm.com/developerworks/http://lwn.net

  • Task of Device DriverDevice initializationHardware operation and managementData transfer between kernel space and user spaceData exchange between hardware and kernel space

  • Function of device driverHardwareDevice DriverApplicationBufferUser spaceKernel Space

  • User space vs Kernel Space programFrom the point of view of CPUMemoryaddressdataINT

  • User space vs Kernel Space program From the point of view of CPUKernel schedule/Kernel APIUser space programKernel space programScheduler, change mode reg. to enter different modeSoft interrupt

  • Address Mapping and accessing of the physical addressPhysical Address spaceUser processs1User processs2User process 3Virtual address mappinguser program access virtual using pointersphysical address of IO device cannot be accessed by user program directlyVirtual address mappingVirtual address mapping

  • Basic operation of device driverDevice controller is often mapped into memory addressD Q

    D Q

    D Q

    Device circuitsData busAddress matching circuit

    Address bus

  • Basic operation of device driverD Q

    D Q

    D Q

    Data busAddress matching circuitAddress busDevice circuits

  • User space vs Kernel Space programUser space programLimited priorityVirtual run environmentLogic addressKey resource access is difficultUser invoke function directlyKernel Space programHighest priorityPhysical run environmentVirtual addressAccess all resourceKernel invoke function

  • Direct memory access(/dev/kmem)kmfd=open("/dev/kmem",O_RDONLY); lseek(kmfd,offset,SEEK_SET); read(kmfd,byteArray,byteArrayLen); close(kmfd);memory is mapped into device file, and can be accessed by file read/writeCan access kernel addressvirtual address of kernelMost started from 0xC0000000memory

    offset

  • Access Physical address directly(/dev/mem)mem_fd=open("/dev/mem",O_RDONLY); b=mmap(0, 0x10000, PROT_READ|PROT_WRITE,MAP_SHARED, mem_fd,0xA0000)close(memfd);

    0xA00000xB0000Pointer bmmap mapping data in file into array

    Physical memoryaccessed by special file /dev/mems mapped into array pointed by b

    Note that value of B may not be 0xA0000, its value is a virtual address coressponding to the physical address 0xA0000

    under Linux, /dev/mem is for special memory access, such as video memoryMay not bye memory device file

  • Directly access IO port(/dev/port)port_fd=open("/dev/port", O_RDWR); lseek(port_fd,port_addr,SEEK_SET); read(port_fd,);write(port_fd,); close(port_fd);Note, not use fopen/fread/fwrite/fclose, because data operation by these function is not fulfilled immediately (buffered)

  • outb()/outw()/inb()/inw() Function#include #include #include #define BASEPORT 0x378 // printerint main(){ ioperm(BASEPORT, 3, 1));// get access permission outb(0, BASEPORT); usleep(100000); printf("status: %d\n", inb(BASEPORT + 1)); ioperm(BASEPORT, 3, 0));// give up exit(0);}ioperm(from,num,turn_on) port address that can be obtained from ioperm is 0x000~0x3FFuse iopl() can obtain all port addressmust run as rootuse gcc -02 o xxx.elf xxx.c to compileoutb(value, port); inb(port); // 8-bitoutw(value, port); inw(port); // 16-bitaccess time is about 1us

  • Access memory directly by user space programwhy we need device driverShare devicesINT management

  • Safe device access method Using Linux device driverDevice driver can access device address by pointerdevice driver also use virtual address but more real than user application(device address mapping can be found in transplanting Linux Kernel)Physical address spaceDevice DriverVirtual address mappingDevice address SpaceDevice address mappingDevice DriverVirtual address mappingDevice address mapping

  • Direct access IO port vs Using device driverDirect IO AccessUser spacesimplepoll mode, slow (response time)difficult to share devices

    Access by device driverKernel spacedifficult to debug and programmingcan use fast INT mode, realtimeeasy to implement device sharing (managed by OS)

  • Device Classification in LinuxCharacter deviceMouseSerial portjoystickBlock devicePrinter , hard diskNetwork deviceAccess by BSD Socket

  • Character device vs Block deviceCharacter deviceRead/write operation is fulfilled immediatelydata buffer is optional

    ADC/DACbuttonLEDsensorBlock deviceneed data buffer to reduce device write/read operationFor slow device such as hard disk

  • Dynamically installable device vs static linked device driverStatic linked device driverChange configuration file, re-compile and install kernelDynamically instable device driverinsmodinstallrmmodremovallsmodquery

  • Abstraction of devices under LinuxDevice fileOpen/Close/Read/WriteExample/dev/mouse/dev/lp0universal IF

  • Device Driver and FileDevice driverDeviceFileCreate by command mknodinstalled by command insmod (or statically compiled into kernel)ApplicationAccess by open/read/write/close APIFind real device river by major device numberSimilar method

  • User space

    Device Driver and FileKernel Space

    Deevice Driverread()write()open()close()User applicationread()write()open()close()Device Filedevice IDdevice IDName of device filename of vice file

  • Structure of Device DriverRegister and unregisterdevice file operation function (API)(*open)()(*write)()(*flush)()(*llseek)()ISR

  • Example of LED device driverCPU

  • struct file_operations LED_fops = { read: LED_read, write: LED_write, open: LED_open, release: LED_release,}; int LED_init_module(void) { SET_MODULE_OWNER(&LED_fops); LED_major = register_chrdev(0, "LED", &LED_fops); LED_off(); LED_status=0; return 0; } void LED_cleanup_module(void) { unregister_chrdev(LED_major, "LED"); } module_init(LED_init_module);module_exit(LED_cleanup_module);Program list (1)pointers of functionsinvoked when device is installed invoked when device is uninstalledTell kernel the name of function to be invoked when install or uninstall device driver

  • program2int LED_open(struct inode *inode, struct file *filp) { printk("LED_open()\n"); MOD_INC_USE_COUNT; return 0; }int LED_release(struct inode *inode, struct file *filp) { printk(LED_release()\n); MOD_DEC_USE_COUNT; return 0; }new vision Linux doesnt use this Macronew vision Linux doesnt use this Macro

  • Program List3ssize_t LED_read (struct file *filp, char *buf, size_t count, loff_t *f_pos) { int i; for (i=0; i
  • #ifndef __KERNEL__ #define __KERNEL__ #endif #ifndef MODULE #define MODULE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include MODULE_AUTHOR("Rendong Ying"); int LED_major, LED_status;Program List4HeaderDevice ID, uer can manually write the number or use automatically assigned number by kernel

  • CompileMakefileCC = arm-elf-linux-gccLD = arm-elf-linux-ldINCLUDE = /usr/local/src/bspLinux/includeLIB_INC = /usr/local/lib/gcc-lib/arm-elf-linux/2.95.3/includeCFLAGS = -O6 -Wall -DCONFIG_KERNELD -DMODULE -D__KERNEL__ -DLinux -nostdinc -I- -I . -I$(INCLUDE) -idirafter $(LIB_INC)

    LED.o: LED.c$(CC) $(CFLAGS) -c LED.c clean:rm -f LED.ogenerate *.o

  • install device driver and create device filechmod +x /tmp/LED.o/sbin/insmod -f ./LED.ocat /proc/devices get device ID instralled into the memorymknod /dev/Lamp c Num1 Num2Num1 major device ID Num2 Minor device IDforce install, ignore version checkingassigned in the program: LED_majorcan be any value

  • User space

    install device driver

    Kernel Space

    Device Driverread()write()open()close()/sbin/insmod -f ./LED.o

  • User space

    Create device fileKernel Space

    Device Driverread()write()open()close()cat /proc/devices obtain major device IDmknod /dev/Lamp c Num1 Num2Num1 Major device ID Num2 Minor device IDDevice FileDevice IDdevice ID

  • Test and use device drivercommandecho 8 > /proc/sys/kernel/printkcat /dev/Lamp cat > /dev/Lamp program void main() { int fd=open(/dev/Lamp, O_RDWR); write(fd, &data, 1); close(fd); }

  • User space

    Use of device driverKernel Space

    Device Driver read() write() open() close()Device Filevoid main() { int fd=open(/dev/Lamp, O_RDWR); write(fd, &data, 1); close(fd); }

  • Uninstall device /sbin/rmmod LEDremove device driver rm -f /dev/Lampdelete device fileFunction ofMOD_INC_USE_COUNT;MOD_DEC_USE_COUNT;

  • User space

    Uninstall device Kernel Space

    Device Driverread()write()open()close()Device File/sbin/rmmod LEDxxrm -f /dev/Lamp

  • Complex Device Driverregister and unregisterdevice and INTDivice operation API(function)(*open)()(*write)()(*flush)()(*llseek)()ISRKernel space bufferData in user space

  • Complex Device Driver(USB Device)Application of IRQif (request_irq(USB_INTR_SOURCE1, usb_ep1_int, SA_INTERRUPT, "USB EP1", 0) < 0) printk("Int. req. failed !\n");

    free_irq(USB_INTR_SOURCE0, 0);cat /proc/interrupts check register INTpoint to ISRINT number, determined by hardwarekernel find INT number from INT status reg. Then call registed function on that numbermask same INTINT IDISR pointerName

  • ISR No return value Fats and small

    void usb_ep1_int(int irq, void *dev_id, struct pt_regs *regs) { // }Specific format for function declaration

  • ISR that receive datavoid usb_ep1_int(int irq, void *dev_id, struct pt_regs *regs) { read_data_from_hardware_FIFO(); send_data_to_buffer();}

  • ISR that send datavoid usb_ep2_int(int irq, void *dev_id, struct pt_regs *regs) { read_data_from_buffer(); send_data_to_hardware_FIFO ();}

  • read functionssize_t usb_ep1_read (struct file *filp, char *buf, size_t count, loff_t *f_pos) { if (data_buffer_empty()) return 0; else copy_data_to_user_space(); return data_copyed; }

  • read function (blocking mode)ssize_t usb_ep1_read (struct file *filp, char *buf, size_t count, loff_t *f_pos) { while(device_driver_buf_empty()) { if (wait_event_interruptible(q_ep2, device_driver_buf_not_empty)) return -ERESTARTSYS; } copy_data_to_user_space(); return data_copyed; }wait_queue_head_t rq_EP2; init_waitqueue_head(&rq_EP2);queue when multiple user application access this device

  • write functionssize_t usb_ep2_write (struct file *filp, char *buf, size_t count, loff_t *f_pos) { if (data_buffer_full()) return 0; else copy_data_to_device_driver_buf(); if (no_transmission_now) send_1st_data(); return data_copyed; }copy_from_user(device_driver_buf, user_buf, size);

  • Memory allocation by device drivermalloc ?

    kmallockfree

    vmallocvfree

  • Prevent open device several timesint LED_flag; int LED_init_module(void) { LED_flag=0; } int LED_open(struct inode *inode, struct file *filp) { if (LED_flag=0) { LED_flag=1; MOD_INC_USE_COUNT; return 0; } else return -ENODEV; } int LED_release(struct inode *inode, struct file *filp) { LED_flag=0; MOD_DEC_USE_COUNT; return 0; }

    need semphora to avoid access conflict

  • Manage several device by one device driverSerial Port Device DriverUART 0UART 0Application

  • User space

    Create device file

    Kernel Space

    Device Driverread()write()open()close()cat /proc/devices Obtain device IDmknod /dev/Lamp c Num1 Num2Num1 Major device ID Num2 Minor device IDMinor dev. ID is used to identify devices that is opened

  • Manage several device by one device driverint dev_open(struct inode *inode, struct file *filp) { int minor = MINOR(inode->i_rdev); filp->private_data=sub_dev_dat[minor]; }

    ssize_t dev_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) { switch(*(filp->private_data)) { }}Allocate data space for each deviceuse data space allocated for the opened device

  • Debug of Character device driver

    Kernel

    Device Driver Device ReadDevice WriteDevice OpenDevice CloseDebug ReadDebug WriteDebug OpenDebug Close 1 2Applicationusing devicedebug and monitorVirtual Serial port, canbe access by minicom

    *****************************************************