2007-06-19 17:04:25

by Jean Delvare

[permalink] [raw]
Subject: Writing a driver for a legacy serial device

Hi all,

I want to write a Linux kernel driver for a device which connects to
the legacy serial port. I started writing a driver, however I am
already stuck at the very beginning. The .connect function of my serial
driver is never called, and I just don't get why. I couldn't find any
documentation about writing such a legacy driver in Documentation nor
in LDD3. Is there anyone out there which could lend a helping hand?

I know that the device and my serial port both work. I can talk to the
device using minicom just fine. I have the following drivers loaded:

$ lsmod | grep 8250
8250_pnp 11648 0
8250 23464 1 8250_pnp
serial_core 19392 1 8250

Serial: 8250/16550 driver $Revision: 1.90 $ 2 ports, IRQ sharing disabled
00:08: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A

But I need to implement my driver in kernel space. My code looks like
this:

static struct serio_device_id taos_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_ANY,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, taos_serio_ids);

static struct serio_driver taos_drv = {
.driver = {
.name = "taos-evm",
},
.description = "TAOS evaluation module driver",
.id_table = taos_serio_ids,
.connect = taos_connect,
.disconnect = taos_disconnect,
.interrupt = taos_interrupt,
};

static int __init taos_init(void)
{
return serio_register_driver(&taos_drv);
}

static void __exit taos_exit(void)
{
serio_unregister_driver(&taos_drv);
}

The problem is that taos_connect is never called. I suppose that I need
different values for .type, .proto or .id, except that I just don't
know what to put there. I tried a few random values without success.
What's the trick?

Thanks,
--
Jean Delvare


2007-06-19 18:59:47

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: Writing a driver for a legacy serial device

Hi Jean,

On 6/19/07, Jean Delvare <[email protected]> wrote:
> Hi all,
>
> I want to write a Linux kernel driver for a device which connects to
> the legacy serial port. I started writing a driver, however I am
> already stuck at the very beginning. The .connect function of my serial
> driver is never called, and I just don't get why. I couldn't find any
> documentation about writing such a legacy driver in Documentation nor
> in LDD3. Is there anyone out there which could lend a helping hand?
>
> I know that the device and my serial port both work. I can talk to the
> device using minicom just fine. I have the following drivers loaded:
>
> $ lsmod | grep 8250
> 8250_pnp 11648 0
> 8250 23464 1 8250_pnp
> serial_core 19392 1 8250
>
> Serial: 8250/16550 driver $Revision: 1.90 $ 2 ports, IRQ sharing disabled
> 00:08: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A
>
> But I need to implement my driver in kernel space. My code looks like
> this:
>
> static struct serio_device_id taos_serio_ids[] = {
> {
> .type = SERIO_RS232,
> .proto = SERIO_ANY,
> .id = SERIO_ANY,
> .extra = SERIO_ANY,
> },
> { 0 }
> };
> MODULE_DEVICE_TABLE(serio, taos_serio_ids);
>
> static struct serio_driver taos_drv = {
> .driver = {
> .name = "taos-evm",
> },
> .description = "TAOS evaluation module driver",
> .id_table = taos_serio_ids,
> .connect = taos_connect,
> .disconnect = taos_disconnect,
> .interrupt = taos_interrupt,
> };
>
> static int __init taos_init(void)
> {
> return serio_register_driver(&taos_drv);
> }
>
> static void __exit taos_exit(void)
> {
> serio_unregister_driver(&taos_drv);
> }
>
> The problem is that taos_connect is never called. I suppose that I need
> different values for .type, .proto or .id, except that I just don't
> know what to put there. I tried a few random values without success.
> What's the trick?
>

You need to load serport modue and play with inputattach utility.

--
Dmitry

2007-06-20 08:56:06

by Jean Delvare

[permalink] [raw]
Subject: Re: Writing a driver for a legacy serial device

Hi Dmitry,

Thanks for your answer, very much appreciated.

