2008-08-05 17:37:55

by Ira W. Snyder

[permalink] [raw]
Subject: Simple UART driver help and TTY questions

Hello LKML,

I'm trying to implement a UART driver that works only in software, just
like many of the examples in LDD3. There isn't a UART driver example in
the book, so I searched around and found some old code from Greg KH on
LinuxJournal.com[1]. You can find the code mentioned in the article at
[2] (the link from the article doesn't work any more). Of course, given
the age of the article, the code doesn't compile anymore. I fixed this
up by commenting out things that I deemed unimportant (like the timer to
send fake data, etc.). I also fixed up the function prototypes that
needed changing, and made the module unloadable. I've attached the code
I'm using at the end of this email.

So, the problem I have is that when I install this driver, it seems to
return -EIO before it even hits any of the driver code. I checked this
by putting a printk at the beginning of every function call in the
module.

The error from busybox microcom is this:
microcom: can't tcsetattr for /dev/ttytiny0: Input/output error

And cat /dev/ttytiny0:
cat: /dev/ttytiny0: Input/output error

Previously to finding this code from LinuxJournal, I had tried to write
my own skeleton driver, basing it on the drivers/serial/ucc_uart.c code.
It has the exact same problem. I've attached it as well.

So, to the best of my research, it seems like the tcsetattr call would
come in at drivers/char/tty_ioctl.c in tty_mode_ioctl() (the TCSETS
case). Maybe I'm wrong, though.

I've built it against both ubuntu's stock kernel (2.6.24 based) and a
recent pull of the kernel.org kernel.

I'd really appreciate help figuring out what this problem is.



And now on to my questions, just to make sure I'm not completely off
track:
1) To implement a driver for a serial port that doesn't have a driver
yet, I'd want to be writing a UART driver, correct? Not a TTY driver.
2) TTY drivers deal with line disciplines, and shouldn't be used to
actually write characters to hardware, correct? Meaning, I shouldn't
need to implement my own tty driver for this to work.

Please CC me on any replies, I'm not subscribed to LKML.

Thanks in advance for any help,
Ira

[1] http://m.linuxjournal.com/article/6331
[2] ftp://ftp.ssc.com/pub/lj/listings/issue104/6331.tgz

Greg KH's tinyserial.c driver, from [2], with my fixes:
======================================================================
/*
* Tiny TTY driver
*
* Copyright (C) 2002 Greg Kroah-Hartman ([email protected])
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This driver shows how to create a minimal serial driver using the 2.5
* kernel's serial driver layer. It does not rely on any backing hardware, but
* creates a timer that emulates data being received from some kind of
* hardware.
*
* Compiled this driver with:

CFLAGS = -Wall -O2 -fomit-frame-pointer -DMODULE -D__KERNEL__
IDIR = /path/to/linux-2.5/include/goes/here

tiny_serial.o::tiny_serial.c
$(CC) $(CFLAGS) -I$(IDIR) -c -o $@ $<
*/

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/module.h>


#define DRIVER_VERSION "v1.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <[email protected]>"
#define DRIVER_DESC "Tiny serial driver"

/* Module information */
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");

#define DELAY_TIME HZ * 2 /* 2 seconds per character */
#define TINY_DATA_CHARACTER 't'

#define TINY_SERIAL_MAJOR 240 /* experimental range */
#define TINY_SERIAL_MINORS 1 /* only have one minor */
#define UART_NR 1 /* only use one port */

#define TINY_SERIAL_NAME "ttytiny"

#define MY_NAME TINY_SERIAL_NAME

