I think I have tracked down a problem that has been written about recently w/r/t the Linux implementation of USB to serial (RS232C) adapters (including modems attached via USB). I will preface my remarks by saying I have, if you'll pardon the pun, peripheral knowledge of what's going on, but not enough depth of Linux kernel or USB knowledge to fix it. This is with 2.4.21.
The problem: when running an interactive session through a USB to serial device (in my case, a Keyspan USA49WLC), as soon as the getty hands off control to login (in my case, mgetty running /bin/login), it sets the ldisc to the usual one, with bits OPOST and ONLCR on. The intent is that whenever \n is seen in the output stream, \r\n actually goes out over the device. Terminals and emulators of course expect that "\r" means "go to the leftmost column" and "\n" means "go down one line." Neither alone is sufficient for "newline," unless your emulator is told that one or the other of those symbols performs both functions (e.g., C-Kermit "set terminal cr-display crlf" coupled w/ setting OPOST|ONLRET). Examining drivers/char/n_tty.c, one can see the opost() routine which accomplishes this. If the tty's modes indicate both OPOST and ONLCR, and the octet to be output is \n, it checks to see there are 2 octets available in the device output buffer. If not, the write() fails. If OK, it calls the device driver's put_char with \r, then the generic part of the routine which outputs the char to be written, or \n in this case. If the device driver defines a put_char routine, it is called, but put_char is not generally defined. Therefore, the tty_default_put_char is called. This is simply a call to the driver's write() routine with length 1. Part of the problem is this is a function returning void. Now, at least in the Keyspan case, the write() routine has an INPROGRESS flag. The generic tty driver dutifully calls the device's write() with the data up to \n (if any), then writes a \r, then a \n. (Remember, put_char('\r') put_char('\n') gets turned into two writes of size 1.) The first one (of \r) goes through just fine. The second one (of \n) however sees the INPROGRESS flag, and dutifully reports back to its caller that the char has not been written (returns written count != requested count, basically). The routine that called it, serial_write(), also dutifully returns the count written. But the problem is that particular return value is discarded because the funtion that called it returns void. There's no "retry loop" or anything. My understanding of USB is that it's packetized, so the lowest level driver may be arranging to have those characters sent in a packet to the serial converter/adapter, hence the INPROGRESS. It would be waiting for the bh to signal that the host controller has finished with the buffer sent to it. So it's a timing issue: if there is enough time between those requests (as when I used insmod keyspan debug=1 with the console being a serial port), all is just fine and the display is "normal." If not, the opost() writes the \r, and drops the \n off the face of the Earth because tty_default_put_char() ignores the fact that request != return. So what's the most practical solution? Can serial_write() pause until INPROGRESS clears? Should a put_char() be added, and how should it be implemented? Should serial_write() just accept the charater and buffer it somehow, and write it onto the USB at some future time (such as in the callback routines)? ------------------------------------------------------- This sf.net email is sponsored by:ThinkGeek Welcome to geek heaven. http://thinkgeek.com/sf _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel