|
Technote HW01ADB-The Untold Story : Space Aliens Ate My MouseRevised by Tim Dierks,Jim Mensch January 1994 Revised (again) by George Warner September 1998 Apple Worldwide Developer Technical Support |
CONTENTS The Cursor Device Manager (CDM)
|
This Technical Note explains a number of esoteric and unknown issues concerning the Apple Desktop Bus (ADB). It is intended to detail information concerning all levels of the ADB, from the hardware to the application usage level. This note is supplementary to the information in The Guide To Macintosh Family Hardware and in the Apple Desktop Bus Specification. The information in the specification is the most accurate source of data, and unless it is specifically refuted, it should be treated as the authoritative source. Changes since October 1991: This note has been rewritten; new information appears throughout the document. In particular, the Cursor Device Manager is discussed in this note for the first time. The information regarding bugs fixed in System 6.0.4 was omitted. Changes since January 1994: The Cursor Device Manager API has been updated for Universal Headers 3.1 and some issues with ROM bugs have been documented. |
The ADB HardwareThe ADB is a simple serial bus with collision detection. A common implementation platform for the protocol is a simple microcontroller: a 2-MHz Motorola 68HC11 has been used with success, although any number of microcontrollers would do a more than adequate job. The 2-MHz clock seemed to be close to minimal for this application; the bus has a relatively low bandwidth, and, given the packet structure, the theoretical maximum bandwidth is on the order of 100 - 200 bytes/second. In practice, the bus is not suitable for data- xtransfer applications; it serves well as a general purpose input device bus, but high data rates will not work well. In general, the timing for the ADB is fairly tolerant of
small variances; however, many Macintoshes are more
demanding than their predecessors. For this reason, devices
should be tested on a wide range of machines; the best test
for compliance is testing. Specifically, the It is important that your device be fairly tolerant of problems on the bus; if a command packet begins but never seems to complete, your device should time out rather than hang. The design of the bus and its connectors means that there can be occasional glitches in the connection with the host, and you should try to be as tolerant of these as possible. Because the ADB bus is open collector, collisions can be detected when a device is attempting to drive the bus high and another device pulls it low. This means that whenever the device is driving the bus high, it should be watching to make sure the bus is actually high; if the bus goes low, some other device is sending at the same time. When a device detects a collision, it should immediately stop transmitting: this means that if two devices are colliding, one of them will detect the collision, while one will not. This occurs because a device can only detect the collision if it is driving the bus high and another device drives it low. The device driving it low has no way to tell that there was a collision, as the bus follows it. Since the detecting device immediately stops transmitting, the other device will not detect the collision. Thus, if there are a number of devices transmitting on the bus, only one of them will complete its transmission without detecting the collision, unless the unlikely occurrence of more than one device transmitting exactly the same data with the same timing occurs, and neither detects the collision. The ADB is not particularly tolerant of devices being connected and disconnected while the bus is live. There isn't any software architecture to detect the presence of new devices or the absence of old ones; furthermore, on some CPUs, the motherboard is not well protected from voltage transients on the ADB connector. Plugging in a device while the Macintosh is powered on could cause damage to the ADB transceiver or other portions of the Macintosh's circuitry. On some portable Macintoshes, the voltage characteristics do not adhere to the ADB specification. Clearly, power is very valuable on all portable computers, so if your device is targeted towards portable use, you should be extremely careful to keep your power consumption as low as possible. While the ADB can supply the full voltage stated in the specification, drawing this much power will lead to much more rapid battery draining. On the PowerBook 140 and 170, there was a specific problem which caused the low-level input voltage to go above the specified maximum of 0.8 volts: it commonly came close to 1.5 volts. This has caused problems for some third-party devices, and it has been corrected on subsequent machines. (There is a recommended service procedure for repairing this problem available from Apple Service representatives, should this be a problem for a user.) Soft Power On Macintoshes with software power control, the machine can be turned on by an ADB device. This is accomplished by momentarily connecting pin 2 on the ADB connector (reserved) to pin 4 (ground). Pin 2 should be kept grounded until pin 3 (+5 volts) comes up to power, letting you know that the machine has actually come on. Some Macintoshes do not have soft-power capabilities; on these machines, grounding pin 2 will have no effect. The ADB ProtocolRegisters Each ADB device has four logical registers; the host can ask the device to talk to or listen on each one of these registers. A talk command asks the device to output the stored value from that register; a listen commands asks the device to accept a new value for that register. A register can contain between two and eight bytes. Some of the registers have predefined functions: register 0 is used as the primary data transfer register for most devices; it is this register which is polled by the input mechanism (as described below). Register 1 has no specified use; it is available for any use the device might require. Register 2 has no specified use for most devices; the ADB specification does define an "extended address device" protocol for register 2 on devices at address 1, but this is unused by most developers. Register 3 is used to identify devices and to separate devices which occupy the same address, as discussed in "Address Resolution" below. Default addresses and handler IDs Each ADB device identifies its software interface with
two constants: the default address and the handler ID. This
pair uniquely identifies a device's software interface; the
default address usually specifies a device's general type
(such as relative pointing device or keyboard), while the
handler ID specified the particular data protocol this
device uses for communication. The default address
categories are as follows:
Table 1--Default address categories The default address is only a guide; there's no real reason a mouse can't be at address 7, but default addresses are assigned on a category basis to try to avoid the case where a user has more than one device at a particular address. By putting all the relative devices at address 3, collisions will be avoided at address 3 for all users who have only one relative pointing device. While the bus is robust with respect to separating devices which are at the same address, the ADBS driver-loading mechanism, which is described below, made it useful to try to avoid having several dissimilar devices at the same address. Default addresses and handler IDs are assigned by Apple Software Licensing when an ADB license contract is completed. Default address 0 is used by the ADB host; addresses 8 through 15 are used as locations for locating devices dynamically. Some devices support more than one data protocol. An
example is the extended keyboard, which can be asked to send
separate key codes for the left and right shift keys. This
change is accomplished by changing its handler ID to 3; the
new handler ID reflects the new data protocol. If your
device receives a request to change handler IDs (via a
listen register 3 command), it should only obey the request
if it knows how to speak the protocol specified by the new
handler ID. For example, the extended keyboard, when
receiving a request to change handler IDs, should accept the
change if it is going to ID 3 or some other ID it knows
about, and should thereafter report that ID as its own in
response to talk register 3 commands. If it receives a
request to change to handler ID A special case is devices which emulate Apple device protocols. For example, you may be constructing a 17-button mouse for use by specially trained squid; this device has a special software protocol to allow it to convey the state of all 17 mouse buttons. However, you may wish to emulate the Apple mouse protocol so your device can be used as a one-button mouse on machines which don't have your driver software installed. Due to the software design of the ADB Manager, if your device is at default address 3, it will have the default mouse driver installed as its driver at startup regardless of its handler ID. When your software loads, you can install a new driver for your device and tell it to begin talking the 17-button protocol. You have two options:
Both approaches work well, but the first one is recommended. It ensures that the current protocol can always be determined by looking at the current handler ID; however, it relies on all devices at that default address handling commands asking them to change to a different handler ID properly, as a device which incorrectly changes its handler ID to your assigned ID would fool you into thinking it was your device. This doesn't seem to be a large problem, but there could be some obscure devices with this bug. Address Resolution Address resolution is the process the ADB Manager uses to separate devices that share the same default address so they power up shadowing each other at a particular address. It relies on devices using collision detection to determine when there is more than one device at a particular address. An ADB device's register 3 is 2 bytes long, and includes 4 bits in which the address is stored. When the device receives a listen register 3 command, it should take its address from this 4-bit field. When it receives a talk register 3 command, it would be redundant to put the device's address in that field: the device's address is already uniquely determined by the fact that the device is responding to the talk register 3 command, which was sent to a specific address. Instead, a random 4-bit value should be returned in this field; this makes it easier to detect collisions between two devices responding to a talk register 3. When a device receives a talk register 3 command, it
should send back all of register 3, including the random
field, and it should pay careful attention to collision
detection. Should a device detect a collision when
responding to a talk register 3 request, there is a special
provision in the ADB protocol which says that the device
should ignore the next listen register 3, which asks it to
change address. The next time the device receives a listen
register 3 command, it should check to see if the handler ID
field is set to Here is a summary of a typical sequence where the host is attempting to separate two devices. There are two devices of the same type, which I will call Fred and Wilma, at address 3.
Each and every ADB controller isn't guaranteed to follow this procedure precisely, but it gives a feeling for the principle behind the address resolution process. You may see some implementations moving devices many more times than is necessary. This is done because some devices have been manufactured to tolerances close enough that not only do they send their bits at exactly the same time and so cannot detect collisions with each other, but they select the same random numbers to transmit. We recommend that you include some low-tolerance device (such as a capacitor on your reset line) to ensure that various devices will respond differently and be able to detect their collisions with each other. Autopolling Autopolling is the primary method by which the host fetches data from your device. The host repeatedly issues talk register 0 commands to your device; if your device responds with data, it is passed to your device's driver, which should act on it as new data. This implies that register 0 should be the primary data transfer register for most devices; registers 1 and 2 are usually only used for supplementary data to configure the device. Most device drivers have no need to issue commands to their device, as all necessary data has been transferred within register 0. When a device wishes to transmit data, it should wait until a command is issued to it or some other device. If, when this transmission is completing, it still wishes to transfer data (if the command was sent to our device, it might have fetched the data already), it should assert SRQ after the data portion of the command by holding the bus low for 300 us after the stop bit. This will alert the host that some device wishes to transmit data. It will then begin polling those addresses which it knows hold devices. If a device does not have any data, the host will move on to the next address, asking each device in turn, until SRQ is no longer asserted, indicating that all pending data has been fetched. When an SRQ is not asserted, the host will continually poll the last device to send it data, sending it talk register 0 commands periodically. This is done under the assumption that this is likely to be the next place the user interacts; if the user types a character, she is very likely to type another soon. On current hosts, this can happen up to 150 times a second, although it can happen much less frequently in some cases. If the device responds with any data, the host will call the device's driver with the data. Your device should only respond with data when sent a talk register 0 command if it has new data. If the status of the device has not changed since the last talk register 0, then it should not respond at all, allowing the bus to time out. This is useful for two reasons. First, it tends to reduce the demands on the host, as your driver need not be called when your device has nothing useful to say. Second, in some ADB implementations, the host can get "hung up" on your device if you always respond. For example, say that you have a device at address 4 which will always respond regardless of whether it has new data; there is another device at address 7. Moreover, the system is currently autopolling address 2. If the device at address 7 asserts SRQ, the system will begin looking through the addresses for the device which has data to send. When it reaches your device at address 4, your device will respond, although it has nothing new to say. On some implementations, this will cause the host to repeatedly ask your device for more data, and your device will continue responding. Meanwhile, device 7 is withering away at the end of the bus, and will never get serviced. What your device should do is not respond to the talk register 0 (since it has no new data); this will allow all host implementations to pass you by and reach the device at address 7, which needs the host's attention. A useful summary of a reasonable algorithm is:
This simple behavior will produce the appropriate responses and SRQ generation for proper bus functioning. It shouldn't be necessary for your device to have any explicit knowledge of whether it is the "active" device or not; a robust basic behavior will eliminate any need for such information. As an optimization, all recent versions of the ADB Manager will not automatically poll a device which does not have a driver service routine installed. In this case, they will switch to autopolling some other device, even if the manager has not been recently communicated with that device. However, the host may poll a device, even if it does not have a service request, in order to try to clear an SRQ on the bus. Bus Initialization Bus initialization doesn't work exactly as it might seem
from looking at some documentation. A ADB DriversDriver Installation In the past, the recommended way to install an ADB driver
was to install a resource of type Currently, the recommended method is to supply the user
with a system extension which will load your driver. This
can either be a simple extension, or it can be contained
within a control panel, should your device require some user
interface for configuration. Your code, when loaded, should
look for your device and install your driver for it. If your
device is at a default address which is not shared with
standard Apple devices, you don't have to concerned with
what driver is installed for you by default--your device can
just power up at its standard address with its handler ID.
Your extension can then locate your device's current address
by indexing through all the known devices with the ADB
Manager call Because your ADB driver is in a system extension which will not load until well into the system startup process, you might need to provide standard system functionality before your driver loads in order to allow the user to interact with the system during the startup process if your device is a standard one (a pointing device or keyboard). This arrangement also allows the user to use your device to control their machine even if they don't have the software installed, such as when they are booting from a floppy. In this case, your device will need to be able to emulate the Apple protocol for mouse or keyboard devices until your software driver loads, as discussed above in "Default Addresses and Handler IDs". Until your driver is installed, your device will be serviced by the default driver for this address. Even if it cannot emulate an Apple device, a device at address 2 or 3 must supply harmless data in register 0 until your driver loads and is installed, as the Apple ADB driver for that address may inadvertantly receive the contents of your register 0 and attempt to use it as input data. If the data in your field caused effects such as the mouse button or shift key sticking down, this could cause problems for the user. If you use the recommended procedure for handler IDs in
this case (powering up with the appropriate Apple handler ID
and switching to your custom ID when your driver loads), you
will need to use ADB commands to find your device at
startup. You should index through the connected ADB devices
with In the original method using |
For history buffs, this is the second time the
recommended procedure for loading ADB drivers has changed.
Initially, it was recommended that ADB drivers be loaded
with INITs; however, at the time, For true history buffs, or possibly for specialized
applications, here is the description of the
|
In order to be able to manage an expanding set of relative movement devices, Apple has created the Cursor Device Manager, which is a software architecture which provides a standard interface to devices of widely varying resolutions and capabilities. This also allows better management of multiple relative devices on a single bus. In the old architecture, all connected devices shared a single button state and acceleration curve, which became a problem for Apple and for third-party device manufacturers. The Cursor Device Manager provides a number of calls for finding, configuring, and manipulating relative devices connected to the bus. It also supports the new extended mouse protocol, which is described below in the "Apple Devices" section. Cursor Device Manager types |
The Cursor Device Manager treats each relative or
absolute device as a Cursor Device. Each one is
specified by a CursorDeviceRec which is defined as
follows: |
typedef struct CursorDevice { struct CursorDevice *nextCursorDevice; // pointer to next record in // linked list CursorData *whichCursor; // pointer to data for target cursor long refCon; // application-defined long unused; // reserved for future OSType devID; // device identifier (from ADB reg 1) Fixed resolution; // units/inch (orig. from ADB reg 1) UInt8 devClass; // device class (from ADB reg 1) UInt8 cntButton; // number of buttons (from ADB reg 1) UInt8 filler1; // reserved for future UInt8 buttons; // state of all buttons UInt8 buttonOp[8]; // action performed per button unsigned long buttonTicks[8]; // ticks when button last went // up (for debounce) long buttonData[8]; // data for the button operation unsigned long doubleClickTime; // device-specific double click speed Fixed acceleration; // current acceleration short privateFields[15]; // fields used internally to CDM }CursorDevice,*CursorDevicePtr; |
The cursor controlled by this cursor device is described
with a CursorDataRec : |
typedef struct CursorData { struct CursorData *nextCursorData; // next in global list Ptr displayInfo; // unused (reserved for future) Fixed whereX; // horizontal position Fixed whereY; // vertical position Point where; // the pixel position Boolean isAbs; // has been stuffed with absolute coords UInt8 buttonCount; // number of buttons currently pressed long screenRes; // pixels per inch on the current display short privateFields[22]; // fields use internally by CDM }CursorData,*CursorDataPtr; |
Most of the fields are fairly self-explanatory. The
fields labeled as private at the end of the
|
Cursor Device Manager Routines CursorDeviceNextDevice:
CursorDeviceNewDevice:
Call New cursor devices are created for all ADB devices with a type 3 or 4 handler ID. This routine should only be needed by devices which are connected though some other method, such as the serial port. CursorDeviceDisposeDevice:
This routine disposes of a cursor device and unlinks it from the device chain. This isn't needed by most developers, but could be useful for non-ADB devices which might be connected and disconnected. CursorDeviceMove:
CursorDeviceButtons:
CursorDeviceButtonUp:
CursorDeviceButtonOp:
|
kButtonNoOp
|
No action |
kButtonSingleClick
| Normal mouse button |
kButtonDoubleClickkButton
|
Click, release, and click again when pressed |
kButtonClickLock
|
Click on press, release on next press |
Custom | Call a custom procedure; data holds its address |
Using the The CursorDeviceSetButtons:
CursorDeviceSetAcceleration:
CursorDeviceDoubleTime: pascal OSErr CursorDeviceDoubleTime(CursorDevicePtr ourDevice;
CursorDeviceUnitsPerInch: pascal OSErr C
Acceleration tables are stored in resources of type
|
type 'accl' {
literal longInt /* Device identifier or device class */
classAbsolute, /* A flat-response device */
classMouse, /* Mechanical or optical mouse */
classTrackball; /* Trackball */
integer = $$CountOf(AcclTable);
/* Number of tables for this device */array AcclTable
{ /* Entries sorted by first value; must have */ /* at least 0.0 and 1.0 tables */unsigned hex longint;
/* Acceleration provided by this table (Fixed) */integer = $$CountOf(AcclPoint); /* Number of control points for this device */
wide array AcclPoint { /* Entries sorted by first value; implicit */
/* first entry (0.0, 0.0); at least one more */
/* entry required. */
unsigned hex longint; /* Device speed (inches per second) (Fixed) */
unsigned hex longint; /* Cursor speed (inches per second) (Fixed) */
};
}; };
The identifier for this Availability Of The Cursor Device Manager The Cursor Device Manager was introduced in the ROMs of
Macintoshes introduced in February, 1993. It may be
installed via software on any Macintosh. To check to see if
the Cursor Device Manager is available, you should use the
standard
Compatibility When the Cursor Device Manager is installed, all Apple
mouse drivers use its interface to move the cursor; this
means that the low memory globals such as |
|
Format |
|
Unique device identifier |
|
Device resolution in units/inch |
|
Device class (Mouse, trackball, etc.) |
|
Number of buttons (0-8) |
The unique device identifier is intended to be a
four-character ASCII identifier similar to the
The device class is a value which is used to identify the type of device and to control the acceleration curve used for that device. The currently defined constants include:
Table 4--Currently defined device classes There currently isn't any mechanism for developers to create or register device classes; if a developer needs a device class not available from Apple, the only alternative available currently is not to use the handler ID 4 extended mouse protocol. Instead they should use a custom handler ID and custom driver software. Apple Keyboard Protocol The Apple keyboards have a simple data transfer protocol. Register 0 is used to inform the host as keys are depressed and released; register 2 is used to communicate the state of the modifier keys and to control the LED indicators on the extended keyboards. The format of register 0 is:
Figure 3-Keyboard Register 0 Format Register 0 can communicate up to two key transitions at
once. Each transition consists of a key code and a key
released bit, which is 0 for key depressions and 1 for key
releases. The key codes are described in Inside
Macintosh volume V, pages 191-192. The special case is
the reset key, which returns the value The format of register 2 is:
Figure 4-Keyboard Register 2 Format The current state of the keys listed in figure 4 is available in bits 6-14 of register 2, if those keys exist on the keyboard being examined. Bits 0-2 hold the current state of the LEDs on the extended keyboard; the states of these LEDs can be changed by sending the keyboard a listen register 2 command. Note that key transition events are generated in register 0 for modifier keys, as they are for all other keys; these keys are available in register 2 in addition to their status being transmitted through register 0. |
The Apple Desktop Bus is patented. In order to build an ADB device, you will need to get a license from Apple. Contact our Software Licensing department at sw.license@apple.com or 800-793-9378 or 512-919-2645. The license is available for a nominal fee in most cases, and the licensing package includes the latest version of the ADB specification, which is the definitive reference to the bus. |
|
Acrobat version of this Note
(68K).
|
Acknowledgments Thanks to Rich Kubota and Quinn "The Eskimo!" To contact us, please use the
Contact Us page. |