Accessing NetWinder Hardware from Linux

Pat Beirne
July 23, 1998


The other documents in this cluster describe how one might access the hardware from the kernel space. This note describes access from application space. Almost all the hardware features of the NetWinder can be programmed from the Linux application space, provided the user has root priviledge.

In short, most of the IO devices are available through /dev/ports, except the video, which is available through /dev/mem.

IO ports

To access the I/O ports from user mode use /dev/port.  It has been setup to allow access to the IO registers.  Simply
open the device, lseek to the port offset (the file handle will already be pointed to IO_BASE), and fire away.

int tmp;
#define outb(p,v) tmp=v; lseek(f_io,p,SEEK_SET); write(f_io,&tmp,1);
#define inb(p) lseek(f_io,p,SEEK_SET), read(f_io,&tmp,1), tmp

f_io = open("/dev/ports",O_RDWR);

The available devices are
Device Group Ports
Keyboard/mouse 60-6f
RTC 70-71
IDE 1f0-1f7
sound 0x250-0x25f
serial (on board) 2f8
Ether10 300-31f
Misc I/O 338-33a
serial (external)  3f8
IDE (dma) e800-e807
You can confirm these on your system by "cat /proc/ioports"


The video system is non-standard in that the port control is through the memory system, not the video system. To get at the video ports, use "/dev/mem". This has the advantage that it may be memory mapped.

To get at the video memory, use the following technique:

f_mem = open("/dev/mem", O_RDWR);
p = mmap(0,0x00200000, PROT_READ | PROT_WRITE, MAP_SHARED, f_mem, 0xd0000000);
p[pixel] = pixel_data;

To get at the video ioports, use the following technique:

f_vid_io = open('/dev/mem", O_RDWR);
p = mmap(0, 0x400, PROT_READ | PROT_WRITE, MAP_SHARED, f_vid_io, 0xd0800000);
p[0x3c5] = reg_num; p[0x3c4] = data;

The registers 3c0, 3c1, 3c2, 3c3, 3c4, 3c5, 3c6, 3c7, 3c8, 3c9, 3ce, 3cf, 3d4, 3d5 do what one would expect.
Further information about the video chip will be forthcoming.


There are many sound devices on board, and this needs some explaining. Sound processing is split into two separate sections.

First, let's get the easy one out of the way. The "modem" chip is connected to the modem port only. Data flows to and from the modem codec chip through a pre-programmed PCI buffer chip (a XC5202). This chip provides fifo services so that the StrongArm can read/write bursts of 4 words, which gets shifted from/to the codec at the codec speed. Typically the codec chip is programmed to sample the modem port at a fixed rate (usually 9600 samples/sec). The PCI buffer chip also handles the IO for ring detect, modem off-hook, and codec reset.

The "soundblaster"/WaveArtist chip is connected to the internal speaker and microphone, to the external audio ports, to the handset jack and to the phone port.

The audio chip has internal mux/mixer capabilities. Audio out from the sound chip can be routed to the line out port (through power amp chips; stereo). Or, audio can be mixed to mono, and routed to the internal speaker and handset; if you wish handset-only operation, you must mute the internal speaker (io 0x338/0x33a). Audio in can be selected from the line-in jack (stereo) , from the internal microphone, from the handset or from the phone; all of these selections are done through the audio-chip-mixer functions.

In general, here is where you will find audio features
Device Ports
audio control 250
joystick/volume control 251
audio data  252
irq control 254
status  255
interrupt status  25c
select speaker line out to mono
mute speaker 338 through to external shift register
select microphone line in mixer rmic
External Audio
select audio in line in mixer lline & rline
seelct audio out line out to lout & rout
audio out line out to mono
audio in line in mixer lmic
handset detect 251, bit 4
audio out line out to mono
audio in line in mixer laux1
off-hook detect 251, bit 5
Device Port
modem codec

Parallel Port

The parallel port operates as one would expect.

EPP mode
Device Port
data 378
status 379
control 37a, bit 5 is "direction" control (1=read, 0=write)
control-swapper 37b
EPP address 37b
EPP data 37c-37f

ECP mode
Device Port
data 378
status 379
control 37a, bit 5 is "direction" control (1=read, 0=write)
fast data 77b

To select these extended modes, you need to set the '977 superI/O chip mode through its CRF0 on device #1 (printer)

The recommended irq for the printer is 23. The '977 chip and '553 chip think this is irq 7, but the software considers it irq 23. If you need a dma number, please contact me ( to arrange this.


Both standard UARTS are so simple that I will not elaborate here.

The infrared UART operates exactly as stated in the '977 data sheet. Please contact me ( if you enable this, as we need to coordinate irq & dma numbers.

Flash ROM

Naturally, we discourage any of you from trying to write to the flash. But if you do, here are some hints.

The flash that is installed is NOT boot block protected; you can write to the whole thing.
Address Device
e000.0338 (port 338) 0x30 bits run the expansion shift register, which contains the flash wp bit
e180.0000 read access
NOTE: this is byte-wide access, uncached, so it's about .7-1us per word!
e180.0000 write a byte to the flash
e100.0068 set address bits a0 & a1 to select 1 of 4 bytes to write
The flash write access is not available from user space; it MUST be done through the flash device driver.

We have provided a flash-write program, and highly recommend that you use it to write to the flash.

At this point, the first block of the flash is NeTTrom (a small boot loader) and the next 8-10 blocks are a mini-Linux kernel, which does the 2nd stage boot.

Libraries & GCC

The libraries that come with the NetWinder are based on glibc-2. This produces the It is so recent that it expects certain aspects to be in the kernel, but the kernel doesn't have these features yet (specifically lchown).

The libstdc++ is designed to work with the glibc. But it is a few months behind glibc, so we had to make a few patches to sync them up.

One of the biggest differences that we have from the x86 versions on Linux is that we have a hardware zero page. For most programs, that is not a problem. But it means that we can never have any code or data at address 0. There is one case in the ELF world where this is important.

When you run a program "foo" that has dynamic linking, it normally loads up at address 0x4000.0000. The other libraries (like libc) follow, add addresses such as 0x401e.0000.

Alternatively, you can invoke your program as " foo" (on the command line). This will load first, which then loads your foo program. Because the binary is a relocatable library, it has no native load address; on the x86, the kernal loads it into address 0. On ArmLinux, we can't do that; so the kernel loads it at 0x0001.0000.

This is just an interesting phenomenon; it shouldn't affect your day to day programming life; if you have a life, that is.