Attached is a small document I wrote and I am wondering if perhaps you would like it to be on the website (ggi or kgi). It isn't completed but if there seems to be enough interest then I'll gladly finish it. I guess it would most appropriately be on the kgi website but all of those people subscribe to this mailing list as well. Thank you, Lee -- Get your free email from www.linuxmail.org Powered by OutblazeTitle: Introduction to Linux Kernel Graphics
Introduction to Linux Kernel Graphics
Introduction
This document is a result of putting together lots of pieces of information needed to get started implememting graphics drivers for Linux. For the beginner, KGI programming seems to have some sort of mystical quality surrounding it. How do people know how to do these things? How did they learn to do this? Do they only teach this in European schools? To be sure, I don't know. But I do know that, in fact, there is nothing mystical about kernel or graphics programming. I also know a lot of people would like to get involved but there doesn't seem to be a straightforward way in which to cut your teeth. It is the purpose of this document to assist people hiking up the steep learning slope associated with KGI programming. For the serious Linux enthuiast, all of this stuff is well worth knowing and I can't imagine a better person to learn it from than me :^) The scope of this document is far from comprehensive. Instead, I conceive of this document as sort of an orientation. KGI is a small part of something quite large and it is easy to wonder where your little piece of KGI fits into the "big picture." Rather than try to explain the KGI API, it is my intention to give you a sense of the framework in which KGI operates. Moreover, I think you will find a lot of the information in this document useful in understanding the KGI source code. As I will repeatedly say, my ears are open and it you have a comment, let me know!
Lee Brown Jr. [EMAIL PROTECTED]
Compiling and Executing
System
Requirements Before you download any code, here is a quick run through of the system requirements needed to actually build and execute the source code. Note that even if you don't have (or want to have) the requirements listed below there is nothing to prevent you from looking at the code and following along with this documentation. I say this for a few reasons
- You may not want to use Linux 2.4
- The process of downloading and following instructions is a pain.
- You believe life is a spectator sport.
That being said, I am curious what happens with this code on different systems. Feedback is welcome here, and you can give me more if you try it out. Try it, you may like it.
- You need to install Linux v2.4.
- You need a PCI VGA card. NOT ISA. I don't know if such things still exist but if they do and you are the unfortunate person with one. Sorry.
- root access to your machine
How to Get the Code
You can download the code from http://someplace.net/
Tarball Contents
The tarball comes with several files. One of which I shamelessly borrowed from the KGI archives. Here is a brief description of each of them.
- `vga.h'
- This file contains all of the definitions useful for VGA programming. This includes port locations, register descriptions, field masks and field values.
- `svd-test.c'
- This file is the user space C program which tests the functionality implemented by the kernel module. This program is kind of like a good Russian car ... simple and straighforward. It is meant to be that way. No mysteries here.
- `svd.h'
- This file contains definitions which are used by both the module and svd-test. This is convenient for ioctl commands.
- `svd.c'
-
This is the kernel module source code. This code is capable of
- Detecting a PCI VGA card.
- Reporting the PCI Configuration of the VGA card.
- Changing the mode of the VGA card.
- Removing itself from the host.
- `Makefile'
- The makefile is convenient for building the module and (de)installation.
Building the Module
Getting 'er up and running is simple.
make
Builds the module and the test program. If you have compilation difficulties then the problem is most certainly that you have symbolic links to the 2.4 include files. We need those files! So go and make the neccessary changes. Then come back and continue as follows.
make install
Installs the module into your system. If you are running on 2.4 like a good mate then a short whir from your hard drive is all you should hear. If you don't have 2.4 in there then you will get a complaint right away (and the module won't install). At this point, you can already see if things are working by using the command:
tail /var/log/messages
When you do this you should get a number of statements about your VGA card resembling something like this:
Sep 15 15:42:03 darkstar kernel: svd_probe Sep 15 15:42:03 darkstar kernel: name: Trident Microsystems 3DIm`age 975 Sep 15 15:42:03 darkstar kernel: class: 0x300 Sep 15 15:42:03 darkstar kernel: device bus: 1 Sep 15 15:42:03 darkstar kernel: devfn: 8 Sep 15 15:42:03 darkstar kernel: vendor: 0x1023 Sep 15 15:42:03 darkstar kernel: device: 0x9750 Sep 15 15:42:03 darkstar kernel: irq: 11 Sep 15 15:42:03 darkstar kernel: revision id: 243
Finally, to remove the module type:
make uninstall
This simply calls rmmod to remove the `svd' module. If you have managed to get to this point then things look good indeed. Before you know it you'll be hacking VGA drivers with the best of them (whoever that might be).
Running the Test Program
When you ran make one of the files generated was `svdt'. This program uses the `svd.o' module to change the modes on your video card. What you should see is some flashing of your screen while the mode is being changed. Not to worry though because within seconds the program automatically changes the mode back to its original state. How all of this works I'll go over in excruciating line-by-line detail.
As root, install the driver:
make install
Execute `svdt'
./svdt
Well, how was it? Hey, it's still more than you can do. Improvements are always welcome. To remove the module just type:
make uninstall
Summary
Summary goes here.
A Close Look at a Simple Video Driver
While writing this, I was tempted to start with `svd-test.c' but I hate it when people put off the punch line until the end. You want to know about kernel drivers not some lame user space C program I wrote on my flight between Blacksburg and Atlanta. So I'll refrain from "leading you on" so to speak and get right to the heart of the matter.
A Note on #include Files
We know we want to add to the Linux kernel. But how exactly is this done? The answer is simple: make a module. So start by looking at `svd.c'. Turn your attention to the header files:
#include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/pci.h> #include <linux/pci_ids.h> #include <asm/io.h> #include <asm/types.h> #include <linux/ioport.h>
All of these header files refer to header files that are included in the linux kernel. Remember we can't use the C Standard Library ... we're implementing it! I'll go back to what each of these header files contains one by one as they are used.
Module Loading
Find (via the search function on your text editor) this following code in svd.c:
module_init(svd_init);
module_exit(svd_exit);
module_init(int *init_func(void)) is a macro which specifies
the function to execute upon loading. A module
does not have a main function as in traditional C
programs(as a matter of fact the Linux kernel proper doesn't have a
main. Why would it?) Instead when the module in installed, the kernel
executes the function specified as the argument of module_init.
This is the module initialization function. As you can see, the module
initialisation function takes a void and returns an int.
In my case, I creatively called the initialization function for svd
svd_init.
module_exit(void *exit_func(void)) is a macro which specifies
the function to execute upon unloading the module. Notice that
module_exit takes the name of a function that returns
void rather than int as does module_init. In this
case we have svd_exit;
So step one of creating a module is to pick a name for your module initialization and exit functions and declare them using the two macros described above. To use these macros:
#include <linux/module.h>.
Initialization Macros
So now examine svd_init. As I said
before, everything starts here.
/* This routine initializes the module. */
static int __init svd_init()
{
if( pci_module_init(&svd_driver))
return -ENODEV;
return 0;
}
Notice the __init macro in the declaration. This specifies
svd_init as a function whose memory can be released after
initialization. In order to save memory, this technique is used for
code that is only used once at initialization and never again. There
are some similar macros used elsewhere in the code. Here is a list of
all related memory saving macros imported by:
#include <linux/init.h>
__init- Designates code to be thrown away after module loading.
__devinit- Designates code to be thrown away after device is initialized.
__exit- Designates code to be thrown away after module is removed.
__devexit- Designates code to be thrown away after device is released.
__initdata- Designates data to be released after module loading.
__devinitdata- Designates data to be released after device is initialized.
__exitdata- Designates data to be released after module ir removed.
__devexitdata- Designates data to be released after device is released.
PCI Initialization
Take another gander at svd_init. All it really does is
make the following call.
pci_module_init(&svd_driver)
Graphics adapters are PCI devices. This means they transfer data
over the PCI bus. It also means you are in luck because Linux has
excellent PCI support built into its API. The call
pci_module_init(&svd_driver) simply tells the kernel's PCI
handling code that we want to be the device driver for a certain
device on the PCI bus. The svd_driver structure tells the PCI
infrastructure what device we're interested in, and which functions to
call if it exists on the system. In theory, the device doesn't
neccessarily have to be on the system at boot time. The code allows
for devices to be be "hot-pluggable". In reality, we know that the
card will be on the system when the module is loaded. All
pci_module_init does is register with PCI support that we are
interested in a PCI device specified in svd_driver.
Here's the declaration of svd_driver.
static struct pci_driver svd_driver = {
name: SVD_NAME,
id_table: svd_id,
probe: &svd_probe,
remove: &svd_remove
};
This is how the structure data reads:
SVD_NAME- An arbitrary name for the device/driver
svd_id- An array of structures (of length one in most cases) defining the type of PCI device for which this is a driver.
svd_probe-
This function is called for all devices on the PCI bus which fits
the description specified by
svd_id. svd_remove-
This function is called when a device which fits the
description specified by
svd_idis removed from the system.
By the way, if you're wondering what the deal is with the notation used in the structures, this is a GCC extension. The variable name is followed by a colon and then it's value. This is only convenient notation. I find it useful and clarifying.
Here is svd_id.
/* The device id */
static struct pci_device_id svd_id[] __devinitdata = {
{ class: PCI_CLASS_DISPLAY_VGA << 8,
class_mask: ~0,
vendor: PCI_ANY_ID,
device: PCI_ANY_ID,
subvendor: PCI_ANY_ID,
subdevice: PCI_ANY_ID, }
};
This is the actual data used by the kernel to identify for which
devices it needs to call svd_probe and svd_remove. If
you look at `linux/pci_ids.h' you will find a long list of
vendors and classes and devices that can be used as values in these
fields. These values are standardized and not Linux specific. In the
case of `svd', I was interested in any VGA card on the PCI bus so
I used the value of PCI_CLASS_DISPLAY_VGA in the class
field. Note the left shift operator. Before you ever use a structure
like pci_device_id, check the header files for the correct
format of the values(this is a discreet way of saying that I screwed
this up and spent hours debugging my mistake so don't let it happen
to you). I didn't care about the other values (I wanted any VGA card)
so I filled in the other fields with PCI_ANY_ID. To use the PCI
related functions, it is neccessary to:
#include <linux/pci.h> #include <linux/pci_ids.h>
The PCI Probe Function
This document was generated on 16 September 2000 using texi2html 1.56k.
