#include <sound/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/moduleparam.h>
MODULE_DESCRIPTION("MIDI serial u16550");
MODULE_LICENSE("GPL");
-MODULE_CLASSES("{sound}");
-MODULE_DEVICES("{{ALSA, MIDI serial u16550}}");
+MODULE_SUPPORTED_DEVICE("{{ALSA, MIDI serial u16550}}");
#define SNDRV_SERIAL_SOUNDCANVAS 0 /* Roland Soundcanvas; F5 NN selects part */
#define SNDRV_SERIAL_MS124T 1 /* Midiator MS-124T */
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 };
-static int boot_devs;
-module_param_array(index, int, boot_devs, 0444);
+module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for Serial MIDI.");
-MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-module_param_array(id, charp, boot_devs, 0444);
+module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for Serial MIDI.");
-MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-module_param_array(enable, bool, boot_devs, 0444);
+module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable UART16550A chip.");
-MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-module_param_array(port, long, boot_devs, 0444);
+module_param_array(port, long, NULL, 0444);
MODULE_PARM_DESC(port, "Port # for UART16550A chip.");
-MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
-module_param_array(irq, int, boot_devs, 0444);
+module_param_array(irq, int, NULL, 0444);
MODULE_PARM_DESC(irq, "IRQ # for UART16550A chip.");
-MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-module_param_array(speed, int, boot_devs, 0444);
+module_param_array(speed, int, NULL, 0444);
MODULE_PARM_DESC(speed, "Speed in bauds.");
-MODULE_PARM_SYNTAX(speed, SNDRV_ENABLED ",allows:{9600,19200,38400,57600,115200},dialog:list");
-module_param_array(base, int, boot_devs, 0444);
+module_param_array(base, int, NULL, 0444);
MODULE_PARM_DESC(base, "Base for divisor in bauds.");
-MODULE_PARM_SYNTAX(base, SNDRV_ENABLED ",allows:{57600,115200,230400,460800},dialog:list");
-module_param_array(outs, int, boot_devs, 0444);
+module_param_array(outs, int, NULL, 0444);
MODULE_PARM_DESC(outs, "Number of MIDI outputs.");
-module_param_array(ins, int, boot_devs, 0444);
+module_param_array(ins, int, NULL, 0444);
MODULE_PARM_DESC(ins, "Number of MIDI inputs.");
-module_param_array(droponfull, bool, boot_devs, 0444);
+module_param_array(droponfull, bool, NULL, 0444);
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");
-module_param_array(adaptor, int, boot_devs, 0444);
+module_param_array(adaptor, int, NULL, 0444);
MODULE_PARM_DESC(adaptor, "Type of adaptor.");
-MODULE_PARM_SYNTAX(adaptor, SNDRV_ENABLED ",allows:{{0=Soundcanvas,1=MS-124T,2=MS-124W S/A,3=MS-124W M/B,4=Generic}},dialog:list");
/*#define SNDRV_SERIAL_MS124W_MB_NOCOMBO 1*/ /* Address outs as 0-3 instead of bitmap */
#define SERIAL_MODE_OUTPUT_TRIGGERED (1 << 3)
typedef struct _snd_uart16550 {
- snd_card_t *card;
- snd_rawmidi_t *rmidi;
- snd_rawmidi_substream_t *midi_output[SNDRV_SERIAL_MAX_OUTS];
- snd_rawmidi_substream_t *midi_input[SNDRV_SERIAL_MAX_INS];
+ struct snd_card *card;
+ struct snd_rawmidi *rmidi;
+ struct snd_rawmidi_substream *midi_output[SNDRV_SERIAL_MAX_OUTS];
+ struct snd_rawmidi_substream *midi_input[SNDRV_SERIAL_MAX_INS];
int filemode; //open status of file
} snd_uart16550_t;
-static snd_card_t *snd_serial_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
+static struct platform_device *devices[SNDRV_CARDS];
-inline static void snd_uart16550_add_timer(snd_uart16550_t *uart)
+static inline void snd_uart16550_add_timer(snd_uart16550_t *uart)
{
if (! uart->timer_running) {
/* timer 38600bps * 10bit * 16byte */
}
}
-inline static void snd_uart16550_del_timer(snd_uart16550_t *uart)
+static inline void snd_uart16550_del_timer(snd_uart16550_t *uart)
{
if (uart->timer_running) {
del_timer(&uart->buffer_timer);
}
/* This macro is only used in snd_uart16550_io_loop */
-inline static void snd_uart16550_buffer_output(snd_uart16550_t *uart)
+static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart)
{
unsigned short buff_out = uart->buff_out;
if( uart->buff_in_count > 0 ) {
}
else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) {
snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
- }
+ }
} else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) {
snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
}
* Note that some devices need OUT2 to be set before they will generate
* interrupts at all. (Possibly tied to an internal pull-up on CTS?)
*/
-static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id)
{
snd_uart16550_t *uart;
/* When the polling mode, this function calls snd_uart16550_io_loop. */
static void snd_uart16550_buffer_timer(unsigned long data)
{
+ unsigned long flags;
snd_uart16550_t *uart;
uart = (snd_uart16550_t *)data;
- spin_lock(&uart->open_lock);
+ spin_lock_irqsave(&uart->open_lock, flags);
snd_uart16550_del_timer(uart);
snd_uart16550_io_loop(uart);
- spin_unlock(&uart->open_lock);
+ spin_unlock_irqrestore(&uart->open_lock, flags);
}
/*
}
}
-static int snd_uart16550_input_open(snd_rawmidi_substream_t * substream)
+static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
- snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, substream->rmidi->private_data, return -ENXIO);
+ snd_uart16550_t *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
if (uart->filemode == SERIAL_MODE_NOT_OPENED)
return 0;
}
-static int snd_uart16550_input_close(snd_rawmidi_substream_t * substream)
+static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
- snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, substream->rmidi->private_data, return -ENXIO);
+ snd_uart16550_t *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
uart->filemode &= ~SERIAL_MODE_INPUT_OPEN;
return 0;
}
-static void snd_uart16550_input_trigger(snd_rawmidi_substream_t * substream, int up)
+static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream, int up)
{
unsigned long flags;
- snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, substream->rmidi->private_data, return);
+ snd_uart16550_t *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
if (up) {
spin_unlock_irqrestore(&uart->open_lock, flags);
}
-static int snd_uart16550_output_open(snd_rawmidi_substream_t * substream)
+static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
- snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, substream->rmidi->private_data, return -ENXIO);
+ snd_uart16550_t *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
if (uart->filemode == SERIAL_MODE_NOT_OPENED)
return 0;
};
-static int snd_uart16550_output_close(snd_rawmidi_substream_t * substream)
+static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
- snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, substream->rmidi->private_data, return -ENXIO);
+ snd_uart16550_t *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
uart->filemode &= ~SERIAL_MODE_OUTPUT_OPEN;
return 0;
};
-inline static int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num )
+static inline int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num )
{
if( uart->buff_in_count + Num < TX_BUFF_SIZE )
return 1;
return 0;
}
-inline static int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte)
+static inline 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 ) {
return 0;
}
-static int snd_uart16550_output_byte(snd_uart16550_t *uart, snd_rawmidi_substream_t * substream, unsigned char midi_byte)
+static int snd_uart16550_output_byte(snd_uart16550_t *uart, struct snd_rawmidi_substream *substream, unsigned char midi_byte)
{
if (uart->buff_in_count == 0 /* Buffer empty? */
&& ((uart->adaptor != SNDRV_SERIAL_MS124W_SA &&
return 1;
}
-static void snd_uart16550_output_write(snd_rawmidi_substream_t * substream)
+static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
unsigned char midi_byte, addr_byte;
- snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, substream->rmidi->private_data, return);
+ snd_uart16550_t *uart = substream->rmidi->private_data;
char first;
static unsigned long lasttime=0;
break;
if (snd_rawmidi_transmit(substream, &midi_byte, 1) != 1)
break;
-#if SNDRV_SERIAL_MS124W_MB_NOCOMBO
+#ifdef SNDRV_SERIAL_MS124W_MB_NOCOMBO
/* select exactly one of the four ports */
addr_byte = (1 << (substream->number + 4)) | 0x08;
#else
spin_unlock_irqrestore(&uart->open_lock, flags);
}
-static void snd_uart16550_output_trigger(snd_rawmidi_substream_t * substream, int up)
+static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
unsigned long flags;
- snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, substream->rmidi->private_data, return);
+ snd_uart16550_t *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
if (up) {
snd_uart16550_output_write(substream);
}
-static snd_rawmidi_ops_t snd_uart16550_output =
+static struct snd_rawmidi_ops snd_uart16550_output =
{
.open = snd_uart16550_output_open,
.close = snd_uart16550_output_close,
.trigger = snd_uart16550_output_trigger,
};
-static snd_rawmidi_ops_t snd_uart16550_input =
+static struct snd_rawmidi_ops snd_uart16550_input =
{
.open = snd_uart16550_input_open,
.close = snd_uart16550_input_close,
{
if (uart->irq >= 0)
free_irq(uart->irq, (void *)uart);
- if (uart->res_base) {
- release_resource(uart->res_base);
- kfree_nocheck(uart->res_base);
- }
- snd_magic_kfree(uart);
+ release_and_free_resource(uart->res_base);
+ kfree(uart);
return 0;
};
-static int snd_uart16550_dev_free(snd_device_t *device)
+static int snd_uart16550_dev_free(struct snd_device *device)
{
- snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, device->device_data, return -ENXIO);
+ snd_uart16550_t *uart = device->device_data;
return snd_uart16550_free(uart);
}
-static int __init snd_uart16550_create(snd_card_t * card,
+static int __init snd_uart16550_create(struct snd_card *card,
unsigned long iobase,
int irq,
unsigned int speed,
int droponfull,
snd_uart16550_t **ruart)
{
- static snd_device_ops_t ops = {
+ static struct snd_device_ops ops = {
.dev_free = snd_uart16550_dev_free,
};
snd_uart16550_t *uart;
int err;
- if ((uart = snd_magic_kcalloc(snd_uart16550_t, 0, GFP_KERNEL)) == NULL)
+ if ((uart = kzalloc(sizeof(*uart), GFP_KERNEL)) == NULL)
return -ENOMEM;
uart->adaptor = adaptor;
uart->card = card;
if ((err = snd_uart16550_detect(uart)) <= 0) {
printk(KERN_ERR "no UART detected at 0x%lx\n", iobase);
- return err;
+ snd_uart16550_free(uart);
+ return -ENODEV;
}
if (irq >= 0 && irq != SNDRV_AUTO_IRQ) {
if (request_irq(irq, snd_uart16550_interrupt,
- SA_INTERRUPT, "Serial MIDI", (void *) uart)) {
+ IRQF_DISABLED, "Serial MIDI", (void *) uart)) {
snd_printk("irq %d busy. Using Polling.\n", irq);
} else {
uart->irq = irq;
return 0;
}
-static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int outs, int ins, snd_rawmidi_t **rmidi)
+static void __init snd_uart16550_substreams(struct snd_rawmidi_str *stream)
{
- snd_rawmidi_t *rrawmidi;
+ struct list_head *list;
+
+ list_for_each(list, &stream->substreams) {
+ struct snd_rawmidi_substream *substream = list_entry(list, struct snd_rawmidi_substream, list);
+ sprintf(substream->name, "Serial MIDI %d", substream->number + 1);
+ }
+}
+
+static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int outs, int ins, struct snd_rawmidi **rmidi)
+{
+ struct snd_rawmidi *rrawmidi;
int err;
if ((err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device, outs, ins, &rrawmidi)) < 0)
return err;
snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_uart16550_input);
snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_uart16550_output);
- sprintf(rrawmidi->name, "uart16550 MIDI #%d", device);
+ strcpy(rrawmidi->name, "Serial MIDI");
+ snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
+ snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
rrawmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
SNDRV_RAWMIDI_INFO_INPUT |
SNDRV_RAWMIDI_INFO_DUPLEX;
return 0;
}
-static int __init snd_serial_probe(int dev)
+static int __init snd_serial_probe(struct platform_device *devptr)
{
- snd_card_t *card;
+ struct snd_card *card;
snd_uart16550_t *uart;
int err;
-
- if (!enable[dev])
- return -ENOENT;
+ int dev = devptr->id;
switch (adaptor[dev]) {
case SNDRV_SERIAL_SOUNDCANVAS:
return -ENOMEM;
strcpy(card->driver, "Serial");
- strcpy(card->shortname, "Serial midi (uart16550A)");
+ strcpy(card->shortname, "Serial MIDI (UART16550A)");
if ((err = snd_uart16550_create(card,
port[dev],
base[dev],
adaptor[dev],
droponfull[dev],
- &uart)) < 0) {
- snd_card_free(card);
- return err;
- }
+ &uart)) < 0)
+ goto _err;
- if ((err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi)) < 0) {
- snd_card_free(card);
- return err;
- }
+ if ((err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi)) < 0)
+ goto _err;
sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s droponfull %d",
card->shortname,
adaptor_names[uart->adaptor],
uart->drop_on_full);
- if ((err = snd_card_register(card)) < 0) {
- snd_card_free(card);
- return err;
- }
- snd_serial_cards[dev] = card;
+ snd_card_set_dev(card, &devptr->dev);
+
+ if ((err = snd_card_register(card)) < 0)
+ goto _err;
+
+ platform_set_drvdata(devptr, card);
return 0;
+
+ _err:
+ snd_card_free(card);
+ return err;
+}
+
+static int snd_serial_remove(struct platform_device *devptr)
+{
+ snd_card_free(platform_get_drvdata(devptr));
+ platform_set_drvdata(devptr, NULL);
+ return 0;
+}
+
+#define SND_SERIAL_DRIVER "snd_serial_u16550"
+
+static struct platform_driver snd_serial_driver = {
+ .probe = snd_serial_probe,
+ .remove = snd_serial_remove,
+ .driver = {
+ .name = SND_SERIAL_DRIVER
+ },
+};
+
+static void __init_or_module snd_serial_unregister_all(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(devices); ++i)
+ platform_device_unregister(devices[i]);
+ platform_driver_unregister(&snd_serial_driver);
}
static int __init alsa_card_serial_init(void)
{
- int dev = 0;
- int cards = 0;
+ int i, cards, err;
- for (dev = 0; dev < SNDRV_CARDS; dev++) {
- if (snd_serial_probe(dev) == 0)
- cards++;
- }
+ if ((err = platform_driver_register(&snd_serial_driver)) < 0)
+ return err;
- if (cards == 0) {
+ cards = 0;
+ for (i = 0; i < SNDRV_CARDS; i++) {
+ struct platform_device *device;
+ if (! enable[i])
+ continue;
+ device = platform_device_register_simple(SND_SERIAL_DRIVER,
+ i, NULL, 0);
+ if (IS_ERR(device))
+ continue;
+ if (!platform_get_drvdata(device)) {
+ platform_device_unregister(device);
+ continue;
+ }
+ devices[i] = device;
+ cards++;
+ }
+ if (! cards) {
#ifdef MODULE
printk(KERN_ERR "serial midi soundcard not found or device busy\n");
#endif
+ snd_serial_unregister_all();
return -ENODEV;
}
return 0;
static void __exit alsa_card_serial_exit(void)
{
- int dev;
-
- for (dev = 0; dev < SNDRV_CARDS; dev++) {
- if (snd_serial_cards[dev] != NULL)
- snd_card_free(snd_serial_cards[dev]);
- }
+ snd_serial_unregister_all();
}
module_init(alsa_card_serial_init)