From: wolff@neuron.et.tudelft.nl (Rogier Wolff) Subject: Device driver organization -> loadable device drivers. Date: 13 Mar 1992 10:33:27 GMT
Hi everyone,
( Source code from Linux is written with > in front, source code which
I propose as new code is written with # in front. Note that I've not
yet tried to compile this code, so it may contain syntax errors, but
it is the intention that counts in this case.)
To read and write to devices, there are routines like:
(taken from char_dev.c at the bottom, already patched by me.)
> int char_rw(int rw,struct inode * inode, struct file * filp, char * buf,
> int count)
> {
> unsigned int major,minor;
> crw_ptr call_addr;
>
> major = MAJOR(inode->i_rdev);
> minor = MINOR(inode->i_rdev);
> if (major >= NRDEVS)
> return -ENODEV;
> if (!(call_addr = crw_table[major]))
> return -ENODEV;
> return call_addr(rw,minor,buf,count,&filp->f_pos,filp->f_flags);
> }
that use a table which holds the addresses of the routines to call.
However there are also places in the kernel that do not use such a
nice structure:
(From init/main.c:)
> tty_init();
> time_init();
> hd_init();
> floppy_init();
This should also be solved with a table like above.
Using the table will allow compiling into the kernel a few empty
device drivers which can be loaded at runtime!
For instance
# struct Devices {
# int (*init)();
# int (*readwrite)();
# int (*ioctl)();
# int numberofminors;
# } devicelist = {
# /* initroutine, read/write , ioctrl ,numberofminors */
# {fd_init ,fd_rw ,fd_ioctl ,32},
# {hd_init ,hd_rw ,NULL /*?*/ ,10},
# {tty_init ,tty_rw ,tty_ioctl ,256},
# {NULL ,NULLi ,NULL ,0}
# };
This would allow modifying the readwrite routine to the following:
# int char_rw(int rw,struct inode * inode, struct file * filp, char * buf,
# int count)
# {
# unsigned int major,minor;
# crw_ptr call_addr;
#
# major = MAJOR(inode->i_rdev);
# minor = MINOR(inode->i_rdev);
# if (major >= NRDEVS)
# return -ENODEV;
# if (minor >= devicelist[major].numberofminors)
# return -ENODEV; /* Linus writes EIO, I think ENODEV is better */
# if (!(call_addr = devicelist[major].readwrite))
# return -ENODEV;
# return call_addr(rw,minor,buf,count,&filp->f_pos,filp->f_flags);
# }
and on similar grounds, the init routine can be tidied up:
#initdevices ()
#{
#int i;
#
#for (i=0;i<NRDEVS;i++)
# {
# if (devicelist[i].init != NULL)
# devicelist[i].numberofminors =
# devicelist[i].init (devicelist[i].numberofminors);
# /* The init routines can detect the hardware that they need,
# and adjust the number of minors that they will support on
# the running configuration. For instance hd_init detects wether
# there is a second harddisk installed, and adjusts the # minors,
# They should return 0 for no hardware. */
# }
#}
And loading a device driver would be something like:
# doloaddevice (char * fname)
# {
# char *start;
#
# if (!suser ()) return -EACCES;
#
# if (curnumerofdevices >= maxnumberofdevices)
# return -EIO;
#
# if (mapintokernelmemory (fname,&start) < 0)
# return -Esomthing;
#
# devicelist[curnumberofdevices].init = start;
# devicelist[curnumberofdevices].nrofminors = (int (*)())start (0);
# if (devicelist[curnumberofdevices].nrofminors == 0) return -EIO;
# /* Code to initialize devicelist[].rw and .ioctrl */
# curnumberofdevices++;
# return OK;
# }
Roger
--
If the opposite of "pro" is "con", what is the opposite of "progress"?
(stolen from kadokev@iitvax ==? technews@iitmax.iit.edu)
EMail: wolff@duteca.et.tudelft.nl ** Tel +31-15-783644 or +31-15-142371