From: Steve deRosier <derosier@pianodisc.com>
To: Takashi Iwai <tiwai@suse.de>
Cc: alsa-devel@lists.sourceforge.net
Subject: [PATCH] serial-u16550 driver. Fixes buffer blocking bug (2nd try)
Date: Tue, 02 Dec 2003 17:41:13 -0800 [thread overview]
Message-ID: <3FCD3F39.5050902@pianodisc.com> (raw)
In-Reply-To: <s5hn0bhuwjg.wl@alsa2.suse.de>
Takashi,
I've completed my changes on the serial-u16550 driver. I have
implemented most of your suggestions to my previous patch. Now:
* There is a user selectable flag "droponfull". Set to 1 and
any new bytes delivered to the driver after the buffer fills
up will be discarded until the buffer is able to flush some
bytes.
* If droponfull==0 (or is not set, the default is 0), the driver
proceeds to block further input by not calling
snd_rawmidi_transmit_ack() and aborting the attempt. It will
try again later.
* I've redone a bit of the interface for the buffer routines.
This was done to support the proper blocking/non-blocking methods
as spelled out above, and to try to protect the buffer data a bit.
So, if droponfull==0, we operate as originally desired (but the
original implementation was broken a bit and this fixes it). If
droponfull==1 we now discard new bytes if our buffer is full; this
behavior fixes the driver "hang" problem we were having.
The changes should have no material effect on the "SNDRV_SERIAL_MS124W_MB"
device, and all others should still work well, though we can only
test with the SNDRV_SERIAL_GENERIC.
Please commit this at your earliest opportunity.
Thanks,
- Steve
----------------
Change log entry: Fixes problem where buffers fill up with SNDRV_SERIAL_GENERIC adaptor
when device doesn't signal CTS by dropping new bytes if the module
parameter "droponfull" == 1.
Index: serial-u16550.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/drivers/serial-u16550.c,v
retrieving revision 1.22
diff -u -p -r1.22 serial-u16550.c
--- serial-u16550.c 14 Oct 2003 13:08:13 -0000 1.22
+++ serial-u16550.c 3 Dec 2003 01:14:42 -0000
@@ -63,6 +63,9 @@ static char *adaptor_names[] = {
"Generic"
};
+#define SNDRV_SERIAL_NORMALBUFF 0 /* Normal blocking buffer operation */
+#define SNDRV_SERIAL_DROPBUFF 1 /* Non-blocking discard operation */
+
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
@@ -73,6 +76,7 @@ static int base[SNDRV_CARDS] = {[0 ... (
static int outs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; /* 1 to 16 */
static int ins[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; /* 1 to 16 */
static int adaptor[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = SNDRV_SERIAL_SOUNDCANVAS};
+static int droponfull[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS -1)] = SNDRV_SERIAL_NORMALBUFF };
MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(index, "Index value for Serial MIDI.");
@@ -99,6 +103,9 @@ MODULE_PARM(outs, "1-" __MODULE_STRING(S
MODULE_PARM_DESC(outs, "Number of MIDI outputs.");
MODULE_PARM(ins, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(ins, "Number of MIDI inputs.");
+MODULE_PARM(droponfull, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(droponfull, "Flag to enable drop-on-full buffer mode");
+MODULE_PARM_SYNTAX(droponfull, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
MODULE_PARM_SYNTAX(outs, SNDRV_ENABLED ",allows:{{1,16}},dialog:list");
MODULE_PARM_SYNTAX(ins, SNDRV_ENABLED ",allows:{{1,16}},dialog:list");
@@ -163,6 +170,7 @@ typedef struct _snd_uart16550 {
int buff_in_count;
int buff_in;
int buff_out;
+ int drop_on_full;
// wait timer
unsigned int timer_running:1;
@@ -194,12 +202,15 @@ inline static void snd_uart16550_del_tim
inline static void snd_uart16550_buffer_output(snd_uart16550_t *uart)
{
unsigned short buff_out = uart->buff_out;
- outb(uart->tx_buff[buff_out], uart->base + UART_TX);
- uart->fifo_count++;
- buff_out++;
- buff_out &= TX_BUFF_MASK;
- uart->buff_out = buff_out;
- uart->buff_in_count--;
+ if( uart->buff_in_count > 0 )
+ {
+ outb(uart->tx_buff[buff_out], uart->base + UART_TX);
+ uart->fifo_count++;
+ buff_out++;
+ buff_out &= TX_BUFF_MASK;
+ uart->buff_out = buff_out;
+ uart->buff_in_count--;
+ }
}
/* This loop should be called with interrupts disabled
@@ -257,9 +268,12 @@ static void snd_uart16550_io_loop(snd_ua
|| uart->adaptor == SNDRV_SERIAL_GENERIC) {
/* Can't use FIFO, must send only when CTS is true */
status = inb(uart->base + UART_MSR);
- if (uart->fifo_count == 0 && (status & UART_MSR_CTS)
- && uart->buff_in_count > 0)
- snd_uart16550_buffer_output(uart);
+ while( (uart->fifo_count == 0) && (status & UART_MSR_CTS) &&
+ (uart->buff_in_count > 0) )
+ {
+ snd_uart16550_buffer_output(uart);
+ status = inb( uart->base + UART_MSR );
+ }
} else {
/* Write loop */
while (uart->fifo_count < uart->fifo_limit /* Can we write ? */
@@ -576,19 +590,33 @@ static int snd_uart16550_output_close(sn
return 0;
};
-inline static void snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte)
+inline static int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num )
{
- unsigned short buff_in = uart->buff_in;
- uart->tx_buff[buff_in] = byte;
- buff_in++;
- buff_in &= TX_BUFF_MASK;
- uart->buff_in = buff_in;
- uart->buff_in_count++;
- if (uart->irq < 0) /* polling mode */
- snd_uart16550_add_timer(uart);
+ if( uart->buff_in_count + Num < TX_BUFF_SIZE )
+ return 1;
+ else
+ return 0;
}
-static void snd_uart16550_output_byte(snd_uart16550_t *uart, snd_rawmidi_substream_t * substream, unsigned char midi_byte)
+inline static int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte)
+{
+ unsigned short buff_in = uart->buff_in;
+ if( uart->buff_in_count < TX_BUFF_SIZE )
+ {
+ uart->tx_buff[buff_in] = byte;
+ buff_in++;
+ buff_in &= TX_BUFF_MASK;
+ uart->buff_in = buff_in;
+ uart->buff_in_count++;
+ if (uart->irq < 0) /* polling mode */
+ snd_uart16550_add_timer(uart);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int snd_uart16550_output_byte(snd_uart16550_t *uart, snd_rawmidi_substream_t * substream, unsigned char midi_byte)
{
if (uart->buff_in_count == 0 /* Buffer empty? */
&& ((uart->adaptor != SNDRV_SERIAL_MS124W_SA &&
@@ -611,13 +639,14 @@ static void snd_uart16550_output_byte(sn
}
}
} else {
- if (uart->buff_in_count >= TX_BUFF_SIZE) {
+ if( !snd_uart16550_write_buffer(uart, midi_byte) ) {
snd_printk("%s: Buffer overrun on device at 0x%lx\n",
uart->rmidi->name, uart->base);
- return;
+ return 0;
}
- snd_uart16550_write_buffer(uart, midi_byte);
}
+
+ return 1;
}
static void snd_uart16550_output_write(snd_rawmidi_substream_t * substream)
@@ -661,40 +690,41 @@ static void snd_uart16550_output_write(s
}
} else {
first = 0;
- while (1) {
- if (snd_rawmidi_transmit(substream, &midi_byte, 1) != 1)
- break;
+ while( 1 == snd_rawmidi_transmit_peek(substream, &midi_byte, 1) )
+ {
/* Also send F5 after 3 seconds with no data to handle device disconnect */
if (first == 0 && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS ||
uart->adaptor == SNDRV_SERIAL_GENERIC) &&
(uart->prev_out != substream->number || jiffies-lasttime > 3*HZ)) {
- /* We will need three bytes of data here (worst case). */
- if (uart->buff_in_count >= TX_BUFF_SIZE - 3)
- break;
-
- /* Roland Soundcanvas part selection */
- /* If this substream of the data is different previous
- substream in this uart, send the change part event */
- uart->prev_out = substream->number;
- /* change part */
- snd_uart16550_output_byte(uart, substream, 0xf5);
- /* data */
- snd_uart16550_output_byte(uart, substream, uart->prev_out + 1);
- /* If midi_byte is a data byte, send the previous status byte */
- if ((midi_byte < 0x80) && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS))
- snd_uart16550_output_byte(uart, substream, uart->prev_status[uart->prev_out]);
- }
+ if( snd_uart16550_buffer_can_write( uart, 3 ) )
+ {
+ /* Roland Soundcanvas part selection */
+ /* If this substream of the data is different previous
+ substream in this uart, send the change part event */
+ uart->prev_out = substream->number;
+ /* change part */
+ snd_uart16550_output_byte(uart, substream, 0xf5);
+ /* data */
+ snd_uart16550_output_byte(uart, substream, uart->prev_out + 1);
+ /* If midi_byte is a data byte, send the previous status byte */
+ if ((midi_byte < 0x80) && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS))
+ snd_uart16550_output_byte(uart, substream, uart->prev_status[uart->prev_out]);
+ }
+ else if( !uart->drop_on_full )
+ break;
- /* buffer full? */
- if (uart->buff_in_count >= TX_BUFF_SIZE)
- break;
+ }
/* send midi byte */
- snd_uart16550_output_byte(uart, substream, midi_byte);
+ if( !snd_uart16550_output_byte(uart, substream, midi_byte) && !uart->drop_on_full )
+ break;
+
if (midi_byte >= 0x80 && midi_byte < 0xf0)
uart->prev_status[uart->prev_out] = midi_byte;
first = 1;
+
+ snd_rawmidi_transmit_ack( substream, 1 );
}
lasttime = jiffies;
}
@@ -755,6 +785,7 @@ static int __init snd_uart16550_create(s
unsigned int speed,
unsigned int base,
int adaptor,
+ int droponfull,
snd_uart16550_t **ruart)
{
static snd_device_ops_t ops = {
@@ -771,6 +802,7 @@ static int __init snd_uart16550_create(s
spin_lock_init(&uart->open_lock);
uart->irq = -1;
uart->base = iobase;
+ uart->drop_on_full = droponfull;
if ((err = snd_uart16550_detect(uart)) <= 0) {
printk(KERN_ERR "no UART detected at 0x%lx\n", iobase);
@@ -900,6 +932,7 @@ static int __init snd_serial_probe(int d
speed[dev],
base[dev],
adaptor[dev],
+ droponfull[dev],
&uart)) < 0) {
snd_card_free(card);
return err;
@@ -910,7 +943,7 @@ static int __init snd_serial_probe(int d
return err;
}
- sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s",
+ sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s droponfull %d",
card->shortname,
uart->base,
uart->irq,
@@ -918,7 +951,8 @@ static int __init snd_serial_probe(int d
(int)uart->divisor,
outs[dev],
ins[dev],
- adaptor_names[uart->adaptor]);
+ adaptor_names[uart->adaptor],
+ uart->drop_on_full);
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
@@ -964,7 +998,7 @@ module_exit(alsa_card_serial_exit)
/* format is: snd-serial=enable,index,id,
port,irq,speed,base,outs,
- ins,adaptor */
+ ins,adaptor,droponfull */
static int __init alsa_card_serial_setup(char *str)
{
@@ -981,7 +1015,8 @@ static int __init alsa_card_serial_setup
get_option(&str,&base[nr_dev]) == 2 &&
get_option(&str,&outs[nr_dev]) == 2 &&
get_option(&str,&ins[nr_dev]) == 2 &&
- get_option(&str,&adaptor[nr_dev]) == 2);
+ get_option(&str,&adaptor[nr_dev]) == 2 &&
+ get_option(&str,&droponfull[nr_dev]) == 2 );
nr_dev++;
return 1;
}
-------------------------------------------------------
This SF.net email is sponsored by: SF.net Giveback Program.
Does SourceForge.net help you be more productive? Does it
help you create better code? SHARE THE LOVE, and help us help
YOU! Click Here: http://sourceforge.net/donate/
next prev parent reply other threads:[~2003-12-03 1:41 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-10-29 21:47 [PATCH] serial-u16550 driver. Fixes buffer blocking bug Steve deRosier
2003-10-30 12:58 ` Takashi Iwai
2003-10-30 21:33 ` Steve deRosier
2003-10-31 17:49 ` Takashi Iwai
2003-11-04 1:44 ` Steve deRosier
2003-11-07 17:28 ` Takashi Iwai
2003-12-03 1:41 ` Steve deRosier [this message]
2003-12-03 13:25 ` [PATCH] serial-u16550 driver. Fixes buffer blocking bug (2nd try) Takashi Iwai
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3FCD3F39.5050902@pianodisc.com \
--to=derosier@pianodisc.com \
--cc=alsa-devel@lists.sourceforge.net \
--cc=tiwai@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.