]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - doc/html/ref/synth-new-target.html
RedBoot TX53 Release 2012-02-15
[karo-tx-redboot.git] / doc / html / ref / synth-new-target.html
1 <!-- Copyright (C) 2003 Red Hat, Inc.                                -->
2 <!-- This material may be distributed only subject to the terms      -->
3 <!-- and conditions set forth in the Open Publication License, v1.0  -->
4 <!-- or later (the latest version is presently available at          -->
5 <!-- http://www.opencontent.org/openpub/).                           -->
6 <!-- Distribution of the work or derivative of the work in any       -->
7 <!-- standard (paper) book form is prohibited unless prior           -->
8 <!-- permission is obtained from the copyright holder.               -->
9 <HTML
10 ><HEAD
11 ><TITLE
12 >Writing New Devices - target</TITLE
13 ><meta name="MSSmartTagsPreventParsing" content="TRUE">
14 <META
15 NAME="GENERATOR"
16 CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
17 "><LINK
18 REL="HOME"
19 TITLE="eCos Reference Manual"
20 HREF="ecos-ref.html"><LINK
21 REL="UP"
22 TITLE="eCos Synthetic Target"
23 HREF="hal-synth-arch.html"><LINK
24 REL="PREVIOUS"
25 TITLE="System Calls"
26 HREF="synth-syscalls.html"><LINK
27 REL="NEXT"
28 TITLE="Writing New Devices - host"
29 HREF="synth-new-host.html"></HEAD
30 ><BODY
31 CLASS="REFENTRY"
32 BGCOLOR="#FFFFFF"
33 TEXT="#000000"
34 LINK="#0000FF"
35 VLINK="#840084"
36 ALINK="#0000FF"
37 ><DIV
38 CLASS="NAVHEADER"
39 ><TABLE
40 SUMMARY="Header navigation table"
41 WIDTH="100%"
42 BORDER="0"
43 CELLPADDING="0"
44 CELLSPACING="0"
45 ><TR
46 ><TH
47 COLSPAN="3"
48 ALIGN="center"
49 >eCos Reference Manual</TH
50 ></TR
51 ><TR
52 ><TD
53 WIDTH="10%"
54 ALIGN="left"
55 VALIGN="bottom"
56 ><A
57 HREF="synth-syscalls.html"
58 ACCESSKEY="P"
59 >Prev</A
60 ></TD
61 ><TD
62 WIDTH="80%"
63 ALIGN="center"
64 VALIGN="bottom"
65 ></TD
66 ><TD
67 WIDTH="10%"
68 ALIGN="right"
69 VALIGN="bottom"
70 ><A
71 HREF="synth-new-host.html"
72 ACCESSKEY="N"
73 >Next</A
74 ></TD
75 ></TR
76 ></TABLE
77 ><HR
78 ALIGN="LEFT"
79 WIDTH="100%"></DIV
80 ><H1
81 ><A
82 NAME="SYNTH-NEW-TARGET">Writing New Devices - target</H1
83 ><DIV
84 CLASS="REFNAMEDIV"
85 ><A
86 NAME="AEN18180"
87 ></A
88 ><H2
89 >Name</H2
90 >Writing New Devices&nbsp;--&nbsp;extending the synthetic target, target-side</DIV
91 ><DIV
92 CLASS="REFSYNOPSISDIV"
93 ><A
94 NAME="AEN18183"><H2
95 >Synopsis</H2
96 ><DIV
97 CLASS="FUNCSYNOPSIS"
98 ><A
99 NAME="AEN18184"><P
100 ></P
101 ><TABLE
102 BORDER="5"
103 BGCOLOR="#E0E0F0"
104 WIDTH="70%"
105 ><TR
106 ><TD
107 ><PRE
108 CLASS="FUNCSYNOPSISINFO"
109 >#include &lt;cyg/hal/hal_io.h&gt;
110       </PRE
111 ></TD
112 ></TR
113 ></TABLE
114 ><P
115 ><CODE
116 ><CODE
117 CLASS="FUNCDEF"
118 >int synth_auxiliary_instantiate</CODE
119 >(const char* package, const char* version, const char* device, const char* instance, const char* data);</CODE
120 ></P
121 ><P
122 ><CODE
123 ><CODE
124 CLASS="FUNCDEF"
125 >void synth_auxiliary_xchgmsg</CODE
126 >(int device_id, int request, int arg1, int arg2, const unsigned char* txdata, int txlen, int* reply, unsigned char* rxdata, int* rxlen, int max_rxlen);</CODE
127 ></P
128 ><P
129 ></P
130 ></DIV
131 ></DIV
132 ><DIV
133 CLASS="REFSECT1"
134 ><A
135 NAME="SYNTH-NEW-TARGET-DESCRIPTION"
136 ></A
137 ><H2
138 >Description</H2
139 ><P
140 >In some ways writing a device driver for the synthetic target is very
141 similar to writing one for a real target. Obviously it has to provide
142 the standard interface for that class of device, so for example an
143 ethernet device has to provide <TT
144 CLASS="FUNCTION"
145 >can_send</TT
146 >,
147 <TT
148 CLASS="FUNCTION"
149 >send</TT
150 >, <TT
151 CLASS="FUNCTION"
152 >recv</TT
153 > and similar
154 functions. Many devices will involve interrupts, so the driver
155 contains ISR and DSR functions and will call
156 <TT
157 CLASS="FUNCTION"
158 >cyg_drv_interrupt_create</TT
159 >,
160 <TT
161 CLASS="FUNCTION"
162 >cyg_drv_interrupt_acknowledge</TT
163 >, and related
164 functions.
165     </P
166 ><P
167 >In other ways writing a device driver for the synthetic target is very
168 different. Usually the driver will not have any direct access to the
169 underlying hardware. In fact for some devices the I/O may not involve
170 real hardware, instead everything is emulated by widgets on the
171 graphical display. Therefore the driver cannot just peek and poke
172 device registers, instead it must interact with host-side code by
173 exchanging message. The synthetic target HAL provides a function
174 <TT
175 CLASS="FUNCTION"
176 >synth_auxiliary_xchgmsg</TT
177 > for this purpose.
178     </P
179 ><P
180 >Initialization of a synthetic target device driver is also very
181 different. On real targets the device hardware already exists when the
182 driver's initialization routine runs. On the synthetic target it is
183 first necessary to instantiate the device inside the I/O auxiliary, by
184 a call to <TT
185 CLASS="FUNCTION"
186 >synth_auxiliary_instantiate</TT
187 >. That
188 function performs a special message exchange with the I/O auxiliary,
189 causing it to load a Tcl script for the desired type of device and run
190 an instantiation procedure within that script.
191     </P
192 ><P
193 >Use of the I/O auxiliary is optional: if the user does not specify
194 <TT
195 CLASS="OPTION"
196 >--io</TT
197 > on the command line then the auxiliary will not
198 be started and hence most I/O operations will not be possible. Device
199 drivers should allow for this possibility, for example by just
200 discarding any data that gets written. The HAL exports a flag
201 <TT
202 CLASS="VARNAME"
203 >synth_auxiliary_running</TT
204 > which should be checked.
205     </P
206 ></DIV
207 ><DIV
208 CLASS="REFSECT1"
209 ><A
210 NAME="SYNTH-NEW-TARGET-INSTANTIATE"
211 ></A
212 ><H2
213 >Instantiating a Device</H2
214 ><P
215 >Device instantiation should happen during the C++ prioritized static
216 constructor phase of system initialization, before control switches to
217 <TT
218 CLASS="FUNCTION"
219 >cyg_user_start</TT
220 > and general application code. This
221 ensures that there is a clearly defined point at which the I/O
222 auxiliary knows that all required devices have been loaded. It can
223 then perform various consistency checks and clean-ups, run the user's
224 <TT
225 CLASS="FILENAME"
226 >mainrc.tcl</TT
227 > script, and make the main window
228 visible.
229     </P
230 ><P
231 >For standard devices generic eCos I/O code will call the device
232 initialization routines at the right time, iterating through the
233 <TT
234 CLASS="VARNAME"
235 >DEVTAB</TT
236 > table in a static constructor. The same
237 holds for network devices and file systems. For more custom devices
238 code like the following can be used:
239     </P
240 ><TABLE
241 BORDER="5"
242 BGCOLOR="#E0E0F0"
243 WIDTH="70%"
244 ><TR
245 ><TD
246 ><PRE
247 CLASS="PROGRAMLISTING"
248 >#include &lt;cyg/infra/cyg_type.h&gt;
249 class mydev_init {
250   public:
251     mydev_init() {
252         &#8230;
253     }
254 };
255 static mydev_init mydev_init_object CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO);</PRE
256 ></TD
257 ></TR
258 ></TABLE
259 ><P
260 >Some care has to be taken because the object
261 <TT
262 CLASS="VARNAME"
263 >mydev_init_object</TT
264 > will typically not be referenced
265 by other code, and hence may get eliminated at link-time. If the code
266 is part of an eCos package then problems can be avoided by putting the
267 relevant file in <TT
268 CLASS="FILENAME"
269 >libextras.a</TT
270 >:
271     </P
272 ><TABLE
273 BORDER="5"
274 BGCOLOR="#E0E0F0"
275 WIDTH="70%"
276 ><TR
277 ><TD
278 ><PRE
279 CLASS="PROGRAMLISTING"
280 >cdl_package CYGPKG_DEVS_MINE {
281     &#8230;
282     compile -library=libextras.a init.cxx
283 }</PRE
284 ></TD
285 ></TR
286 ></TABLE
287 ><P
288 >For devices inside application code the same can be achieved by
289 linking the relevant module as a <TT
290 CLASS="FILENAME"
291 >.o</TT
292 > file rather
293 than putting it in a <TT
294 CLASS="FILENAME"
295 >.a</TT
296 > library.
297     </P
298 ><P
299 >In the device initialization routine the main operation is a call to
300 <TT
301 CLASS="FUNCTION"
302 >synth_auxiliary_instantiate</TT
303 >. This takes five
304 arguments, all of which should be strings:
305     </P
306 ><P
307 ></P
308 ><DIV
309 CLASS="VARIABLELIST"
310 ><DL
311 ><DT
312 ><TT
313 CLASS="VARNAME"
314 >package</TT
315 ></DT
316 ><DD
317 ><P
318 >For device drivers which are eCos packages this should be a directory
319 path relative to the eCos repository, for example
320 <TT
321 CLASS="LITERAL"
322 >devs/eth/synth/ecosynth</TT
323 >. This will allow the I/O
324 auxiliary to find the various host-side support files for this package
325 within the install tree. If the device is application-specific and not
326 part of an eCos package then a NULL pointer can be used, causing the
327 I/O auxiliary to search for the support files in the current directory
328 and then in <TT
329 CLASS="FILENAME"
330 >~/.ecos/synth</TT
331 >
332 instead. 
333         </P
334 ></DD
335 ><DT
336 ><TT
337 CLASS="VARNAME"
338 >version</TT
339 ></DT
340 ><DD
341 ><P
342 >For eCos packages this argument should be the version of the package
343 that is being used, for example <TT
344 CLASS="LITERAL"
345 >current</TT
346 >. A simple
347 way to get this version is to use the
348 <TT
349 CLASS="FUNCTION"
350 >SYNTH_MAKESTRING</TT
351 > macro on the package name.
352 If the device is application-specific then a NULL pointer should be
353 used. 
354         </P
355 ></DD
356 ><DT
357 ><TT
358 CLASS="VARNAME"
359 >device</TT
360 ></DT
361 ><DD
362 ><P
363 >This argument specifies the type of device being instantiated, for
364 example <TT
365 CLASS="LITERAL"
366 >ethernet</TT
367 >. More specifically the I/O
368 auxiliary will append a <TT
369 CLASS="FILENAME"
370 >.tcl</TT
371 > suffix, giving
372 the name of a Tcl script that will handle all I/O requests for the
373 device. If the application requires several instances of a type
374 of device then the script will only be loaded once, but the script
375 will contain an instantiation procedure that will be called for each
376 device instance. 
377         </P
378 ></DD
379 ><DT
380 ><TT
381 CLASS="VARNAME"
382 >instance</TT
383 ></DT
384 ><DD
385 ><P
386 >If it is possible to have multiple instances of a device then this
387 argument identifies the particular instance, for example
388 <TT
389 CLASS="LITERAL"
390 >eth0</TT
391 > or <TT
392 CLASS="LITERAL"
393 >eth1</TT
394 >. Otherwise a NULL
395 pointer can be used.
396         </P
397 ></DD
398 ><DT
399 ><TT
400 CLASS="VARNAME"
401 >data</TT
402 ></DT
403 ><DD
404 ><P
405 >This argument can be used to pass additional initialization data from
406 eCos to the host-side support. This is useful for devices where eCos
407 configury must control certain aspects of the device, rather than
408 host-side configury such as the target definition file, because eCos
409 has compile-time dependencies on some or all of the relevant options.
410 An example might be an emulated frame buffer where eCos has been
411 statically configured for a particular screen size, orientation and
412 depth. There is no fixed format for this string, it will be
413 interpreted only by the device-specific host-side Tcl script. However
414 the string length should be limited to a couple of hundred bytes to
415 avoid possible buffer overflow problems.
416         </P
417 ></DD
418 ></DL
419 ></DIV
420 ><P
421 >Typical usage would look like:
422     </P
423 ><TABLE
424 BORDER="5"
425 BGCOLOR="#E0E0F0"
426 WIDTH="70%"
427 ><TR
428 ><TD
429 ><PRE
430 CLASS="PROGRAMLISTING"
431 >    if (!synth_auxiliary_running) {
432       return;
433     }
434     id = synth_auxiliary_instantiate("devs/eth/synth/ecosynth",
435              SYNTH_MAKESTRING(CYGPKG_DEVS_ETH_ECOSYNTH),
436              "ethernet",
437              "eth0",
438              (const char*) 0);</PRE
439 ></TD
440 ></TR
441 ></TABLE
442 ><P
443 >The return value will be a device identifier which can be used for
444 subsequent calls to <TT
445 CLASS="FUNCTION"
446 >synth_auxiliary_xchgmsg</TT
447 >. If
448 the device could not be instantiated then <TT
449 CLASS="LITERAL"
450 >-1</TT
451 > will
452 be returned. It is the responsibility of the host-side software to
453 issue suitable diagnostics explaining what went wrong, so normally the
454 target-side code should fail silently.
455     </P
456 ><P
457 >Once the desired device has been instantiated, often it will be
458 necessary to do some additional initialization by a message exchange.
459 For example an ethernet device might need information from the
460 host-side about the MAC address, the <A
461 HREF="synth-new-target.html#SYNTH-NEW-TARGET-INTERRUPTS"
462 >interrupt vector</A
463 >, and
464 whether or not multicasting is supported.
465     </P
466 ></DIV
467 ><DIV
468 CLASS="REFSECT1"
469 ><A
470 NAME="SYNTH-NEW-TARGET-XCHGMSG"
471 ></A
472 ><H2
473 >Communicating with a Device</H2
474 ><P
475 >Once a device has been instantiated it is possible to perform I/O by
476 sending messages to the appropriate Tcl script running inside the
477 auxiliary, and optionally getting back replies. I/O operations are
478 always initiated by the eCos target-side, it is not possible for the
479 host-side software to initiate data transfers. However the host-side
480 can raise interrupts, and the interrupt handler inside the target can
481 then exchange one or more messages with the host.
482     </P
483 ><P
484 >There is a single function to perform I/O operations,
485 <TT
486 CLASS="FUNCTION"
487 >synth_auxiliary_xchgmsg</TT
488 >. This takes the following
489 arguments: 
490     </P
491 ><P
492 ></P
493 ><DIV
494 CLASS="VARIABLELIST"
495 ><DL
496 ><DT
497 ><TT
498 CLASS="VARNAME"
499 >device_id</TT
500 ></DT
501 ><DD
502 ><P
503 >This should be one of the identifiers returned by a previous
504 call to <TT
505 CLASS="FUNCTION"
506 >synth_auxiliary_instantiate</TT
507 >, specifying the
508 particular device which should perform some I/O.
509          </P
510 ></DD
511 ><DT
512 ><TT
513 CLASS="VARNAME"
514 >request</TT
515 ></DT
516 ><DD
517 ><P
518 >Request are just signed 32-bit integers that identify the particular
519 I/O operation being requested. There is no fixed set of codes, instead
520 each type of device can define its own.
521          </P
522 ></DD
523 ><DT
524 ><TT
525 CLASS="VARNAME"
526 >arg1</TT
527 >, <TT
528 CLASS="VARNAME"
529 >arg2</TT
530 ></DT
531 ><DD
532 ><P
533 >For some requests it is convenient to pass one or two additional
534 parameters alongside the request code. For example an ethernet device
535 could define a multicast-all request, with <TT
536 CLASS="VARNAME"
537 >arg1</TT
538 >
539 controlling whether this mode should be enabled or disabled. Both
540 <TT
541 CLASS="VARNAME"
542 >arg1</TT
543 > and <TT
544 CLASS="VARNAME"
545 >arg2</TT
546 > should be signed
547 32-bit integers, and their values are interpreted only by the
548 device-specific Tcl script.
549          </P
550 ></DD
551 ><DT
552 ><TT
553 CLASS="VARNAME"
554 >txdata</TT
555 >, <TT
556 CLASS="VARNAME"
557 >txlen</TT
558 ></DT
559 ><DD
560 ><P
561 >Some I/O operations may involve sending additional data, for example
562 an ethernet packet. Alternatively a control operation may require many
563 more parameters than can easily be encoded in <TT
564 CLASS="VARNAME"
565 >arg1</TT
566 >
567 and <TT
568 CLASS="VARNAME"
569 >arg2</TT
570 >, so those parameters have to be placed in
571 a suitable buffer and extracted at the other end.
572 <TT
573 CLASS="VARNAME"
574 >txdata</TT
575 > is an arbitrary buffer of
576 <TT
577 CLASS="VARNAME"
578 >txlen</TT
579 > bytes that should be sent to the host-side.
580 There is no specific upper bound on the number of bytes that can be
581 sent, but usually it is a good idea to allocate the transmit buffer
582 statically and keep transfers down to at most several kilobytes.
583          </P
584 ></DD
585 ><DT
586 ><TT
587 CLASS="VARNAME"
588 >reply</TT
589 ></DT
590 ><DD
591 ><P
592 >If the host-side is expected to send a reply message then
593 <TT
594 CLASS="VARNAME"
595 >reply</TT
596 > should be a pointer to an integer variable
597 and will be updated with a reply code, a simple 32-bit integer. The
598 synthetic target HAL code assumes that the host-side and target-side
599 agree on the protocol being used: if the host-side will not send a
600 reply to this message then the <TT
601 CLASS="VARNAME"
602 >reply</TT
603 > argument
604 should be a NULL pointer; otherwise the host-side must always send
605 a reply code and the <TT
606 CLASS="VARNAME"
607 >reply</TT
608 > argument must be valid.
609          </P
610 ></DD
611 ><DT
612 ><TT
613 CLASS="VARNAME"
614 >rxdata</TT
615 >, <TT
616 CLASS="VARNAME"
617 >rxlen</TT
618 ></DT
619 ><DD
620 ><P
621 >Some operations may involve additional data coming from the host-side,
622 for example an incoming ethernet packet. <TT
623 CLASS="VARNAME"
624 >rxdata</TT
625 >
626 should be a suitably-sized buffer, and <TT
627 CLASS="VARNAME"
628 >rxlen</TT
629 > a
630 pointer to an integer variable that will end up containing the number
631 of bytes that were actually received. These arguments will only be
632 used if the host-side is expected to send a reply and hence the
633 <TT
634 CLASS="VARNAME"
635 >reply</TT
636 > argument was not NULL.
637          </P
638 ></DD
639 ><DT
640 ><TT
641 CLASS="VARNAME"
642 >max_rxlen</TT
643 ></DT
644 ><DD
645 ><P
646 >If a reply to this message is expected and that reply may involve
647 additional data, <TT
648 CLASS="VARNAME"
649 >max_rxlen</TT
650 > limits the size of that
651 reply. In other words, it corresponds to the size of the
652 <TT
653 CLASS="VARNAME"
654 >rxdata</TT
655 > buffer.
656          </P
657 ></DD
658 ></DL
659 ></DIV
660 ><P
661 >Most I/O operations involve only some of the arguments. For example
662 transmitting an ethernet packet would use the
663 <TT
664 CLASS="VARNAME"
665 >request</TT
666 >, <TT
667 CLASS="VARNAME"
668 >txdata</TT
669 > and
670 <TT
671 CLASS="VARNAME"
672 >txlen</TT
673 > fields (in addition to
674 <TT
675 CLASS="VARNAME"
676 >device_id</TT
677 > which is always required), but would not
678 involve <TT
679 CLASS="VARNAME"
680 >arg1</TT
681 > or <TT
682 CLASS="VARNAME"
683 >arg2</TT
684 > and no
685 reply would be expected. Receiving an ethernet packet would involve
686 <TT
687 CLASS="VARNAME"
688 >request</TT
689 >, <TT
690 CLASS="VARNAME"
691 >rxdata</TT
692 >,
693 <TT
694 CLASS="VARNAME"
695 >rxlen</TT
696 > and <TT
697 CLASS="VARNAME"
698 >max_rxlen</TT
699 >; in addition
700 <TT
701 CLASS="VARNAME"
702 >reply</TT
703 > is needed to get any reply from the host-side
704 at all, and could be used to indicate whether or not any more packets
705 are buffered up. A control operation such as enabling multicast mode
706 would involve <TT
707 CLASS="VARNAME"
708 >request</TT
709 > and <TT
710 CLASS="VARNAME"
711 >arg1</TT
712 >,
713 but none of the remaining arguments.
714     </P
715 ></DIV
716 ><DIV
717 CLASS="REFSECT1"
718 ><A
719 NAME="SYNTH-NEW-TARGET-INTERRUPTS"
720 ></A
721 ><H2
722 >Interrupt Handling</H2
723 ><P
724 >Interrupt handling in the synthetic target is much the same as on a
725 real target. An interrupt object is created using
726 <TT
727 CLASS="FUNCTION"
728 >cyg_drv_interrupt_create</TT
729 >, attached, and unmasked.
730 The emulated device - in other words the Tcl script running inside the
731 I/O auxiliary - can raise an interrupt. Subject to interrupts being
732 disabled and the appropriate vector being masked, the system will
733 invoke the specified ISR function. The synthetic target HAL
734 implementation does have some limitations: there is no support for
735 nested interrupts, interrupt priorities, or a separate interrupt
736 stack. Supporting those might be appropriate when targetting a
737 simulator that attempts to model real hardware accurately, but not for
738 the simple emulation provided by the synthetic target.
739     </P
740 ><P
741 >Of course the actual implementation of the ISR and DSR functions will
742 be rather different for a synthetic target device driver. For real
743 hardware the device driver will interact with the device by reading
744 and writing device registers, managing DMA engines, and the like. A
745 synthetic target driver will instead call
746 <TT
747 CLASS="FUNCTION"
748 >synth_auxiliary_xchgmsg</TT
749 > to perform the I/O
750 operations.
751     </P
752 ><P
753 >There is one other significant difference between interrupt handling
754 on the synthetic target and on real hardware. Usually the eCos code
755 will know which interrupt vectors are used for which devices. That
756 information is fixed when the target hardware is designed. With the
757 synthetic target interrupt vectors are assigned to devices on the host
758 side, either via the target definition file or dynamically when the
759 device is instantiated. Therefore the initialization code for a
760 target-side device driver will need to request interrupt vector
761 information from the host-side, via a message exchange. Such interrupt
762 vectors will be in the range 1 to 31 inclusive, with interrupt 0 being
763 reserved for the real-time clock.
764     </P
765 ></DIV
766 ><DIV
767 CLASS="NAVFOOTER"
768 ><HR
769 ALIGN="LEFT"
770 WIDTH="100%"><TABLE
771 SUMMARY="Footer navigation table"
772 WIDTH="100%"
773 BORDER="0"
774 CELLPADDING="0"
775 CELLSPACING="0"
776 ><TR
777 ><TD
778 WIDTH="33%"
779 ALIGN="left"
780 VALIGN="top"
781 ><A
782 HREF="synth-syscalls.html"
783 ACCESSKEY="P"
784 >Prev</A
785 ></TD
786 ><TD
787 WIDTH="34%"
788 ALIGN="center"
789 VALIGN="top"
790 ><A
791 HREF="ecos-ref.html"
792 ACCESSKEY="H"
793 >Home</A
794 ></TD
795 ><TD
796 WIDTH="33%"
797 ALIGN="right"
798 VALIGN="top"
799 ><A
800 HREF="synth-new-host.html"
801 ACCESSKEY="N"
802 >Next</A
803 ></TD
804 ></TR
805 ><TR
806 ><TD
807 WIDTH="33%"
808 ALIGN="left"
809 VALIGN="top"
810 >System Calls</TD
811 ><TD
812 WIDTH="34%"
813 ALIGN="center"
814 VALIGN="top"
815 ><A
816 HREF="hal-synth-arch.html"
817 ACCESSKEY="U"
818 >Up</A
819 ></TD
820 ><TD
821 WIDTH="33%"
822 ALIGN="right"
823 VALIGN="top"
824 >Writing New Devices - host</TD
825 ></TR
826 ></TABLE
827 ></DIV
828 ></BODY
829 ></HTML
830 >