Write directly to a serial port from kernel space?

Hi everyone,

I am still working on improving my braille device driver. So far, it supports outputting data on two separate braille displays. Both of these displays are connected to the computer via USB cables. They cause no problems.

Now, however, I have gotten hold of a braille display that can only be connected to a computer via a serial cable. This machine doesn't have a serial port, so I managed to get hold of a USB serial adapter which is working fine under FreeBSD.
Ideally, I would love to integrate this newest braille display with my existing braille framework. But is it at all possible to write to a serial device from kernel space?

If I cannot directly write to a serial port from kernel space, what other possibilities do I have to add this braille display to my existing device driver?
One thing I am considering is to write a program (let's call it [cmd=]mkbrl[/cmd]) that would open the serial port and then, somehow, connect the braille display to the kernel so that the display got a separate device node. Would that approach work or be at all possible?

Looking forward to any reply.

All the best,
Peter.
FreeBSD 9.0-RELEASE Amd64
 
Of course it is possible, but is it wise? Don't know enough about your intent and motivations to be able to comment further. Why kernel space? Where does the data come from? (usually from user space).

BTW, I wrote a Braille translation program a few decades ago. It actually implemented much of NROFF to output formatted Braille using the same input files and for regular print. I don't think I would want to embed that kind of code in kernel space. As you know, for decent Braille output, there are many rules for shortening the output such that it is not a one-to-one ASCII text to Braille mapping (if done right).
 
Thanks for your reply.

You are right that the data will always come from user space to the connected serial device. For serial devices, I would be able to live with the fact that I should write a user daemon instead, since serial braille devices are almost non-existent (to the best of my knowledge).

But with regard to my braille device driver, it works like this and if possible, I should like for serial devices to receive the same treatment: When a USB braille device is connected, I probe for the device on its vendor and product IDs. If successful, I create a device node and I am now able to write output to the display as if it were a regular file. This means that most programs are able to support braille if they can redirect output to a file.
So, when I connect a serial device, I should like for it also to receive a device node. If I study the source code to mdconfig(8), that should provide me with a way to do it.
Or do you have any other suggestions?

As with regard to rules for abbreviations, I wonder why you wouldn't imbed that kind of code into kernel space? The way I see it, it's a generic braille thing so it could be implemented once for the displays I currently support and, if new displays were added in the future, they would also support text abbreviations and I would think this a feature.

I hope this has cleared things up a bit.
Regards,

Peter.
FreeBSD 9.0-RELEASE/AMD64
 
I'm not sure that you can trigger those sorts of actions merely by plugging in a serial port device. Certainly standard serial ports don't have that hardware mechanism, although perhaps special serial ports might have it.

But serial ports come already pre-configured at boot time and device nodes are already created for each existing serial port. I could imagine a smart program using modem control signals to trigger some actions, or a daemon waking up to a new serial device based on some stream of characters being sent in. But why bother with all that. The nodes are already created, e.g. /dev/ttyu0, so you just plug in your brailler printer and send stuff to the /dev/ttyu0 file like any other printer. Or you can write a daemon to handle the device, particularly if you also want to do Braille translation on the fly.

I would definitely put Braille translation in either a user space program or daemon, not in the kernel, for similar, though less extreme reasons as to not putting English to French translation in the kernel. Braille translation is not simply 1-to-1, nor even strictly rule-based. There are numerous abbreviations and shortcuts that are best handled by table lookup -- you need a dictionary, one that should be changeable, and other rules that depend on word context, so you need to buffer a phrase if not a whole line. When you go to translate a word, there are often several different possible contractions that could be used. You pretty much have to try them all out and figure out which one leads to the shortest result *for the whole word*. There are also many idiosyncrasies that pretty much just have to be handled in an exceptions table. All in all, not the kind of stuff for kernel space...
 
monkeyboy,

Thanks again for your reply. I have resigned myself to write a user daemon for that device and use sockets (or similar mechanisms) for communicating with that device. At least, I'll go down that route and see where that leads.

I know that braille has many abbreviations (I'm blind myself so I've used it since going to school), so I know most of the things about abbreviations. I also have rules and tables for both Danish and English abbreviations, but I'll work with that later once I've sorted out some other things.

Out of sheer curiosity: I don't understand why you wouldn't want to imbed abbreviations into kernel space. The way I see it, the keyboard driver does something similar with its keyboard layouts. A userspace program feeds the kbd(4) driver its layout via an ioctl(2) call. Why couldn't (or shouldn't) one do the same with braille abbreviations? I don't want to imbed abbreviations directly into the C code. That would be the worst possible way to do it, I agree with you on that point. I would go for the way that kbdcontrol(1) gives the kbd(4) driver its layout. I am quite aware that the one-to-one mapping of characters doesn't work in the case of abbreviating words, but I think it should be manageable to imbed some logic in kernel space by creating a hash table containing word parts and their corresponding abbreviations upon receiving an ioctl(2) call and store the data in the softc structure associated with each device. At least, I've seen similar things done before in drivers in the FreeBSD source tree.