#define dbg(fmt, arg...) \
do { \
if (debug) \
printk (KERN_DEBUG "%s: %s: " fmt "\n", \
MY_NAME , __FUNCTION__ , ## arg); \
} while (0)
#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , MY_NAME , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , MY_NAME , ## arg)

#define FUNC_ENTER() do { printk(KERN_INFO "Enter: %s\n", __func__); } while (0)


static int debug;

#if 0
static struct timer_list *timer;
#endif

static void tiny_stop_tx(struct uart_port *port)
{
FUNC_ENTER();
dbg ();
}

static void tiny_stop_rx(struct uart_port *port)
{
FUNC_ENTER();
dbg ();
}

static void tiny_enable_ms(struct uart_port *port)
{
FUNC_ENTER();
dbg ();
}

#if 0
static void tiny_tx_chars(struct uart_port *port)
{
struct circ_buf *xmit = &port->info->xmit;
int count;

dbg ();
if (port->x_char) {
dbg ("wrote %2x", port->x_char);
port->icount.tx++;
port->x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
tiny_stop_tx(port, 0);
return;
}

count = port->fifosize >> 1;
do {
dbg ("wrote %2x", xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);

if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_event(port, EVT_WRITE_WAKEUP);

if (uart_circ_empty(xmit))
tiny_stop_tx(port, 0);
}
#endif

static void tiny_start_tx(struct uart_port *port)
{
FUNC_ENTER();
dbg ();
}

#if 0
static void tiny_timer (unsigned long data)
{
struct uart_port *port;
struct tty_struct *tty;

dbg ();

port = (struct uart_port *)data;
if (!port)
return;
if (!port->info)
return;
tty = port->info->tty;
if (!tty)
return;

/* add one character to the tty port */
/* this doesn't actually push the data through unless tty->low_latency is set */
tty_insert_flip_char(tty, TINY_DATA_CHARACTER, 0);

tty_flip_buffer_push(tty);

/* resubmit the timer again */
timer->expires = jiffies + DELAY_TIME;
add_timer (timer);

/* see if we have any data to transmit */
tiny_tx_chars(port);
}
#endif

static unsigned int tiny_tx_empty(struct uart_port *port)
{
FUNC_ENTER();
return 0;
}

static unsigned int tiny_get_mctrl(struct uart_port *port)
{
FUNC_ENTER();
return 0;
}

static void tiny_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
FUNC_ENTER();
}

static void tiny_break_ctl(struct uart_port *port, int break_state)
{
FUNC_ENTER();
}

#if 0
static void
tiny_change_speed(struct uart_port *port, unsigned int cflag,
unsigned int iflag, unsigned int quot)
{
/* get the byte size */
switch (cflag & CSIZE) {
case CS5:
dbg ("data bits = 5");
break;
case CS6:
dbg ("data bits = 6");
break;
case CS7:
dbg ("data bits = 7");
break;
default: // CS8
dbg ("data bits = 8");
break;
}

/* determine the parity */
if (cflag & PARENB)
if (cflag & PARODD)
dbg (" - parity = odd\n");
else
dbg (" - parity = even\n");
else
dbg (" - parity = none\n");

/* figure out the stop bits requested */
if (cflag & CSTOPB)
dbg (" - stop bits = 2\n");
else
dbg (" - stop bits = 1\n");

/* figure out the flow control settings */
if (cflag & CRTSCTS)
dbg (" - RTS/CTS is enabled\n");
else
dbg (" - RTS/CTS is disabled\n");

/* Set baud rate */
//UART_PUT_DIV_LO(port, (quot & 0xff));
//UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8));
}
#endif

static int tiny_startup(struct uart_port *port)
{
FUNC_ENTER();
#if 0
/* this is the first time this port is opened */
/* do any hardware initialization needed here */

/* create our timer and submit it */
if (!timer) {
timer = kmalloc (sizeof (*timer), GFP_KERNEL);
if (!timer)
return -ENOMEM;
}
timer->data = (unsigned long )port;
timer->expires = jiffies + DELAY_TIME;
timer->function = tiny_timer;
add_timer (timer);
#endif
return 0;
}

static void tiny_shutdown(struct uart_port *port)
{
FUNC_ENTER();
#if 0
/* The port is being closed by the last user. */
/* Do any hardware specific stuff here */

/* shut down our timer */
del_timer (timer);
#endif
}

static const char *tiny_type(struct uart_port *port)
{
FUNC_ENTER();
return "tinytty";
}

static void tiny_release_port(struct uart_port *port)
{
FUNC_ENTER();
}

static int tiny_request_port(struct uart_port *port)
{
FUNC_ENTER();
return 0;
}

static void tiny_config_port(struct uart_port *port, int flags)
{
FUNC_ENTER();
}

static int tiny_verify_port(struct uart_port *port, struct serial_struct *ser)
{
FUNC_ENTER();
return 0;
}

static struct uart_ops tiny_ops = {
.tx_empty = tiny_tx_empty,
.set_mctrl = tiny_set_mctrl,
.get_mctrl = tiny_get_mctrl,
.stop_tx = tiny_stop_tx,
.start_tx = tiny_start_tx,
.stop_rx = tiny_stop_rx,
.enable_ms = tiny_enable_ms,
.break_ctl = tiny_break_ctl,
.startup = tiny_startup,
.shutdown = tiny_shutdown,
#if 0
.change_speed = tiny_change_speed,
#endif
.type = tiny_type,
.release_port = tiny_release_port,
.request_port = tiny_request_port,
.config_port = tiny_config_port,
.verify_port = tiny_verify_port,
};

static struct uart_port tiny_port = {
.ops = &tiny_ops,
};

static struct uart_driver tiny_reg = {
.owner = THIS_MODULE,
.driver_name = TINY_SERIAL_NAME,
.dev_name = TINY_SERIAL_NAME,
.major = TINY_SERIAL_MAJOR,
.minor = TINY_SERIAL_MINORS,
.nr = UART_NR,
};


static int __init tiny_init(void)
{
int result;

info ("Tiny serial driver");

result = uart_register_driver(&tiny_reg);
if (result)
return result;

result = uart_add_one_port(&tiny_reg, &tiny_port);
if (result)
uart_unregister_driver(&tiny_reg);

return result;
}

static void __exit tiny_exit(void)
{
uart_remove_one_port(&tiny_reg, &tiny_port);
uart_unregister_driver(&tiny_reg);
}

module_init (tiny_init);
module_exit (tiny_exit);


My own vuart driver:
======================================================================
#define DEBUG 1

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>

#include <linux/serial.h>
#include <linux/serial_core.h>

#define FUNC_ENTER() do { pr_info("ENTER: %s\n", __func__); } while (0)

struct vuart_dev {
struct uart_port port;
};

static const char driver_name[] = "vuart";
static const char tty_dev_name[] = "vtty";
static struct vuart_dev priv0, priv1;



static unsigned int vuart_tx_empty(struct uart_port *port)
{
FUNC_ENTER();
return 1;
}

static void vuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
FUNC_ENTER();
}

