[BACK]Return to dki.html CVS log [TXT][DIR] Up to [local] / prex-old / doc / html / doc

File: [local] / prex-old / doc / html / doc / dki.html (download) (as text)

Revision 1.1, Tue Jun 3 09:38:42 2008 UTC (15 years, 11 months ago) by nbrk
Branch point for: MAIN

Initial revision

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <title>Prex Driver-Kernel Interface</title>
  <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
  <meta name="keywords" content="Prex, embedded, real-time, operating system, RTOS, open source, free">
  <meta name="author" content="Kohsuke Ohtani">
  <link rel="stylesheet" type="text/css" href="../default.css" media="screen">
  <link rel="stylesheet" type="text/css" href="../print.css" media="print">
</head>
<body>
<div id="top">
</div>
<div id="middle">

<table id="content" cellpadding="0" cellspacing="0">
  <tbody>

    <tr>
      <td id="header" colspan="2" valign="top">
        <table width="100%" border="0" cellspacing="0" cellpadding="0">
        <tr>
          <td id="logo">
            <a href="http://prex.sourceforge.net/">
            <img alt="Prex logo" src="../img/logo.gif" border="0"
            style="width: 281px; height: 56px;"></a>
          </td>
          <td id="brief" align="right" valign="bottom">
            An Open Source, Royalty-free,<br>
	    Real-time Operating System
          </td>
        </tr>
        </table>
      </td>
    </tr>

    <tr>
      <td id="directory" style="vertical-align: top;">
      <a href="http://prex.sourceforge.net/">Prex Home</a> >
      <a href="index.html">Document Index</a> >
      Driver-Kernel Interface
    </tr>
    <tr><td class="pad" colspan="2" style="vertical-align: top;"></td></tr>

    <tr>
      <td id="main" style="vertical-align: top;">
      <h1>Prex Driver-Kernel Interface</h1>

<i>Version 1.0.2, 2007/12/23</i><br>
<br>

<h3>Table of Contents</h3>
<ul>
  <li><a href="#intro">Introduction</a></li>
</ul>
<ul>
  <li><a href="#gen">General Information</a>
  <ul>
    <li><a href="#gen">Data Types</a></li>
    <li><a href="#gen">Calls from ISR</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#obj">Device Object</a>
  <ul>
    <li><a href="#obj">device_create</a></li>
    <li><a href="#obj">device_delete</a></li>
    <li><a href="#obj">device_broadcast</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#kmem">Kernel Memory</a>
  <ul>
    <li><a href="#kmem">kmem_alloc</a></li>
    <li><a href="#kmem">kmem_free</a></li>
    <li><a href="#kmem">kmem_map</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#umem">User Memory</a>
  <ul>
    <li><a href="#umem">umem_copyin</a></li>
    <li><a href="#umem">umem_copyout</a></li>
    <li><a href="#umem">umem_strnlen</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#page">Physical Page</a>
  <ul>
    <li><a href="#page">page_alloc</a></li>
    <li><a href="#page">page_free</a></li>
    <li><a href="#page">page_reserve</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#int">Interrupt</a>
  <ul>
    <li><a href="#int">irq_attach</a></li>
    <li><a href="#int">irq_detach</a></li>
    <li><a href="#int">irq_lock</a></li>
    <li><a href="#int">irq_unlock</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#sched">Scheduler</a>
  <ul>
    <li><a href="#sched">sched_lock</a></li>
    <li><a href="#sched">sched_unlock</a></li>
    <li><a href="#sched">sched_tsleep</a></li>
    <li><a href="#sched">sched_wakeup</a></li>
    <li><a href="#sched">sched_dpc</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#timer">Timer</a>
  <ul>
    <li><a href="#timer">timer_callout</a></li>
    <li><a href="#timer">timer_stop</a></li>
    <li><a href="#timer">timer_delay</a></li>
    <li><a href="#timer">timer_count</a></li>
    <li><a href="#timer">timer_hook</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#misc">Miscellaneous</a>
  <ul>
    <li><a href="#misc">task_capable</a></li>
    <li><a href="#misc">exception_post</a></li>
    <li><a href="#misc">phys_to_virt</a></li>
    <li><a href="#misc">virt_to_phys</a></li>
    <li><a href="#misc">machine_reset</a></li>
    <li><a href="#misc">machine_dump</a></li>
    <li><a href="#misc">debug_attach</a></li>
    <li><a href="#misc">printk</a></li>
    <li><a href="#misc">panic</a></li>
  </ul>
  </li>
</ul>
<br>
<br>

<h2 id="intro">Introduction</h2>
<p>
The Prex kernel provides the minimum service for the device drivers.
Since the driver module is separated from the kernel module, the drivers
can not access other kernel functions beyond this interface.
This mechanism helps to isolate the kernel from the driver codes.
</p>
<p>
This document describes the Driver-Kernel Interface (DKI) that can be
used by device drivers.
</p>

<h2 id="gen">General Information</h2>

<h3>Data Types</h3>
<p>
The following data types are defined by kernel.
</p>

<table border="1" width="60%" cellspacing="0">
<tbody>
<tr>
  <th>Data type</th>
  <th>Description</th>
</tr>

<tr>
  <td>device_t</td>
  <td>Used to identify the device object.</td>
</tr>
<tr>
  <td>task_t</td>
  <td>Used to identify the task.</td>
</tr>
</tbody>
</table>

<h3>Calls from ISR</h3>
<p>
The driver-kernel service is limited at interrupt level
because the kernel does not synchronize all data accesses
for interrupt level access.
So, the device driver can use only the following functions
from the interrupt service routine.
</p>
<ul>
  <li>irq_lock()</li>
  <li>irq_unlock()</li>
  <li>sched_wakeup()</li>
  <li>sched_stat()</li>
  <li>timer_callout()</li>
  <li>timer_stop()</li>
  <li>timer_count()</li>
  <li>sched_lock()</li>
  <li>sched_unlock()</li>
  <li>sched_tsleep()</li>
  <li>sched_wakeup()</li>
  <li>sched_dpc()</li>
  <li>exception_post()</li>
  <li>printk()</li>
  <li>panic()</li>
  <li>machine_reset()</li>
  <li>machine_dump()</li>
</ul>


<h2 id="obj">Device Object</h2>
<p>
The device object is created by the driver to communicate to the
application. Usually, the driver creates a device object for an existing
physical device. And, it can also be used to handle logical or virtual devices.
</p>

<pre>
device_t device_create(const struct devio *io, const char *name, int flags);
int device_delete(device_t dev);
int device_broadcast(int event, int force);
</pre>

<dl>
<dt>device_create()</dt>
<dd>
Creates device object with the specified name in <i>name</i>.
The <i>io</i> argument points to the device I/O table for the device object.
This function returns the ID of the created device object on success, or
0 on failure.
<pre>
/*
 * Device object
 */
typedef int *device_t;
</pre>
All device object has its associated device I/O table. The table defines
the function pointer for the corresponding request routines.
<pre>
/*
 * Device I/O table
 */
struct devio {
    int     (*open)(device_t dev, int mode);
    int     (*close)(device_t dev);
    int     (*read)(device_t dev, char *buf, u_long *size, u_long offset);
    int     (*write)(device_t dev, char *buf, u_long *size, u_long offset);
    int     (*ioctl)(device_t dev, int cmd, u_long arg);
    int     (*event)(device_t dev, int event);
};
</pre>
The driver can specify the one same I/O table for the different device
objects. All device I/O routine can get the device object ID as its
first argument. So, each routine can determine the request is sent to
which device object.
</dd>
</dl>

<dl>
<dt>device_delete()</dt>
<dd>
Deletes the device object specified in <i>dev</i>.
This function returns ENODEV if the specified device object does not exist.
</dd>
</dl>

<dl>
<dt>device_broadcast()</dt>
<dd>
Broadcasts the message specified by <i>event</i> to all device objects.
If <i>force</i> is true, a kernel will ignore the value returned by
each driver, and continue event notification.
If <i>force</i> is false and any driver returns any error for the event,
a kernel stops the event notification. In this case, this function
returns an error code which is returned by that driver.
</dd>
</dl>


<h2 id="kmem">Kernel Memory</h2>
The kernel provides the following memory allocation services for drivers.
Please note that it can not allocate lager buffer than one page.
If the driver needs larger buffer, it should use page_alloc()
 instead of kmem_alloc().
<pre>
void *kmem_alloc(size_t size);
void  kmem_free(void *ptr);
void *kmem_map(void *addr, size_t size);
</pre>

<dl>
<dt>kmem_alloc()</dt>
<dd>
Allocates the kernel buffer for the specified <i>size</i> bytes.
It returns the pointer to the allocated buffer on success, or NULL on failure.
</dd>
</dl>

<dl>
<dt>kmem_free()</dt>
<dd>
Frees the allocated kernel buffer pointed by <i>ptr</i>.
</dd>
</dl>

<dl>
<dt>kmem_map()</dt>
<dd>
Maps the specified virtual address <i>addr</i> to the kernel address.
It returns the pointer mapped in the kernel memory on success, or NULL if
there is no mapped memory.
</dd>
</dl>