A few more things: I am not against keeping abbreviations and such in user space and I could write a daemon to take care of that, but I also think it could be worthwhile to have a framework in the kernel for braille devices as we do for other types of devices. Especially some braille stuff that's BSD licensed - it doesn't exist out there

All the best,

Peter.
FreeBSD 9.0-RELEASE/AMD64
 
I am hearing that you propose to embed a full blown Braille translator in kernel space. To me, that is like embedding a language translator in kernel space... perhaps its just me, but I generally believe in the notion that the kernel is for minimal services that users cannot do on their own.

I still don't have a sense of just how acquainted you are with Braille. Would you embed Grade 0, 1, 2 *and* 3 translation in the kernel? You realize you would have to buffer at least lines and words in the kernel. In fact, to get Braille formatted PAGES correct, you'd have to know about the complex rules of formatting Braille pages. And of course Braille differs from language to language and even has different rules within languages, depending on context. You really want to code logic in the kernel to keep track of whether a " character is an open " or a close " (ASCII doesn't have that distinction).

Its not just about abbreviations/contractions, but also the context they are in. For example, "th" in "think" is coded differently than "th" in "pothole". And Braille is somewhat dynamic and threatens to be regularized, hopefully for the better, again not the kind of stuff that belongs in the kernel. I see it very differently from a keyboard map.
 
Well, I know about the braille grades you're talking about. So far, I've implemented the regular computer braille and I am considering implementing grade 2 at some point. Whether I should imbed that in kernel space or not, I don't know. You strongly advise against it, so believing that you're the better qualified, I'll keep your points in mind. The "proper" way to do it would then be to make a user space daemon that did the translation into Grade 2 braille and send the resulting shortened strings to the kernel device driver, if I understand you correctly. The kernel could then still handle the protocol-specific tasks of writing the strings to the various braille displays. Would that be the way you'd do it?

I am fully aware that it's a complex topic. I have looked at various braille source code (the only package that comes to mind makes a difficult job much more difficult by hiding all the complexities). I still want to tackle this in a meaningful way and if the translation into Grade 2 requires a separate user daemon that would sort of be all right, but it would limit the usefulness of a unified API for standard programs and we'd end up with a situation where programs would have to be re-compiled or rewritten to get decent braille support.
One of the things that makes the braille driver shine compared to, for example, BRLTTY, is that standard programs such as [cmd=]echo[/cmd] , [cmd=]mplayer[/cmd], [cmd=]csh[/cmd] doesn't need to be changed in order to support braille output, since they can redirect their output to a file, in this case a device node. They would require many changes if I were to try and imbed brltty-specific functions into their code base. BRLTTY is a fine program, though, but I think that hardware support should be the kernel's job and not a userspace job.
 
