FreeBSD developers' handbook.2001
.pdfChapter 22 USB Devices
address 0. The services layer will proceed to retrieve the various descriptors through the default pipe. After that it will send a Set Address request to move the device away from the default device address (address 0). Multiple device drivers might be able to support the device. For example a modem driver might beable to support an ISDN TA through the AT compatibility interface. A driver for that specific model of the ISDN adapter might however be able to provide much better support for this device. To support this flexibility, the probes return priorities indicating their level of support. Support for a specific revision of a product ranks the highest and the generic driver the lowest priority. It might also be that multiple drivers could attach to one device if there are multiple interfaceswithin one configuration. Each driver only needs to support a subset of the interfaces.
The probing for a driver for a newly attached device checks first for device specific drivers. If notfound, the probe code iterates over all supported configurations until a driver attaches in a configuration. To support devices with multiple drivers on different interfaces, the probe iteratesover all interfaces in a configuration that have not yet been claimed by a driver. Configurations that exceed the power budget for the hub are ignored. During attach the driver should initialise the device to its proper state, but not reset it, as this will make the device disconnect itself from the bus and restart the probing process for it. To avoid consuming unnecessary bandwidth should not claim the interrupt pipe at attach time, but should postpone allocating the pipe until the file is opened and the data is actually used. When the file is closed the pipe should be closed again, eventhough the device might still be attached.
22.4.1 Device disconnect and detach
A device driver should expect to receive errors during any transaction with the device. The designof USB supports and encourages the disconnection of devices at any point in time. Drivers should make sure that they do the right thing when the device disappears.
Furthermore a device that has been disconnected and reconnected will not be reattached at the same device instance. This might change in the future when more devices support serial numbers (see the device descriptor) or other means of defining an identity for a device have been developed.
The disconnection of a device is signalled by a hub in the interrupt packet delivered to the hub driver. The status change information indicates which port has seen a connection change. The device detach method for all device drivers for the device connected on that port are called and the structures cleaned up. If the port status indicates that in the mean time a device has been connected to that port, the procedure for probing and attaching the device will be started. A device reset will produce a disconnect-connect sequence on the hub and will be handled as described above.
22.5 USB Drivers Protocol Information
The protocol used over pipes other than the default pipe is undefined by the USB specification. Information on this can be found from various sources. The most accurate source is the developer’s section on the USB home pages [ 1].
212
Chapter 22 USB Devices
From these pages a growing number of deviceclass specifications are available. These specifications specify what a compliant device should look like from a driver perspective, basic functionality it needs to provide and the protocol that is to be used over the communication channels. The USB specification [ 2] includes the description of the Hub Class. A class specification for Human Interface Devices (HID) has been created to cater for keyboards, tablets, bar-code readers, buttons, knobs, switches, etc. A third example is the class specification for mass storage devices. For a full list of device classes see the developers sectionon the USB home pages [ 1].
For many devices the protocol information has not yet been published however. Information on the protocol being used might be available from the company making the device. Some companies will require you to sign a Non -Disclosure Agreement (NDA) before giving you the specifications. This in most cases precludes making the driver open source.
Another good source of information is the Linux driver sources, as a number of companies have started to provide drivers for Linux for their devices. It is always a good idea to contact the authors of those drivers for their source of information.
Example: Human Interface Devices The specification for the Human Interface Devices like keyboards, mice, tablets, buttons, dials,etc. is referred to in other device class specifications and is used in many devices.
For example audio speakers provide endpoints to the digital to analogue converters and possibly an extra pipe for a microphone. They also provide a HID endpoint in a separate interface for the buttons and dials on the front of the device. The same is true for the monitor control class. It is straightforward to build support for these interfaces through the available kernel and userland libraries together with the HID class driver or the generic driver. Another device that serves as an example for interfaces within one configuration driven by different device drivers is a cheap keyboard with built-in legacy mouse port. To avoid having the cost of including the hardware for a USB hub in the device, manufacturers combined the mouse data received from the PS/2 port on the back of the keyboard and the keypresses from the keyboard into two separate interfaces in the same configuration. The mouse and keyboard drivers each attach to the appropriate interface and allocate the pipes to the two independent endpoints.
Example: Firmware download Many devices that have been developed are based on a general purpose processor with anadditional USB core added to it. Because the development of drivers and firmware for USB devices is still very new, many devices require the downloading of the firmware after they have been connected.
The procedure followed is straightforward. The device identifies itself through a vendor and product Id. The first driver probes and attaches to it and downloads the firmware into it. After that the device soft resets itself and the driver is detached. After a short pause the devicere announces its presence on the bus. The device will have changed its vendor/product/revision Id to reflect the fact that it has been supplied with firmware and as a consequence a second driver will probe it and attach to it.
An example of these types of devices is the ActiveWire I/O board, based on the EZ-USB chip. For this chip a generic firmware downloader is available. The firmware downloaded into the ActiveWire board changes the revision Id. It will then perform a soft reset of the USB part of the EZ-USB chip to disconnect from the USB bus and again reconnect.
Example: Mass Storage Devices Support for mass storage devices is mainly built around existing protocols. The
213
Chapter 22 USB Devices
Iomega USB Zipdrive is based on the SCSI version of their drive. The SCSI commands and status messages are wrapped in blocks and transferred over the bulk pipes to and from the device, emulating a SCSI controller over the USB wire. ATAPI and UFI commands are supported in a similar fashion.
The Mass Storage Specification supports 2 different types of wrapping of the command block.The initial attempt was based on sending the command and status through the default pipe and using bulk transfers for the data to be moved between the host and the device. Based on experience a second approach was designed that was based on wrapping the command and status blocks and sending them over the bulk out and in endpoint. The specification specifies exactly what has to happen when and what has to be done in case an error condition is encountered. The biggest challenge when writing drivers for these devices is to fit USB based protocol into theexisting support for mass storage devices. CAM provides hooks to do this in a fairly straight forward way. ATAPI is less simple as historically the IDE interface has never had many different appearances.
The support for the USB floppy from Y-E Data is again less straightforward as a new command set has been designed.
214
Chapter 23 NewBus
This chapter will talk about the FreeBSD NewBus architecture.
215
XII. Architectures
Chapter 24 x86 Assembly Language
Programming
This chapter was written by G. Adam Stanislav. Whiz Kid Technomagic (http://www.whizkidtech.net/)
24.1 Synopsis
Assembly language programing under Unix is highly undocumented. It is generally assumed that no one would ever want to use it because various Unix systems run on different microprocessors, so everything should be written in C for portability.
In reality, C portability is quite a myth. Even C programs need to be modified when ported from one Unix to another, regardless of what processor each runs on. Typically, such a program is full of conditional statements depending on the system it is compiled for.
Even if we believe that all of Unix software should be written in C, or some other high-level language, we still need assembly language programmers: Who else would write the section of C library that accesses the kernel?
In this chapter I will attempt to show you how you can use assembly language writing Unix programs, specifically under FreeBSD.
This chapter does not explain the basics of assembly language. There are enough resources about that (for a complete online course in assembly language, see Randall Hyde’s Art of Assembly Language (http://webster.cs.ucr.edu/); or if you prefer a printed book, take a look at Jeff Duntemann’s Assembly Language Step-by-Step (http://www.int80h.org/cgi-bin/isbn?isbn=0471375233)). However, once the chapter is finished, any assembly language programmer will be able to write programs for FreeBSD quickly and efficiently.
Copyright © 2000-2001 G. Adam Stanislav. All rights reserved.
24.2 The Tools
24.2.1 The Assembler
The most important tool for assembly language programming is the assembler, the software that converts assembly language code into machine language.
Two very different assemblers are available for FreeBSD. One is as(1), which uses the traditional Unix assembly language syntax. It comes with the system.
217
Chapter 24 x86 Assembly Language Programming
The other is /usr/ports/devel/nasm. It uses the Intel syntax. Its main advantage is that it can assemble code for many operating systems. It needs to be installed separately, but is completely free.
This chapter uses nasm syntax because most assembly language programmers coming to FreeBSD from other operating systems will find it easier to understand. And, because, quite frankly, that is what I am used to.
24.2.2 The Linker
The output of the assembler, like that of any compiler, needs to be linked to form an executable file.
The standard ld(1) linker comes with FreeBSD. It works with the code assembled with either assembler.
24.3 System Calls
24.3.1 Default Calling Convention
By default, the FreeBSD kernel uses the C calling convention. Further, although the kernel is accessed using int 80h, it is assumed the program will call a function that issues int 80h, rather than issuing int 80h directly.
This convention is very convenient, and quite superior to the Microsoft convention used by MS DOS. Why? Because the Unix convention allows any program written in any language to access the kernel.
An assembly language program can do that as well. For example, we could open a file:
kernel:
int 80h ; Call kernel ret
open:
push dword mode push dword flags push dword path mov eax, 5
call kernel
add esp, byte 12 ret
This is a very clean and portable way of coding. If you need to port the code to a Unix system which uses a different interrupt, or a different way of passing parameters, all you need to change is the kernel procedure.
218
Chapter 24 x86 Assembly Language Programming
But assembly language programmers like to shave off cycles. The above example requires a call/ret combination. We can eliminate it by pushing an extra dword:
open:
push dword mode push dword flags push dword path mov eax, 5
push eax ; Or any other dword int 80h
add esp, byte 16
The 5 that we have placed in EAX identifies the kernel function, in this case open.
24.3.2 Alternate Calling Convention
FreeBSD is an extremely flexible system. It offers other ways of calling the kernel. For it to work, however, the system must have Linux emulation installed.
Linux is a Unix-like system. However, its kernel uses the same system-call convention of passing parameters in registers MS DOS does. As with the Unix convention, the function number is placed in EAX. The parameters, however, are not passed on the stack but in EBX, ECX, EDX, ESI, EDI, EBP:
open:
mov eax, 5 mov ebx, path
mov ecx, flags mov edx, mode int 80h
This convention has a great disadvantage over the Unix way, at least as far as assembly language programming is concerned: Every time you make a kernel call you must push the registers, then pop them later. This makes your code bulkier and slower. Nevertheless, FreeBSD gives you a choice.
If you do choose the Linux convention, you must let the system know about it. After your program is assembled and linked, you need to brand the executable:
% brandelf -f Linux filename
219
Chapter 24 x86 Assembly Language Programming
24.3.3 Which Convention Should You Use?
If you are coding specifically for FreeBSD, you should always use the Unix convention: It is faster, you can store global variables in registers, you do not have to brand the executable, and you do not impose the installation of the Linux emulation package on the target system.
If you want to create portable code that can also run on Linux, you will probably still want to give the FreeBSD users as efficient a code as possible. I will show you how you can accomplish that after I have explained the basics.
24.3.4 Call Numbers
To tell the kernel which system service you are calling, place its number in EAX. Of course, you need to know what the number is.
24.3.4.1 The syscalls File
The numbers are listed in syscalls. locate syscalls finds this file in several different formats, all produced automatically from syscalls.master.
You can find the master file for the default Unix calling convention in /usr/src/sys/kern/syscalls.master. If you need to use the other convention implemented in the Linux emulation mode, read
/usr/src/sys/i386/linux/syscalls.master.
Note: Not only do FreeBSD and Linux use different calling conventions, they sometimes use different numbers for the same functions.
syscalls.master describes how the call is to be made:
0STD NOHIDE { int nosys(void); } syscall nosys_args int
1STD NOHIDE { void exit(int rval); } exit rexit_args void
2STD POSIX { int fork(void); }
3STD POSIX { ssize_t read(int fd, void *buf, size_t nbyte); }
4STD POSIX { ssize_t write(int fd, const void *buf, size_t nbyte); }
5STD POSIX { int open(char *path, int flags, int mode); }
6STD POSIX { int close(int fd); }
etc...
It is the leftmost column that tells us the number to place in EAX.
The rightmost column tells us what parameters to push. They are pushed from right to left.
220
Chapter 24 x86 Assembly Language Programming
For example, to open a file, we need to push the mode first, then flags, then the address at which the path is stored.
24.4 Return Values
A system call would not be useful most of the time if it did not return some kind of a value: The file descriptor of an open file, the number of bytes read to a buffer, the system time, etc.
Additionally, the system needs to inform us if an error occurs: A file does not exist, system resources are exhausted, we passed an invalid parameter, etc.
24.4.1 Man Pages
The traditional place to look for information about various system calls under Unix systems are the man pages. FreeBSD describes its system calls in section 2, sometimes in section 3.
For example, open(2) says:
If successful, open() returns a non-negative integer, termed a file descriptor. It returns -1 on failure, and sets errno to indicate the error.
The assembly language programmer new to Unix and FreeBSD will immediately ask the puzzling question: Where is errno and how do I get to it?
Note: The information presented in the man pages applies to C programs. The assembly language programmer needs additional information.
24.4.2 Where Are the Return Values?
Unfortunately, it depends... For most system calls it is in EAX, but not for all. A good rule of thumb, when working with a system call for the first time, is to look for the return value in EAX. If it is not there, you need further research.
221