<h2 id="umem">User Memory</h2>
<p>
Since an access to user memory may cause a page fault, the user
buffer manipulation is handled by the kernel core code.
The driver should not access the user buffer directly. Instead, 
it should use the following kernel services.
</p>
<pre>
int umem_copyin(void *uaddr, void *kaddr, size_t len);
int umem_copyout(void *kaddr, void *uaddr, size_t len);
int umem_strnlen(const char *uaddr, size_t maxlen, size_t *len);
</pre>

<dl>
<dt>umem_copyin</dt>
<dd>
Copies the data from the user buffer to the kernel area.
Returns 0 on success, or EFAULT on failure.
</dd>
</dl>

<dl>
<dt>umem_copyout</dt>
<dd>
Copies the data from the kernel buffer to the user area.
Returns 0 on success, or EFAULT on failure.
</dd>
</dl>

<dl>
<dt>umem_strnlen</dt>
<dd>
Gets the length of specified string in <i>uaddr</i>.
Returns 0 on success, or EFAULT on failure.
The returned length does not include a NULL terminator.
</dd>
</dl>

<h2 id="page">Physical Page</h2>
<pre>
void *page_alloc(u_long size);
void  page_free(void *addr, u_long size);
int   page_reserve(void *addr, u_long size);
</pre>

<dl>
<dt>page_alloc()</dt>
<dd>
Allocates continuous pages for the specified <i>size</i> bytes.
This function returns the physical address of the allocated pages, or
returns NULL on failure. The kernel does not zero-fill this new page.
The requested size is automatically round up to the page boundary.
</dd>
</dl>

<dl>
<dt>page_free()</dt>
<dd>
Frees allocated page block. The caller must provide the size information
in <i>size</i> argument that was specified for page_alloc().
</dd>
</dl>

<dl>
<dt>page_reserve()</dt>
<dd>
Reserves pages in the specified address.
This function returns 0 on success, or -1 on failure.
</dd>
</dl>


<h2 id="int">Interrupt</h2>
<p>
The Prex kernel encapsulates the save/restore of the previous interrupt
state. irq_lock() will automatically save the previous interrupt state
if needed. So, the driver must call irq_unlock() for the same count of
the irq_lock() call.
</p>

<pre>
int  irq_attach(int irqno, int prio, int shared, int (*isr)(int), void (*ist)(int));
void irq_detach(int handle);
void irq_lock(void);
void irq_unlock(void);
</pre>

<dl>
<dt>irq_attach()</dt>
<dd>
Attaches to the <i>ISR</i> (interrupt service request) and <i>ist</i>
(interrupt service thread) to the interrupt vector specified in <i>irqno</i>.
The argument <i>prio</i> is the logical interrupt priority level. The smaller
priority value is higher priority for interrupt processing.
The caller can specify one of the following interrupt priority levels.
<pre>
/*
 * Interrupt priority levels
 */
#define IPL_NONE	0	/* Nothing */
#define IPL_COMM	1	/* Serial, Parallel */
#define IPL_BLOCK	2	/* FDD, IDE */
#define IPL_NET		3	/* Network */
#define IPL_DISPLAY	4	/* Screen */
#define IPL_INPUT	5	/* Keyboard, Mouse */
#define IPL_AUDIO	6	/* Audio */
#define IPL_BUS		7	/* USB, PCCARD */
#define IPL_RTC		8	/* RTC Alarm */
#define IPL_PROFILE	9	/* Profiling timer */
#define IPL_CLOCK	10	/* System Clock Timer */
#define IPL_HIGH	11	/* Everything */
</pre>
If <i>shared</i> argument is true, the kernel allows the other irq owner
to attach to the same irq vector.
</dd>
</dl>

<dl>
<dt>irq_detach()</dt>
<dd>
Detaches the interrupt from the IRQ specified by <i>handle</i>.
</dd>
</dl>

<dl>
<dt>irq_lock()</dt>
<dd>
Masks all H/W interrupts, and increments the IRQ lock count.
</dd>
</dl>

<dl>
<dt>irq_unlock()</dt>
<dd>
Decrements the IRQ lock count. If the IRQ lock count becomes 0, 
the H/W interrupts are unmasked.
</dd>
</dl>


<h2 id="sched">Scheduler</h2>
<p>
The thread can sleep/wakeup for the specific event. The event works as
the queue of the sleeping threads.
</p>

<pre>
void sched_lock(void);
void sched_unlock(void);
int  sched_tsleep(struct event *evt, u_long timeout);
void sched_wakeup(struct event *evt);
void sched_dpc(struct dpc *dpc, void (*func)(void *), void *arg);
</pre>

<dl>
<dt>sched_lock()</dt>
<dd>
Disables the thread switch, and increments the scheduling lock count.
This is used to synchronize the thread execution to protect 
global resources. Since the scheduling lock count can be nested, 
the caller must call the sched_unlock() routine the same number of
lock count.
</dd>
</dl>

