On Thu, Mar 27, 2008 at 11:37:38PM +0100, Tilman Schmidt wrote: > On Thu, 27 Mar 2008 14:58:50, Karel Zak wrote: > > I don't think that we have to care about difference between termios > > and termios2. It's glibc job (and glibc supports the new method > > when available). > > Be that as it may. What glibc does not support, however, is the actual > benefit of the new method, namely setting arbitrary bit rates. The glibc > functions only accept speed_t values (ie. the limited set Bnnn constants > defined in asm/termbits.h) for specifying the input and output speeds. Yes and no... ;-) Few notes about speed: 1/ you needn't to translate the speed (number) to Bxxx constant. This translation is supported by cfsetspeed() -- unfortunately there isn't any man page about it. You have to read glibc source code... 2/ the range of supported speeds is checked by cfset{i,o}speed(), so you cannot use it for arbitrary bit rates. 3/ fortunately, it seems that tcsetattr() (that translate from glibc to kernel termios) doesn't check the speed setting. So you can bypass cfset{i,o}speed() and set it manually. ... so, see the patch bellow. > That is what I did initially. It earned me a request from Mike not to > "start off with a hobbled program". Sometime, the perfect is the enemy of the good :-) > > Is there any way how to test ldattach(8)? Do you have any simple > > test (I don't have GIGASET_M101;-) ? > > You don't need one. The LD will happily load without a device attached > and only complain afterwards if nothing responds on the line. So if you > have a kernel built with CONFIG_GIGASET_M101=m (like most current > distribution kernels I know of) or =y you can test with the GIGASET_M101 > LD and watch for the syslog message: > > kernel: ser_gigaset ser_gigaset.0: Could not initialize the device. Cool. See (non-standard speed): # lsmod | grep gigaset # /ldattach -s 999999 M101 /dev/ttyS0 # lsmod | grep gigaset ser_gigaset 17993 2 gigaset 57809 1 ser_gigaset crc_ccitt 10432 1 gigaset isdn 132513 1 gigaset # dmesg ... gigaset: Driver for Gigaset 307x ser_gigaset: Tilman Schmidt ser_gigaset: Serial Driver for Gigaset 307x using Siemens M101 ser_gigaset ser_gigaset.0: Could not initialize the device. Karel >From d14b5161e7a84f95a6873dc6537d584de9e5a8b6 Mon Sep 17 00:00:00 2001 From: Karel Zak <kzak@xxxxxxxxxx> Date: Fri, 28 Mar 2008 02:16:37 +0100 Subject: [PATCH] ldattach: use glibc termios Signed-off-by: Karel Zak <kzak@xxxxxxxxxx> --- sys-utils/ldattach.c | 146 ++++++++++++------------------------------------- 1 files changed, 36 insertions(+), 110 deletions(-) diff --git a/sys-utils/ldattach.c b/sys-utils/ldattach.c index a696e88..801dd1c 100644 --- a/sys-utils/ldattach.c +++ b/sys-utils/ldattach.c @@ -21,7 +21,7 @@ #include <fcntl.h> #include <sys/ioctl.h> #include <errno.h> -#include <asm/termbits.h> +#include <termios.h> #include <unistd.h> #include <err.h> @@ -31,15 +31,16 @@ do { if (debug) fprintf(stderr , "%s:" format "\n" , progname , ## arg); } while (0) #ifndef N_GIGASET_M101 -#define N_GIGASET_M101 16 +# define N_GIGASET_M101 16 #endif -#ifndef PACKAGE_STRING -#define PACKAGE_STRING "me" +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #endif -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +/* attach a line discipline ioctl */ +#ifndef TIOCSETD +# define TIOCSETD 0x5423 #endif static const char *progname; @@ -78,105 +79,6 @@ static int lookup_ld(const char *s) return -1; } -/* replacement for tcsetattr(3) and friends supporting arbitrary speed values */ - -/* some archs don't have separate struct termios2 */ -#ifndef TCGETS2 -#define termios2 termios -#define TCGETS2 TCGETS -#define TCSETS2 TCSETS -#define TCSETSW2 TCSETSW -#define TCSETSF2 TCSETSF -#endif - -static int tcgetattr2(int fd, struct termios2 *pts) -{ - return ioctl(fd, TCGETS2, pts); -} - -static int tcsetattr2(int fd, int option, const struct termios2 *pts) -{ - int request; - - switch (option) { - case TCSANOW: - request = TCSETS2; - break; - case TCSADRAIN: - request = TCSETSW2; - break; - case TCSAFLUSH: - request = TCSETSF2; - break; - default: - errno = -EINVAL; - return -1; - } - return ioctl(fd, request, pts); -} - -static void cfmakeraw2(struct termios2 *pts) -{ - pts->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); - pts->c_oflag &= ~OPOST; - pts->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); - pts->c_cflag &= ~(CSIZE|PARENB); - pts->c_cflag |= CS8; -} - -/* table of standard line speeds */ -static const struct speed_entry { int s; speed_t v; } -speed_table[] = { - { 50, B50 }, - { 75, B75 }, - { 110, B110 }, - { 134, B134 }, - { 150, B150 }, - { 200, B200 }, - { 300, B300 }, - { 600, B600 }, - { 1200, B1200 }, - { 1800, B1800 }, - { 2400, B2400 }, - { 4800, B4800 }, - { 9600, B9600 }, - { 19200, B19200 }, - { 38400, B38400 } -#ifdef B57600 - ,{ 57600, B57600 } -#endif -#ifdef B115200 - ,{ 115200, B115200 } -#endif -#ifdef B230400 - ,{ 230400, B230400 } -#endif -}; - -static int cfsetspeed2(struct termios2 *pts, int speed) -{ - size_t i; - - /* try POSIX method first */ - for (i = 0; i < ARRAY_SIZE(speed_table); i++) - if (speed_table[i].s == speed) { - pts->c_cflag &= ~CBAUD; - pts->c_cflag |= speed_table[i].v; - return 0; - } - -#ifdef BOTHER - /* new method available */ - pts->c_ospeed = pts->c_ispeed = speed; - pts->c_cflag &= ~CBAUD; - pts->c_cflag |= BOTHER; - return 0; -#else - /* new method not available */ - return -1; -#endif -} - static void __attribute__((__noreturn__)) usage(int exitcode) { size_t i; @@ -190,10 +92,34 @@ static void __attribute__((__noreturn__)) usage(int exitcode) exit(exitcode); } +static int my_cfsetspeed(struct termios *ts, int speed) +{ + /* Standard speeds + * -- cfsetspeed() is able to translate number to Bxxx constants + */ + if (cfsetspeed(ts, speed) == 0) + return 0; + + /* Nonstandard speeds + * -- we have to bypass glibc and set the speed manually (because + * glibc checks for speed and supports Bxxx bit rates only)... + */ +#ifdef _HAVE_STRUCT_TERMIOS_C_ISPEED +# define BOTHER 0010000 /* non standard rate */ + dbg("using non-standard speeds"); + ts->c_ospeed = ts->c_ispeed = speed; + ts->c_cflag &= ~CBAUD; + ts->c_cflag |= BOTHER; + return 0; +#else + return -1; +#endif +} + int main(int argc, char **argv) { int tty_fd; - struct termios2 ts; + struct termios ts; int speed = 0, bits = '-', parity = '-', stop = '-'; int ldisc; int optc; @@ -278,10 +204,10 @@ int main(int argc, char **argv) dbg("opened %s", dev); /* set line speed and format */ - if (tcgetattr2(tty_fd, &ts) < 0) + if (tcgetattr(tty_fd, &ts) < 0) err(EXIT_FAILURE, _("cannot get terminal attributes for %s"), dev); - cfmakeraw2(&ts); - if (speed && cfsetspeed2(&ts, speed) < 0) + cfmakeraw(&ts); + if (speed && my_cfsetspeed(&ts, speed) < 0) errx(EXIT_FAILURE, _("speed %d unsupported"), speed); switch (stop) { case '1': @@ -312,7 +238,7 @@ int main(int argc, char **argv) break; } ts.c_cflag |= CREAD; /* just to be on the safe side */ - if (tcsetattr2(tty_fd, TCSAFLUSH, &ts) < 0) + if (tcsetattr(tty_fd, TCSAFLUSH, &ts) < 0) err(EXIT_FAILURE, _("cannot set terminal attributes for %s"), dev); dbg("set to raw %d %c%c%c: cflag=0x%x", -- 1.5.3.8 -- To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html