serial-u16550.c

来自「linux 内核源代码」· C语言 代码 · 共 1,050 行 · 第 1/3 页

C
1,050
字号
					/* 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;			}			/* send 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;	}	spin_unlock_irqrestore(&uart->open_lock, flags);}static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream,					 int up){	unsigned long flags;	struct snd_uart16550 *uart = substream->rmidi->private_data;	spin_lock_irqsave(&uart->open_lock, flags);	if (up)		uart->filemode |= SERIAL_MODE_OUTPUT_TRIGGERED;	else		uart->filemode &= ~SERIAL_MODE_OUTPUT_TRIGGERED;	spin_unlock_irqrestore(&uart->open_lock, flags);	if (up)		snd_uart16550_output_write(substream);}static struct snd_rawmidi_ops snd_uart16550_output ={	.open =		snd_uart16550_output_open,	.close =	snd_uart16550_output_close,	.trigger =	snd_uart16550_output_trigger,};static struct snd_rawmidi_ops snd_uart16550_input ={	.open =		snd_uart16550_input_open,	.close =	snd_uart16550_input_close,	.trigger =	snd_uart16550_input_trigger,};static int snd_uart16550_free(struct snd_uart16550 *uart){	if (uart->irq >= 0)		free_irq(uart->irq, uart);	release_and_free_resource(uart->res_base);	kfree(uart);	return 0;};static int snd_uart16550_dev_free(struct snd_device *device){	struct snd_uart16550 *uart = device->device_data;	return snd_uart16550_free(uart);}static int __devinit snd_uart16550_create(struct snd_card *card,				       unsigned long iobase,				       int irq,				       unsigned int speed,				       unsigned int base,				       int adaptor,				       int droponfull,				       struct snd_uart16550 **ruart){	static struct snd_device_ops ops = {		.dev_free =	snd_uart16550_dev_free,	};	struct snd_uart16550 *uart;	int err;	if ((uart = kzalloc(sizeof(*uart), GFP_KERNEL)) == NULL)		return -ENOMEM;	uart->adaptor = adaptor;	uart->card = card;	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);		snd_uart16550_free(uart);		return -ENODEV;	}	if (irq >= 0 && irq != SNDRV_AUTO_IRQ) {		if (request_irq(irq, snd_uart16550_interrupt,				IRQF_DISABLED, "Serial MIDI", uart)) {			snd_printk("irq %d busy. Using Polling.\n", irq);		} else {			uart->irq = irq;		}	}	uart->divisor = base / speed;	uart->speed = base / (unsigned int)uart->divisor;	uart->speed_base = base;	uart->prev_out = -1;	uart->prev_in = 0;	uart->rstatus = 0;	memset(uart->prev_status, 0x80, sizeof(unsigned char) * SNDRV_SERIAL_MAX_OUTS);	init_timer(&uart->buffer_timer);	uart->buffer_timer.function = snd_uart16550_buffer_timer;	uart->buffer_timer.data = (unsigned long)uart;	uart->timer_running = 0;	/* Register device */	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, uart, &ops)) < 0) {		snd_uart16550_free(uart);		return err;	}	switch (uart->adaptor) {	case SNDRV_SERIAL_MS124W_SA:	case SNDRV_SERIAL_MS124W_MB:		/* MS-124W can draw power from RTS and DTR if they		   are in opposite states. */ 		outb(UART_MCR_RTS | (0&UART_MCR_DTR), uart->base + UART_MCR);		break;	case SNDRV_SERIAL_MS124T:		/* MS-124T can draw power from RTS and/or DTR (preferably		   both) if they are asserted. */		outb(UART_MCR_RTS | UART_MCR_DTR, uart->base + UART_MCR);		break;	default:		break;	}	if (ruart)		*ruart = uart;	return 0;}static void __devinit snd_uart16550_substreams(struct snd_rawmidi_str *stream){	struct snd_rawmidi_substream *substream;	list_for_each_entry(substream, &stream->substreams, list) {		sprintf(substream->name, "Serial MIDI %d", substream->number + 1);	}}static int __devinit snd_uart16550_rmidi(struct snd_uart16550 *uart, int device,				      int outs, int ins,				      struct snd_rawmidi **rmidi){	struct snd_rawmidi *rrawmidi;	int err;	err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device,			      outs, ins, &rrawmidi);	if (err < 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);	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;	rrawmidi->private_data = uart;	if (rmidi)		*rmidi = rrawmidi;	return 0;}static int __devinit snd_serial_probe(struct platform_device *devptr){	struct snd_card *card;	struct snd_uart16550 *uart;	int err;	int dev = devptr->id;	switch (adaptor[dev]) {	case SNDRV_SERIAL_SOUNDCANVAS:		ins[dev] = 1;		break;	case SNDRV_SERIAL_MS124T:	case SNDRV_SERIAL_MS124W_SA:		outs[dev] = 1;		ins[dev] = 1;		break;	case SNDRV_SERIAL_MS124W_MB:		outs[dev] = 16;		ins[dev] = 1;		break;	case SNDRV_SERIAL_GENERIC:		break;	default:		snd_printk("Adaptor type is out of range 0-%d (%d)\n",			   SNDRV_SERIAL_MAX_ADAPTOR, adaptor[dev]);		return -ENODEV;	}	if (outs[dev] < 1 || outs[dev] > SNDRV_SERIAL_MAX_OUTS) {		snd_printk("Count of outputs is out of range 1-%d (%d)\n",			   SNDRV_SERIAL_MAX_OUTS, outs[dev]);		return -ENODEV;	}	if (ins[dev] < 1 || ins[dev] > SNDRV_SERIAL_MAX_INS) {		snd_printk("Count of inputs is out of range 1-%d (%d)\n",			   SNDRV_SERIAL_MAX_INS, ins[dev]);		return -ENODEV;	}	card  = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);	if (card == NULL)		return -ENOMEM;	strcpy(card->driver, "Serial");	strcpy(card->shortname, "Serial MIDI (UART16550A)");	if ((err = snd_uart16550_create(card,					port[dev],					irq[dev],					speed[dev],					base[dev],					adaptor[dev],					droponfull[dev],					&uart)) < 0)		goto _err;	err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi);	if (err < 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,		uart->base,		uart->irq,		uart->speed,		(int)uart->divisor,		outs[dev],		ins[dev],		adaptor_names[uart->adaptor],		uart->drop_on_full);	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 __devexit 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		= __devexit_p( snd_serial_remove),	.driver		= {		.name	= SND_SERIAL_DRIVER	},};static void 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 i, cards, err;	if ((err = platform_driver_register(&snd_serial_driver)) < 0)		return err;	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){	snd_serial_unregister_all();}module_init(alsa_card_serial_init)module_exit(alsa_card_serial_exit)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?