\begin{new}{6.8.1997}
\chapter{Hardware Independend Device Driver - HIDD}

\section{Introduction}

The AmigaOS is built on the Amigas' custom chips. This is a fact which is
eventually discovered when you hit the rather tight limits they impose
and try to circumvent them by adding new hardware. For the new hardware,
you also need a device driver. But sometimes, the applications can't be
made to use this new driver because the old one is compiled in or, even
worse, the OS refuses to use anything besides the built in driver or,
even more worse, the OS doesn't use a driver to access this chip at all.

AROS was designed to be a portable OS and be compatible to the old AmigaOS.
But we had to design something which lessens these burdens without
becoming incompatible nor loosing too much speed. So we developed the
idea of the HIDD - the Hardware Independend Device Driver.

\section{Features}

HIDDs offer a consistent API for everything one could want to do with
a device. Here is a quick overview:

\begin{itemize}
\item Query the system for all available HIDDs or only for certain types
(eg. all serial HIDDs or all graphics HIDDs).
\item Configure a HIDD
\item Use a HIDD
\end{itemize}

The complete life cycle of a HIDD is like this:

\begin{enumeration}
\item The OS boots. HIDDs on external cards and in the ROM get installed by
the OS in the global list of all available HIDDs. Also the OS searches for
HIDDs installed on the harddisk.

\item The OS reads the extended romtags from all HIDDs and puts that
information in the global list of all available HIDDs.

\item Some application asks for a list with the informations about
all HIDDs or a specific type of HIDD.

\item The application loads the HIDD and the config plugin.
This makes the HIDD initialize some internal data structures but
not always the hardware. A HIDD might be the driver for several kinds
of different hardwares which are all available.

\item The application asks for the current config of the HIDD. If the
config plugin has its own GUI, the application displays it. Otherwise,
the application displays the information in an own window. For this,
the application queries the config plugin for all available modes.

\item Whenever the user changes something in the applications window,
the application changes the HIDD and queries the config plugin for
the current config plus the new list of available modes. This allows
to have modes where certain other modes are not available (eg.
24bit depth with more than 800x600).

\item When the user presses ok, the application or config plugin closes
the window/GUI. The Ok or Apply button must be ghosted as long as
the HIDD says that the configuration is not ok. The application can
now expunge the config plugin. If a HIDD supports saving its config,
it must do so.

\item When the device is explicitly activated or used for the first time
(eg. data is written to it), it will use the configuration to initialize
the hardware.

\item The user can deactivate the device and change the config if the
HIDD permits that.

\end{enumeration}

\section{The HIDD Support API}

\begin{code}
/* Get a list with pointers to HIDD devices */
ULONG HIDD_FindHIDD (struct TagItem *, Class ** hiddArray);
\end{code}

You can then use the HIDD API to query the devices for their infos. Use
|FreeVec()| to dispose the array. |HIDDV_FindHIDD_All| as type gives
the complete list of all known HIDDs.

\section{The HIDD API}

HIDDs are BOOPSI objects which support the Exec Device API.

\begin{methods}
\item{LONG OM_SET (struct TagItem * AttrList)}
Change some attributes of a HIDD.

The return type is device specific but should be 0 in case of success
and non-zero in case of an error. A good practice is either to return
an error code or the number of an offending tag in the taglist.

\item{LONG OM_GET (Tag AttrID, IPTR * Storage)} Query a single attribute
from the HIDD in general (eg. its name and version) and the current status.
You can only query attributes which are gettable.

The return type is device specific but should be 0 in case of success
and non-zero in case of an error.

\item{LONG OM_MGET (struct TagItem * AttrList)} Query a single attribute
from the HIDD in general (eg. its name and version) and the current status.
You can only query attributes which are gettable. The |ti_Data| fields of
|AttrList| must be pointers of the type which is expected for the
respective attribute.

The return type is device specific but should be 0 in case of success
and non-zero in case of an error. A good practice is either to return
an error code or the number of an offending tag in the taglist.