<dl>
<dt>sched_unlock()</dt>
<dd>
Decrements the scheduling lock count. If the scheduling lock count becomes 0, 
the thread switch is enabled again.
</dd>
</dl>

<dl>
<dt>sched_tsleep()</dt>
<dd>
Sleep the current thread until specified event occurs.
The caller can specify <i>timeout</i> value in msec.
If the <i>timeout</i> value is 0, the timeout timer does not work.
<pre>
/*
 * Event for sleep/wakeup
 */
struct event {
    struct queue    sleepq;         /* Queue for waiting thread */
    char            *name;          /* Event name */
};
</pre>
</dd>
</dl>

<dl>
<dt>sched_wakeup()</dt>
<dd>
Wakes up all threads that are waiting for the specified event.
</dd>
</dl>

<dl>
<dt>sched_dpc()</dt>
<dd>
Programs DPC (Deferred Procedure Call).
<pre>
/*
 * DPC object
 */
struct dpc {
	struct queue	link;		/* Linkage on DPC queue */
	int		state;
	void		(*func)(void *); /* Call back routine */
	void		*arg;		/* Argument to pass */
};
</pre>
</dd>
</dl>

<h2 id="timer">Timer</h2>
<pre>
void   timer_callout(struct timer *tmr, void (*func)(u_long), u_long arg, u_long msec);
void   timer_stop(struct timer *tmr);
u_long timer_delay(u_long msec);
u_long timer_count(void);
int    timer_hook(void (*func)(int));
</pre>


<dl>
<dt>timer_callout()</dt>
<dd>
Requests a call out timer. The specified <i>func</i> routine will be
called with <i>arg</i> argument after <i>msec</i>. The caller must
allocate the memory for the timer structure for <i>tmr</i>.
<pre>
/*
 * Timer structure
 */
struct timer {
    struct list link;           /* Linkage on timer chain */
    int         active;         /* True if active */
    u_long      expire;         /* Expire time (ticks) */
    u_long      interval;       /* Time interval */
    void        (*func)(void *); /* Function to call */
    void        *arg;           /* Function argument */
    struct event event;         /* Event for this timer */
};
</pre>
</dd>
</dl>

<dl>
<dt>timer_stop()</dt>
<dd>
Stops a running timer.
</dd>
</dl>

<dl>
<dt>timer_delay()</dt>
<dd>
Delays thread execution.
</dd>
</dl>


<dl>
<dt>timer_count()</dt>
<dd>
Returns current timer count (ticks since bootup).
</dd>
</dl>

<dl>
<dt>timer_hook()</dt>
<dd>
Installs a hook routine for the timer tick.
</dd>
</dl>


<h2 id="misc">Miscellaneous</h2>
<pre>
int   task_capable(task_t task);
int   exception_post(task_t task, int exc);
void *phys_to_virt(void *p_addr);
void *virt_to_phys(void *v_addr);
void  machine_reset(void);
void  machine_dump(int index);
void  debug_attach(void (*func)(char *));
void  printk(const char *fmt, ...);
void  panic(const char *fmt, ...);
</pre>


<dl>
<dt>task_capable()</dt>
<dd>
Checks the task capability for the speciifed item.
</dd>
</dl>

<dl>
<dt>exception_post()</dt>
<dd>
Posts an exception for the specific task.
</dd>
</dl>

<dl>
<dt>machine_reset()</dt>
<dd>
Resets the system.
</dd>
</dl>

<dl>
<dt>machine_dump()</dt>
<dd>
Dumps the system information for debug.
</dd>
</dl>

<dl>
<dt>phys_to_virt()</dt>
<dd>
Return the kernel virtual address from specifid physical address.
</dd>
</dl>

<dl>
<dt>virt_to_phys()</dt>
<dd>
Return the mapped physical address from specifid virtual address.
</dd>
</dl>

<dl>
<dt>debug_attach()</dt>
<dd>
Attaches to the external output routine for the printk().
</dd>
</dl>

<dl>
<dt>printk()</dt>
<dd>
Prints the driver message to the output device.
The message is enabled only with debugging kernel.
</dd>
</dl>

<dl>
<dt>panic()</dt>
<dd>
Stops the system for the fatal error.
</dd>
</dl>


      </td>
    </tr>
    <tr>
      <td id="footer" colspan="2" style="vertical-align: top;">
        <a href="http://sourceforge.net">
        <img src="http://sourceforge.net/sflogo.php?group_id=132028&amp;type=1"
        alt="SourceForge.net Logo" border="0" height="31" width="88"></a><br>
        Copyright&copy; 2005-2007 Kohsuke Ohtani
      </td>
    </tr>

  </tbody>
</table>

</div>
<div id="bottom"></div>

</body>
</html>