% Tries to follow TEMPLATE for Usenix papers 
% It is well known that the Author absolutely detests TeX.
% This version uses the latex2e styles, not the very ancient 2.09 stuff.
% adapted for Ottawa Linux Symposium

\documentclass[twocolumn]{article}
\usepackage{ols,epsfig}
\begin{document}

%don't want date printed
\date{}

%make title bold and 14 pt font (Latex default is non-bold, 16 pt)
\title{\Large \bf "Will Code For Hardware" -- Supporting the Unsupported and
Getting Cool Toys}

%for single author (just remove % characters)
\author{
Nathan I.\ Laredo \\
{\em Stradis, Inc.} \\
{\em 3170 Sugarplum Road, NE}\\
{\em Atlanta, Georgia, 30345-1553 USA}\\
{\normalsize laredo@gnu.org, http://mpeg.openprojects.net} \\
} % end author

\maketitle

% You have to do this to suppress page numbers.  Don't ask.
\thispagestyle{empty}

\subsection*{Abstract}

This paper discusses the development of the Stradis MPEG2 hardware
decoder driver for Linux.  It addresses development process, driver
architechture, and problems encountered even with the full technical
support of Stradis and full documentation on all of the chips used
on the board.   It will also cover some techniques used to protect
intellectual property of the manufacturer as well as well as covering
the optimization of the driver for real use after the initial just-get-
it-working hack.   The Video4Linux API was used for the driver, and an
overview of the extensions to the API will also be presented.

\section{Introduction}

I was first contacted by Doug Ledford who was swamped with far more
projects than the average human is capable of supporting in early 1999
about some new toys he had been given in exchange for writing a Linux
driver.   It was a good deal for Stradis.  The Chief Technical Officer
at Stradis, Chris Hodges, mailed Doug a package with two MPEG-2 decoder
boards, the Philips SAA7146 PCI Bridge Software API Description (which
turned out to be only useful to understand the Windows driver), the
Philips SAA7146 Data Sheet (a book actually), a CD-R with some MPEG
test sequences, the Windows drivers and software, and the actual source
code to the Windows playback application.   I thought to myself, "This
should be a piece of cake," so I told Doug that I would be happy to
take over this project he would never have time for.  I received a
phone call from Stradis just as I was crawling into bed.  They decided
they wanted Linux support because they had a customer that was asking
for it, and I learned that they have no great love for Microsoft either.
The driver was to be written in exchange for two \$1000 value 50Mbps
MPEG2 decoder boards. \\

I received a package from Red Hat with the hardware just before I
started packing for my move to Atlanta after an unusual four years
in the Air Force.  I thumbed through the documentation, installed the 
hardware, and tried the Windows driver.  It failed.  Since Stradis
was in Atlanta, I decided to just wait until I got there to get it
working. \\

I moved into my new apartment March 1st and spent two weeks getting
30 boxes of junk sorted out and new furniture purchased.  I met with
the CEO and CTO of Stradis two weeks later.  After sticking an
oscilloscope on the card, we discovered that all of my problems were
caused by my PCI bus running at 37MHz, an unfortunate consequence
of my I-have-a-faster-machine-than-you-have ego trip.   The Windows
driver has since been hacked to work with the faster speed.  I
honestly had zero code written at this point, but I was able to
pick up a manual for the MPEG decoder chip on the board. \\

\section{The Blank Page}

Every writer hates to stare at a blank page, especially when writing
a paper for a conference with the deadline the same day.   I had zero
code, and the project seemed a more daunting task than I thought I
could handle.   Using bttv.c as a reference, I hacked out a skeleton
of a driver that did nothing but printk for everything.  I followed
the Windows driver initialization code and poked that into the
skeleton after I borrowed the pci device detection code from the
bttv driver. \\

I continued hacking in code, replacing every printk I had with code
to actually do something.   I quickly progressed from no code to 
something that closely resembled a driver that could very well work,
but I had no way to test it fully without finishing more of
it.  From a feeling that I would never finish, I reached a point
where I thought that I was almost finished with the driver, but I
soon discovered that nothing that I had written actually did what
it was supposed to do. \\

\section{Bugs Are Everywhere, Even in Data Books}

After about five days of debugger's block, my brain was about to explode.
This was defused by an offer from Chris Hodges to stick the old
oscilloscope on the card to see what it was actually doing.  The
first thing that I learned is that Windows apparently has a concept
of breakpoints and watches everywhere, and I only had printk and
learned to return -1 on module init to break out, with usual
precautions against leaking kernel memory. \\

In theory, everything in my driver should have been working
perfectly.  In reality, I produced nothing.  The card was nicely
designed with a LED that would turn off as soon as the FPGA was
properly programmed.   Of course in the end I discovered that it
was not the FPGA loader code that was wrong, it was the code that
wrote to the 16-bit interface of the SAA7146. \\

Philips, in their infinite wisdom, designed a chip that would
raise an IRQ when a transfer was "finished" before the transfer
was complete.  Not only that, but I was guilty of treating a
32-bit pointer as if it were an 8-bit pointer, so between my
crashing the kernel all day and the Philips chip not working
as the manual describes, it was a wonder that I made any progress
at all. \\

Since there was a direct path from the IBM MPEG decoder chip
through the FPGA to the Philips SAA7121 video encoder chip,
and the FPGA was not required to access the I2C bus, I decided
the next order of business was to get the SAA7121 programmed
properly for output.   The code was already written but like the
FPGA code, it did not work either.   The SAA7146 has a smart I2C
interface and a really annoyingly wrong manual.  After much
oscilloscope poking on the card, we discovered that it
also suffered from the same "I'm done now but not really" problem
as the other parts.  It also suffered from a severe case of
poor examples in the manual. \\

\section{It Works!  It Really Works!}

The way the Stradis card is designed, the FPGA must be programmed
properly before anything else can be tested, so once we got the
FPGA programmed, I fleshed out the code to program the microcode
into the IBM MPEG decoder chip.   I had already written it, but
never actually called the code since the FPGA was not working
before.   I was still on my second visit to Stradis at this point
and felt motivated to pull an all-night hack session after seeming
to get the IBM chip programmed on the first try.   I am not quite
sure why the hours between 1AM and 4AM are so productive, but
I am quite thankful that they exist. \\

The IBM chip seemed to get programmed on the first try.  I was
lucky, but during my all night hack session I got nothing more
interesting than colorbars produced directly by the SAA7121
video encoder.   The IBM chip would produce output that
resembled feeding random data to it.   At this point, everything
was still being done by polling.  No IRQ routines were yet
written.   This was day two at Stradis.  Around lunchtime,
I realized that I was walking all over my DMA buffer.  I was
filling it with new data while the previous block transfer
was in progress. \\

After lunch, I wrote the code to poll for block transfer complete
before loading the new data into the buffer, and as if by magic,
I saw beautiful full-frame-rate NTSC output from the elementary
MPEG2 streams.   No audio yet, but beautiful video.   Audio would
prove to be a thorn in my side, and in the end a trivial bug,
but that is a story for later. \\

\section{Total Time Elapsed: 5 days.  No Interruptions}

The people at Stradis were impressed.  I found myself with a job
offer.   I was also given an opportunity to go to Las Vegas to the
National Association of Broadcasters 1999 convention to demonstrate
the card running in Linux.  Needless to say, I accepted the free
trip.   The show was mid-April, and between the design of the
new revision of the decoder board and preparing to ship everything
to the show and setup the booth, everyone at Stradis was quite busy. \\

At this point, the driver was working for MPEG video and still
using 99\% of the CPU because it used no interrupts.  I hacked out
some code to split a transport stream into audio and video streams
since the IBM chip required them to be written to different ports.
The driver needed to be moved to an interrupt-based architecture
as well to support the audio properly.   The IBM chip has a very
small audio buffer and a large video buffer.  Threshold interrupts
could be setup to tell the driver what buffer was starving for data. \\

Interrupts were a bit more complicated than I first imagined.
Thanks to Alan Cox, I learned the virtues of the wait queue.
Without {\tt \small \verb+wake_up_interruptible()+ and
\verb+interruptible_sleep_on()+}, I would have never figured out
how to structure the driver.  The driver also needed a true ring buffer,
but that would have to wait until after NAB99 which was quickly
approaching. \\

Just before the show I got the interrupt-based driver working
perfectly on my dual PII400 machine.  It was working on less
than 1\% cpu, and I solved that elusive audio bug.  Apparently
in writing the audio microcode I was trying to do 16-bit writes
when the chip could only take an 8-bit write so half of the
microcode was being lost to the great bit bucket in the sky. \\

Now I could take it to Las Vegas and show of a driver that uses next
to zero cpu and does both video and sound, and in the meantime
I hacked together the extra few lines of code it took to do
a fixed-size VGA video overlay to framebuffer memory.  Little
did I realize how absolutely horrid the performance of the
Compaq Presario that was used for the show was.   On the NAB99 show
floor I was hacking the driver back to do no interrupts and
no audio only minutes before the show was to open. \\


\section{After the First 99\% of Development Comes the Next 99\%}

Overall the major mysterious bugs in the driver were attributable
to pointer math being done behind my back.   Treating a 32-bit
pointer as an 8-bit pointer is not wise, especially if you must
wait through fsck on a Compaq Presario with a Quantum Bigfoot
drive.   The ring buffer code was no exception.   While in North
Carolina in May for Linux Expo, I was sitting at Red Hat trying
to figure out what was causing the random noise every time
the buffer wrapped around.   I banged my head against the desk,
played five levels of Ms. Pac Man, drank about twelve cans of
orange juice, only to find another elusive pointer error. \\

Dr. Michael Fulbright at Red Hat was nice enough to let me demo
my driver in the RHAD Labs booth at Linux Expo.  This demo
was complete with audio and video and starwars MPEG trailer.
By this point my machine had become a dual Pentium III 550,
so I knew that the real question would not be answered until
I got home from the conference and tried the driver on the
piece of work Compaq Presario.   Indeed I had a good solid
driver that even stood up as the Compaq began to swap. \\

Now the question came up from Stradis, "This is nice that it
all works, but you're still using the console to do everything.
We think it should have some graphical user interface like the
Windows version with VCR-like buttons."  But, luckily I'd just
listened to Miguel and Federico and decided that GNOME was
the way to go.   So far, this part has not materialized, but
some day it will.   I like to keep my hands in the kernel if
possible, and the original agreement was to write the driver
in exchange for two cards, and it mentioned nothing of a user
interface. \\

The driver also needed statistical collection and frame and
timecode tracking, as well as other functions not specifically
required for the actual playback of the MPEG files, but instead
for the applications that the board was actually intended for
when installed in a professional environment. \\


\section{Can I Buy You a Thought?}

I knew it would happen from the start.  Stradis came back to me
and said, "You know, it would probably be better if we didn't
provide our competition with everything that they needed to
reverse engineer our board and produce a cheap knockoff by
taking advantage of all the time and effort that we've invested
in the board."   Ok.  This is fair enough.   "There's a lot
of effort put into the FPGA code for example, and withholding
that would make it next to impossible to do anything with the
driver without obtaining a proper FPGA licence."   Enter the
next two weeks I spent moving all the intitialization code
around so that the FPGA and IBM microcode could all be loaded
runtime instead of included in the kernel itself. \\

Yet another chance to crash my machine.  In retrospect, it may
have been wise for me to setup a dedicated NFS server and use
NFS root for kernel development so that long delays from crashes
would be non-existant, but I have limited means at home.   The
new microcode loader also allows a user to change to new FPGA
code without ever recompiling the driver again.  This could prove
useful in a world of people who would not want to hack kernels.
The board is soft enough to allow one pixel wide timing changes
just by updating the FPGA code. \\

So what do we gain by allowing the firmware to be uploaded instead
of compiling in the kernel?   It means that some Asian knock-off
company will have a harder time reverse engineering the board
without the FPGA bitfile which not only lets the Stradis board be
more flexible than any other board, but it also was a considerable
investment in hardware development time.  Giving anyone this
firmware allows them to potentially copy the Stradis card and mass
produce it in such a way that Stradis could not compete as a small
startup company and would fail.  This eases the fears of Stradis
relating to the idea of an open source driver.\\

\section{The Alan Cox Seal of Approval}

After all is said and done, I still had to get the elusive Alan
Cox Seal of Approval.  I sent Alan a copy of the API changes, and
naturally he sent me back a one line cryptic reply as if I were
some coding machine.   Sometime around Linux Expo, I lost all of
Alan's comments on the proposed changes to the API.  Yes, there
were other comments outside of email longer than one line. \\

Once again, I sent an email with the proposed API (which just
happened to exactly match the one I had already implemented),
and he obligingly sent me back yet another suggestion.  After
a short chat, everyone seemed to be happy and Alan hinted that
we could see the new stuff in the 2.2.11 kernel.   I had earlier
met Linus when he did a keynote at a conference in Atlanta and
found out that there would be no problems getting the driver
itself into the 2.2 tree. \\

\section{The Extended Video4Linux API}

\subsection{VIDIOCSPLAYMODE:}
This set the output video mode (PAL/NTSC/SECAM) As well as
special features such as GENLOCK, Pause, Fast Forward, Single
Frame Step, Slow Motion, Normal Play, and Non-Interlace Mode,
Black Frame, and Colorbar output. \\

\subsection{VIDIOCSWRITEMODE:}
This tells the driver what type of data to expect on write().
The user-mode code could write compressed MPEG audio, MPEG video,
an on-screen-display overlay bitmap (alpha blending done in
hardware by the IBM MPEG decoder, written in native format),
Closed Captioning or Teletext bytes to overlay using the
SAA7121 video output, or MJPEG (which was for other devices, not
the Stradis decoder)  \\

\subsection{VIDIOCGPLAYINFO:}
This returns information about the current stream being played.
Info returned includes frames output since decode began, the
horizontal and vertical unscaled sizes, current SMPTE timecode
the current picture type, current temporal reference, and
the last user data found in the compressed stream. \\

\subsection{VIDIOCSFIRMWARE:}
This was added to load new FPGA bitfiles and IBM Decoder
microcode once the device driver is loaded.  A driver can
use the "loadwhat" field to address the given code to a
specific area of a card. \\

\section{Usage}
\subsection{The Simple Case}
{\tt \small \begin{verbatim}
cat susi_080.m2v >/dev/video0
\end{verbatim} }
for sending a video elementary stream to the decoder card for playback
without video framebuffer overlay. \\

\subsection{The Most Complicated Case}
{\tt \small \begin{verbatim}
parsempeg french.mpeg 224 192 \end{verbatim} } for sending a transport
stream with video on  PID 224 and audio on PID 192 for playback without
the video framebuffer overlay. \\

MPEG playback at its finest.  Multiple opens were hacked in around an
upper level Video4Linux restriction in order to allow a user to use
separate processes for sending the MPEG file to the card for decoding
and doing other controls with the card.   This way a Video4Linux-compliant
program such as tvset could be used for the VGA overlay while cat or
a more complicated MPEG parser is used to actually send the MPEG sequence
to the card for decoding. \\

Still remaining to implement is the MMAP capture interface of Video4Linux
and a poll routine to allow the user to use select to synchronize events
on the pending output decoded video frame.  \\

Alan also suggested that I use spinlocks.  My SMP system thanked
me immediately when I made that change.

\section{Conclusion}

At the start, I began to doubt that I would ever be able to get the
hardware to do anything and that Stradis would ask for the cards back
in frustration.   The moral of the story is always follow pointers and
never forget to check your references, and if you ever offer to write
a device driver in exchange for free hardware, even the coolest hardware
in the world, you are grossly underestimating your own worth.  The
mythical man month really was right after all. \\


\section{Acknowledgments}

Special thanks go to Alan Cox for his sage advice, and to the countless
people who helped edit this paper.

\section{Availability}

The Stradis 4:2:2 Hardware MPEG-2 Decoder driver and the development
diary is at
\begin{center}
{\tt http://mpeg.openprojects.net/}\\
\end{center}

\end{document}