static unsigned int vuart_get_mctrl(struct uart_port *port)
{
FUNC_ENTER();
return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
}

static void vuart_stop_tx(struct uart_port *port)
{
FUNC_ENTER();
}

static void vuart_start_tx(struct uart_port *port)
{
FUNC_ENTER();
}

static void vuart_stop_rx(struct uart_port *port)
{
FUNC_ENTER();
}

static void vuart_enable_ms(struct uart_port *port)
{
FUNC_ENTER();
}

static void vuart_break_ctl(struct uart_port *port, int break_state)
{
FUNC_ENTER();
}

static int vuart_startup(struct uart_port *port)
{
FUNC_ENTER();
return 0;
}

static void vuart_shutdown(struct uart_port *port)
{
FUNC_ENTER();
}

static void vuart_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
FUNC_ENTER();
}

static const char *vuart_type(struct uart_port *port)
{
FUNC_ENTER();
return "VUART";
}

static int vuart_request_port(struct uart_port *port)
{
FUNC_ENTER();
return 0;
}

static void vuart_config_port(struct uart_port *port, int flags)
{
FUNC_ENTER();
}

static void vuart_release_port(struct uart_port *port)
{
FUNC_ENTER();
}

static int vuart_verify_port(struct uart_port *port, struct serial_struct *ser)
{
FUNC_ENTER();
return 0;
}

static struct uart_ops vuart_uart_ops = {
.tx_empty = vuart_tx_empty,
.set_mctrl = vuart_set_mctrl,
.get_mctrl = vuart_get_mctrl,
.stop_tx = vuart_stop_tx,
.start_tx = vuart_start_tx,
.stop_rx = vuart_stop_rx,
.enable_ms = vuart_enable_ms,
.break_ctl = vuart_break_ctl,
.startup = vuart_startup,
.shutdown = vuart_shutdown,
.set_termios = vuart_set_termios,
.type = vuart_type,
.release_port = vuart_release_port,
.request_port = vuart_request_port,
.config_port = vuart_config_port,
.verify_port = vuart_verify_port,
};