\item{LONG HIDDM_BeginIO (struct IORequest *)} Initiate a device operation.
See the Exec Device API for details.

\item{LONG HIDDM_AbortIO (struct IORequest *)} Abort a running device
operation. See the Exec Device API for details.

\item{HIDDT_Config HIDDM_LoadConfigPlugin (APTR PluginData)}
Tells the HIDD to load its configuration plugin. This method returns
a pointer to the plugin. |PluginData| is a pointer with plugin
specific data. For details, look into the manual for the HIDD.

\end{methods}

\section{The HIDD Config Plugin API}

\begin{methods}
\item{LONG OM_SET (struct TagItem * AttrList)}
Change some attributes of a HIDD Config Plugin (HIDD CP).

The return type is device specific but should be 0 in case of success
and non-zero in case of an error. A good practice is either to return
an error code or the number of an offending tag in the taglist.

Note that changing attributes changes only the HIDD CP, never the HIDD
itself. When the HIDD CP tells you that the current config works, then
you can copy the config to the HIDD.

\item{LONG OM_GET (Tag AttrID, IPTR * Storage)} Query a single attribute
from the HIDD CP. You can only query attributes which are gettable.

The return type is HIDD CP specific but should be 0 in case of success
and non-zero in case of an error.

\item{LONG OM_MGET (struct TagItem * AttrList)} Query a single attribute
from the HIDD CP. You can only query attributes which are gettable. The
|ti_Data| fields of |AttrList| must be pointers of the type which is
expected for the respective attribute.

The return type is HIDD CP specific but should be 0 in case of success
and non-zero in case of an error. A good practice is either to return
an error code or the number of an offending tag in the taglist.

\item{void HIDDM_QueryConfig (struct TagItem ** AttrList)}
Ask the HIDD CP for the current configuration of the HIDD. The AttrList
should be built in such a way that one can go back to the current config by
either loading the device for the first time or disabling it and use
|OM_SET| with this AttrList. Some applications will save this list to a
file and load it again later to configure the HIDD.

\item{void HIDDM_FreeConfig (struct TagItem * AttrList)}
Dispose the list of attributes which you got by |HIDDM_QueryConfig()|.

\item{ULONG HIDDM_QueryModes (struct TagItem ** tagList)}
Ask the HIDD CP about the currently available modes.

The taglist consists of tags which have the types |BOOL|,
|HIDDT_Limit| (a min and max value), |HIDDT_List| (a list with
string/value pairs or one-of-many selection) or |HIDDT_OptionList| (same as
|HIDDT_List| but for some-of-many selection. The result is
passed as a bitfield).

HIDD CPs which supply their own GUI don't need to support this
tag (but most will because you need something like this internally
anyway).

\item{ULONG HIDDM_Apply (void)} Apply the current config to the HIDD.
If you dispose the HIDD CP, then all changes will be lost.

\item{STRPTR HIDDM_ValueToString (Tag tag, IPTR value)} Convert the
value |value| for the tag |tag| into a human readable string.
The string returned must not be written to or be freed.

HIDD CPs which supply their own GUI don't need to support this
tag (but most will because you need something like this internally
anyway).

The application will use this value to generate the visual feedback
in its GUI.

\item{IPTR HIDDM_StringToValue (Tag tag, STRPTR string)} Convert
the string |string| for the tag |tag| back into a value.

HIDD CPs which supply their own GUI don't need to support this
tag (but most will because you need something like this internally
anyway).

Also note that a HIDD can ask that you return exactly the string
which was passed to you by |HIDDM_ValueToString()| (ie. the
string must have the same address).

\item{STRPTR HIDDM_GetTagName (Tag tag)} Return a human readble string
with the name for a tag. For example a serial HIDD with the
tag |HIDDV_Serial_Baudrate| might return |"Baud rate"|. The
application will use this to generate its GUI.

\end{methods}

\subsection{Common tags for all HIDDs}

\begin{taglist}
\item{HIDDA_Type,ULONG,G} This is the basic type of the HIDD (eg. serial, parallel,
graphics).