On Tue, 19 Jun 2007 14:59:34 -0400, Dmitry Torokhov wrote:
> Hi Jean,
>
> On 6/19/07, Jean Delvare <[email protected]> wrote:
> > Hi all,
> >
> > I want to write a Linux kernel driver for a device which connects to
> > the legacy serial port. I started writing a driver, however I am
> > already stuck at the very beginning. The .connect function of my serial
> > driver is never called, and I just don't get why. I couldn't find any
> > documentation about writing such a legacy driver in Documentation nor
> > in LDD3. Is there anyone out there which could lend a helping hand?
> >
> > I know that the device and my serial port both work. I can talk to the
> > device using minicom just fine. I have the following drivers loaded:
> >
> > $ lsmod | grep 8250
> > 8250_pnp 11648 0
> > 8250 23464 1 8250_pnp
> > serial_core 19392 1 8250
> >
> > Serial: 8250/16550 driver $Revision: 1.90 $ 2 ports, IRQ sharing disabled
> > 00:08: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A
> >
> > But I need to implement my driver in kernel space. My code looks like
> > this:
> >
> > static struct serio_device_id taos_serio_ids[] = {
> > {
> > .type = SERIO_RS232,
> > .proto = SERIO_ANY,
> > .id = SERIO_ANY,
> > .extra = SERIO_ANY,
> > },
> > { 0 }
> > };
> > MODULE_DEVICE_TABLE(serio, taos_serio_ids);
> >
> > static struct serio_driver taos_drv = {
> > .driver = {
> > .name = "taos-evm",
> > },
> > .description = "TAOS evaluation module driver",
> > .id_table = taos_serio_ids,
> > .connect = taos_connect,
> > .disconnect = taos_disconnect,
> > .interrupt = taos_interrupt,
> > };
> >
> > static int __init taos_init(void)
> > {
> > return serio_register_driver(&taos_drv);
> > }
> >
> > static void __exit taos_exit(void)
> > {
> > serio_unregister_driver(&taos_drv);
> > }
> >
> > The problem is that taos_connect is never called. I suppose that I need
> > different values for .type, .proto or .id, except that I just don't
> > know what to put there. I tried a few random values without success.
> > What's the trick?
>
> You need to load serport modue and play with inputattach utility.

Ah, I see. There's no way to detect what device is connected to the
serial port, so we need a user-space tool to bind the port to the right
driver? Makes some sense, even though it's a but strange that I need
something called inputattach for a device which isn't an input device.

So I've set CONFIG_SERIO_SERPORT=m, compiled and loaded serport. Then I
added a new protocol number in <linux/serio.h>:

#define SERIO_TAOSEVM 0x40

Then I added the following entry to inputattach and recompiled it:

{ "--taos-evm", "-taos", B1200, CS8, SERIO_TAOSEVM, 0, 0, 0, NULL },

Then I changed my driver code to:

static struct serio_device_id taos_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_TAOSEVM,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};

And lastly I ran, as root:

./inputattach -taos /dev/ttyS0

I see the following line in the logs as a result:

serio: Serial port ttyS0

But unfortunately, my driver's .connect function is still not called.
I guess that I missed one step? Any idea what it would be?

Thanks,
--
Jean Delvare

2007-06-21 03:11:42

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: Writing a driver for a legacy serial device

On Wednesday 20 June 2007 04:56, Jean Delvare wrote:
> Hi Dmitry,
>
> Thanks for your answer, very much appreciated.
>
> On Tue, 19 Jun 2007 14:59:34 -0400, Dmitry Torokhov wrote:
> >
> > You need to load serport modue and play with inputattach utility.
>
> Ah, I see. There's no way to detect what device is connected to the
> serial port, so we need a user-space tool to bind the port to the right
> driver? Makes some sense, even though it's a but strange that I need
> something called inputattach for a device which isn't an input device.