static struct uart_driver vuart_driver = {
.owner = THIS_MODULE,
.driver_name = driver_name,
.dev_name = tty_dev_name,
.major = 240,
.minor = 0,
.nr = 2,
};

static int __init
vuart_init (void)
{
int ret;

ret = uart_register_driver(&vuart_driver);

if (ret) {
pr_err("%s: could not register UART driver\n", driver_name);
goto out_register_driver;
}

memset(&priv0, sizeof(struct vuart_dev), 0);
priv0.port.line = 0;
priv0.port.ops = &vuart_uart_ops;
spin_lock_init(&priv0.port.lock);
ret = uart_add_one_port(&vuart_driver, &priv0.port);

if (ret) {
pr_err("%s: could not add port vuart0\n", driver_name);
goto out_add_port0;
}

memset(&priv1, sizeof(struct vuart_dev), 0);
priv1.port.line = 1;
priv1.port.ops = &vuart_uart_ops;
spin_lock_init(&priv1.port.lock);
ret = uart_add_one_port(&vuart_driver, &priv1.port);

if (ret) {
pr_err("%s: could not add port vuart1\n", driver_name);
goto out_add_port1;
}

printk ("Module %s loaded\n", driver_name);
return 0;

out_add_port1:
uart_remove_one_port(&vuart_driver, &priv0.port);
out_add_port0:
uart_unregister_driver(&vuart_driver);
out_register_driver:
return ret;
}

static void __exit
vuart_exit (void)
{
uart_remove_one_port(&vuart_driver, &priv0.port);
uart_remove_one_port(&vuart_driver, &priv1.port);
uart_unregister_driver(&vuart_driver);
printk ("Module %s removed\n", driver_name);
}

MODULE_AUTHOR("Ira W. Snyder <[email protected]>");
MODULE_DESCRIPTION("Test Driver");
MODULE_LICENSE("GPL");

module_init(vuart_init);
module_exit(vuart_exit);


2008-08-05 21:21:33

by Jiri Slaby

[permalink] [raw]
Subject: Re: Simple UART driver help and TTY questions

On 08/05/2008 06:33 PM, Ira Snyder wrote:
> Hello LKML,
> So, the problem I have is that when I install this driver, it seems to
> return -EIO before it even hits any of the driver code. I checked this
> by putting a printk at the beginning of every function call in the
> module.
>
> The error from busybox microcom is this:
> microcom: can't tcsetattr for /dev/ttytiny0: Input/output error
>
> And cat /dev/ttytiny0:
> cat: /dev/ttytiny0: Input/output error
>
> Previously to finding this code from LinuxJournal, I had tried to write
> my own skeleton driver, basing it on the drivers/serial/ucc_uart.c code.
> It has the exact same problem. I've attached it as well.
>
> So, to the best of my research, it seems like the tcsetattr call would
> come in at drivers/char/tty_ioctl.c in tty_mode_ioctl() (the TCSETS
> case). Maybe I'm wrong, though.
>
> I've built it against both ubuntu's stock kernel (2.6.24 based) and a
> recent pull of the kernel.org kernel.
>
> I'd really appreciate help figuring out what this problem is.

Attach straces of your tries.

2008-08-06 19:32:33

by Ira W. Snyder

[permalink] [raw]
Subject: Re: Simple UART driver help and TTY questions