\item{HIDDA_SubType,ULONG,G} This is a more specific type. If |HIDDA_Type| is
|HIDDV_Type_Serial|, then this is a bitfield with one or more bits
of |HIDDV_Type_Serial_RS232| or |HIDDV_Type_Serial_RS488| set.

\item{HIDDA_Producer,ULONG,G} The ID of the producer as handed out by Amiga
International.

\item{HIDDA_Name,STRPTR,G} The name of this device (eg. serial.device).

\item{HIDDA_HardwareName,STRPTR,G} The name of the hardware
(eg. "Builtin Serial Port", "COM1", "CyberVision/3D", etc.). Note that
you must initialize some HIDDs before you can query this attribute
because some HIDDs work with more than one type of hardware.

\item{HIDDA_Active,BOOL,ISG} Tells if the device is active or
(de-)actives it when set.

\item{HIDDA_Status,ULONG,G} The current status of a HIDD. This is a
set of bits which show if the init of the hardware was successful,
if the device is active or if the device is ready to be activated.

\end{taglist}

\subsection{Tags for some HIDDs}

\begin{taglist}
\item{HIDDA_Shared,ULONG,ISG} Allow to share a HIDD with other
applications or lock it for single use. This might be used
in a sound HIDD or a serial HIDD or a graphics HIDD.

Values for |HIDDA_Shared| are:

\begin{description}
\item{|HIDDV_Shared_Exclusive|} Try to get the HIDD exclusively.
If someone else has locked the HIDD exclusive or shared already,
this will fail.

\item{|HIDDV_Shared_Shared|} Try to share the HIDD with other
apps. This will fail if someone else has already locked the
HIDD exclusively.

\item{|HIDDV_Shared_NonExclusive|} Use this mode if it doesn't
matter if you can't get it. This might be used for apps which
want to play sounds in the background when someone inserts a disk
into the drive or similar.

\item{|HIDDV_Shared_NotAvailable|} This can only read back. If the
attribute contains this value, the HIDD doesn't support sharing.

\end{description}

\end{taglist}

\section{Sample HIDDs}

\subsection{Serial HIDD}

The type of a serial HIDD is |HIDDV_Type_Serial| and the names
for serial specific things is prefixed with |HIDD?_Serial_|.

Subtypes of serial HIDDs are |HIDDV_RS232| and |HIDDV_RS488|, for
example.

\begin{taglist}
\item{HIDDA_Serial_BaudRate,ULONG,ISG} The baud rate in baud (bits
per second) or a logical baudrate (1: 300baud, 2: 600baud,
3: 1200baud, 4: 2400baud, 5: 4800, 6: 9600, 7: 19200, 8: 38400,
9: 57600, 10: 64000, 11: 76800, 12: 112000(?), 13: 200kbaud,
14: 400kbaud, 15: 1Mbaud, 16: 2MBaud, 17: 4MBaud, 18: 10MBaud,
19: 20MBaud, 20: 40MBaud, 21: 100MBaud, etc).

\item{HIDDA_Serial_DataLength,ULONG,ISG} The number of data bits. Most
HIDDs support only 7 or 8 bits but you should expect at least anything
between 5 and 8.

\item{HIDDA_Serial_StopBits,ULONG,ISG} The number of stopbits between
two data bytes multiplied by 16 (ie. one stopbit is 16, one and a half
would be 24 and two stopbits is 32).

\end{taglist}

\subsection{Sound HIDD}

