Writing serial drivers for OS X (1)

At least one thing can be improved on Mac Dev Center: the code sample repository. I am not talking about documentation. In this particular case, there’s not much new to write about. The I/O Kit documentation (grab the pdf while it is stil there) is sufficient. On the shelves are tons on books about C and C++. What I want is a collection of simple, better templates (examples) that cover each and every major IOService (pdf) subclass. To refresh memory,  IOService is the sole direct subclass of IORegistryEntry and is the base class of almost all I/O Kit family superclasses. IOService defines methods that support the life cycle of I/O Kit drivers. Or, simpler: drivers are subclasses of IOService. Keep this in mind. I’ll get back to it.

I have zero experience in writing device drivers in general, not only for Mac. But this project of mine made me do it. It is a pain not because “writing device drivers is a black art” (which, by the way, it isn’t), but because it is a black art due to the lack of examples and poor communication skills of some writers that stubbornly refuse to allow complete coverage of the code they are reviewing. I went over Ole Halvorsen’s / Douglas Clarke’s book (I bought a kindle version): quite a good reading with the only gripe that some examples are a pain to follow and the companion code (that can be downloaded) does not include exactly the chapter 11 project, i.e. the serial driver. LOL 🙂 😀 Bummer.

To keep with my previous idea, to make things more complicated, writing device drivers is a never–ending code–install–test–kernel panic–restart–code… (etc) loop, with emphasis on kernel–panic part. Normally this is done with two machines, one for coding and one for debugging. But I have only one MacBook and I went through multiple kernel panic situations which I don’t know how will fingerprint my machine’s life expectancy… FYI, fingerprinting is a newer addition to the corporate boilerplate language. For example, “this decision will fingerprint the project”, another, posh, way to say “this bullshit of yours will bring down the entire damn thing”.

Sample cu explanation

Serial ports are commonly misunderstood. Having been involved with them for a while I thought I clear up some of the confusion.

The two ports are actually named after their traditional usage. A tty.* port was intended to run getty on a directly connected terminal, a terminal that, if wired correctly, asserts DTR (one of the RS232 signals). A getty process using a tty.* serial connection would block in open until the TTY asserted DTR (that is the terminal was switched on).

The cu (call unix) port was used mostly by the uucp family of unix communication tools, that is the unix email system used before the advent of the internet. To cause a typical modem to dial, it was necessary to open the port without waiting for DTR, which is typically only asserted one a connection has been established after dialing. WIth an open port uucp could then issue an AT command and wait for a connection with the other side. With an established connection the modem asserts DTR, from that point on the cu and tty ports are exactly the same. Note with many modems the DTR signal often tracks DCD (carrier detect).

With either port type once a raised DTR signal is dropped the port is disconnected and will start returning EIO errors. This is basically a hint to the client process that things have come to an end and need to terminate all processes in the process group connected to the terminal port.

One problem with this basic design is that sometimes tty or other serial devices are connected using only 3-wires, that is ground, txdata, rxdata. In this case the standard tty port will not open. You have two options in this circumstance. The more difficult option is to loopback the DSR to the DTR on the computer side of the rs232 plug, or alternatively you can open the port with O_NONBLOCK then use tcsetattr to set the CLOCAL flag indicating that DTR should be ignore.

Finally although this is the canonical interface the only serial drivers that I know implement the full RS232 signal protocol are Apple’s 16×50 drivers. I’m not sure how much of this signalling is implemented by any other driver, so your milage will vary. In retrospect it perhaps would have been a good idea to document this somewhere ;-).

I start this new series with the intention of documenting my attempts of writing serial port drivers for mac. This will be the first post in this series. More to come

Filed in C stuff, Kernel and drivers, Serial. Bookmark the permalink.