On Tue, Aug 05, 2008 at 11:21:18PM +0200, Jiri Slaby wrote:
> On 08/05/2008 06:33 PM, Ira Snyder wrote:
>> Hello LKML,
>> So, the problem I have is that when I install this driver, it seems to
>> return -EIO before it even hits any of the driver code. I checked this
>> by putting a printk at the beginning of every function call in the
>> module.
>>
>> The error from busybox microcom is this:
>> microcom: can't tcsetattr for /dev/ttytiny0: Input/output error
>>
>> And cat /dev/ttytiny0:
>> cat: /dev/ttytiny0: Input/output error
>>
>> Previously to finding this code from LinuxJournal, I had tried to write
>> my own skeleton driver, basing it on the drivers/serial/ucc_uart.c code.
>> It has the exact same problem. I've attached it as well.
>>
>> So, to the best of my research, it seems like the tcsetattr call would
>> come in at drivers/char/tty_ioctl.c in tty_mode_ioctl() (the TCSETS
>> case). Maybe I'm wrong, though.
>>
>> I've built it against both ubuntu's stock kernel (2.6.24 based) and a
>> recent pull of the kernel.org kernel.
>>
>> I'd really appreciate help figuring out what this problem is.
>
> Attach straces of your tries.

Here is a strace of "cat /proc/ttytiny0":
======================================================================
execve("/bin/cat", ["cat", "/dev/ttytiny0"], [/* 21 vars */]) = 0
brk(0) = 0x8050000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f05000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=46987, ...}) = 0
mmap2(NULL, 46987, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7ef9000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/tls/i686/cmov/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\260e\1"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1364388, ...}) = 0
mmap2(NULL, 1369712, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7daa000
mmap2(0xb7ef3000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x149) = 0xb7ef3000
mmap2(0xb7ef6000, 9840, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7ef6000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7da9000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb7da96b0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb7ef3000, 4096, PROT_READ) = 0
munmap(0xb7ef9000, 46987) = 0
brk(0) = 0x8050000
brk(0x8071000) = 0x8071000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/locale.alias", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=2586, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f04000
read(3, "# Locale name alias data base.\n#"..., 4096) = 2586
read(3, "", 4096) = 0
close(3) = 0
munmap(0xb7f04000, 4096) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_IDENTIFICATION", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_IDENTIFICATION", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=373, ...}) = 0
mmap2(NULL, 373, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f04000
close(3) = 0
open("/usr/lib/gconv/gconv-modules.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=25700, ...}) = 0
mmap2(NULL, 25700, PROT_READ, MAP_SHARED, 3, 0) = 0xb7efd000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_MEASUREMENT", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_MEASUREMENT", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=23, ...}) = 0
mmap2(NULL, 23, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7efc000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_TELEPHONE", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_TELEPHONE", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=59, ...}) = 0
mmap2(NULL, 59, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7efb000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_ADDRESS", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_ADDRESS", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=155, ...}) = 0
mmap2(NULL, 155, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7efa000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_NAME", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_NAME", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=77, ...}) = 0
mmap2(NULL, 77, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7ef9000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_PAPER", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_PAPER", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=34, ...}) = 0
mmap2(NULL, 34, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7da8000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_MESSAGES", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_MESSAGES", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
close(3) = 0
open("/usr/lib/locale/en_US.utf8/LC_MESSAGES/SYS_LC_MESSAGES", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=52, ...}) = 0
mmap2(NULL, 52, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7da7000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_MONETARY", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_MONETARY", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=286, ...}) = 0
mmap2(NULL, 286, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7da6000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_COLLATE", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_COLLATE", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=921214, ...}) = 0
mmap2(NULL, 921214, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7cc5000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_TIME", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_TIME", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=2451, ...}) = 0
mmap2(NULL, 2451, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7cc4000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_NUMERIC", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_NUMERIC", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=54, ...}) = 0
mmap2(NULL, 54, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7cc3000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_CTYPE", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_CTYPE", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=254076, ...}) = 0
mmap2(NULL, 254076, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7c84000
close(3) = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
open("/dev/ttytiny0", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFCHR|0660, st_rdev=makedev(240, 1), ...}) = 0
read(3, 0x8057000, 4096) = -1 EIO (Input/output error)
write(2, "cat: ", 5) = 5
write(2, "/dev/ttytiny0", 13) = 13
open("/usr/share/locale/en_US.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en_US.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en_US/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_US.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_US.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_US/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, ": Input/output error", 20) = 20
write(2, "\n", 1) = 1
close(3) = 0
close(1) = 0
close(2) = 0
exit_group(1) = ?

And an strace of "busybox microcom /dev/ttytiny0":
======================================================================
execve("./bin/busybox", ["./bin/busybox", "microcom", "/dev/ttytiny0"], [/* 21 vars */]) = 0
brk(0) = 0x80dd000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7fa1000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=46987, ...}) = 0
mmap2(NULL, 46987, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f95000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/tls/i686/cmov/libcrypt.so.1", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0000\7\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0644, st_size=38300, ...}) = 0
mmap2(NULL, 201052, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7f63000
mmap2(0xb7f6c000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x8) = 0xb7f6c000
mmap2(0xb7f6e000, 155996, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7f6e000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/tls/i686/cmov/libm.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0@4\0\000"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0644, st_size=149328, ...}) = 0
mmap2(NULL, 147584, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7f3e000
mmap2(0xb7f61000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x23) = 0xb7f61000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/tls/i686/cmov/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\260e\1"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1364388, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f3d000
mmap2(NULL, 1369712, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7dee000
mmap2(0xb7f37000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x149) = 0xb7f37000
mmap2(0xb7f3a000, 9840, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7f3a000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7ded000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb7ded6b0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb7f37000, 4096, PROT_READ) = 0
munmap(0xb7f95000, 46987) = 0
getpid() = 6041
brk(0) = 0x80dd000
brk(0x80fe000) = 0x80fe000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/locale.alias", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=2586, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7fa0000
read(3, "# Locale name alias data base.\n#"..., 4096) = 2586
read(3, "", 4096) = 0
close(3) = 0
munmap(0xb7fa0000, 4096) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_IDENTIFICATION", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_IDENTIFICATION", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=373, ...}) = 0
mmap2(NULL, 373, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7fa0000
close(3) = 0
open("/usr/lib/gconv/gconv-modules.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=25700, ...}) = 0
mmap2(NULL, 25700, PROT_READ, MAP_SHARED, 3, 0) = 0xb7f99000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_MEASUREMENT", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_MEASUREMENT", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=23, ...}) = 0
mmap2(NULL, 23, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f98000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_TELEPHONE", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_TELEPHONE", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=59, ...}) = 0
mmap2(NULL, 59, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f97000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_ADDRESS", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_ADDRESS", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=155, ...}) = 0
mmap2(NULL, 155, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f96000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_NAME", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_NAME", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=77, ...}) = 0
mmap2(NULL, 77, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f95000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_PAPER", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_PAPER", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=34, ...}) = 0
mmap2(NULL, 34, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7dec000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_MESSAGES", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_MESSAGES", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
close(3) = 0
open("/usr/lib/locale/en_US.utf8/LC_MESSAGES/SYS_LC_MESSAGES", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=52, ...}) = 0
mmap2(NULL, 52, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7deb000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_MONETARY", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_MONETARY", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=286, ...}) = 0
mmap2(NULL, 286, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7dea000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_COLLATE", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_COLLATE", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=921214, ...}) = 0
mmap2(NULL, 921214, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7d09000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_TIME", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_TIME", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=2451, ...}) = 0
mmap2(NULL, 2451, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7d08000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_NUMERIC", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_NUMERIC", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=54, ...}) = 0
mmap2(NULL, 54, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7d07000
close(3) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_CTYPE", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_CTYPE", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=254076, ...}) = 0
mmap2(NULL, 254076, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7cc8000
close(3) = 0
getuid32() = 0
open("/var/lock/LCK..ttytiny0", O_WRONLY|O_CREAT|O_EXCL|O_TRUNC|O_LARGEFILE, 0644) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7cc7000
_llseek(3, 0, [0], SEEK_CUR) = 0
write(3, "6041\n", 5) = 5
munmap(0xb7cc7000, 4096) = 0
close(3) = 0
rt_sigaction(SIGHUP, {0x80588dd, [HUP], SA_RESTART}, {SIG_DFL}, 8) = 0
rt_sigaction(SIGINT, {0x80588dd, [INT], SA_RESTART}, {SIG_DFL}, 8) = 0
rt_sigaction(SIGPIPE, {0x80588dd, [PIPE], SA_RESTART}, {SIG_DFL}, 8) = 0
rt_sigaction(SIGTERM, {0x80588dd, [TERM], SA_RESTART}, {SIG_DFL}, 8) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_CONTINUE or TCSETSF, {B38400 -opost -isig -icanon -echo ...}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0
open("/dev/ttytiny0", O_RDWR|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 3
fcntl64(3, F_SETFL, O_RDONLY) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0xbfd62460) = -1 EIO (Input/output error)
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0xbfd62430) = -1 EIO (Input/output error)
ioctl(3, SNDCTL_TMR_CONTINUE or TCSETSF, {B9600 -opost -isig -icanon -echo ...}) = -1 EIO (Input/output error)
open("/usr/share/locale/en_US.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en_US.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en_US/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_US.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_US.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_US/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, "microcom: can\'t tcsetattr for /d"..., 64) = 64
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0
ioctl(0, SNDCTL_TMR_CONTINUE or TCSETSF, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
unlink("/var/lock/LCK..ttytiny0") = 0
exit_group(1) = ?


Thanks for the help,
Ira

2008-08-06 21:25:33

by Jiri Slaby

[permalink] [raw]
Subject: Re: Simple UART driver help and TTY questions

conOn 08/05/2008 06:33 PM, Ira Snyder wrote:
> static void tiny_config_port(struct uart_port *port, int flags)
> {
> FUNC_ENTER();

if (flags & UART_CONFIG_TYPE)
port->type = PORT_16550A;

> }

According to the straces, you get -EIO from ioctl and read which most likely
means TTY_IO_ERROR bit set due to tiny_port->type = PORT_UNKNOWN (i.e. 0). Try
the above.

2008-08-06 21:46:46

by Ira W. Snyder

[permalink] [raw]
Subject: Re: Simple UART driver help and TTY questions

On Wed, Aug 06, 2008 at 11:11:00PM +0200, Jiri Slaby wrote:
> conOn 08/05/2008 06:33 PM, Ira Snyder wrote:
>> static void tiny_config_port(struct uart_port *port, int flags)
>> {
>> FUNC_ENTER();
>
> if (flags & UART_CONFIG_TYPE)
> port->type = PORT_16550A;
>
>> }
>
> According to the straces, you get -EIO from ioctl and read which most
> likely means TTY_IO_ERROR bit set due to tiny_port->type = PORT_UNKNOWN
> (i.e. 0). Try the above.

Not quite, but it got me on the right track. I needed to set port->type
before calling uart_add_one_port().

Now it gets into my code. Previously, it had never even called any of my
code. None of it. Unfortunately, I ran it and it segfaulted. Turns out
that Greg's tinyserial driver didn't implement ops->set_termios() and
that was the cause. Implementing that got everything working.

Now I get in my dmesg:
[ 73.813893] ttytiny: Tiny serial driver
[ 83.714486] Enter: tiny_startup
[ 83.717676] Enter: tiny_set_termios
[ 83.721193] Enter: tiny_set_mctrl
[ 85.463793] Enter: tiny_stop_rx
[ 85.466987] Enter: tiny_set_mctrl
[ 85.470328] Enter: tiny_shutdown

And that looks very reasonable. (It was produced by cat /dev/ttytiny0,
for your information).

Thanks a lot for your help! That problem had me completely stumped for a
couple of days now :)

Ira

2008-08-06 21:51:57

by Jiri Slaby

[permalink] [raw]
Subject: Re: Simple UART driver help and TTY questions

On 08/06/2008 11:46 PM, Ira Snyder wrote:
> On Wed, Aug 06, 2008 at 11:11:00PM +0200, Jiri Slaby wrote:
>> conOn 08/05/2008 06:33 PM, Ira Snyder wrote:
>>> static void tiny_config_port(struct uart_port *port, int flags)
>>> {
>>> FUNC_ENTER();
>> if (flags & UART_CONFIG_TYPE)
>> port->type = PORT_16550A;
>>
>>> }
>> According to the straces, you get -EIO from ioctl and read which most
>> likely means TTY_IO_ERROR bit set due to tiny_port->type = PORT_UNKNOWN
>> (i.e. 0). Try the above.
>
> Not quite, but it got me on the right track. I needed to set port->type
> before calling uart_add_one_port().

Ah,
.flags = ASYNC_BOOT_AUTOCONF
I guess?

+ I'm sure you will need to set up more entries of your uart_port structure.