Okay, here are some examples, how a sound.hidd could be implemented on
different hardware-bases. This is how the class would behave, if a method
HIDDM_SendMIDI was sent (I don't know, if such a method would make sense,
but it's only for illustration issues).

Amiga with internal sound (subclass of hiddclass):

There are two possibilities, how to handle it. The first is, not to handle
it, so that the method is passes on to the hiddclass (which doesn't know
this method either) and then on to the rootclass, which returns 0 (FALSE)
on unknown methods. The second possibility is to implement it in
soundhiddclass and return FALSE immediatly (because we know that the
internal Amiga soundsystem can't handle MIDI).

Amiga with sound-card on zorro-bus (subclass of zorroclass):

The sound-card passes all methods through to its superclass, except methods
for playing/receiving/whatever music. It can either implement them totally
on its own or might use some features of its superclass, for example a
general method for sending data to a zorro-card.

Amiga with internal sound or soundcard and additional MIDI-card:

This configuration would have two HIDDs, one for MIDI only and one for
sound in general. For the implementation of the last one see above (either
Amiga with internal sound or Amiga with sound-card). The MIDI HIDD-class
could subclass the general sound class (without knowing, if it is capable
of playing MIDI) and pass on all methods except MIDI relevant methods. It
would fully overload these. Another solution would be to subclass hiddclass
directly and ignore every non-MIDI sound command. While the general class
would be unit 0, the MIDI class would be unit 1, so that an application can
choose between the normal sound-system (either the internal Amiga
soundsystem or a sound-card, which might have MIDI capabilities on its own)
or the MIDI card. If the MIDI class would subclass the normal soundhidd, it
would feature non-MIDI sound, too (by passing the methods on). Of course,
it had to pass a query to a HIDDA_Capabilities attribute on to the
superclass, so that the capabilities of the superclass can be recognized by
the application for unit 1, too.

PC with soundblaster-super-ultra-pro-whatever:

This HIDD could(!) subclass a class, which handles soundblaster-cards in
general, i.e. the functions that are common to all soundblaster-card (which
itself could subclass something like a pcbusclass). Normally this class
would pass all methods on to its superclass, but it could implement some
methods on its own or partly overload some methods, where this specific
soundblaster-card had advantages/different features than the other
soundblaster-cards.

o Some thoughts about the sound.hidd:

  o An attribute HIDDA_Capabilities [..G], which could define things like:
    o HIDDV_Sound_MIDI - sound-system is able to play MIDI sounds (possibly by
      using an external MIDI device, such as a keyboard)
    o HIDDV_Sound_SFX - sound-system is capable of playing simple sounds (e.g.
      the internal pc-speaker)
    o HIDDV_Sound_Music
    o HIDDV_Sound_Speech

  o An attribute HIDDA_Sound_Shared [IS.], which could take the following
    values:
    o HIDDV_Sound_NonExclusiveLocked - allow other application to make
      instances (i.e. objects) of the same sound-unit
    o HIDDV_Sound_NonExclusiveNotLocked - as above, but allow the
      sound-system to temporarily disable access to the unit for that
      application. This happens, if another application wants to overtake
      the sound-system in an exclusive mode. This mode makes sense if an
      application wants to play sound-effects of an informational
      character, which are not important for program execution

    o HIDDV_Sound_Exclusive - May be used, if an application wants to play
      music, which shouldn't be disturbed by sound-effects. Of course it's
      no problem to access other sound-units/-devices, while one is locked
      exclusively.

  o Possibly attributes HIDDA_Sound_ActivateHook, ..._InactivateHook [ISG]
    These attributes could be used by an application to provide hooks, which
    are called, if a not-locked unit is exclusively locked by another
    application (or this exclusive lock is freed). So these attributes
    makes only sense with HIDDV_Sound_NonExclusiveNotLocked.

\section{Internals}

A HIDD is a normal Exec Device which creates a BOOPSI class when
loaded. A HIDD is recognised by the name in the ROMtag structure.
This name must begin with the four letters "HIDD" (in that order).
Note that the name of the HIDD is the string after the first four
letters. Also note that a HIDD need not have a unique name.

Every HIDD has an extended ROMtag structure which contains the
infos needed to find a HIDD by |HIDD_FindHIDD()|.

HIDDs are BOOPSI objects but unlike other BOOPSI objects, they
are not created by classname but by the pointer returned by
|HIDD_FindHIDD()|.

\section{Random unsorted ideas}

\end{new}