Because serio interface is mostly used with input devices. For all other
devices I think universal answer is "userspace" but with input devices
we want to do processing in kernel so we can route events into console
and other standard interfaces (although one coudl use uinput to achieve
similar result).

>
> So I've set CONFIG_SERIO_SERPORT=m, compiled and loaded serport. Then I
> added a new protocol number in <linux/serio.h>:
>
> #define SERIO_TAOSEVM 0x40
>
> Then I added the following entry to inputattach and recompiled it:
>
> { "--taos-evm", "-taos", B1200, CS8, SERIO_TAOSEVM, 0, 0, 0, NULL },
>
> Then I changed my driver code to:
>
> static struct serio_device_id taos_serio_ids[] = {
> {
> .type = SERIO_RS232,
> .proto = SERIO_TAOSEVM,
> .id = SERIO_ANY,
> .extra = SERIO_ANY,
> },
> { 0 }
> };
>
> And lastly I ran, as root:
>
> ./inputattach -taos /dev/ttyS0
>
> I see the following line in the logs as a result:
>
> serio: Serial port ttyS0
>
> But unfortunately, my driver's .connect function is still not called.
> I guess that I missed one step? Any idea what it would be?
>

Not sure. Could you check /sys/bus/serio/devices/serioX/id/* and verify
that inputattach sets up serio port properly?

--
Dmitry

2007-06-21 09:33:21

by Jean Delvare

[permalink] [raw]
Subject: Re: Writing a driver for a legacy serial device

Hi Dmitry,

On Wed, 20 Jun 2007 23:11:32 -0400, Dmitry Torokhov wrote:
> On Wednesday 20 June 2007 04:56, Jean Delvare wrote:
> > Ah, I see. There's no way to detect what device is connected to the
> > serial port, so we need a user-space tool to bind the port to the right
> > driver? Makes some sense, even though it's a but strange that I need
> > something called inputattach for a device which isn't an input device.
>
> Because serio interface is mostly used with input devices. For all other
> devices I think universal answer is "userspace" but with input devices
> we want to do processing in kernel so we can route events into console
> and other standard interfaces (although one coudl use uinput to achieve
> similar result).

OK. This leads me to a question: is it OK for me to add support for my
non-input device to inputattach, or is a separate, dedicated helper
tool preferred? Both ways are fine with me, I don't know what the input
subsystem maintainers expect.

> > But unfortunately, my driver's .connect function is still not called.
> > I guess that I missed one step? Any idea what it would be?
>
> Not sure. Could you check /sys/bus/serio/devices/serioX/id/* and verify
> that inputattach sets up serio port properly?

Thanks for the hint, I checked that and the proto value was 42 instead
of the expected 40. Reading the source code of my local copy of
inputattach.c, I found that SERIO_RS232 was OR'd to the value. This
seems to be a rather old bug which is already fixed upstream:

http://linuxconsole.cvs.sourceforge.net/linuxconsole/ruby/utils/inputattach.c?r1=1.23&r2=1.24

But for some reason the openSuse package is lagging behind. I'll go
update it.

After fixing this, I finally see my .connect function being called! Now
I can start doing the real driver development work. Thanks a lot for
your highly valuable help, Dmitry :)

--
Jean Delvare

2007-06-21 14:47:38

by David Woodhouse

[permalink] [raw]
Subject: Re: Writing a driver for a legacy serial device

On Thu, 2007-06-21 at 11:33 +0200, Jean Delvare wrote:
> OK. This leads me to a question: is it OK for me to add support for my
> non-input device to inputattach, or is a separate, dedicated helper
> tool preferred? Both ways are fine with me, I don't know what the
> input subsystem maintainers expect.

You might do better to implement it as a line discipline instead.
Or just do it in userspace. What exactly are you trying to do?

--
dwmw2

2007-06-21 18:37:50

by Jean Delvare

[permalink] [raw]
Subject: Re: Writing a driver for a legacy serial device

Hi David,

On Thu, 21 Jun 2007 22:47:12 +0800, David Woodhouse wrote:
> On Thu, 2007-06-21 at 11:33 +0200, Jean Delvare wrote:
> > OK. This leads me to a question: is it OK for me to add support for my
> > non-input device to inputattach, or is a separate, dedicated helper
> > tool preferred? Both ways are fine with me, I don't know what the
> > input subsystem maintainers expect.
>
> You might do better to implement it as a line discipline instead.
> Or just do it in userspace. What exactly are you trying to do?

I am writing a driver for a TAOS evaluation module. This device is a
limited SMBus master, connecting to the serial port. The evaluation
chip is connected to the SMBus. In my case this is a TSL2550 light
sensor, but virtually all compatible TAOS evaluation modules could be
supported.

I2C bus drivers have to be implemented in the kernel, so user-space
isn't an option for me.

I just posted a first (working) version of my driver, if you want to
take a look:
http://lists.lm-sensors.org/pipermail/i2c/2007-June/001508.html

Thanks,
--
Jean Delvare

2007-06-21 23:31:52

by Arnd Bergmann

[permalink] [raw]
Subject: Re: Writing a driver for a legacy serial device

On Thursday 21 June 2007, Jean Delvare wrote:
> I2C bus drivers have to be implemented in the kernel, so user-space
> isn't an option for me.

Well, you could have an i2c_algorithm that exports a character device
node to user space, and then have a trivial user application that
simply relays between that and the serial port.

It's probably not much different to what you have in the end though.

Arnd <><

2007-06-22 19:47:53

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: Writing a driver for a legacy serial device

On 6/21/07, Jean Delvare <[email protected]> wrote:
>
> OK. This leads me to a question: is it OK for me to add support for my
> non-input device to inputattach, or is a separate, dedicated helper
> tool preferred? Both ways are fine with me, I don't know what the input
> subsystem maintainers expect.
>

Your device does not need any initialization done by userspace, does
it? How widespread is this device? inputattach has "--dump" option
which sets up a SERIO_RS232/0/0/0 serio port. You could mark your
serio driver as manual bind driver and bind it trhough sysfs (echo -n
"taos-evm" /sys/device/serio/devices/serioX/drvctl to bind it).

--
Dmitry

2007-06-23 08:33:33

by Jean Delvare

[permalink] [raw]
Subject: Re: Writing a driver for a legacy serial device

Hi Dmitry,

On Fri, 22 Jun 2007 15:47:43 -0400, Dmitry Torokhov wrote:
> On 6/21/07, Jean Delvare <[email protected]> wrote:
> >
> > OK. This leads me to a question: is it OK for me to add support for my
> > non-input device to inputattach, or is a separate, dedicated helper
> > tool preferred? Both ways are fine with me, I don't know what the input
> > subsystem maintainers expect.
>
> Your device does not need any initialization done by userspace, does
> it?

No, it doesn't. But it wants a specific serial line speed and mode.

> How widespread is this device?

Not widespread. It's a family of evaluation modules for I2C/SMBus
chips. They will mainly be used to develop and test chip drivers, I
suppose. But OTOH, I'm not sure how it matters. We're in year 2007, I
pretty much doubt that any of the devices supported by inputattach is
still in widespread use. As a matter of fact, inputattach has been
broken in Suse for half of the supported devices for almost two years
now, and I couldn't find any bug report about it.

> inputattach has "--dump" option
> which sets up a SERIO_RS232/0/0/0 serio port. You could mark your
> serio driver as manual bind driver and bind it trhough sysfs (echo -n
> "taos-evm" /sys/device/serio/devices/serioX/drvctl to bind it).

One problem I foresee is that the dump mode sets the port to 2400 bps,
while my evaluation module wants 1200 bps.

Another problem is that the dump mode of inputattach doesn't appear to
create a serio device. Probably not very surprising, as dump_init()
never returns. So I don't think I can use that.

--
Jean Delvare