Dr. Dobb's Journal June 2001
This month, we continue the exploration of Linux as a development platform. I said a while back that I needed a project to develop, a raison d'être. I've found two programming projects that I need to begin with a programmer's editor that suits me and a device driver. I'll address the genesis of both projects this month.
I haven't weaned myself from the Windows operating environment and might never. The reason is the season. I'm writing this in mid-March as the ides of April looms near, and I don't know of a trustworthy Linux replacement for TurboTax, particularly one that can import last year's tax data. (The ides of April is really on the 13th for those who care. Besides, we have until the 16th this year.)
Most of my work these days uses the laptop also because of the season. I explained in the April column the difficulties I had getting Linux to work on the laptop. It's finally working, and I'm on the road a lot this month. Those who made fun of us Floridians during our November-December dance of the dangling chad must sing a different tune in March. We have Spring Training and you don't. Almost every Major League baseball team is within an easy drive of my house. Eat your hearts out, sports fans. The DobbsMobile runs steadily between my house and the training camps during March. I take advantage of each trip to search out fellow programmers and write in solitude while Judy takes in the baseball games. She's a bleacher screecher, so by April, she's tan and hoarse. Every man's dream. A beautiful bronze soulmate who loves sports and can't talk back. Only lasts a couple of days, though. I get to go to about every third game, still having to work, you see. Judy is the sports nut in this family. She'd watch a snake fight if they'd put it on television.
On a recent such trip, I was the recipient of some minor road rage. The DobbsMobile is a 37-foot RV without some of the driving conveniences of a car like a rear-view mirror and good side visibility. The side mirrors work for normal driving, but those angled on-ramps can put a driver into a blind spot unable to see oncoming traffic. When that happens, you learn to find your merge opportunity in advance and then just plow in. That almost always works. Drivers in Florida usually give big motorhomes a lot of room, figuring the driver is a white-haired old guy with poor eyesight, hard of hearing, slow reflexes, Viagra in the medicine cabinet, and Glenn Miller on the stereo. My eyesight is just fine, thank you.
The blind merge doesn't work when someone in the lane you've targeted speeds up or someone in an adjacent lane decides to come over. That's what happened this time. As I merged, I saw out the side window a top-down convertible in my lane, where I was about to be, veering left toward the other lane to miss me, then squealing rubber back over about two feet in front of me. The driver blew his horn after he got in front of me. Why do they do that? He had changed lanes because he wanted the exit coming up, and I guess he figured I'd see him and yield. Now he was mad. I saw him scramble for pencil and pad in the glove compartment. He had seen the Dr. Dobb's Journal logo on the side panel with my name, editor status, and e-mail address, and he wanted to write it down. He was going to write a letter to the editor, by gum. Trouble was, in the heat of the moment, he didn't remember what the side panel said. What he saw in his rear view mirror was like Figure 1, the front of the DobbsMobile, which displays only the magazine's logo. Imagine his confusion and frustration as he tried to drive his car, keep out of the way of this huge vehicle bearing down with some crazy old guy at the wheel, not miss his exit, read the logo in reverse, and write it all down. Assuming he got it, all he had was the Dr. Dobb's name. If he isn't a programmer, it might not mean much to him.
I never got that letter. Maybe some chiropractor in Pinellas County got one, but I never did.
I do get letters, though. I've received many letters from readers about my sojourn into Linuxland, and many helpful readers have addressed the problems I've reported. Because I write these columns about two months in advance, I sometimes have a solution before the column that reports a problem is published. Don't let that stop you, though. If I need help or get something wrong, I want to hear about it. I get a lot of the same advice, which is reassuring, particularly if it agrees with what I've already discovered for myself. When it does not, that gives me something more to think about. In the past, I've tried diligently to answer all the e-mail that this column gets. I can't promise to continue doing that, though, because of the high level of interest my Linux comments generate.
Several readers requested that I refer to Linux as GNU/Linux. Richard Stallman made the same request in an e-mail exchange that I published a while back and again in a letter to DDJ in April of this year. Linux, after all, is only the kernel. Much of the rest of the OS's environment is based on work produced by the GNU project. It's probably the right thing to do, but don't expect many people to comply. Until the major Linux distributions and all the book publishers make the same concession, I doubt that the full and proper designation will stick. Besides, it's inconvenient to remember to type it that way. Maybe they should name it Glynnix or something cute like that.
Most of the letters I receive are positive and supportive. But if you ever write an article about Linux, beware that some Linux enthusiasts share a common malady, a syndrome of the closed mind commonly called "tunnel vision." Here's how the ailment manifests itself. You write many positive things about Linux in your article. Then you question only one thing, one little old negative thing. The wagons circle and the flaming arrows arrive in the next mail. Not only do they call your sanity and ancestry into question, but to demonstrate your ignorance, they proceed to make the very same proLinux arguments you yourself made in your article.
Just thought you ought to know. I understand emacs zealots are like-minded. Now, watch me ignore my own warning...
We programmers get emotional, chauvinistic, and evangelical about our editors. You take your life in your hands when you blaspheme an editor program.
Over the years, I've used so many different editors that I really don't have a favorite. I can use almost any editor as long as it does not have characteristics that annoy me and that I cannot change. But every editor that comes with Linux and KDE has at least one such annoying characteristic. That includes emacs, the holy grail of programmer's editors, which has several.
Emacs is a wonderful program. They call it a programmer's editor, but it is much more. It is a marvelous programmer's environment with many tools and extensions and support for custom user extensions. Beyond that, I won't enumerate emacs's positive attributes. If you are an emacs evangelist, I hereby give you my permission to ignore the nice things I just said about it and zero in on these criticisms. You probably will, anyway.
Mostly I like emacs, but I don't like everything about it, particularly the XEmacs GUI version. Maybe what I don't like is what I don't know how to change. And some of what I don't like is not in emacs itself but in the packages that people have contributed as extensions. The documentation accompanying the software tries to be helpful, but it's really only reference material for those who already understand the program. There's a tutorial, but it does not discuss configuration and extensions. Somebody out there needs to write "Emacs for Dodos," or "Teach Yourself Emacs in 68 Months." Herb Schildt, are you listening?
When editing text, I am accustomed to using the up and down arrow keys to scroll the display. When the cursor hits the bottom of the window and I press that down arrow, I like for the text to scroll up one line leaving the cursor on the next bottom line. Lots of other people must like that, too, because that's how most text editor programs do it. But with emacs, when the cursor hits the bottom line, the text scrolls up a half a window's worth, moving the cursor up to the middle line. I have to go looking for where I was in the text, and I don't like that. I don't care how many programmers are used to it, it just ain't intuitive. There has to be a way to change that behavior, short of getting the source code and recompiling the program.
I don't like most of how the compiler tool is implemented. You can program the command that emacs uses to invoke the compiler, but I can't find how to program it to use the current editor window's filename to invoke the compiler command. (Maybe it's there, but I haven't found it yet.) I'm one of those older programmers who think you shouldn't need a complex makefile just to compile and link a simple "hello world" program. I also wish the compiler tool could automatically associate error messages in the compiler output with the offending line of code in the edit buffer window, IDE-style. Even venerable old Brief could do that. Maybe the emacs compiler tool can't do it because emacs doesn't keep a running display of row and column numbers where the cursor is positioned. That's something else I don't like.
I really dislike how emacs imposes its default styles on source code text files. Its notion of brace placement and indenting is seriously impaired. Okay, so that's a personal preference, but emacs refuses to permit overrides. For example, there are lines of text wherein emacs decides you can't insert a tab character at the beginning of the line. No overrides, you just can't do it. After some poking around I figured out how to turn that feature off. Of course, I lost all the other smart indenting at the same time. Then, after a reboot, the feature suppression did not persist, and I found I could not get it to work again. So for now, until I figure it out again, I edit C and C++ text files without the filename extensions. That's really lame.
Finally, XEmacs has one more annoying behavior. Every now and then it decides that you can't terminate it. I'm not sure what conditions bring this about, but it happens a lot. None of the usual ways of terminating a program work. They have no effect. The program is running and it's going to keep running. You can still edit text files and use the extension tools, but you can't exit from the program. You have to use the Ctrl+Esc command to open the list of current running processes and kill XEmacs. They ought to fix that.
XEmacs, with all its annoyances, is still the only GUI editor in the current Linux distribution that I can bear to use. All the others have one other annoyance that makes them totally unusable. The font they use is unreadable and unchangeable. Programmers need to be able to tell the difference between parens and braces, for example, and you can't do that with this crippled font in these crippled editors.
Surely, I'll get flamed by programmers who think I ought to take the time to burrow through the arcane scripts and hidden documentation and learn how to configure emacs to my tastes. I might be willing to get into emacs customization if its script language was more like C and less like LISP. (Why do they always boast about something being "LISP-like" as if that was something a C programmer would want?) The last thing I need is to learn another programming language. Well, maybe not the very last thing, but it's pushing "Snoop Doggy Dog Sings Puff Daddy's Greatest Hits" for bottom of the list.
It's a question of priorities. Learning and doing all that configuration takes a certain amount of skill, which I have, lots of patience, which I have not, and a tolerance for drudgery, which I have only begrudgingly. Having written several editors, including one for the Quincy IDE, I know how it is done, and I have the source code. What better first project than porting that editor, which uses contemporary Standard C++ idioms such as namespaces and STL, to Linux? Surely it would be more fun than modifying some other old editor. It probably wouldn't take as long, either. Then and only then will I have my editor of choice. Unless one of the many flames I receive about this discussion includes something really useful a URL where I can find the perfect programmer's editor or the ideal emacs configuration file.
Assuming I reroll my own editor, what application framework will I use for the project? I had thought that I would use the KDE framework classes. I also considered the QT class library upon which KDE is built. Neither framework uses the newer features of Standard C++, such as namespaces, new-style casts, STL container classes, exception handling, and so on. In their quest for platform independency, they seem to have settled on the lowest common denominator compiler.
As a result, I am combing the Web for other GUI application frameworks. Following my comments that I was zeroing in on KDE a couple of months ago, many readers e-mailed suggestions for other packages to look at. Consequently, I have not yet chosen a programming environment for applications development on Linux. If I don't find one, my first project might be a wrapper.
My second project does not need an application framework. It is a device driver for the Roland UM-1 USB MIDI Interface Cable, and I'll probably write it in C.
My laptop does not have a MIDI port connector. The Roland cable adapts the USB port to MIDI IN and OUT. No Linux driver came with it (Windows and Mac only) and I have not found one to download. There are many MIDI applications for Linux that I want to run on the laptop, and I plan to port some of my custom MIDI apps to Linux too, so I need to be able to communicate with MIDI devices from the laptop. Traditionally, computers used the game port on sound cards and a MIDI adaptor cable. My laptop does not have a game port. Toshiba assumes you'll just go get yourself a USB game controller device, I suppose. The Roland device takes care of MIDI for my Windows apps, but I want it to work with Linux, too.
MIDI IN and OUT ports are similar to serial ports. They use much of the same hardware but with opto-isolators for the electrical signals and at a fixed baud rate, which is not one of the standard serial port baud rates. Applications software to read and write MIDI IN and OUT should be virtually indistinguishable from software to read and write the serial ports. The device driver should be similar to that for serial ports too, except that in this case it has to speak to the USB port instead of the old-time COMn devices.
This project involves several learning curves. I already understand MIDI protocols and how to write a C/C++ program in the Linux command-line programming environment, so those curves are flat for me. But I did not know how to write a Linux device driver. To that end, I got the book, Linux Device Drivers, by Alessandro Rubini (O'Reilly & Associates, 1998). The publisher has a large inventory of Linux titles and is one of the movers and shakers in the Open Source movement. O'Reilly manages to keep older books in print as long as they are relevant, in contrast to the publishing model of larger trend-driven publishers who kill off technical titles as soon as they are several months old and not hot sellers anymore. Linux Device Drivers is one of the best programmers' books I have ever read, and I do not say such things lightly. It covers the subject completely, is well organized, uses relevant examples, and is written in a clear and concise style.
Linux applications communicate with device drivers by using the Linux filesystem. Programs open, close, read, and write devices by using direct input/output functions instead of stdio and iostream buffered I/O. Applications also use the ioctl function for low-level commands to the device.
Linux implements devices as pseudofiles in the filesystem under the /dev subdirectory. The MIDI file is /dev/sequencer, for example. (There is also a /dev/sequencer 2, but I don't know its purpose, yet.) A program opens the pseudofile and reads data from and writes data to the pseudofile. You create such pseudofiles with the mknod command at the command line or in a shell script. By themselves, these files do nothing. There must be an associated device-driver program, also called a "module."
You install a device-driver program, which is a relocatable object file built by the compiler, by issuing the insmod command on the command line before applications can use the device. The insmod command links the driver to the kernel. You can also permanently link the driver by rebuilding the kernel. When the driver is installed, it registers itself and its capabilities with the kernel.
Each pseudofile has associated major and minor numbers, which you specify as mknod command-line options, and which the driver conveys to the kernel when it registers itself. The major number associates the pseudofile with its device driver module. When a program opens, reads, and writes a device pseudofile, the kernel passes those operations to the device-driver module associated with the pseudofile by the major number.
Linux Device Drivers uses a memory-based device driver named "scull" or "skull," depending on where you are in the book, to demonstrate how device drivers work without actually implementing any hardware. To show you how to build a real driver, the book uses the standard parallel port to implement a device and its driver. These are intuitive examples and ones a programmer can use and experiment with to learn about device drivers. The book includes a lot of source code and no disk, but it doesn't seem to tell you where to get the source code, so I'll tell you: ftp://ftp.ora.com/pub/examples/linux/drivers/.
The author makes one silly mistake, a common one among programmers who do not understand contemporary programming idioms (C programmers, for example). When a device driver registers itself with the kernel, it passes the address of a file_operations structure, which contains the addresses of the driver's functions to implement open, read, write, and so on, operations. The author says, "This design is the first evidence we've seen of the object-oriented design of the Linux kernel." Nonsense. Over the years, I've watched as people in this industry (mostly marketeers) appropriate, misuse, and consequentially redefine such previously clear and concise technical terms as "relational database" and "structured programming." It's really amusing to see a time-worn tradition like a structure with function pointer members being called "object oriented," particularly when the faux pas comes from such a good programmer and writer.
My second learning curve is the USB system. As I write this I do not yet understand USB protocols. To that end, I downloaded the USB specifications document from http://www.usb.org/developers/ docs.html. It's a 5.5-MB zip file with PDF documents, which tells you everything you ever wanted to know about USB except how to write a USB driver for a particular device. But an understanding of the underlying hardware is essential for a device-driver author, and this document explains that part of the problem.
Linux distributions include all the source code for existing USB device drivers, so I have those programs to study as well. They seem to use the device-driver idiom called "layered modularization," which the Rubini book explains in detail.
My last curve might be a steep one. I have to know specifically how the Roland UM-1 device works. I am about to try to find someone in Roland who can provide the specifications. This is the biggest stumbling block most Linux device-driver authors encounter cooperation from the hardware vendor. Winmodem programmers have many such tales to tell. I don't think the vendors necessarily want to keep their protocols a secret. It would be in their best interests to have more software and platform support. I think instead that it's just difficult to find a person in a vendor's organization who has the technical knowledge you need and the authority to pass it on, particularly when the knowledge is located in another country and the people speak another language.
If I cannot find what I need from someone within Roland, I can always reverse-engineer the Windows device driver. Where is Andrew Schulman when you really need him?
DDJ