Beruflich Dokumente
Kultur Dokumente
Specifying cross-compilation
The CPU architecture and cross-compiler prefix are defined through the ARCH and CROSS_COMPILE variables in the toplevel Makefile. The Makefile defines CC = $(CROSS_COMPILE)gcc See comments in Makefile for details The easiest solution is to modify the Makefile. Example, ARM platform, cross-compiler: arm-linux-gcc ARCH ?= arm CROSS_COMPILE ?= arm-linuxOther solutions
Pass ARCH and CROSS_COMPILE on the make command line Define ARCH and CROSS_COMPILE as environment variables Don't forget to have the values properly set at all steps, otherwise the kernel configuration and build system gets confused
arch/arm/configs example
BusyBox commands!
[, [[, addgroup, adduser, adjtimex, ar, arp, arping, ash, awk, basename, bbconfig, bbsh, brctl, bunzip2, busybox, bzcat, bzip2, cal, cat, catv, chat, chattr, chcon, chgrp, chmod, chown, chpasswd, chpst, chroot, chrt, chvt, cksum, clear, cmp, comm, cp, cpio, crond, crontab, cryptpw, cttyhack, cut, date, dc, dd, deallocvt, delgroup, deluser, depmod, devfsd, df, dhcprelay, diff, dirname, dmesg, dnsd, dos2unix, dpkg, dpkg_deb, du, dumpkmap, dumpleases, e2fsck, echo, ed, egrep, eject, env, envdir, envuidgid, ether_wake, expand, expr, fakeidentd, false, fbset, fbsplash, fdflush, fdformat, fdisk, fetchmail, fgrep, find, findfs, fold, free, freeramdisk, fsck, fsck_minix, ftpget, ftpput, fuser, getenforce, getopt, getsebool, getty, grep, gunzip, gzip, halt, hd, hdparm, head, hexdump, hostid, hostname, httpd, hush, hwclock, id, ifconfig, ifdown, ifenslave, ifup, inetd, init, inotifyd, insmod, install, ip, ipaddr, ipcalc, ipcrm, ipcs, iplink, iproute, iprule, iptunnel, kbd_mode, kill, killall, killall5, klogd, lash, last, length, less, linux32, linux64, linuxrc, ln, load_policy, loadfont, loadkmap, logger, login, logname, logread, losetup, lpd, lpq, lpr, ls, lsattr, lsmod, lzmacat, makedevs, man, matchpathcon, md5sum, mdev, mesg, microcom, mkdir, mke2fs, mkfifo, mkfs_minix, mknod, mkswap, mktemp, modprobe, more, mount, mountpoint, msh, mt, mv, nameif, nc, netstat, nice, nmeter, nohup, nslookup, od, openvt, parse, passwd, patch, pgrep, pidof, ping, ping6, pipe_progress, pivot_root, pkill, poweroff, printenv, printf, ps, pscan, pwd, raidautorun, rdate, rdev, readahead, readlink, readprofile, realpath, reboot, renice, reset, resize, restorecon, rm, rmdir, rmmod, route, rpm, rpm2cpio, rtcwake, run_parts, runcon, runlevel, runsv, runsvdir, rx, script, sed, selinuxenabled, sendmail, seq, sestatus, setarch, setconsole, setenforce, setfiles, setfont, setkeycodes, setlogcons, setsebool, setsid, setuidgid, sh, sha1sum, showkey, slattach, sleep, softlimit, sort, split, start_stop_daemon, stat, strings, stty, su, sulogin, sum, sv, svlogd, swapoff, swapon, switch_root, sync, sysctl, syslogd, tac, tail, tar, taskset, tcpsvd, tee, telnet, telnetd, test, tftp, tftpd, time, top, touch, tr, traceroute, true, tty, ttysize, tune2fs, udhcpc, udhcpd, udpsvd, umount, uname, uncompress, unexpand, uniq, unix2dos, unlzma, unzip, uptime, usleep, uudecode, uuencode, vconfig, vi, vlock, watch, watchdog, wc, wget, which, who, whoami, xargs, yes, zcat, zcip
Configuring BusyBox
Get the latest stable sources from http://busybox.net Configure BusyBox (creates a .config file): make defconfig Good to begin with BusyBox. Configures BusyBox with all options for regular users. make allnoconfig Unselects all options. Good to configure only what you need. make xconfig (graphical) or make menuconfig (text) Same configuration interfaces as the ones used by the Linux kernel.
Compiling BusyBox
Set the cross-compiler prefix in the configuration interface: BusyBox Settings -> Build Options -> Cross Compiler prefix Example: arm-linuxSet the installation directory in the configuration interface: BusyBox Settings -> Installation Options -> BusyBox installation prefix Add the cross-compiler path to the PATH environment variable: export PATH=/usr/local/arm/3.3.2/bin:$PATH Compile BusyBox: make Install it (this creates a Unix directory structure symbolic links to the busybox executable): make install
Bootloaders
The bootloader is a piece of code responsible for
Basic hardware initialization Loading of an application binary, usually an operating system kernel, from flash storage, from the network, or from another type of non-volatile storage. Possibly uncompression of the application binary Execution of the application
Besides these basic functions, most bootloaders provide a shell with various commands implementing different operations.
Loading of data from storage or network, memory inspection, hardware diagnostics and testing, etc.
This piece of code is usually a 1st stage bootloader, which will load the full bootloader itself. The bootloader can then offer all its features. It typically understands filesystem formats so that the kernel file can be loaded directly from a normal filesystem.
GRUB, Grand Unified Bootloader, the most powerful one. http://www.gnu.org/software/grub/ Can read many filesystem formats to load the kernel image and the configuration, provides a powerful shell with various commands, can load kernel images over the network, etc. LILO, the original Linux Loader http://freshmeat.net/projects/lilo/ Syslinux, for network and removable media booting http://syslinux.zytor.com
There are also a lot of other open-source or proprietary bootloaders, often architecture-specific
RedBoot, Yaboot, PMON, etc.
U-Boot
U-Boot is a typical free software project Freely available at http://www.denx.de/wiki/U-Boot Documentation available at http://www.denx.de/wiki/UBoot/Documentation The latest development source code is available in a Git repository: http://git.denx.de/cgi-bin/gitweb.cgi?p=uboot.git;a=summary Development and discussions happen around an open mailinglist http://lists.denx.de/pipermail/u-boot/ Since the end of 2008, it follows a fixed-interval release schedule. Every two months, a new version is released. Versions are named YYYY.MM.
Assuming that your board is already supported by U-Boot, there should be one file corresponding to your board, for example include/configs/omap2420h4.h.
Compile U-Boot, by specifying the cross-compiler prefix. Example, if your cross-compiler executable is arm-linux-gcc: make CROSS_COMPILE=arm-linux-
Installing U-Boot
U-Boot must usually be installed in flash memory to be executed by the hardware. Depending on the hardware, the installation of U-Boot is done in a different way:
The board provides some kind of specific boot monitor, which allows to flash the second stage bootloader. In this case, refer to the board documentation and tools U-Boot is already installed, and can be used to flash a new version of U-Boot. However, be careful: if the new version of U-Boot doesn't work, the board is unusable The board provides a JTAG interface, which allows to write to the flash memory remotely, without any system running on the board. It also allows to rescue a board if the bootloader doesn't work.
U-boot prompt
Connect the target to the host through a serial console Power-up the board. On the serial console, you will see something like: U-Boot 1.1.2 (Aug 3 2004 - 17:31:20) RAM Configuration: Bank #0: 00000000 8 MB Flash: 2 MB In: serial Out: serial Err: serial u-boot # The U-Boot shell offers a set of commands. We will study the most important ones, see the documentation for a complete reference or the help command.
Information commands
U-Boot> flinfo DataFlash:AT45DB021 Nb pages: 1024 Page Size: 264 Size= 270336 bytes Logical address: 0xC0000000 Area 0: C0000000 to C0001FFF (RO) Bootstrap Area 1: C0002000 to C0003FFF Environment Area 2: C0004000 to C0041FFF (RO) U-Boot U-Boot> nand info Device 0: NAND 256MiB 3,3V 8-bit, sector size 128 KiB U-Boot> version U-Boot 2009.08 (Nov 15 2009 - 14:48:35)
Flash information
Can vary from one board to the other (according to the U-Boot compile configuration)
Network configuration
U-boot mkimage
The kernel image that U-Boot loads and boots must be prepared, so that an U-Boot specific header is added in front of the image This is done with a tool that comes in U-Boot, mkimage Debian / Ubuntu: just install the uboot-mkimage package. Or, compile it by yourself: simply configure U-Boot for any board of any architecture and compile it. Then install mkimage: cp tools/mkimage /usr/local/bin/ The special target uImage of the kernel Makefile can then be used to generate a kernel image suitable for U-Boot.
boot commands
Specify kernel boot parameters: Continues on u-boot # setenv bootargs mem=64M \ console=ttyS0,115200 line the same init=/sbin/init \ root=/dev/mtdblock0 Execute the kernel from a given physical address (RAM or flash): bootm 0x01030000
Rom code
X-loader
Found in NAND or in MMC Copied to the CPU's internal RAM. Initializes the external DRAM controller + other devices Found in NAND or in MMC (u-boot.bin file) Copied to DRAM Can also initialize some devices Found in NAND, MMC, USB, network, serial Copied to DRAM (depending on U-boot's features)
U-boot
Linux kernel
Kernel
- Uncompresses itself - Initializes the kernel core and statically compiled drivers (needed to access the root filesystem) - Mounts the root filesystem (specified by the root kernel parameter) - Executes the first userspace program (specified by the init kernel parameter)
Drawbacks
Assumption that all device drivers needed to mount the root filesystem (storage and filesystem drivers) are statically compiled inside the kernel. Assumption can be correct for most embedded systems, where the hardware is known and the kernel can be fine-tuned for the system. Assumption is mostly wrong for desktop and servers, since a single kernel image should support a wide range of devices and filesystems
More flexibility was needed Modules have this flexibility, but they are not available before mounting the root filesystem Need to handle complex setups (RAID, NFS, etc.)
Solution
A solution is to include a small temporary root filesystem with modules, in the kernel itself. This small filesystem is called the initramfs. This initramfs is a gzipped cpio archive of this basic root filesystem
A gzipped cpio archive is a kind of zip file, with a much simpler format
The initramfs scripts will detect the hardware, load the corresponding kernel modules, and mount the real root filesystem. Finally the initramfs scripts will run the init application in the real root filesystem and the system can boot as usual. The initramfs technique completely replaces init ramdisks (initrds). Initrds were used in Linux 2.4, but are no longer needed.
unchanged
Kernel
- Uncompresses itself - Initializes the kernel core and statically compiled drivers - Uncompresses an initramfs cpio archive (if existing, in the kernel image or copied to memory by the bootloader) and extracts it to the kernel file cache (no mounting, no filesystem). - If found in the initramfs, executes the first userspace program: /init
Userspace:/sbin/init
- Runs commands to configure the device (if not done yet in the initramfs) - Starts up system services (daemons, servers) and user programs
user id group id
Summary
For embedded systems, two interesting solutions No initramfs: all needed drivers are included inside the kernel, and the final root filesystem is mounted directly Everything inside the initramfs
Copy the gdb5.3.tar.gz in /temp Extract and get in folder Run the following command
./configure --target=arm-linux --prefix=/usr/local/arm-gdb
make
make install
Major steps
Major steps
Now move to
cd /temp/gdb7.x/gdb/gdbserver Type the following command
make CC=/usr/local/arm/4.3.2/bin/armlinux-gcc
Testing code
WAP a bug based code Compile the code Download the code on board via zmodem Run the code It should hit segmentation fault
Major steps
Move to following
cd /usr/local/arm-gdb/bin Copy the buggy code exe to this path
Major steps
On PC run
./arm-linux-gdb
Introduction to Device Driver Introduction to LKML/ Modules Writing Sample Modules Linux Device Drivers and Types Character Device Driver: A close look A close look to related Data Structures A skeleton of device driver w.r.t types An example driver demo Testing few drivers via applications
Linux/drivers
Largest amount of code in the kernel tree (~1.5M). device, bus, platform and general directories. drivers/char n_tty.c is the default line discipline. drivers/block elevator.c, genhd.c, linear.c, ll_rw_blk.c, raidN.c. drivers/net specific drivers and general routines Space.c and net_init.c. drivers/scsi scsi_*.c files are generic; sd.c (disk), sr.c (CD-ROM), st.c (tape), sg.c (generic). General:
cdrom, ide, isdn, parport, pcmcia, pnp, sound, telephony, video.
Buses i2c, pci, sbus, usb. Platforms acorn, macintosh, s390, sgi.
If you want to add code to a Linux kernel, the most basic way to do that is to add some source files to the kernel source tree and recompile the kernel. In fact, the kernel configuration process consists mainly of choosing which files to include in the kernel to be compiled. But you can also add code to the Linux kernel while it is running. A chunk of code that you add in this way is called a loadable kernel module.
These modules can do lots of things, but they typically are one of two things: 1) Device drivers; 2) File System drivers; The kernel isolates certain functions, including these, especially well so they don't have to be intricately wired into the rest of the kernel.
Terminology
Loadable kernel modules are often called just kernel modules or just modules, but those are rather misleading terms because there are lots of kinds of modules in the world and various pieces built into the base kernel can easily be called modules. We use the term loadable Some people think of LKMs as outside of the kernel. They speak of LKMs communicating with the kernel. This is a mistake; LKMs (when loaded) are very much part of the kernel. The correct term for the part of the kernel that is bound into the image that you boot, i.e. all of the kernel except the LKMs, is "base kernel. LKMs communicate with the base kernel.
You often have a choice between putting a module into the kernel by loading it as an LKM or binding it into the base kernel. LKMs have a lot of advantages over binding into the base kernel and I recommend them wherever possible.
One advantage is that you don't have to rebuild your kernel as often. This saves you time and spares you the possibility of introducing an error in rebuilding and reinstalling the base kernel. Once you have a working base kernel, it is good to leave it untouched as long as possible.
There is a tendency to think of LKMs like user space programs. They do share a lot of their properties, but LKMs are definitely not user space programs. They are part of the kernel. As such, they have free run of the system and can easily crash it. Security point of view LKMs are not a good way of implementing a secure kernel services?
They offer room for hackers often leading the programmer prove something stupid
A view : LKMs
LKMs
BKI
Making Loadable Kernel Modules An LKM lives in a single ELF object file (normally named like "serial.o"). You typically keep all your LKM object files in a particular directory (near your base kernel image makes sense). When you use the insmod program to insert an LKM into the kernel, you give the name of that object file.
LKM Utilities
The programs you need to load and unload and otherwise work with LKMs are in the package modutils. This package contains the following programs to help you use LKMs: Insmod Insert an LKM into the kernel. Rmmod Remove an LKM from the kernel. Depmod Determine interdependencies between LKMs. Ksyms Display symbols that are exported by the kernel for use by new LKMs. Lsmod List currently loaded LKMs. Modinfo Display contents of .modinfo section in an LKM object file. Modprobe Insert or remove an LKM or set of LKMs intelligently. For example, if you must load A before loading B, Modprobe will automatically load A when you tell it to load B.
A difficult insertion - 1
Now lets look at a more difficult insertion. If you try insmod msdos.o you will probably get a raft of error messages like: msdos.o: unresolved symbol fat_date_unix2dos msdos.o: unresolved symbol fat_add_cluster1 msdos.o: unresolved symbol fat_put_super ... This is because msdos.o contains external symbol references to the symbols mentioned and there are no such symbols exported by the kernel. To prove this, do a cat /proc/ksyms to list every symbol that is exported by the kernel (i.e. available for binding to LKMs). You will see that 'fat_date_unix2dos' is nowhere in the list.
A difficult insertion - 2
How do you get it into the list? By loading another LKM, one which defines those symbols and exports them. In this case, it is the LKM in the file fat.o. So do insmod fat.o and then see that "fat_date_unix2dos" is in /proc/ksyms. Now redo the insmod msdos.o and it works. Look at /proc/modules and see that both LKMs are loaded and one depends on the other: msdos 5632 0 (unused) fat 30400 0 [msdos] How did I know fat.o was the module I was missing? Just a little ingenuity. A more robust way to address this problem is to use depmod and modprobe instead of insmod
A difficult insertion -3
When your symbols look like "fat_date_unix2dos_R83fb36a1", the problem may be more complex than just getting prerequisite LKMs loaded. When the error message is "kernel/module version mismatch, Often, you need to pass parameters to the LKM when you insert it. For example, a device driver wants to know the address and IRQ of the device it is supposed to drive. Or the network driver wants to know how much diagnostic tracing you want it to do. Here is an example of that: insmod ne.o io=0x300 irq=11 Here, I am loading the device driver for my NE2000-like Ethernet adapter and telling it to drive the Ethernet adapter at IO address 0x300, which generates interrupts on IRQ 11.
/proc/modules -1
To see the presently loaded LKMs, do cat /proc/modules You see a line like
serial 24484 0
The left column is the name of the LKM, which is normally the name of the object file from which you loaded it, minus the ".o" suffix. The "24484" is the size in bytes of the LKM in memory. The "0" is the use count. It tells how many things presently depend on the LKM being loaded. Typical "things" are open devices or mounted fileystems. It is important because you cannot remove an LKM unless the use count is zero. The LKM itself maintains this count, but the module manager uses it to decide whether to permit an unload.
/proc/modules -2
There is an exception to the above description of the use count. You may see -1 in the use count column. What that means is that this LKM does not use usecounts to determine when it is OK to unload. Instead, the LKM has registered a subroutine that the module manager can call that will return an indication of whether or not it is OK to unload the LKM. In this case, the LKM ought to provide you with some custom interface, and some documentation, to determine when the LKM is free to be unloaded. Do not confuse use count with "dependencies", which are described as below here with another example, with more information: lp 5280 0 (unused) parport_pc 7552 1 parport 7600 1 [lp parport_pc]
/proc/modules -3
The stuff in square dependencies. brackets ("[lp parport_pc]") describes
Here, the modules lp and parport_pc both refer to addresses within module parport (via external symbols that parport exports). So lp and parport_pc are "dependent" on (and are "dependencies of" parport not a use count. You cannot unload an LKM that has dependencies. But you can remove those dependencies by unloading the dependent LKMs. The "(unused)" legend means the LKM has never been used.
Unresolved Symbols
The most common and most frustrating failure in loading an LKM is a bunch of error messages about unresolved symbols, like this: msdos.o: unresolved symbol fat_date_unix2dos msdos.o: unresolved symbol fat_add_cluster1 msdos.o: unresolved symbol fat_put_super ... There are actually a bunch of different problems that result in this symptom. In any case, you can get closer to the problem by looking at /proc/ksyms and confirming that the symbols in the message are indeed not in the list.
To ease this burden, insmod has a -f option that "forces" insmod to ignore the kernel version mismatch and insert the module anyway. As it is so unusual for there to be a significant difference between any two kernel versions, I recommend you always use -f. You will, however, still get a warning message about the mismatch. There's no way to shut that off. if you get the error message isn't one about mismatched kernel versions, but simply "unresolved symbol reference. Nothing will work, even a -f
insmod makes an init_module system call to load the LKM into kernel memory. Loading it is the easy. How does the kernel know to use it? The answer is that the init_module system call invokes the LKM's initialization routine as it loads the LKM. insmod passes to init_module the address of the subroutine in the LKM named init_module as its initialization routine.
If we set up init_module to call a kernel function that registers the subroutines that the LKM contains.
Modinfo
You can use the modinfo program to interpret the contents of the .modinfo section. What is in the .modinfo section and who uses it? insmod uses the .modinfo section for the following: It contains the kernel release number for which the module was built. I.e. of the kernel source tree whose header files were used in compiling the module. It describes the form of the LKM's parameters. insmod uses this information to format the parameters you supply on the insmod command line into data structure initial values, which insmod inserts into the LKM as it loads it.
A final Note:
Internal workings of the Linux kernel with respect to LKMs can be started looking at following codes. You should not need to know any of this in order to develop, build, and use LKMs. The code to handle LKMs is in the source files kernel/module.c in the Linux source tree. The kernel module loader lives in kernel/kmod.c.
Building modules
Parameter passing
EXPORTING symbols
CHAR DRIVERS
There are three types of device driver
Char (c) Block (b) Network
Linux Treats every device as a file and to interface the driver uses device nodes found in /dev historically Network device driver unlike char, and block uses a different approach for the same
Char devices are accessed through names in the filesystem. Those names are called special files or device files or simply nodes of the filesystem tree; they are conventionally located in the /dev directory. Special files for char drivers are identified by a c in the first column of the output of ls l. Block devices appear in /dev as well, but they are identified by a b.
The focus of this session is on char devices, but much of the following information applies to block devices as well.
The major number identifies the driver associated with the device.
For example, /dev/null and /dev/zero ar e both managed by driver 1, whereas virtual consoles and serial terminals are managed by driver 4; similarly, both vcs1 and vcsa1 devices are managed by driver 7.
The kernel uses the major number at open time to dispatch execution to the appropriate driver. It is common for a driver to control several devices (as shown in the listing); The minor number provides a way for the driver to differ entiate among them.
Whenever an operation is performed on a character device file associated with that major number, the kernel finds and invokes the proper function from the file_operations structure.
For this reason, the pointer passed to register_chrdev should point to a global structure within the driver, not to one local to the modules initialization function.
superuser privileges are required for this operation. The command takes three arguments in addition to the name of the file being created.
For example, the command
Minor numbers should be in the range 0 to 255 because, for historical reasons, they are sometimes stored in a single byte. There are sound reasons to extend the range of available minor numbers, but for the time being, the eight-bit limit is still in force
The major number returned is always positive, while negative return values are error codes.
Please note the behavior is slightly differ ent in the two cases: the function returns the allocated major number if the caller requests a dynamic number, but returns 0 (not the major number) when successfully registering a predefined major number.
The arguments are the major number being released and the name of the associated device. The kernel compares the name to the register ed name for that number, if any:
if they differ, -EINVAL is returned. The kernel also returns EINVAL if the major number is out of the allowed range.
File Operations
Lets look at the various operations a driver can perform on the devices it manages. An open device is identified internally by a file structure, and the kernel uses the file_operations structure to access the drivers functions. The structure, defined in <linux/fs.h>, is an array of function pointers. Each file is associated with its own set of functions (by including a field called f_op that points to a file_operations structure).
File Operations
The operations are mostly in charge of implementing the system calls and are thus named open, read, and so on. We can consider the file to be an object and the functions operating on it to be its methods, using object-oriented programming terminology to denote actions declared by an object to act on itself. This is the first sign of object-oriented programming we see in the Linux kernel. The file_operations structure has been slowly getting bigger as new functionality is added to the kernel. The addition of new operations can, of course, create portability problems for device drivers.
File Operations
Instantiations of the structure in each driver used to be declared using standard C syntax, and new operations were normally added to the end of the structure; A simple recompilation of the drivers would place a NULL value for that operation, thus selecting the default behavior, usually what you wanted. Since then, kernel developers have switched to a tagged initialization format that allows initialization of structure fields by name, thus circumventing most problems with changed data structures. The tagged initialization, however, is not standard C but a (useful) extension specific to the GNU compiler.
File Operations
The following list shows what operations appear in struct file_operations for the 2.4 series of kernels, in the order in which they appear.
loff_t (*llseek) (struct file *, loff_t, int);
The llseek method is used to change the current read/write position in a file, and the new position is returned as a (positive) return value. The loff_t is a long offset and is at least 64 bits wide even on 32-bit platforms. Errors are signaled by a negative return value. If the function is not specified for the driver, a seek relative to end-of-file fails, while other seeks succeed by modifying the position counter in the file structure (described in The file Structure).
File Operations
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
Used to retrieve data from the device. A null pointer in this position causes the read system call to fail with -EINVAL (Invalid argument). A non-negative return value represents the number of bytes successfully read (the return value is a signed size type, usually the native integer type for the target platform).
File Operations
int (*readdir) (struct file *, void *, filldir_t); This field should be NULL for device files; it is used for reading directories, and is only useful to filesystems. unsigned int (*poll) (struct file *, struct poll_table_struct *); The poll method is the back end of two system calls, poll and select, both used to inquire if a device is readable or writable or in some special state. Either system call can block until a device becomes readable or writable.
If a driver doesnt define its poll method, the device is assumed to be both readable and writable, and in no special state. The return value is a bit mask describing the status of the device.
File Operations
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); The ioctl system call offers a way to issue device-specific commands. Additionally, a few ioctl commands are recognized by the kernel without referring to the fops table. If the device doesnt offer an ioctl entry point, the system call retur ns an error for any request that isnt predefined (-ENOTTY, No such ioctl for device). int (*mmap) (struct file *, struct vm_area_struct *); mmap is used to request a mapping of device memory to a processs address space. If the device doesnt implement this method, the mmap system call retur ns -ENODEV.
File Operations
int (*open) (struct inode *, struct file *); Though this is always the first operation performed on the device file, the driver is not required to declare a corresponding method. If this entry is NULL, opening the device always succeeds, but your driver isnt notified. int (*flush) (struct file *); The flush operation is invoked when a process closes its copy of a file descriptor for a device; it should execute (and wait for) any outstanding operations on the device. This must not be confused with the fsync operation requested by user programs. Currently, flush is used only in the network file system (NFS) code. If flush is NULL, it is simply not invoked.
File Operations
int (*release) (struct inode *, struct file *);
This operation is invoked when the file structure is being released. Like open, release can be missing.
Note:
Referer linux/fs.h data structure for a complete detail
};
mode_t f_mode;
The file mode identifies the file as either readable or writable (or both), by means of the bits FMODE_READ and FMODE_WRITE.
void *private_data;
The open system call sets this pointer to NULL before calling the open method for the driver. The driver is free to make its own use of the field or to ignore it private_data is a useful resource for preserving state information across system calls
/* this structure tells the kernel which operations are supported and how */ static struct file_operations simple_fops = { open: simple_open, release: simple_release, read: simple_read };
int init_module(void) { int result; /* set the owner field of simple_fops */ SET_MODULE_OWNER (&simple_fops); printk (KERN_DEBUG "registering simple_char\n"); result = register_chrdev( major_num, NAME, &simple_fops); if (result < 0) { printk (KERN_WARNING "simple_char: unsuccessful request of major #: %d\n", major_num); return result; /* report any problems during registration */
/* get and cache the length of the phrase */ if (phrase == NULL) phrase = default_phrase; phrase_length = strlen(phrase); /* if we're using dynamic allocation, find out which # we were assigned */ if (major_num == 0) major_num = result; return 0;
/* cleanup_module is called when the module is unloaded */ void cleanup_module(void) { int result; printk(KERN_DEBUG "unregistering simple_char\n"); /* we have to make sure and clean up after ourselves */ result = unregister_chrdev(major_num, NAME); if (result < 0){ printk(KERN_WARNING "simple_char: unregister_chrdev(%d, " NAME ") returned '%d'\n", major_num, result); } }
Putting it together
Device driver in Linux is basically a file representation Device model of Linux is a new move in Linux 2.6 with sysfs Synchronization and KCP have improved for Multi core There is a plenty of room for New Device Vendors and instance of such devices too Backwards compatibility is a difficult task to achieve but a regular updates can ease this a bit Device software is the next generation requirement and Linux has a huge population in this