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 Outblaze
Title: 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

  1. You may not want to use Linux 2.4
  2. The process of downloading and following instructions is a pain.
  3. 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.

  1. You need to install Linux v2.4.
  2. 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.
  3. 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
  1. Detecting a PCI VGA card.
  2. Reporting the PCI Configuration of the VGA card.
  3. Changing the mode of the VGA card.
  4. 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_id is 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.

Reply via email to