portman2x4.c

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

C
877
字号
	/* Wait for settling */	while ((portman_read_status(pm) & ESTB) == ESTB)		cpu_relax();}static int portman_probe(struct parport *p){	/* Initialize the parallel port data register.  Will set Rx clocks	 * low in case we happen to be addressing the Rx ports at this time.	 */	/* 1 */	parport_write_data(p, 0);	/* Initialize the parallel port command register, thus initializing	 * hardware handshake lines to midi box:	 *	 *                                  Strobe = 0	 *                                  Interrupt Enable = 0            	 */	/* 2 */	parport_write_control(p, 0);	/* Check if Portman PC/P 2x4 is out there. */	/* 3 */	parport_write_control(p, RXDATA0);	/* Write Strobe=0 to command reg. */	/* Check for ESTB to be clear */	/* 4 */	if ((parport_read_status(p) & ESTB) == ESTB)		return 1;	/* CODE 1 - Strobe Failure. */	/* Set for RXDATA0 where no damage will be done. */	/* 5 */	parport_write_control(p, RXDATA0 + STROBE);	/* Write Strobe=1 to command reg. */	/* 6 */	if ((parport_read_status(p) & ESTB) != ESTB)		return 1;	/* CODE 1 - Strobe Failure. */	/* 7 */	parport_write_control(p, 0);	/* Reset Strobe=0. */	/* Check if Tx circuitry is functioning properly.  If initialized 	 * unit TxEmpty is false, send out char and see if if goes true.	 */	/* 8 */	parport_write_control(p, TXDATA0);	/* Tx channel 0, strobe off. */	/* If PCP channel's TxEmpty is set (TxEmpty is read through the PP	 * Status Register), then go write data.  Else go back and wait.	 */	/* 9 */	if ((parport_read_status(p) & TXEMPTY) == 0)		return 2;	/* Return OK status. */	return 0;}static int portman_device_init(struct portman *pm){	portman_flush_input(pm, 0);	portman_flush_input(pm, 1);	return 0;}/********************************************************************* * Rawmidi *********************************************************************/static int snd_portman_midi_open(struct snd_rawmidi_substream *substream){	return 0;}static int snd_portman_midi_close(struct snd_rawmidi_substream *substream){	return 0;}static void snd_portman_midi_input_trigger(struct snd_rawmidi_substream *substream,					   int up){	struct portman *pm = substream->rmidi->private_data;	unsigned long flags;	spin_lock_irqsave(&pm->reg_lock, flags);	if (up)		pm->mode[substream->number] |= PORTMAN2X4_MODE_INPUT_TRIGGERED;	else		pm->mode[substream->number] &= ~PORTMAN2X4_MODE_INPUT_TRIGGERED;	spin_unlock_irqrestore(&pm->reg_lock, flags);}static void snd_portman_midi_output_trigger(struct snd_rawmidi_substream *substream,					    int up){	struct portman *pm = substream->rmidi->private_data;	unsigned long flags;	unsigned char byte;	spin_lock_irqsave(&pm->reg_lock, flags);	if (up) {		while ((snd_rawmidi_transmit(substream, &byte, 1) == 1))			portman_write_midi(pm, substream->number, byte);	}	spin_unlock_irqrestore(&pm->reg_lock, flags);}static struct snd_rawmidi_ops snd_portman_midi_output = {	.open =		snd_portman_midi_open,	.close =	snd_portman_midi_close,	.trigger =	snd_portman_midi_output_trigger,};static struct snd_rawmidi_ops snd_portman_midi_input = {	.open =		snd_portman_midi_open,	.close =	snd_portman_midi_close,	.trigger =	snd_portman_midi_input_trigger,};/* Create and initialize the rawmidi component */static int __devinit snd_portman_rawmidi_create(struct snd_card *card){	struct portman *pm = card->private_data;	struct snd_rawmidi *rmidi;	struct snd_rawmidi_substream *substream;	int err;		err = snd_rawmidi_new(card, CARD_NAME, 0, 			      PORTMAN_NUM_OUTPUT_PORTS, 			      PORTMAN_NUM_INPUT_PORTS, 			      &rmidi);	if (err < 0) 		return err;	rmidi->private_data = pm;	strcpy(rmidi->name, CARD_NAME);	rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |		            SNDRV_RAWMIDI_INFO_INPUT |                            SNDRV_RAWMIDI_INFO_DUPLEX;	pm->rmidi = rmidi;	/* register rawmidi ops */	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, 			    &snd_portman_midi_output);	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, 			    &snd_portman_midi_input);	/* name substreams */	/* output */	list_for_each_entry(substream,			    &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,			    list) {		sprintf(substream->name,			"Portman2x4 %d", substream->number+1);	}	/* input */	list_for_each_entry(substream,			    &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams,			    list) {		pm->midi_input[substream->number] = substream;		sprintf(substream->name,			"Portman2x4 %d", substream->number+1);	}	return err;}/********************************************************************* * parport stuff *********************************************************************/static void snd_portman_interrupt(void *userdata){	unsigned char midivalue = 0;	struct portman *pm = ((struct snd_card*)userdata)->private_data;	spin_lock(&pm->reg_lock);	/* While any input data is waiting */	while ((portman_read_status(pm) & INT_REQ) == INT_REQ) {		/* If data available on channel 0, 		   read it and stuff it into the queue. */		if (portman_data_avail(pm, 0)) {			/* Read Midi */			midivalue = portman_read_midi(pm, 0);			/* put midi into queue... */			if (pm->mode[0] & PORTMAN2X4_MODE_INPUT_TRIGGERED)				snd_rawmidi_receive(pm->midi_input[0],						    &midivalue, 1);		}		/* If data available on channel 1, 		   read it and stuff it into the queue. */		if (portman_data_avail(pm, 1)) {			/* Read Midi */			midivalue = portman_read_midi(pm, 1);			/* put midi into queue... */			if (pm->mode[1] & PORTMAN2X4_MODE_INPUT_TRIGGERED)				snd_rawmidi_receive(pm->midi_input[1],						    &midivalue, 1);		}	}	spin_unlock(&pm->reg_lock);}static int __devinit snd_portman_probe_port(struct parport *p){	struct pardevice *pardev;	int res;	pardev = parport_register_device(p, DRIVER_NAME,					 NULL, NULL, NULL,					 0, NULL);	if (!pardev)		return -EIO;		if (parport_claim(pardev)) {		parport_unregister_device(pardev);		return -EIO;	}	res = portman_probe(p);	parport_release(pardev);	parport_unregister_device(pardev);	return res ? -EIO : 0;}static void __devinit snd_portman_attach(struct parport *p){	struct platform_device *device;	device = platform_device_alloc(PLATFORM_DRIVER, device_count);	if (!device)		return;	/* Temporary assignment to forward the parport */	platform_set_drvdata(device, p);	if (platform_device_add(device) < 0) {		platform_device_put(device);		return;	}	/* Since we dont get the return value of probe	 * We need to check if device probing succeeded or not */	if (!platform_get_drvdata(device)) {		platform_device_unregister(device);		return;	}	/* register device in global table */	platform_devices[device_count] = device;	device_count++;}static void snd_portman_detach(struct parport *p){	/* nothing to do here */}static struct parport_driver portman_parport_driver = {	.name   = "portman2x4",	.attach = snd_portman_attach,	.detach = snd_portman_detach};/********************************************************************* * platform stuff *********************************************************************/static void snd_portman_card_private_free(struct snd_card *card){	struct portman *pm = card->private_data;	struct pardevice *pardev = pm->pardev;	if (pardev) {		if (pm->pardev_claimed)			parport_release(pardev);		parport_unregister_device(pardev);	}	portman_free(pm);}static int __devinit snd_portman_probe(struct platform_device *pdev){	struct pardevice *pardev;	struct parport *p;	int dev = pdev->id;	struct snd_card *card = NULL;	struct portman *pm = NULL;	int err;	p = platform_get_drvdata(pdev);	platform_set_drvdata(pdev, NULL);	if (dev >= SNDRV_CARDS)		return -ENODEV;	if (!enable[dev]) 		return -ENOENT;	if ((err = snd_portman_probe_port(p)) < 0)		return err;	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);	if (card == NULL) {		snd_printd("Cannot create card\n");		return -ENOMEM;	}	strcpy(card->driver, DRIVER_NAME);	strcpy(card->shortname, CARD_NAME);	sprintf(card->longname,  "%s at 0x%lx, irq %i", 		card->shortname, p->base, p->irq);	pardev = parport_register_device(p,                     /* port */					 DRIVER_NAME,           /* name */					 NULL,                  /* preempt */					 NULL,                  /* wakeup */					 snd_portman_interrupt, /* ISR */					 PARPORT_DEV_EXCL,      /* flags */					 (void *)card);         /* private */	if (pardev == NULL) {		snd_printd("Cannot register pardevice\n");		err = -EIO;		goto __err;	}	if ((err = portman_create(card, pardev, &pm)) < 0) {		snd_printd("Cannot create main component\n");		parport_unregister_device(pardev);		goto __err;	}	card->private_data = pm;	card->private_free = snd_portman_card_private_free;		if ((err = snd_portman_rawmidi_create(card)) < 0) {		snd_printd("Creating Rawmidi component failed\n");		goto __err;	}	/* claim parport */	if (parport_claim(pardev)) {		snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base);		err = -EIO;		goto __err;	}	pm->pardev_claimed = 1;	/* init device */	if ((err = portman_device_init(pm)) < 0)		goto __err;	platform_set_drvdata(pdev, card);	/* At this point card will be usable */	if ((err = snd_card_register(card)) < 0) {		snd_printd("Cannot register card\n");		goto __err;	}	snd_printk(KERN_INFO "Portman 2x4 on 0x%lx\n", p->base);	return 0;__err:	snd_card_free(card);	return err;}static int __devexit snd_portman_remove(struct platform_device *pdev){	struct snd_card *card = platform_get_drvdata(pdev);	if (card)		snd_card_free(card);	return 0;}static struct platform_driver snd_portman_driver = {	.probe  = snd_portman_probe,	.remove = __devexit_p(snd_portman_remove),	.driver = {		.name = PLATFORM_DRIVER	}};/********************************************************************* * module init stuff *********************************************************************/static void snd_portman_unregister_all(void){	int i;	for (i = 0; i < SNDRV_CARDS; ++i) {		if (platform_devices[i]) {			platform_device_unregister(platform_devices[i]);			platform_devices[i] = NULL;		}	}			platform_driver_unregister(&snd_portman_driver);	parport_unregister_driver(&portman_parport_driver);}static int __init snd_portman_module_init(void){	int err;	if ((err = platform_driver_register(&snd_portman_driver)) < 0)		return err;	if (parport_register_driver(&portman_parport_driver) != 0) {		platform_driver_unregister(&snd_portman_driver);		return -EIO;	}	if (device_count == 0) {		snd_portman_unregister_all();		return -ENODEV;	}	return 0;}static void __exit snd_portman_module_exit(void){	snd_portman_unregister_all();}module_init(snd_portman_module_init);module_exit(snd_portman_module_exit);

⌨️ 快捷键说明

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