peterlaursen said:
The "proper" way to do it would then be to make a user space daemon that did the translation into Grade 2 braille and send the resulting shortened strings to the kernel device driver, if I understand you correctly. The kernel could then still handle the protocol-specific tasks of writing the strings to the various braille displays. Would that be the way you'd do it?

One of the things that makes the braille driver shine compared to, for example, BRLTTY, is that standard programs such as [cmd=]echo[/cmd] , [cmd=]mplayer[/cmd], [cmd=]csh[/cmd] doesn't need to be changed in order to support braille output, since they can redirect their output to a file, in this case a device node.
Yes, the role of a Braille daemon as I would suggest is what you are describing. But, while I've not used BRLTTY, it sounds essentially exactly like this daemon. So I am not understanding what it is that BRLTTY doesn't do that you want. It looks pretty good and thoughtfully designed.

I'm not understanding why you say that csh would need to be changed. And I don't get why you talk about such commands redirecting output to a file. Why would you do that? I assume you are talking about using a "refreshable" Braille display, a one-line Braille tactile device. Or are you talking about Braille printers?

For a refreshable display, I would think you want to create a shell, even the login shell, whose standard (and error) output ports (1 and 2) are captured by the Braille translation process which in turn would drive the Braille refreshable display. I assume you know about the script(1) command. If not, look it up and see if its architecture meets your needs. It gives you a shell where the output is captured by the script process and copied into a file. You could use the same method to capture text output from any program and funnel it through a Braille translation routine before outputting to the refreshable display.

For a Braille printer, it would seem to be even easier to make a Braille translation filter that gets inserted into the line printer daemon architecture (e.g. LPR, printcap or CUPS).

All of this stuff is in user space.
 
I am talking about a refreshable braille display. While BRLTTY drives everything from user space, I don't see that as a wise solution, since the operating system (which, I hope you agree) should detect and communicate with hardware devices directly if at all possible. I still see it as the kernel's job to communicate with the hardware, thereby making it easily accessible for other programs through device nodes.
For example # echo 'braille test' > /dev/brl0 would print the text to the first connected braille display if my driver was loaded.
If I were to do this using BRLTTY and its corresponding API, I would have to rewrite the echo command in order to add braille support, which is one of the many reasons why only a handful of programs supports native braille output. I don't understand your reasons for wanting to communicate with the hardware in user space rather than in kernel space?

I should add that I am also writing this device driver for educational purposes, so I do appreciate your inputs very much. I am just trying to understand your reasons for preferring that all this should be done in user space rather than in the kernel, where I think hardware communications belong.

While the script(1) command would do the trick sometimes, it wouldn't necessarily work in single-user mode or during FreeBSD installation, which are some more reasons for me preferring kernel space.
 
