brintos

brintos / linux-shallow public Read only

0
0
Text · 12.8 KiB · 4e57e3b Raw
537 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>,4 *                   Hannu Savolainen 1993-1996,5 *                   Rob Hooft6 *                   7 *  Routines for control of AdLib FM cards (OPL2/OPL3/OPL4 chips)8 *9 *  Most if code is ported from OSS/Lite.10 */11 12#include <sound/opl3.h>13#include <linux/io.h>14#include <linux/delay.h>15#include <linux/module.h>16#include <linux/init.h>17#include <linux/slab.h>18#include <linux/ioport.h>19#include <sound/minors.h>20#include "opl3_voice.h"21 22MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Hannu Savolainen 1993-1996, Rob Hooft");23MODULE_DESCRIPTION("Routines for control of AdLib FM cards (OPL2/OPL3/OPL4 chips)");24MODULE_LICENSE("GPL");25 26static void snd_opl2_command(struct snd_opl3 * opl3, unsigned short cmd, unsigned char val)27{28	unsigned long flags;29	unsigned long port;30 31	/*32	 * The original 2-OP synth requires a quite long delay33	 * after writing to a register.34	 */35 36	port = (cmd & OPL3_RIGHT) ? opl3->r_port : opl3->l_port;37 38	spin_lock_irqsave(&opl3->reg_lock, flags);39 40	outb((unsigned char) cmd, port);41	udelay(10);42 43	outb((unsigned char) val, port + 1);44	udelay(30);45 46	spin_unlock_irqrestore(&opl3->reg_lock, flags);47}48 49static void snd_opl3_command(struct snd_opl3 * opl3, unsigned short cmd, unsigned char val)50{51	unsigned long flags;52	unsigned long port;53 54	/*55	 * The OPL-3 survives with just two INBs56	 * after writing to a register.57	 */58 59	port = (cmd & OPL3_RIGHT) ? opl3->r_port : opl3->l_port;60 61	spin_lock_irqsave(&opl3->reg_lock, flags);62 63	outb((unsigned char) cmd, port);64	inb(opl3->l_port);65	inb(opl3->l_port);66 67	outb((unsigned char) val, port + 1);68	inb(opl3->l_port);69	inb(opl3->l_port);70 71	spin_unlock_irqrestore(&opl3->reg_lock, flags);72}73 74static int snd_opl3_detect(struct snd_opl3 * opl3)75{76	/*77	 * This function returns 1 if the FM chip is present at the given I/O port78	 * The detection algorithm plays with the timer built in the FM chip and79	 * looks for a change in the status register.80	 *81	 * Note! The timers of the FM chip are not connected to AdLib (and compatible)82	 * boards.83	 *84	 * Note2! The chip is initialized if detected.85	 */86 87	unsigned char stat1, stat2, signature;88 89	/* Reset timers 1 and 2 */90	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_TIMER1_MASK | OPL3_TIMER2_MASK);91	/* Reset the IRQ of the FM chip */92	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_IRQ_RESET);93	signature = stat1 = inb(opl3->l_port);	/* Status register */94	if ((stat1 & 0xe0) != 0x00) {	/* Should be 0x00 */95		dev_dbg(opl3->card->dev, "OPL3: stat1 = 0x%x\n", stat1);96		return -ENODEV;97	}98	/* Set timer1 to 0xff */99	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER1, 0xff);100	/* Unmask and start timer 1 */101	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_TIMER2_MASK | OPL3_TIMER1_START);102	/* Now we have to delay at least 80us */103	udelay(200);104	/* Read status after timers have expired */105	stat2 = inb(opl3->l_port);106	/* Stop the timers */107	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_TIMER1_MASK | OPL3_TIMER2_MASK);108	/* Reset the IRQ of the FM chip */109	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_IRQ_RESET);110	if ((stat2 & 0xe0) != 0xc0) {	/* There is no YM3812 */111		dev_dbg(opl3->card->dev, "OPL3: stat2 = 0x%x\n", stat2);112		return -ENODEV;113	}114 115	/* If the toplevel code knows exactly the type of chip, don't try116	   to detect it. */117	if (opl3->hardware != OPL3_HW_AUTO)118		return 0;119 120	/* There is a FM chip on this address. Detect the type (OPL2 to OPL4) */121	if (signature == 0x06) {	/* OPL2 */122		opl3->hardware = OPL3_HW_OPL2;123	} else {124		/*125		 * If we had an OPL4 chip, opl3->hardware would have been set126		 * by the OPL4 driver; so we can assume OPL3 here.127		 */128		if (snd_BUG_ON(!opl3->r_port))129			return -ENODEV;130		opl3->hardware = OPL3_HW_OPL3;131	}132	return 0;133}134 135/*136 *  AdLib timers137 */138 139/*140 *  Timer 1 - 80us141 */142 143static int snd_opl3_timer1_start(struct snd_timer * timer)144{145	unsigned long flags;146	unsigned char tmp;147	unsigned int ticks;148	struct snd_opl3 *opl3;149 150	opl3 = snd_timer_chip(timer);151	spin_lock_irqsave(&opl3->timer_lock, flags);152	ticks = timer->sticks;153	tmp = (opl3->timer_enable | OPL3_TIMER1_START) & ~OPL3_TIMER1_MASK;154	opl3->timer_enable = tmp;155	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER1, 256 - ticks);	/* timer 1 count */156	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp);	/* enable timer 1 IRQ */157	spin_unlock_irqrestore(&opl3->timer_lock, flags);158	return 0;159}160 161static int snd_opl3_timer1_stop(struct snd_timer * timer)162{163	unsigned long flags;164	unsigned char tmp;165	struct snd_opl3 *opl3;166 167	opl3 = snd_timer_chip(timer);168	spin_lock_irqsave(&opl3->timer_lock, flags);169	tmp = (opl3->timer_enable | OPL3_TIMER1_MASK) & ~OPL3_TIMER1_START;170	opl3->timer_enable = tmp;171	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp);	/* disable timer #1 */172	spin_unlock_irqrestore(&opl3->timer_lock, flags);173	return 0;174}175 176/*177 *  Timer 2 - 320us178 */179 180static int snd_opl3_timer2_start(struct snd_timer * timer)181{182	unsigned long flags;183	unsigned char tmp;184	unsigned int ticks;185	struct snd_opl3 *opl3;186 187	opl3 = snd_timer_chip(timer);188	spin_lock_irqsave(&opl3->timer_lock, flags);189	ticks = timer->sticks;190	tmp = (opl3->timer_enable | OPL3_TIMER2_START) & ~OPL3_TIMER2_MASK;191	opl3->timer_enable = tmp;192	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER2, 256 - ticks);	/* timer 1 count */193	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp);	/* enable timer 1 IRQ */194	spin_unlock_irqrestore(&opl3->timer_lock, flags);195	return 0;196}197 198static int snd_opl3_timer2_stop(struct snd_timer * timer)199{200	unsigned long flags;201	unsigned char tmp;202	struct snd_opl3 *opl3;203 204	opl3 = snd_timer_chip(timer);205	spin_lock_irqsave(&opl3->timer_lock, flags);206	tmp = (opl3->timer_enable | OPL3_TIMER2_MASK) & ~OPL3_TIMER2_START;207	opl3->timer_enable = tmp;208	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp);	/* disable timer #1 */209	spin_unlock_irqrestore(&opl3->timer_lock, flags);210	return 0;211}212 213/*214 215 */216 217static const struct snd_timer_hardware snd_opl3_timer1 =218{219	.flags =	SNDRV_TIMER_HW_STOP,220	.resolution =	80000,221	.ticks =	256,222	.start =	snd_opl3_timer1_start,223	.stop =		snd_opl3_timer1_stop,224};225 226static const struct snd_timer_hardware snd_opl3_timer2 =227{228	.flags =	SNDRV_TIMER_HW_STOP,229	.resolution =	320000,230	.ticks =	256,231	.start =	snd_opl3_timer2_start,232	.stop =		snd_opl3_timer2_stop,233};234 235static int snd_opl3_timer1_init(struct snd_opl3 * opl3, int timer_no)236{237	struct snd_timer *timer = NULL;238	struct snd_timer_id tid;239	int err;240 241	tid.dev_class = SNDRV_TIMER_CLASS_CARD;242	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;243	tid.card = opl3->card->number;244	tid.device = timer_no;245	tid.subdevice = 0;246	err = snd_timer_new(opl3->card, "AdLib timer #1", &tid, &timer);247	if (err >= 0) {248		strcpy(timer->name, "AdLib timer #1");249		timer->private_data = opl3;250		timer->hw = snd_opl3_timer1;251	}252	opl3->timer1 = timer;253	return err;254}255 256static int snd_opl3_timer2_init(struct snd_opl3 * opl3, int timer_no)257{258	struct snd_timer *timer = NULL;259	struct snd_timer_id tid;260	int err;261 262	tid.dev_class = SNDRV_TIMER_CLASS_CARD;263	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;264	tid.card = opl3->card->number;265	tid.device = timer_no;266	tid.subdevice = 0;267	err = snd_timer_new(opl3->card, "AdLib timer #2", &tid, &timer);268	if (err >= 0) {269		strcpy(timer->name, "AdLib timer #2");270		timer->private_data = opl3;271		timer->hw = snd_opl3_timer2;272	}273	opl3->timer2 = timer;274	return err;275}276 277/*278 279 */280 281void snd_opl3_interrupt(struct snd_hwdep * hw)282{283	unsigned char status;284	struct snd_opl3 *opl3;285	struct snd_timer *timer;286 287	if (hw == NULL)288		return;289 290	opl3 = hw->private_data;291	status = inb(opl3->l_port);292	if (!(status & 0x80))293		return;294 295	if (status & 0x40) {296		timer = opl3->timer1;297		snd_timer_interrupt(timer, timer->sticks);298	}299	if (status & 0x20) {300		timer = opl3->timer2;301		snd_timer_interrupt(timer, timer->sticks);302	}303}304 305EXPORT_SYMBOL(snd_opl3_interrupt);306 307/*308 309 */310 311static int snd_opl3_free(struct snd_opl3 *opl3)312{313	if (snd_BUG_ON(!opl3))314		return -ENXIO;315	if (opl3->private_free)316		opl3->private_free(opl3);317	snd_opl3_clear_patches(opl3);318	release_and_free_resource(opl3->res_l_port);319	release_and_free_resource(opl3->res_r_port);320	kfree(opl3);321	return 0;322}323 324static int snd_opl3_dev_free(struct snd_device *device)325{326	struct snd_opl3 *opl3 = device->device_data;327	return snd_opl3_free(opl3);328}329 330int snd_opl3_new(struct snd_card *card,331		 unsigned short hardware,332		 struct snd_opl3 **ropl3)333{334	static const struct snd_device_ops ops = {335		.dev_free = snd_opl3_dev_free,336	};337	struct snd_opl3 *opl3;338	int err;339 340	*ropl3 = NULL;341	opl3 = kzalloc(sizeof(*opl3), GFP_KERNEL);342	if (!opl3)343		return -ENOMEM;344 345	opl3->card = card;346	opl3->hardware = hardware;347	spin_lock_init(&opl3->reg_lock);348	spin_lock_init(&opl3->timer_lock);349 350	err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops);351	if (err < 0) {352		snd_opl3_free(opl3);353		return err;354	}355 356	*ropl3 = opl3;357	return 0;358}359 360EXPORT_SYMBOL(snd_opl3_new);361 362int snd_opl3_init(struct snd_opl3 *opl3)363{364	if (! opl3->command) {365		dev_err(opl3->card->dev,366			"snd_opl3_init: command not defined!\n");367		return -EINVAL;368	}369 370	opl3->command(opl3, OPL3_LEFT | OPL3_REG_TEST, OPL3_ENABLE_WAVE_SELECT);371	/* Melodic mode */372	opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION, 0x00);373 374	switch (opl3->hardware & OPL3_HW_MASK) {375	case OPL3_HW_OPL2:376		opl3->max_voices = MAX_OPL2_VOICES;377		break;378	case OPL3_HW_OPL3:379	case OPL3_HW_OPL4:380		opl3->max_voices = MAX_OPL3_VOICES;381		/* Enter OPL3 mode */382		opl3->command(opl3, OPL3_RIGHT | OPL3_REG_MODE, OPL3_OPL3_ENABLE);383	}384	return 0;385}386 387EXPORT_SYMBOL(snd_opl3_init);388 389int snd_opl3_create(struct snd_card *card,390		    unsigned long l_port,391		    unsigned long r_port,392		    unsigned short hardware,393		    int integrated,394		    struct snd_opl3 ** ropl3)395{396	struct snd_opl3 *opl3;397	int err;398 399	*ropl3 = NULL;400	err = snd_opl3_new(card, hardware, &opl3);401	if (err < 0)402		return err;403	if (! integrated) {404		opl3->res_l_port = request_region(l_port, 2, "OPL2/3 (left)");405		if (!opl3->res_l_port) {406			dev_err(card->dev, "opl3: can't grab left port 0x%lx\n", l_port);407			snd_device_free(card, opl3);408			return -EBUSY;409		}410		if (r_port != 0) {411			opl3->res_r_port = request_region(r_port, 2, "OPL2/3 (right)");412			if (!opl3->res_r_port) {413				dev_err(card->dev, "opl3: can't grab right port 0x%lx\n", r_port);414				snd_device_free(card, opl3);415				return -EBUSY;416			}417		}418	}419	opl3->l_port = l_port;420	opl3->r_port = r_port;421 422	switch (opl3->hardware) {423	/* some hardware doesn't support timers */424	case OPL3_HW_OPL3_SV:425	case OPL3_HW_OPL3_CS:426	case OPL3_HW_OPL3_FM801:427		opl3->command = &snd_opl3_command;428		break;429	default:430		opl3->command = &snd_opl2_command;431		err = snd_opl3_detect(opl3);432		if (err < 0) {433			dev_dbg(card->dev, "OPL2/3 chip not detected at 0x%lx/0x%lx\n",434				opl3->l_port, opl3->r_port);435			snd_device_free(card, opl3);436			return err;437		}438		/* detect routine returns correct hardware type */439		switch (opl3->hardware & OPL3_HW_MASK) {440		case OPL3_HW_OPL3:441		case OPL3_HW_OPL4:442			opl3->command = &snd_opl3_command;443		}444	}445 446	snd_opl3_init(opl3);447 448	*ropl3 = opl3;449	return 0;450}451 452EXPORT_SYMBOL(snd_opl3_create);453 454int snd_opl3_timer_new(struct snd_opl3 * opl3, int timer1_dev, int timer2_dev)455{456	int err;457 458	if (timer1_dev >= 0) {459		err = snd_opl3_timer1_init(opl3, timer1_dev);460		if (err < 0)461			return err;462	}463	if (timer2_dev >= 0) {464		err = snd_opl3_timer2_init(opl3, timer2_dev);465		if (err < 0) {466			snd_device_free(opl3->card, opl3->timer1);467			opl3->timer1 = NULL;468			return err;469		}470	}471	return 0;472}473 474EXPORT_SYMBOL(snd_opl3_timer_new);475 476int snd_opl3_hwdep_new(struct snd_opl3 * opl3,477		       int device, int seq_device,478		       struct snd_hwdep ** rhwdep)479{480	struct snd_hwdep *hw;481	struct snd_card *card = opl3->card;482	int err;483 484	if (rhwdep)485		*rhwdep = NULL;486 487	/* create hardware dependent device (direct FM) */488 489	err = snd_hwdep_new(card, "OPL2/OPL3", device, &hw);490	if (err < 0) {491		snd_device_free(card, opl3);492		return err;493	}494	hw->private_data = opl3;495	hw->exclusive = 1;496#ifdef CONFIG_SND_OSSEMUL497	if (device == 0)498		hw->oss_type = SNDRV_OSS_DEVICE_TYPE_DMFM;499#endif500	strcpy(hw->name, hw->id);501	switch (opl3->hardware & OPL3_HW_MASK) {502	case OPL3_HW_OPL2:503		strcpy(hw->name, "OPL2 FM");504		hw->iface = SNDRV_HWDEP_IFACE_OPL2;505		break;506	case OPL3_HW_OPL3:507		strcpy(hw->name, "OPL3 FM");508		hw->iface = SNDRV_HWDEP_IFACE_OPL3;509		break;510	case OPL3_HW_OPL4:511		strcpy(hw->name, "OPL4 FM");512		hw->iface = SNDRV_HWDEP_IFACE_OPL4;513		break;514	}515 516	/* operators - only ioctl */517	hw->ops.open = snd_opl3_open;518	hw->ops.ioctl = snd_opl3_ioctl;519	hw->ops.write = snd_opl3_write;520	hw->ops.release = snd_opl3_release;521 522	opl3->hwdep = hw;523	opl3->seq_dev_num = seq_device;524#if IS_ENABLED(CONFIG_SND_SEQUENCER)525	if (snd_seq_device_new(card, seq_device, SNDRV_SEQ_DEV_ID_OPL3,526			       sizeof(struct snd_opl3 *), &opl3->seq_dev) >= 0) {527		strcpy(opl3->seq_dev->name, hw->name);528		*(struct snd_opl3 **)SNDRV_SEQ_DEVICE_ARGPTR(opl3->seq_dev) = opl3;529	}530#endif531	if (rhwdep)532		*rhwdep = hw;533	return 0;534}535 536EXPORT_SYMBOL(snd_opl3_hwdep_new);537