Author: | Aaron Digulla |
---|---|
Copyright: | Copyright © 2001, The AROS Development Team |
Version: | 45860 |
Date: | 2012-10-04 |
Note
This document is currently only a draft and as such will most likely change before it is accepted as an official specification. It might also be deprecated if a better approach has been found in the mean time, and doesn't necessarily correspond precisely with the current implementations.
A HIDD is a Hardware Independent Device Driver - a collection of code that provides an interface to hardware that hides as many details of the hardware as practical. Most applications do not need to know all the details of the device they use, they simply want to get on with using the device.
As we are implementing the Amiga Operation System we still want to support the existing software that runs on this platform. This means that we need to also provide an interface to the Exec style devices.
With this in mind, the design goals of the HIDD system are:
To implement the code and interface reuse design goal we have implemented our drivers in an object-oriented fashion, providing single inheritance but multiple interfaces (similar to the Java language). The inheritance hierarchy allows us to start with a basic driver, and enhance this by adding more levels of device dependence until we come to a driver for a specific device.
To provide a method of dynamic driver-functionality the driver objects are arranged in a tree that shows their connection mechanism. For example, a PCI-based Ethernet card is connected to a PCI bus, so the Ethernet card driver is a child of the PCI bus. Similar an IDE hard disk is normally connected to an IDE controller - so the disk will be a child of the IDE controller.
Note
This does not mean that the Ethernet card driver is a subclass of the bus driver. Only the dynamic behaviour of the drivers is subject to the connection-oriented approach.
A few concepts are hidden in all the above. To begin with, knowledge of object-oriented programming is assumed for this document, as is a basic understand of device drivers. This manual is not designed to teach either object-oriented programming or device driver programming - both of these come only from experience. I hope that this manual will help however - I am learning as I write it.
Throughout this manual a few terms will be used frequently and often interchangeably, hopefully for the few times that I miss these in editing I shall try and clarify them here.
The first two are class and device. The device is the physical implementation of the hardware we are controlling, and the class is the code that is controlling that hardware. You normally only have one class for each device, although some devices may provide multiple functions. In that case you would need to provide multiple classes for the different functions.
The second two are object and driver. The object is an instantiated class and this is the driver for the device. There can be a number of drivers for the same device, but they must all control separate devices. There will be one instantiated driver for every class of device that exists in the system.
The HIDD system embodies a collection of object classes and a shared library providing device driver facilities to the AROS operating system. This chapter describes the operating model of the classes and objects.
It consists of the following sections
The HIDD system is broken up into a collection of classes with a strict inheritance hierarchy. A HIDD class implements a device driver for a single device or in rare cases a group of devices and provides an interface for other programs and devices to access.
In order to maintain portability of interfaces across a wide range of hardware this interface will in general not present the raw interface to the underlying hardware. Instead it will present a generic interface that describes many different hardware implementations. This allows for the best reuse of both interfaces and code.
This reuse is enforced by the hierarchy of classes with common device functions restricted to a subsection of the hierarchy. An example of this is disk devices. There are three common disk interfaces available today - SCSI, IDE and floppy. All these devices provide similar functions such as the ability to read and write blocks, and determine the geometry of the disk.
Whilst the implementations of these devices may change, the interface does not. A file system needs to talk to a disk-like device, but it does not care what the underlying hardware supports -- it only requires the interface. This idea forms the first part of the hierarchy structure - and from where the name HIDD comes. These interfaces provide a hardware independent method of access devices.
<!-- img src="hidd-model-class-1.png" alt="HIDD Class Tree Structure" /-->
hidd +- disk | +- floppy | +- ide | +- ram | +- scsi | +- virtual +- graphics +- parallel +- serial
If we examine the tree structure above we can see that the class tree starts with the hidd class. This is the base class that all HIDD classes inherit from. It provides many useful facilities dealing with initialisation and interaction of HIDDs. A complete discussion of this class is found in the HIDD Class chapter.
Below this there are a number of different classes, each providing a different type of functionality. At the moment the diagram only shows the hidd.disk tree. This contains five entries -- all detailing slightly different kinds of devices. The hidd.disk.virtual is a virtual disk device which provides the ability to address a file as is it were a real device. Similarly the hidd.disk.ram provides access to a fixed size virtual RAM disk.
The hidd.disk.floppy provides access to the normal floppy disk controller. The hidd.disk.ide and hidd.disk.scsi provide access to common hard disk drive implementations.
XXX - Where do CD-ROM's and the like fit in? They are like disk devices, but have some other features that make them different. The Amiga device structure had them as a disk device but with an extra interface. I think that this is probably the way to go. But then you have to differentiate from IDE CD-ROMs, SCSI CD-ROMs and the like. In which case you would use hidd.cdrom... but then you have two different interfaces on the same level declaring the same functionality? Does this mean we actually need another level? I hope not. An alternative would be to hidd.disk.cdrom.whatever to emphasise that CD-ROMs are like disk devices, but with a few extra functions?
To complicate matters however the above is only half the story. There is another half of the tree that have different semantics -- providing access to the raw hardware. An example of this type of class would be a SCSI controller -- something that is not always accessed by user programs.
There are however a number of different SCSI controllers available, so there is more specialisation of classes here.
<!-- img src="hidd-model-class-2.png" alt="HIDD Class Tree Structure" /-->
hidd +- disk +- graphics +- parallel +- scsi | +- ... +- serial
The above picture adds more devices into the class hierarchy. We see now that there is a hidd.scsi subtree containing a number of different SCSI controllers. In this case the hidd.scsi layer provides an interface to the functions that a SCSI bus provides, and the hidd.scsi.#? classes provide the implementation for a specific SCSI controller.
This is still not where the story ends. These SCSI controllers may have different ways of interfacing with the computer, and may even have different controllers for different hardware platforms. This introduces another layer of the tree structure.
<!--img src="hidd-model-class-3.png" alt="XXX" /-->
hidd +- disk | +- ... | +- scsi | +- ... +- graphics +- parallel +- scsi | +- aha | +- cont | +- isa | +- pci | +- zorroii +- serial
We now see that there are more classes with hidd.scsi.aha as the parent. These provide different versions of the SCSI controller. We can see in the example above that there are three extra classes: hidd.scsi.cont.isa, hidd.scsi.cont.pci, and hidd.scsi.cont.zorroii. These allow us to interface to the controller no matter what form of hardware platform we are using.
hidd.scsi.cont.pci access the controller through a PCI interface -- possibly using memory-mapped IO. hidd.scsi.cont.isa access the device through the ISA bus -- using inb() and outb() style instructions. Finally the hidd.scsi.cont.zorroii device may access the device through the Zorro-II bus, or in some cases it may only act as an interface to the ROM-based Exec device.
The class model as described previously allows the definition of classes providing some degree of abstraction between types of devices (for example disk devices) and the implementation of those devices (disk controllers). It does not however address the problem of connecting the two distinct classes.
Most computer systems have some degree of flexibility about device connections -- you can add, move, or remove devices. This possibility allows for device connectivity to change (from the operating system point of view) every time the operating system starts. This coupled with the dynamic nature of plug-and-play hardware resource allocation, requires a dynamic connection model.
The HIDD system provides this by describing the connections at the object level. This has two advantages: you can easily reconfigure the connections at any time -- without having to restart the system in many cases, and it allows classes to be reused easily to support multiple instances of the same device.
The interconnection model used could be loosely described as being a bus model. All devices are connected to the object that could be considered to be their parent in the hardware of the system.
Take the example of a SCSI disk again. The SCSI disk is connected to a SCSI controller (optionally one of many). This SCSI controller is connected to some kind of bus -- for example PCI. Finally the PCI bus is connected to some central point of the system that is the parent of all available devices. This is shown more clearly in a diagram.
<!-- img src="hidd-model-obj-1.png" alt="Connection of SCSI disk" /-->
hidd +- disk | +- ... | +- scsi | +- ... +- ... +- scsi | + aha | + cont | +- isa | +- pci | +- zorroii +- ...
It is important here to realise that the connection diagram shown above does not have anything to do with class hierarchies. If we provide a slightly different version of the diagram showing class names this should become clearer.
This is arguably the most important thing to remember when discussing this topic.
The benefits of this connection model are numerous, providing:
A HIDD driver can exist in different states throughout the life of the operating system. The following section describes all the states known about by the root HIDD class.
All HIDD drivers start in the unknown state. This is the state of a driver when it has either just been loaded into memory, or when it is inside the kernel, but before it is first initialised.
At this point the driver cannot tell whether the hardware it is tied to exist, and cannot access the device. There will have been no objects created for this driver yet.
From the unloaded state, the only allowed next state is the probed state.
The probed state is entered after the driver has checked whether the device exists. Normally a driver will only be in this state when the device exists, however kernel-based drivers that cannot be unloaded will also be in this state.
Note that the driver still has not allocated any resources and there have been no instances of this driver created. It is possible for the driver to be unloaded from memory in this state, but only under low memory conditions.
This can only be reached from the ready state, but signifies that there are instances of the driver created and in use by either a user program or another driver. In this state the driver will not be unloaded from memory, even under low memory conditions.
The opened state does not consider the number of instances that have been created of this driver.
When a removable device has been removed, the driver enters the remove state. Note that this does not apply to removable media such as floppy disks, but rather removable devices such as PCMCIA cards and USB devices.
This state is not normally used by many drivers, however it is available for those drivers that may require it.
Note
This is a preliminary document. It's neither complete nor correct. It's purpose is to offer a basis for discussion not to put things into concrete.
The AmigaOS is built on the Amiga's 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 or loosing too much speed. So we developed the idea of the HIDD - the Hardware Independent Device Driver.
HIDDs offer a consistent API for everything one could want to do with a device. Here is a quick overview:
The complete life cycle of a HIDD is like this:
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.
HIDDs are BOOPSI objects which support the Exec Device API.
Change some attributes of a HIDD.
The return code is 0 in case of success or != 0 in case of an error. If the return code is > 0, then it's the number of the offending tag in the list, if it's < 0, then it's an error code. You can use HIDDM_ValueToString() with the special tag HIDDA_ErrorCode to convert this error code into a string.
Query a single attribute from the HIDD in general (e.g. its name and version) and the current status. You can only query attributes which are gettable.
The return code is 0 in case of success or < 0 in case of an error. You can use HIDDM_ValueToString() with the special tag HIDDA_ErrorCode to convert the error code into a string.
Query one or more attributes from the HIDD in general (e.g. 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 code is 0 in case of success or != 0 in case of an error. If the return code is > 0, then it's the number of the offending tag in the list, if it's < 0, then it's an error code. You can use HIDDM_ValueToString() with the special tag HIDDA_ErrorCode to convert this error code into a string.
Change some attributes of a HIDD Config Plugin (HIDD CP).
The return code is 0 in case of success or != 0 in case of an error. If the return code is > 0, then it's the number of the offending tag in the list, if it's < 0, then it's an error code. You can use HIDDM_ValueToString() with the special tag HIDDA_ErrorCode to convert this error code into a string.
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.
Query a single attribute from the HIDD CP. You can only query attributes which are gettable.
The return code is 0 in case of success or < 0 in case of an error. You can use HIDDM_ValueToString() with the special tag HIDDA_ErrorCode to convert the error code into a string.
Query one or more attributes 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 code is 0 in case of success or != 0 in case of an error. If the return code is > 0, then it's the number of the offending tag in the list, if it's < 0, then it's an error code. You can use HIDDM_ValueToString() with the special tag HIDDA_ErrorCode to convert this error code into a string.
Ask the HIDD CP about its current configuration. The AttrList should be built in such a way that one can go back to the current config by loading the device for the first time and use OM_SET with this AttrList or by disabling it and use OM_SET. A typical use of this will be to save this list to a file and load it next time when one needs to configure the HIDD.
The current configuration of the HIDD CP is a copy of the HIDDs current configuration when the HIDD CP is created. Then you can change it and the HIDD CP will act as if the HIDD itself had changed. When you are done, you can apply the changes to the HIDD itself (aka OK or Apply) or just forget about them (aka Cancel).
Tip
If you write a HIDD, then you can use the power of BOOPSI and TagItem lists to create this list. Pass this method to the superclass first and then attach your local taglist with TAG_MORE. Or you can filter the taglist of the superclass and build your own taglist (and dispose the taglist of the superclass by HIDDM_FreeConfig()).
Ask the HIDD CP about the currently available modes.
The taglist consists of tags which have the types BOOL, HIDDT_Limit (a minimum and maximum 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).
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 something like this is needed internally anyway).
The application will use this value to generate the visual feedback in its GUI.
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 something like this is needed internally anyway).
Also note that a HIDD can ask that you return exactly the string which was passed to you by HIDDM_ValueToString() (i.e. the string must have the same address).
In case of an error, you can ask for the error code and use this code in HIDDM_ValueToString() to get a string with the meaning of the error. This is mostly used when the HIDD tells you that it doesn't like a certain tag in a taglist. When this happens, you can query this code to find out what the HIDD doesn't like about the tag.
Note that you can supply this tag when you try to create or change attributes of a HIDD. If you do this, you must still pass a pointer to LONG to NewObject() or SetAttrs(). In case of an error, it will be filled with the error code.
Tells which kinds of locking the HIDD supports. Can be read from the class and from an existing HIDD. The possible values are:
Try to get access to the HIDD if you opened it in shared mode. The values for mode are HIDDV_Lock_Exclusive and HIDDV_Lock_Shared. You can add the flag HIDDV_Lock_Try. HIDDV_Lock_Exclusive means that you want the HIDD for your own. If someone else has a lock on the HIDD, this will block unless HIDDV_Lock_Try is set. HIDDV_Lock_Shared will only block if no exclusive locks exist and HIDDV_Lock_Try is not set.
If HIDDV_Lock_Try is not set, this will block until the HIDD can be locked as you wish.
The method will return FALSE if the lock could not be established. It will return something else if the lock could be established.
Note that some HIDDs don't support locking. Use HIDDM_Class_Get() to find out which do and which don't at runtime and read the documentation for the HIDDs.
The alarm HIDD allows to call a hook after a certain time.
The type of an alarm HIDD is HIDDV_Type_Alarm and the names for alarm-specific things are prefixed with HIDD?_Alarm_.
Subtypes of this HIDD are HIDDV_Type_Alarm_VB (vertical blank interrupt), and HIDDV_Type_Alarm_Real (real time clock).
This kind of HIDD cannot be shared. If you try to create a second alarm HIDD of a specific class, you will get the error HIDDV_Error_UniqueObject. If you need shared access to this HIDD, use the timer.hidd.
Ticks are the smallest interval an alarm HIDD can provide. This tells how long n ticks would last in real life.
Type: | struct tv * |
---|---|
Applicability: | ISG |
This is the time for the next alarm. This implies single shot mode. The hook is called only once. The time is specified as absolute system time.
Type: | struct tv * |
---|---|
Applicability: | ISG |
This is the time for the next alarm. This implies repeat mode. The hook is called every time after interval has elapsed.
Type: | BOOL |
---|---|
Applicability: | SG |
(De-)Activate this alarm HIDD. When created, the alarm hidd is always inactive.
Type: | ULONG |
---|---|
Applicability: | G |
This is a tag of the class. It contains the unit number you must pass to the timer.hidd if you want to access this alarm 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_Type_Serial_RS232 and HIDDV_Type_Serial_RS488, for example.
Type: | ULONG |
---|---|
Applicability: | ISG |
The bits per second or a logical BPS rate (300baud, 600baud, 1200, 2400, 4800, 9600, 19200, 31500 (MIDI), 38400, etc.) The logical BPS rates have the bit 31 set.
When you query the list of available modes, you will get an HIDDT_Limit for this attribute. If the limits have bit 31 set, the device supports only fixed BPS rates. If the limits don't have this bit set, this means that the device supports variable BPS rates. If you use a logical BPS rate, you must make sure that you don't exceed the limits. For example, some device might support any BPS rate between 5000bps and 100000bps. This means that only the logical BPS rates between 9600 and 74k (including both) are available.
Also note that a HIDD might not support every BPS rate in the range. There might be arbitrary steps, so you must set the BPS rate and then read it back to see what the HIDD can do. The HIDD should always select a BPS rate which is next to the one the user wants.
Type: | ULONG |
---|---|
Applicability: | 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.
Type: | ULONG |
---|---|
Applicability: | ISG |
The number of stopbits between two data bytes multiplied by 16 (i.e. one stopbit is 16, one and a half would be 24 and two stopbits is 32).
Type: | ULONG |
---|---|
Applicability: | ISG |
If the Keyboard HIDD can work with more than one type of keyboard, you can specify the type here or if the HIDD can figure the type of keyboard itself, it can offer the type here. If the HIDD doesn't support this, this value is 0 and can't be changed by setting it. The method HIDDM_QueryModes() should return a type HIDDT_Limit with minimum and maximum both 0.
Type: | struct MsgPort * |
---|---|
Applicability: | ISG |
When the user presses a key, the HIDD should report this by sending a HIDDT_Keyboard_Event message to this port. The message looks like this:
typedef struct { struct Message ke_Message; ULONG ke_Key[1]; } HIDDT_Keyboard_Event;
ke_Key[] contains the X11 code for the key. See /usr/include/X11/keysymdef.h for available keycodes. If the key has been pressed, bit 31 will be set. If the key has been released, bit 31 will be cleared.
If the user pressed more then one key, the other keys are in ke_Key[1], ke_Key[2], etc. The number of keys in the message is calculated by the macro HIDDQ_Keyboard_GetNumKeys(msg).
A graphics HIDD allows to create bitmaps, display them and draw in them.
The graphics HIDD supports the following methods:
Make the HIDD execute a simple command. Simple commands execute very fast and don't do any checks. They were implemented to give you raw speed when you need it.
Command is the command to execute and Length is the size of the command (including both Command and Length).
The result of HIDDM_Graphics_QCmd() depends on the command that is to be executed.
Make the HIDD execute a command. The commands executed this way are checked for validity (e.g. clipping is performed) and they may take very long to execute.
Command is the command to execute and Length is the size of the command (including both Command and Length).
The result of HIDDM_Graphics_Cmd() depends on the command that is to be executed.
This is like HIDDM_Graphics_Cmd() but executes more than one command at once. length is the size of all commands plus all parameters. The format of the separate commands is the same as in HIDDM_Graphics_Cmd().
You can't use commands which return values with HIDDM_Graphics_MCmd(). If you use such commands with HIDDM_Graphics_MCmd(), the returned values will be lost.
Type: | ULONG |
---|---|
Applicability: | ISG |
Create a bitmap with this width or query the width. Note that most HIDD don't support to resize a bitmap. The width is in HIDD units. Some graphics HIDDs support text mode, where this is in characters. But most of the time, this will be in screen or printer pixels.
Type: | ULONG |
---|---|
Applicability: | ISG |
Create a bitmap with this height or query the height. Note that most HIDD don't support to resize a bitmap. The height is in HIDD units. Some graphics HIDDs support text mode, where this is in characters. But most of the time, this will be in screen or printer pixels.
Type: | UWORD |
---|---|
Applicability: | IG |
Create a bitmap with this depth. When the bitmap has been created, you can query the attribute. The number of distinct colors is 1L << depth. Most HIDDs will support depths like 1, 8, 15, 16, 24 and 32 bit.
Type: | BOOL |
---|---|
Applicability: | IG |
Create a bitmap which should later be displayed. When the bitmap has been created, you can query the attribute. On some systems, this will also display the bitmap when the method returns. To be safe, always call HIDDV_Graphics_Cmd_ShowBitmap() afterwards.
Type: | ULONG |
---|---|
Applicability: | G |
Check if a bitmap is visible. Can return HIDDV_Bitmap_Visible_No, HIDDV_Bitmap_Visible_Yes and HIDDV_Bitmap_Visible_Partial (if it's not fully visible).
Type: | ULONG |
---|---|
Applicability: | ISG |
The display mode. Every HIDD defines its own list and uses its own values. Use the method HIDDM_ValueToString() to get the meanings of this attribute.
Type: | APTR |
---|---|
Applicability: | ISG |
This is the address of the RAM of the graphics memory. Note that most HIDDs don't support to set this value. This can be used to access the video hardware directly. If you plan this, you must check if the HIDD supports this and if it does, then you must take the appropriate steps specified in the HIDDs' docs to tell the HIDD what you are doing (e.g. disable the HIDD). After you did this, you can use HIDDA_Graphics_Format to find out the format in which the data is stored here.
A HIDD which doesn't support direct memory access will return NULL.
Type: | ULONG |
---|---|
Applicability: | ISG |
Tell the format of the data at HIDDA_BitMap_BaseAddress. See this tag for details.
Type: | ULONG |
---|---|
Applicability: | G |
Query the number of bytes which make up one line on the display. This can be different from HIDDA_BitMap_BytesPerPixel * HIDDA_BitMap_Width.
Type: | ULONG |
---|---|
Applicability: | G |
Query the number of bytes which make up one pixel on the display. This can be different from the number of bits divided by eight. If one byte contains informations of several pixels, then this will be 0.
Type: | ULONG |
---|---|
Applicability: | G |
Query the HIDD for the best size for drawing areas or drawing commands. Most graphics chips have a certain blocking size, i.e. it doesn't matter if you copy 6 bits or 30 but 33 is slow. The HIDD will return 32 in this case.
Type: | LONG |
---|---|
Applicability: | IG |
Query or initialize the left edge position of a bitmap which is displayable. The position can be change with HIDDV_Graphics_Cmd_MoveBitMap. The value of the position is in HIDD units. Some graphics HIDDs support text mode, where this is in characters. But most of the time, this will be in screen or printer pixels.
Type: | LONG |
---|---|
Applicability: | IG |
Query or initialize the top edge position of a bitmap which is displayable. The position can be change with HIDDV_Graphics_Cmd_MoveBitMap. The value of the position is in HIDD units. Some graphics HIDDs support text mode, where this is in characters. But most of the time, this will be in screen or printer pixels.
Copy a rectangular area from the drawing area src to the drawing area stored in dest (which may be src). The source area is not changed (except when both rectangles overlap). The mode of the GC dest determines how the copy takes place.
In quick mode, the following restrictions are not checked: It's not checked whether the source and destination rectangles are is completely inside the valid area, nor whether the areas overlap. If they overlap, the results are unpredictable. Also drawing modes are ignored. If the two bitmaps in the GCs have a different depth, copying might be slow.
Copying bitmaps between two different HIDDs is executed in a way that matches the following pseudo-algorithm: First the destination HIDD is queried to determine whether it understands the format of the source HIDD. If it does, then the destination HIDD does the copying. If it doesn't, then the source is asked whether it understands the destination HIDDs' format. If it does, then the source HIDD does the copying. If neither supports the format of the other, then the default CopyArea of the graphics HIDD base class will be invoked, which copies the bitmaps pixel by pixel with HIDDV_Graphics_Cmd_GetPixel() and HIDDV_Graphics_Cmd_SetPixel().
Set the pixel at (x,``y``) direct to val without making use of the gc attributes, like colors, drawmode, colormask, etc. This command is available in quick and normal mode.
In quick mode, the pixel is always set, even if the coordinates are illegal, and it will always return 1 (but it might crash the machine if the coordinates are invalid).
Changes the pixel at (x,``y``). The color of the pixel depends on the attributes of gc, e.g. colors, drawmode, colormask, etc. This command is available in quick and normal mode.
If the command is executed in normal mode, the coordinates are checked. If the pixel could be set, the command will return 1 else 0.
In quick mode, the pixel is always set, even if the coordinates are illegal, and it will always return 1 (but it might crash the machine if the coordinates are invalid).
Queries the color of the pixel at (x,``y``). This command is available in quick and normal mode. When executed in quick mode, the color will be returned as the physical value for that color in the format used by the HIDD. If the command is executed in normal mode, the coordinates are checked and the color returned is a logical color (i.e. a 24-bit RGB value). If the pixel could be queried, the command will return its value and ~0 (i.e. all bits set) otherwise.
Note that in quick mode, the command always returns something, but if the coordinates are outside the valid coordinates, this can crash your machine or return random values.
Draws a solid polygon from (x1,``y1``) to (x2,``y2``) in the specified gc. This command is available in quick and normal mode. In normal mode, the polygon is clipped against the drawing area and no point is drawn twice.
In quick mode, the polygon should be convex, otherwise the results are unpredictable.
Type: | ULONG |
---|---|
Applicability: | SG |
This is the draw mode. There are 16 possible modes and they are defined as follows:
dest = ((mode & 1) && src && dest) ```` ((mode & 2) && src && !dest) ```` ((mode & 4) && !src && dest) ```` ((mode & 8) && !src && !dest) ;
The most useful values are HIDDV_GC_DrawMode_Copy (0x03) which copies src into dest (this is the default) and HIDDV_GC_DrawMode_XOr (0x06) which inverts dest according to src.
Type: | ULONG |
---|---|
Applicability: | SG |
Prevents some color bits from changing. This attribute is only considered in normal mode. This can slow rendering somewhat.
Type: | UWORD |
---|---|
Applicability: | SG |
Provide a simple pattern while drawing lines. This attribute is only considered in normal mode.
Type: | HIDDT_BitMap |
---|---|
Applicability: | SG |
This is a shape bitmap. When drawing into the destination bitmap, only those bits will be changed where this bitmap has bits set. This bitmap can be smaller than the destination bitmap; bits outside this bitmap are considered to be 0.
To disable this, set the attribute to NULL (this is also the default). Note that enabling this slows rendering down, sometimes very much so.
Okay, here are some examples of 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).
There are two possibilities of how to handle it. The first is to not handle it, so that the method is passed 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 immediately (because we know that the internal Amiga soundsystem can't handle MIDI).
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.
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 would have to pass a query for a HIDDA_Capabilities attribute on to the superclass, so that the capabilities of the superclass would be recognized by the application for unit 1, too.
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.
An IRQ HIDD is a frontend for the IRQ hardware of your computer. Whenever the computer generates an IRQ, the IRQ HIDD will catch it and check for handlers for this IRQ. If any handlers are available, the IRQ HIDD will call them.
An IRQ HIDD uses IRQ IDs to do its job. Those IDs are not related to the IRQ numbers in the hardware.
An IRQ handler is a callback hook with a priority. The handler gets a pointer the handler info given to HIDDM_IRQ_AddHandler() and to the hardware-specific IRQ data. For the format of this data, see the docs of the specific IRQ HIDD.
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().
The HIDD Tool Library (HIDDTL) must offer a way to make the process which wants to execute a method on the HIDD to wait if the HIDD is locked. It must also offer functions to lock/unlock a semaphore to allow the HIDD to block. If no locking is possible (e.g. NetBSD), then there must be a way to query this, too.
There must be a set of functions to install IRQ handlers.