peterlaursen said:
I am talking about a refreshable braille display. While BRLTTY drives everything from user space, I don't see that as a wise solution, since the operating system (which, I hope you agree) should detect and communicate with hardware devices directly if at all possible. I still see it as the kernel's job to communicate with the hardware, thereby making it easily accessible for other programs through device nodes.
Well, yes and no. I would not embed a Postscript preprocessor in the kernel, nor code to format, interpret or do complex line handling in a printer driver. Low level communications and I/O handling, yes of course it belongs in the kernel. But a Braille translator is more akin to a Postscript or PCL filter than a communications protocol handler. OpenGL doesn't belong in the kernel either. These kinds of big, software-based filters and pre/post-processors are often best done in firmware in the device. That's where Postscript itself usually lives. If not in firmware, then in user space filters (e.g. Ghostscript, all of the printer filters in printcap, etc). It sounds like you want to treat the Braille display as if it had a full blown Braille translator in firmware on the device, but it doesn't so you want to emulate that in kernel. But it get messy at the edges, like at boot or install time, when such high-level pre-processing software isn't on board yet...
peterlaursen said:
For example # echo 'braille test' > /dev/brl0 would print the text to the first connected braille display if my driver was loaded.
If I were to do this using BRLTTY and its corresponding API, I would have to rewrite the echo command in order to add braille support, which is one of the many reasons why only a handful of programs supports native braille output.
But echo, csh, indeed ANY program that did standard input/output to a terminal would work fine with BRLTTY or the script(1) style method, without any mods or rewrites needed to the basic Unix software. Things would only be problematic, maybe, during boot or install time, which is the small exception. Indeed, its my understanding (not being blind), that actually text-to-speech based solutions are preferred for many text-only situations, and would work just as well, if not more efficiently for the boot and install phases (I do installs only every few years per machine). The Braille display is most useful when line and page formatting are critical, like page layouts, tables, etc -- but you should tell me if you agree.
peterlaursen said:
I don't understand your reasons for wanting to communicate with the hardware in user space rather than in kernel space?
Not sure what you mean... its the kernel that is still doing the low-level I/O, interrupt processing, handshaking etc. I don't view Braille translation as a "communicating" piece of the system. It is a high-level software-based pre-processing filter and formatter, requiring user-loadable tables, algorithm/rule changes depending on user context, and extensive "read-ahead" and "look-behind", it has to understand the notion of words, even sentences and text pages -- all high level stuff. These elements are not low-level communication tasks.
peterlaursen said:
While the script(1) command would do the trick sometimes, it wouldn't necessarily work in single-user mode or during FreeBSD installation, which are some more reasons for me preferring kernel space.
Tricky but not impossible to have it work during installs. Definitely not that hard to have it work in single-user mode. I believe BRLTTY claims to be able to work under these conditions. Embedding in the kernel won't make it work during BIOS or loader booting and you'd have to do a kernel .ko module because it won't work in standard install kernels as distributed. In these cases, it really belongs either in firmware in the display, or an outboard "smart module" that sits between the serial port and the device.

For a real solution, if I couldn't convince the manufacturer to stick this in the firmware, I would get a small smartmodule and put it in that device's firmware. But to start, I'd say the script(1) would work 99% of the time, the major missing piece is for graphical/GUI software, like KDE, Gnome, and their apps. But kernel won't be better for that anyways. There probably is a way to get X Windows to funnel text through a Braille daemon, but I haven't looked into such an idea.

That's my rec anyways, take the script(1) source code strip it apart to divert the output to your display... solves 99% of the text-based programs with no mods to those programs. Then look into getting a programmable smart module of some sort (e.g. Raspberry Pi for $25 http://www.raspberrypi.org/faqs or similar cheap DOS-based or ARM-based module) and shove the translator into it to sit between Freebsd and your display. It would work for 100% cases and won't depend on FreeBSD.

Maybe part of the disconnect here is that I'm thinking Grade 2 "contracted" Braille, whereas perhaps you are focused more on Grade 0 "computer Braille". Yes Grade 0 is so stripped down and simplistic that it perhaps could reasonably be stuck in the kernel as a sideshow to the tty(4) interface. I could see that. But not contracted Braille. Perhaps that's a good compromise, as Grade 0 would probably get you through installs and boots, but to do proper contracted (Grade 2) Braille, it requires a whole lot more that, in my opinion, doesn't belong in the kernel. Grade 1 (non-contracted), well a toss up, but still far, far simpler than Grade 2.
 
Thanks for an insightful discussion, monkeyboy.
I'll mark this thread solved since I've reached the conclusion that I'll write the serial port stuff in user space and perhaps work on the grade 0 to grade 2 translator in user space using script(1) as you've suggested.
For grade 0 braille, script can easily output to a device node if done properly.

Making this driver independent of the FreeBSD kernel is not currently high priority since it's basically a one-man project and I'm currently more interested in getting more hardware supported by my existing USB driver. Your idea of imbedding the translator into hardware is a good idea as long as I can keep the stuff BSD-licensed.

Best regards,

Peter.
FreeBSD 9.0/AMD64
 
Back
Top