brintos

brintos / linux-shallow public Read only

0
0
Text · 38.0 KiB · b38a4e2 Raw
1541 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Soundfont generic routines.4 *	It is intended that these should be used by any driver that is willing5 *	to accept soundfont patches.6 *7 *  Copyright (C) 1999 Steve Ratcliffe8 *  Copyright (c) 1999-2000 Takashi Iwai <tiwai@suse.de>9 */10/*11 * Deal with reading in of a soundfont.  Code follows the OSS way12 * of doing things so that the old sfxload utility can be used.13 * Everything may change when there is an alsa way of doing things.14 */15#include <linux/uaccess.h>16#include <linux/slab.h>17#include <linux/export.h>18#include <sound/core.h>19#include <sound/soundfont.h>20#include <sound/seq_oss_legacy.h>21 22/* Prototypes for static functions */23 24static int open_patch(struct snd_sf_list *sflist, const char __user *data,25		      int count, int client);26static struct snd_soundfont *newsf(struct snd_sf_list *sflist, int type, char *name);27static int is_identical_font(struct snd_soundfont *sf, int type, unsigned char *name);28static int close_patch(struct snd_sf_list *sflist);29static int probe_data(struct snd_sf_list *sflist, int sample_id);30static void set_zone_counter(struct snd_sf_list *sflist,31			     struct snd_soundfont *sf, struct snd_sf_zone *zp);32static struct snd_sf_zone *sf_zone_new(struct snd_sf_list *sflist,33				       struct snd_soundfont *sf);34static void set_sample_counter(struct snd_sf_list *sflist,35			       struct snd_soundfont *sf, struct snd_sf_sample *sp);36static struct snd_sf_sample *sf_sample_new(struct snd_sf_list *sflist,37					   struct snd_soundfont *sf);38static void sf_sample_delete(struct snd_sf_list *sflist,39			     struct snd_soundfont *sf, struct snd_sf_sample *sp);40static int load_map(struct snd_sf_list *sflist, const void __user *data, int count);41static int load_info(struct snd_card *card, struct snd_sf_list *sflist,42		     const void __user *data, long count);43static int remove_info(struct snd_sf_list *sflist, struct snd_soundfont *sf,44		       int bank, int instr);45static void init_voice_info(struct soundfont_voice_info *avp);46static void init_voice_parm(struct soundfont_voice_parm *pp);47static struct snd_sf_sample *set_sample(struct snd_soundfont *sf,48					struct soundfont_voice_info *avp);49static struct snd_sf_sample *find_sample(struct snd_soundfont *sf, int sample_id);50static int load_data(struct snd_sf_list *sflist, const void __user *data, long count);51static void rebuild_presets(struct snd_sf_list *sflist);52static void add_preset(struct snd_sf_list *sflist, struct snd_sf_zone *cur);53static void delete_preset(struct snd_sf_list *sflist, struct snd_sf_zone *zp);54static struct snd_sf_zone *search_first_zone(struct snd_sf_list *sflist,55					     int bank, int preset, int key);56static int search_zones(struct snd_sf_list *sflist, int *notep, int vel,57			int preset, int bank, struct snd_sf_zone **table,58			int max_layers, int level);59static int get_index(int bank, int instr, int key);60static void snd_sf_init(struct snd_sf_list *sflist);61static void snd_sf_clear(struct snd_sf_list *sflist);62 63/*64 * lock access to sflist65 */66static void67lock_preset(struct snd_sf_list *sflist)68{69	unsigned long flags;70	mutex_lock(&sflist->presets_mutex);71	spin_lock_irqsave(&sflist->lock, flags);72	sflist->presets_locked = 1;73	spin_unlock_irqrestore(&sflist->lock, flags);74}75 76 77/*78 * remove lock79 */80static void81unlock_preset(struct snd_sf_list *sflist)82{83	unsigned long flags;84	spin_lock_irqsave(&sflist->lock, flags);85	sflist->presets_locked = 0;86	spin_unlock_irqrestore(&sflist->lock, flags);87	mutex_unlock(&sflist->presets_mutex);88}89 90 91/*92 * close the patch if the patch was opened by this client.93 */94int95snd_soundfont_close_check(struct snd_sf_list *sflist, int client)96{97	unsigned long flags;98	spin_lock_irqsave(&sflist->lock, flags);99	if (sflist->open_client == client)  {100		spin_unlock_irqrestore(&sflist->lock, flags);101		return close_patch(sflist);102	}103	spin_unlock_irqrestore(&sflist->lock, flags);104	return 0;105}106 107 108/*109 * Deal with a soundfont patch.  Any driver could use these routines110 * although it was designed for the AWE64.111 *112 * The sample_write and callargs parameters allow a callback into113 * the actual driver to write sample data to the board or whatever114 * it wants to do with it.115 */116int117snd_soundfont_load(struct snd_card *card,118		   struct snd_sf_list *sflist, const void __user *data,119		   long count, int client)120{121	struct soundfont_patch_info patch;122	unsigned long flags;123	int  rc;124 125	if (count < (long)sizeof(patch)) {126		dev_err(card->dev, "patch record too small %ld\n", count);127		return -EINVAL;128	}129	if (copy_from_user(&patch, data, sizeof(patch)))130		return -EFAULT;131 132	count -= sizeof(patch);133	data += sizeof(patch);134 135	if (patch.key != SNDRV_OSS_SOUNDFONT_PATCH) {136		dev_err(card->dev, "The wrong kind of patch %x\n", patch.key);137		return -EINVAL;138	}139	if (count < patch.len) {140		dev_err(card->dev, "Patch too short %ld, need %d\n",141			count, patch.len);142		return -EINVAL;143	}144	if (patch.len < 0) {145		dev_err(card->dev, "poor length %d\n", patch.len);146		return -EINVAL;147	}148 149	if (patch.type == SNDRV_SFNT_OPEN_PATCH) {150		/* grab sflist to open */151		lock_preset(sflist);152		rc = open_patch(sflist, data, count, client);153		unlock_preset(sflist);154		return rc;155	}156 157	/* check if other client already opened patch */158	spin_lock_irqsave(&sflist->lock, flags);159	if (sflist->open_client != client) {160		spin_unlock_irqrestore(&sflist->lock, flags);161		return -EBUSY;162	}163	spin_unlock_irqrestore(&sflist->lock, flags);164 165	lock_preset(sflist);166	rc = -EINVAL;167	switch (patch.type) {168	case SNDRV_SFNT_LOAD_INFO:169		rc = load_info(card, sflist, data, count);170		break;171	case SNDRV_SFNT_LOAD_DATA:172		rc = load_data(sflist, data, count);173		break;174	case SNDRV_SFNT_CLOSE_PATCH:175		rc = close_patch(sflist);176		break;177	case SNDRV_SFNT_REPLACE_DATA:178		/*rc = replace_data(&patch, data, count);*/179		break;180	case SNDRV_SFNT_MAP_PRESET:181		rc = load_map(sflist, data, count);182		break;183	case SNDRV_SFNT_PROBE_DATA:184		rc = probe_data(sflist, patch.optarg);185		break;186	case SNDRV_SFNT_REMOVE_INFO:187		/* patch must be opened */188		if (!sflist->currsf) {189			dev_err(card->dev,190				"soundfont: remove_info: patch not opened\n");191			rc = -EINVAL;192		} else {193			int bank, instr;194			bank = ((unsigned short)patch.optarg >> 8) & 0xff;195			instr = (unsigned short)patch.optarg & 0xff;196			if (! remove_info(sflist, sflist->currsf, bank, instr))197				rc = -EINVAL;198			else199				rc = 0;200		}201		break;202	}203	unlock_preset(sflist);204 205	return rc;206}207 208 209/* check if specified type is special font (GUS or preset-alias) */210static inline int211is_special_type(int type)212{213	type &= 0x0f;214	return (type == SNDRV_SFNT_PAT_TYPE_GUS ||215		type == SNDRV_SFNT_PAT_TYPE_MAP);216}217 218 219/* open patch; create sf list */220static int221open_patch(struct snd_sf_list *sflist, const char __user *data,222	   int count, int client)223{224	struct soundfont_open_parm parm;225	struct snd_soundfont *sf;226	unsigned long flags;227 228	spin_lock_irqsave(&sflist->lock, flags);229	if (sflist->open_client >= 0 || sflist->currsf) {230		spin_unlock_irqrestore(&sflist->lock, flags);231		return -EBUSY;232	}233	spin_unlock_irqrestore(&sflist->lock, flags);234 235	if (copy_from_user(&parm, data, sizeof(parm)))236		return -EFAULT;237 238	if (is_special_type(parm.type)) {239		parm.type |= SNDRV_SFNT_PAT_SHARED;240		sf = newsf(sflist, parm.type, NULL);241	} else 242		sf = newsf(sflist, parm.type, parm.name);243	if (sf == NULL) {244		return -ENOMEM;245	}246 247	spin_lock_irqsave(&sflist->lock, flags);248	sflist->open_client = client;249	sflist->currsf = sf;250	spin_unlock_irqrestore(&sflist->lock, flags);251 252	return 0;253}254 255/*256 * Allocate a new soundfont structure.257 */258static struct snd_soundfont *259newsf(struct snd_sf_list *sflist, int type, char *name)260{261	struct snd_soundfont *sf;262 263	/* check the shared fonts */264	if (type & SNDRV_SFNT_PAT_SHARED) {265		for (sf = sflist->fonts; sf; sf = sf->next) {266			if (is_identical_font(sf, type, name)) {267				return sf;268			}269		}270	}271 272	/* not found -- create a new one */273	sf = kzalloc(sizeof(*sf), GFP_KERNEL);274	if (sf == NULL)275		return NULL;276	sf->id = sflist->fonts_size;277	sflist->fonts_size++;278 279	/* prepend this record */280	sf->next = sflist->fonts;281	sflist->fonts = sf;282 283	sf->type = type;284	sf->zones = NULL;285	sf->samples = NULL;286	if (name)287		memcpy(sf->name, name, SNDRV_SFNT_PATCH_NAME_LEN);288 289	return sf;290}291 292/* check if the given name matches to the existing list */293static int294is_identical_font(struct snd_soundfont *sf, int type, unsigned char *name)295{296	return ((sf->type & SNDRV_SFNT_PAT_SHARED) &&297		(sf->type & 0x0f) == (type & 0x0f) &&298		(name == NULL ||299		 memcmp(sf->name, name, SNDRV_SFNT_PATCH_NAME_LEN) == 0));300}301 302/*303 * Close the current patch.304 */305static int306close_patch(struct snd_sf_list *sflist)307{308	unsigned long flags;309 310	spin_lock_irqsave(&sflist->lock, flags);311	sflist->currsf = NULL;312	sflist->open_client = -1;313	spin_unlock_irqrestore(&sflist->lock, flags);314 315	rebuild_presets(sflist);316 317	return 0;318 319}320 321/* probe sample in the current list -- nothing to be loaded */322static int323probe_data(struct snd_sf_list *sflist, int sample_id)324{325	/* patch must be opened */326	if (sflist->currsf) {327		/* search the specified sample by optarg */328		if (find_sample(sflist->currsf, sample_id))329			return 0;330	}331	return -EINVAL;332}333 334/*335 * increment zone counter336 */337static void338set_zone_counter(struct snd_sf_list *sflist, struct snd_soundfont *sf,339		 struct snd_sf_zone *zp)340{341	zp->counter = sflist->zone_counter++;342	if (sf->type & SNDRV_SFNT_PAT_LOCKED)343		sflist->zone_locked = sflist->zone_counter;344}345 346/*347 * allocate a new zone record348 */349static struct snd_sf_zone *350sf_zone_new(struct snd_sf_list *sflist, struct snd_soundfont *sf)351{352	struct snd_sf_zone *zp;353 354	zp = kzalloc(sizeof(*zp), GFP_KERNEL);355	if (!zp)356		return NULL;357	zp->next = sf->zones;358	sf->zones = zp;359 360	init_voice_info(&zp->v);361 362	set_zone_counter(sflist, sf, zp);363	return zp;364}365 366 367/*368 * increment sample counter369 */370static void371set_sample_counter(struct snd_sf_list *sflist, struct snd_soundfont *sf,372		   struct snd_sf_sample *sp)373{374	sp->counter = sflist->sample_counter++;375	if (sf->type & SNDRV_SFNT_PAT_LOCKED)376		sflist->sample_locked = sflist->sample_counter;377}378 379/*380 * allocate a new sample list record381 */382static struct snd_sf_sample *383sf_sample_new(struct snd_sf_list *sflist, struct snd_soundfont *sf)384{385	struct snd_sf_sample *sp;386 387	sp = kzalloc(sizeof(*sp), GFP_KERNEL);388	if (!sp)389		return NULL;390 391	sp->next = sf->samples;392	sf->samples = sp;393 394	set_sample_counter(sflist, sf, sp);395	return sp;396}397 398/*399 * delete sample list -- this is an exceptional job.400 * only the last allocated sample can be deleted.401 */402static void403sf_sample_delete(struct snd_sf_list *sflist, struct snd_soundfont *sf,404		 struct snd_sf_sample *sp)405{406	/* only last sample is accepted */407	if (sp == sf->samples) {408		sf->samples = sp->next;409		kfree(sp);410	}411}412 413 414/* load voice map */415static int416load_map(struct snd_sf_list *sflist, const void __user *data, int count)417{418	struct snd_sf_zone *zp, *prevp;419	struct snd_soundfont *sf;420	struct soundfont_voice_map map;421 422	/* get the link info */423	if (count < (int)sizeof(map))424		return -EINVAL;425	if (copy_from_user(&map, data, sizeof(map)))426		return -EFAULT;427 428	if (map.map_instr < 0 || map.map_instr >= SF_MAX_INSTRUMENTS)429		return -EINVAL;430	431	sf = newsf(sflist, SNDRV_SFNT_PAT_TYPE_MAP|SNDRV_SFNT_PAT_SHARED, NULL);432	if (sf == NULL)433		return -ENOMEM;434 435	prevp = NULL;436	for (zp = sf->zones; zp; prevp = zp, zp = zp->next) {437		if (zp->mapped &&438		    zp->instr == map.map_instr &&439		    zp->bank == map.map_bank &&440		    zp->v.low == map.map_key &&441		    zp->v.start == map.src_instr &&442		    zp->v.end == map.src_bank &&443		    zp->v.fixkey == map.src_key) {444			/* the same mapping is already present */445			/* relink this record to the link head */446			if (prevp) {447				prevp->next = zp->next;448				zp->next = sf->zones;449				sf->zones = zp;450			}451			/* update the counter */452			set_zone_counter(sflist, sf, zp);453			return 0;454		}455	}456 457	/* create a new zone */458	zp = sf_zone_new(sflist, sf);459	if (!zp)460		return -ENOMEM;461 462	zp->bank = map.map_bank;463	zp->instr = map.map_instr;464	zp->mapped = 1;465	if (map.map_key >= 0) {466		zp->v.low = map.map_key;467		zp->v.high = map.map_key;468	}469	zp->v.start = map.src_instr;470	zp->v.end = map.src_bank;471	zp->v.fixkey = map.src_key;472	zp->v.sf_id = sf->id;473 474	add_preset(sflist, zp);475 476	return 0;477}478 479 480/* remove the present instrument layers */481static int482remove_info(struct snd_sf_list *sflist, struct snd_soundfont *sf,483	    int bank, int instr)484{485	struct snd_sf_zone *prev, *next, *p;486	int removed = 0;487 488	prev = NULL;489	for (p = sf->zones; p; p = next) {490		next = p->next;491		if (! p->mapped &&492		    p->bank == bank && p->instr == instr) {493			/* remove this layer */494			if (prev)495				prev->next = next;496			else497				sf->zones = next;498			removed++;499			kfree(p);500		} else501			prev = p;502	}503	if (removed)504		rebuild_presets(sflist);505	return removed;506}507 508 509/*510 * Read an info record from the user buffer and save it on the current511 * open soundfont.512 */513static int514load_info(struct snd_card *card,515	  struct snd_sf_list *sflist, const void __user *data, long count)516{517	struct snd_soundfont *sf;518	struct snd_sf_zone *zone;519	struct soundfont_voice_rec_hdr hdr;520	int i;521 522	/* patch must be opened */523	sf = sflist->currsf;524	if (!sf)525		return -EINVAL;526 527	if (is_special_type(sf->type))528		return -EINVAL;529 530	if (count < (long)sizeof(hdr)) {531		dev_err(card->dev, "Soundfont error: invalid patch zone length\n");532		return -EINVAL;533	}534	if (copy_from_user((char*)&hdr, data, sizeof(hdr)))535		return -EFAULT;536	537	data += sizeof(hdr);538	count -= sizeof(hdr);539 540	if (hdr.nvoices <= 0 || hdr.nvoices >= 100) {541		dev_err(card->dev, "Soundfont error: Illegal voice number %d\n",542			hdr.nvoices);543		return -EINVAL;544	}545 546	if (count < (long)sizeof(struct soundfont_voice_info) * hdr.nvoices) {547		dev_err(card->dev,548			"Soundfont Error: patch length(%ld) is smaller than nvoices(%d)\n",549			count, hdr.nvoices);550		return -EINVAL;551	}552 553	switch (hdr.write_mode) {554	case SNDRV_SFNT_WR_EXCLUSIVE:555		/* exclusive mode - if the instrument already exists,556		   return error */557		for (zone = sf->zones; zone; zone = zone->next) {558			if (!zone->mapped &&559			    zone->bank == hdr.bank &&560			    zone->instr == hdr.instr)561				return -EINVAL;562		}563		break;564	case SNDRV_SFNT_WR_REPLACE:565		/* replace mode - remove the instrument if it already exists */566		remove_info(sflist, sf, hdr.bank, hdr.instr);567		break;568	}569 570	for (i = 0; i < hdr.nvoices; i++) {571		struct snd_sf_zone tmpzone;572 573		/* copy awe_voice_info parameters */574		if (copy_from_user(&tmpzone.v, data, sizeof(tmpzone.v))) {575			return -EFAULT;576		}577 578		data += sizeof(tmpzone.v);579		count -= sizeof(tmpzone.v);580 581		tmpzone.bank = hdr.bank;582		tmpzone.instr = hdr.instr;583		tmpzone.mapped = 0;584		tmpzone.v.sf_id = sf->id;585		if (tmpzone.v.mode & SNDRV_SFNT_MODE_INIT_PARM)586			init_voice_parm(&tmpzone.v.parm);587 588		/* create a new zone */589		zone = sf_zone_new(sflist, sf);590		if (!zone)591			return -ENOMEM;592 593		/* copy the temporary data */594		zone->bank = tmpzone.bank;595		zone->instr = tmpzone.instr;596		zone->v = tmpzone.v;597 598		/* look up the sample */599		zone->sample = set_sample(sf, &zone->v);600	}601 602	return 0;603}604 605 606/* initialize voice_info record */607static void608init_voice_info(struct soundfont_voice_info *avp)609{610	memset(avp, 0, sizeof(*avp));611 612	avp->root = 60;613	avp->high = 127;614	avp->velhigh = 127;615	avp->fixkey = -1;616	avp->fixvel = -1;617	avp->fixpan = -1;618	avp->pan = -1;619	avp->amplitude = 127;620	avp->scaleTuning = 100;621 622	init_voice_parm(&avp->parm);623}624 625/* initialize voice_parm record:626 * Env1/2: delay=0, attack=0, hold=0, sustain=0, decay=0, release=0.627 * Vibrato and Tremolo effects are zero.628 * Cutoff is maximum.629 * Chorus and Reverb effects are zero.630 */631static void632init_voice_parm(struct soundfont_voice_parm *pp)633{634	memset(pp, 0, sizeof(*pp));635 636	pp->moddelay = 0x8000;637	pp->modatkhld = 0x7f7f;638	pp->moddcysus = 0x7f7f;639	pp->modrelease = 0x807f;640 641	pp->voldelay = 0x8000;642	pp->volatkhld = 0x7f7f;643	pp->voldcysus = 0x7f7f;644	pp->volrelease = 0x807f;645 646	pp->lfo1delay = 0x8000;647	pp->lfo2delay = 0x8000;648 649	pp->cutoff = 0xff;650}	651 652/* search the specified sample */653static struct snd_sf_sample *654set_sample(struct snd_soundfont *sf, struct soundfont_voice_info *avp)655{656	struct snd_sf_sample *sample;657 658	sample = find_sample(sf, avp->sample);659	if (sample == NULL)660		return NULL;661 662	/* add in the actual sample offsets:663	 * The voice_info addresses define only the relative offset664	 * from sample pointers.  Here we calculate the actual DRAM665	 * offset from sample pointers.666	 */667	avp->start += sample->v.start;668	avp->end += sample->v.end;669	avp->loopstart += sample->v.loopstart;670	avp->loopend += sample->v.loopend;671 672	/* copy mode flags */673	avp->sample_mode = sample->v.mode_flags;674 675	return sample;676}677 678/* find the sample pointer with the given id in the soundfont */679static struct snd_sf_sample *680find_sample(struct snd_soundfont *sf, int sample_id)681{682	struct snd_sf_sample *p;683 684	if (sf == NULL)685		return NULL;686 687	for (p = sf->samples; p; p = p->next) {688		if (p->v.sample == sample_id)689			return p;690	}691	return NULL;692}693 694 695static int696validate_sample_info(struct soundfont_sample_info *si)697{698	if (si->end < 0 || si->end > si->size)699		return -EINVAL;700	if (si->loopstart < 0 || si->loopstart > si->end)701		return -EINVAL;702	if (si->loopend < 0 || si->loopend > si->end)703		return -EINVAL;704	/* be sure loop points start < end */705	if (si->loopstart > si->loopend)706		swap(si->loopstart, si->loopend);707	return 0;708}709 710/*711 * Load sample information, this can include data to be loaded onto712 * the soundcard.  It can also just be a pointer into soundcard ROM.713 * If there is data it will be written to the soundcard via the callback714 * routine.715 */716static int717load_data(struct snd_sf_list *sflist, const void __user *data, long count)718{719	struct snd_soundfont *sf;720	struct soundfont_sample_info sample_info;721	struct snd_sf_sample *sp;722 723	/* patch must be opened */724	sf = sflist->currsf;725	if (!sf)726		return -EINVAL;727 728	if (is_special_type(sf->type))729		return -EINVAL;730 731	if (count < (long)sizeof(sample_info)) {732		return -EINVAL;733	}734	if (copy_from_user(&sample_info, data, sizeof(sample_info)))735		return -EFAULT;736	data += sizeof(sample_info);737	count -= sizeof(sample_info);738 739	// SoundFont uses S16LE samples.740	if (sample_info.size * 2 != count)741		return -EINVAL;742 743	/* Check for dup */744	if (find_sample(sf, sample_info.sample)) {745		/* if shared sample, skip this data */746		if (sf->type & SNDRV_SFNT_PAT_SHARED)747			return 0;748		return -EINVAL;749	}750 751	if (sample_info.size > 0) {752		if (sample_info.start < 0)753			return -EINVAL;754 755		// Here we "rebase out" the start address, because the756		// real start is the start of the provided sample data.757		sample_info.end -= sample_info.start;758		sample_info.loopstart -= sample_info.start;759		sample_info.loopend -= sample_info.start;760		sample_info.start = 0;761 762		if (validate_sample_info(&sample_info) < 0)763			return -EINVAL;764	}765 766	/* Allocate a new sample structure */767	sp = sf_sample_new(sflist, sf);768	if (!sp)769		return -ENOMEM;770 771	sp->v = sample_info;772	sp->v.sf_id = sf->id;773	sp->v.dummy = 0;774	sp->v.truesize = 0;775 776	/*777	 * If there is wave data then load it.778	 */779	if (sp->v.size > 0) {780		int  rc;781		rc = sflist->callback.sample_new782			(sflist->callback.private_data, sp, sflist->memhdr,783			 data, count);784		if (rc < 0) {785			sf_sample_delete(sflist, sf, sp);786			return rc;787		}788		sflist->mem_used += sp->v.truesize;789	}790 791	return count;792}793 794 795/* log2_tbl[i] = log2(i+128) * 0x10000 */796static const int log_tbl[129] = {797	0x70000, 0x702df, 0x705b9, 0x7088e, 0x70b5d, 0x70e26, 0x710eb, 0x713aa,798	0x71663, 0x71918, 0x71bc8, 0x71e72, 0x72118, 0x723b9, 0x72655, 0x728ed,799	0x72b80, 0x72e0e, 0x73098, 0x7331d, 0x7359e, 0x7381b, 0x73a93, 0x73d08,800	0x73f78, 0x741e4, 0x7444c, 0x746b0, 0x74910, 0x74b6c, 0x74dc4, 0x75019,801	0x75269, 0x754b6, 0x75700, 0x75946, 0x75b88, 0x75dc7, 0x76002, 0x7623a,802	0x7646e, 0x766a0, 0x768cd, 0x76af8, 0x76d1f, 0x76f43, 0x77164, 0x77382,803	0x7759d, 0x777b4, 0x779c9, 0x77bdb, 0x77dea, 0x77ff5, 0x781fe, 0x78404,804	0x78608, 0x78808, 0x78a06, 0x78c01, 0x78df9, 0x78fef, 0x791e2, 0x793d2,805	0x795c0, 0x797ab, 0x79993, 0x79b79, 0x79d5d, 0x79f3e, 0x7a11d, 0x7a2f9,806	0x7a4d3, 0x7a6ab, 0x7a880, 0x7aa53, 0x7ac24, 0x7adf2, 0x7afbe, 0x7b188,807	0x7b350, 0x7b515, 0x7b6d8, 0x7b899, 0x7ba58, 0x7bc15, 0x7bdd0, 0x7bf89,808	0x7c140, 0x7c2f5, 0x7c4a7, 0x7c658, 0x7c807, 0x7c9b3, 0x7cb5e, 0x7cd07,809	0x7ceae, 0x7d053, 0x7d1f7, 0x7d398, 0x7d538, 0x7d6d6, 0x7d872, 0x7da0c,810	0x7dba4, 0x7dd3b, 0x7ded0, 0x7e063, 0x7e1f4, 0x7e384, 0x7e512, 0x7e69f,811	0x7e829, 0x7e9b3, 0x7eb3a, 0x7ecc0, 0x7ee44, 0x7efc7, 0x7f148, 0x7f2c8,812	0x7f446, 0x7f5c2, 0x7f73d, 0x7f8b7, 0x7fa2f, 0x7fba5, 0x7fd1a, 0x7fe8d,813	0x80000,814};815 816/* convert from linear to log value817 *818 * conversion: value = log2(amount / base) * ratio819 *820 * argument:821 *   amount = linear value (unsigned, 32bit max)822 *   offset = base offset (:= log2(base) * 0x10000)823 *   ratio = division ratio824 *825 */826int827snd_sf_linear_to_log(unsigned int amount, int offset, int ratio)828{829	int v;830	int s, low, bit;831	832	if (amount < 2)833		return 0;834	for (bit = 0; ! (amount & 0x80000000L); bit++)835		amount <<= 1;836	s = (amount >> 24) & 0x7f;837	low = (amount >> 16) & 0xff;838	/* linear approximation by lower 8 bit */839	v = (log_tbl[s + 1] * low + log_tbl[s] * (0x100 - low)) >> 8;840	v -= offset;841	v = (v * ratio) >> 16;842	v += (24 - bit) * ratio;843	return v;844}845 846EXPORT_SYMBOL(snd_sf_linear_to_log);847 848 849#define OFFSET_MSEC		653117		/* base = 1000 */850#define OFFSET_ABSCENT		851781		/* base = 8176 */851#define OFFSET_SAMPLERATE	1011119		/* base = 44100 */852 853#define ABSCENT_RATIO		1200854#define TIMECENT_RATIO		1200855#define SAMPLERATE_RATIO	4096856 857/*858 * mHz to abscent859 * conversion: abscent = log2(MHz / 8176) * 1200860 */861static int862freq_to_note(int mhz)863{864	return snd_sf_linear_to_log(mhz, OFFSET_ABSCENT, ABSCENT_RATIO);865}866 867/* convert Hz to AWE32 rate offset:868 * sample pitch offset for the specified sample rate869 * rate=44100 is no offset, each 4096 is 1 octave (twice).870 * eg, when rate is 22050, this offset becomes -4096.871 *872 * conversion: offset = log2(Hz / 44100) * 4096873 */874static int875calc_rate_offset(int hz)876{877	return snd_sf_linear_to_log(hz, OFFSET_SAMPLERATE, SAMPLERATE_RATIO);878}879 880 881/* calculate GUS envelope time */882static int883calc_gus_envelope_time(int rate, int start, int end)884{885	int r, p, t;886	r = (3 - ((rate >> 6) & 3)) * 3;887	p = rate & 0x3f;888	if (!p)889		p = 1;890	t = end - start;891	if (t < 0) t = -t;892	if (13 > r)893		t = t << (13 - r);894	else895		t = t >> (r - 13);896	return (t * 10) / (p * 441);897}898 899/* convert envelope time parameter to soundfont parameters */900 901/* attack & decay/release time table (msec) */902static const short attack_time_tbl[128] = {90332767, 32767, 5989, 4235, 2994, 2518, 2117, 1780, 1497, 1373, 1259, 1154, 1058, 970, 890, 816,904707, 691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377,905361, 345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188,906180, 172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94,90790, 86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47,90845, 43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23,90922, 21, 20, 19, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12,91011, 11, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 0,911};912 913static const short decay_time_tbl[128] = {91432767, 32767, 22614, 15990, 11307, 9508, 7995, 6723, 5653, 5184, 4754, 4359, 3997, 3665, 3361, 3082,9152828, 2765, 2648, 2535, 2428, 2325, 2226, 2132, 2042, 1955, 1872, 1793, 1717, 1644, 1574, 1507,9161443, 1382, 1324, 1267, 1214, 1162, 1113, 1066, 978, 936, 897, 859, 822, 787, 754, 722,917691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377, 361,918345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188, 180,919172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94, 90,92086, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47, 45,92143, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23, 22,922};923 924/* delay time = 0x8000 - msec/92 */925int926snd_sf_calc_parm_hold(int msec)927{928	int val = (0x7f * 92 - msec) / 92;929	if (val < 1) val = 1;930	if (val >= 126) val = 126;931	return val;932}933 934/* search an index for specified time from given time table */935static int936calc_parm_search(int msec, const short *table)937{938	int left = 1, right = 127, mid;939	while (left < right) {940		mid = (left + right) / 2;941		if (msec < (int)table[mid])942			left = mid + 1;943		else944			right = mid;945	}946	return left;947}948 949/* attack time: search from time table */950int951snd_sf_calc_parm_attack(int msec)952{953	return calc_parm_search(msec, attack_time_tbl);954}955 956/* decay/release time: search from time table */957int958snd_sf_calc_parm_decay(int msec)959{960	return calc_parm_search(msec, decay_time_tbl);961}962 963int snd_sf_vol_table[128] = {964	255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49,965	47,46,45,43,42,41,40,39,38,37,36,35,34,34,33,32,966	31,31,30,29,29,28,27,27,26,26,25,24,24,23,23,22,967	22,21,21,21,20,20,19,19,18,18,18,17,17,16,16,16,968	15,15,15,14,14,14,13,13,13,12,12,12,11,11,11,10,969	10,10,10,9,9,9,8,8,8,8,7,7,7,7,6,6,970	6,6,5,5,5,5,5,4,4,4,4,3,3,3,3,3,971	2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,972};973 974 975#define calc_gus_sustain(val)  (0x7f - snd_sf_vol_table[(val)/2])976#define calc_gus_attenuation(val)	snd_sf_vol_table[(val)/2]977 978/* load GUS patch */979static int980load_guspatch(struct snd_card *card,981	      struct snd_sf_list *sflist, const char __user *data, long count)982{983	struct patch_info patch;984	struct snd_soundfont *sf;985	struct snd_sf_zone *zone;986	struct snd_sf_sample *smp;987	int note, sample_id;988	int rc;989 990	if (count < (long)sizeof(patch)) {991		dev_err(card->dev, "patch record too small %ld\n", count);992		return -EINVAL;993	}994	if (copy_from_user(&patch, data, sizeof(patch)))995		return -EFAULT;996	count -= sizeof(patch);997	data += sizeof(patch);998 999	if ((patch.len << (patch.mode & WAVE_16_BITS ? 1 : 0)) != count)1000		return -EINVAL;1001 1002	sf = newsf(sflist, SNDRV_SFNT_PAT_TYPE_GUS|SNDRV_SFNT_PAT_SHARED, NULL);1003	if (sf == NULL)1004		return -ENOMEM;1005	smp = sf_sample_new(sflist, sf);1006	if (!smp)1007		return -ENOMEM;1008	sample_id = sflist->sample_counter;1009	smp->v.sample = sample_id;1010	smp->v.start = 0;1011	smp->v.end = patch.len;1012	smp->v.loopstart = patch.loop_start;1013	smp->v.loopend = patch.loop_end;1014	smp->v.size = patch.len;1015 1016	if (validate_sample_info(&smp->v) < 0) {1017		sf_sample_delete(sflist, sf, smp);1018		return -EINVAL;1019	}1020 1021	/* set up mode flags */1022	smp->v.mode_flags = 0;1023	if (!(patch.mode & WAVE_16_BITS))1024		smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_8BITS;1025	if (patch.mode & WAVE_UNSIGNED)1026		smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_UNSIGNED;1027	smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_NO_BLANK;1028	if (!(patch.mode & (WAVE_LOOPING|WAVE_BIDIR_LOOP|WAVE_LOOP_BACK)))1029		smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_SINGLESHOT;1030	if (patch.mode & WAVE_BIDIR_LOOP)1031		smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_BIDIR_LOOP;1032	if (patch.mode & WAVE_LOOP_BACK)1033		smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_REVERSE_LOOP;1034 1035	if (patch.mode & WAVE_16_BITS) {1036		/* convert to word offsets */1037		smp->v.size /= 2;1038		smp->v.end /= 2;1039		smp->v.loopstart /= 2;1040		smp->v.loopend /= 2;1041	}1042	/*smp->v.loopend++;*/1043 1044	smp->v.dummy = 0;1045	smp->v.truesize = 0;1046	smp->v.sf_id = sf->id;1047 1048	/* set up voice info */1049	zone = sf_zone_new(sflist, sf);1050	if (!zone) {1051		sf_sample_delete(sflist, sf, smp);1052		return -ENOMEM;1053	}1054 1055	/*1056	 * load wave data1057	 */1058	if (smp->v.size > 0) {1059		rc = sflist->callback.sample_new1060			(sflist->callback.private_data, smp, sflist->memhdr,1061			 data, count);1062		if (rc < 0) {1063			sf_sample_delete(sflist, sf, smp);1064			kfree(zone);1065			return rc;1066		}1067		/* memory offset is updated after */1068	}1069 1070	/* update the memory offset here */1071	sflist->mem_used += smp->v.truesize;1072 1073	zone->v.sample = sample_id; /* the last sample */1074	zone->v.rate_offset = calc_rate_offset(patch.base_freq);1075	note = freq_to_note(patch.base_note);1076	zone->v.root = note / 100;1077	zone->v.tune = -(note % 100);1078	zone->v.low = (freq_to_note(patch.low_note) + 99) / 100;1079	zone->v.high = freq_to_note(patch.high_note) / 100;1080	/* panning position; -128 - 127 => 0-127 */1081	zone->v.pan = (patch.panning + 128) / 2;1082#if 01083	pr_debug(1084		 "gus: basefrq=%d (ofs=%d) root=%d,tune=%d, range:%d-%d\n",1085		 (int)patch.base_freq, zone->v.rate_offset,1086		 zone->v.root, zone->v.tune, zone->v.low, zone->v.high);1087#endif1088 1089	/* detuning is ignored */1090	/* 6points volume envelope */1091	if (patch.mode & WAVE_ENVELOPES) {1092		int attack, hold, decay, release;1093		attack = calc_gus_envelope_time1094			(patch.env_rate[0], 0, patch.env_offset[0]);1095		hold = calc_gus_envelope_time1096			(patch.env_rate[1], patch.env_offset[0],1097			 patch.env_offset[1]);1098		decay = calc_gus_envelope_time1099			(patch.env_rate[2], patch.env_offset[1],1100			 patch.env_offset[2]);1101		release = calc_gus_envelope_time1102			(patch.env_rate[3], patch.env_offset[1],1103			 patch.env_offset[4]);1104		release += calc_gus_envelope_time1105			(patch.env_rate[4], patch.env_offset[3],1106			 patch.env_offset[4]);1107		release += calc_gus_envelope_time1108			(patch.env_rate[5], patch.env_offset[4],1109			 patch.env_offset[5]);1110		zone->v.parm.volatkhld = 1111			(snd_sf_calc_parm_hold(hold) << 8) |1112			snd_sf_calc_parm_attack(attack);1113		zone->v.parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) |1114			snd_sf_calc_parm_decay(decay);1115		zone->v.parm.volrelease = 0x8000 | snd_sf_calc_parm_decay(release);1116		zone->v.attenuation = calc_gus_attenuation(patch.env_offset[0]);1117#if 01118		dev_dbg(card->dev,1119			"gus: atkhld=%x, dcysus=%x, volrel=%x, att=%d\n",1120			zone->v.parm.volatkhld,1121			zone->v.parm.voldcysus,1122			zone->v.parm.volrelease,1123			zone->v.attenuation);1124#endif1125	}1126 1127	/* fast release */1128	if (patch.mode & WAVE_FAST_RELEASE) {1129		zone->v.parm.volrelease = 0x807f;1130	}1131 1132	/* tremolo effect */1133	if (patch.mode & WAVE_TREMOLO) {1134		int rate = (patch.tremolo_rate * 1000 / 38) / 42;1135		zone->v.parm.tremfrq = ((patch.tremolo_depth / 2) << 8) | rate;1136	}1137	/* vibrato effect */1138	if (patch.mode & WAVE_VIBRATO) {1139		int rate = (patch.vibrato_rate * 1000 / 38) / 42;1140		zone->v.parm.fm2frq2 = ((patch.vibrato_depth / 6) << 8) | rate;1141	}1142	1143	/* scale_freq, scale_factor, volume, and fractions not implemented */1144 1145	if (!(smp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT))1146		zone->v.mode = SNDRV_SFNT_MODE_LOOPING;1147	else1148		zone->v.mode = 0;1149 1150	/* append to the tail of the list */1151	/*zone->bank = ctrls[AWE_MD_GUS_BANK];*/1152	zone->bank = 0;1153	zone->instr = patch.instr_no;1154	zone->mapped = 0;1155	zone->v.sf_id = sf->id;1156 1157	zone->sample = set_sample(sf, &zone->v);1158 1159	/* rebuild preset now */1160	add_preset(sflist, zone);1161 1162	return 0;1163}1164 1165/* load GUS patch */1166int1167snd_soundfont_load_guspatch(struct snd_card *card,1168			    struct snd_sf_list *sflist, const char __user *data,1169			    long count)1170{1171	int rc;1172	lock_preset(sflist);1173	rc = load_guspatch(card, sflist, data, count);1174	unlock_preset(sflist);1175	return rc;1176}1177 1178 1179/*1180 * Rebuild the preset table.  This is like a hash table in that it allows1181 * quick access to the zone information.  For each preset there are zone1182 * structures linked by next_instr and by next_zone.  Former is the whole1183 * link for this preset, and latter is the link for zone (i.e. instrument/1184 * bank/key combination).1185 */1186static void1187rebuild_presets(struct snd_sf_list *sflist)1188{1189	struct snd_soundfont *sf;1190	struct snd_sf_zone *cur;1191 1192	/* clear preset table */1193	memset(sflist->presets, 0, sizeof(sflist->presets));1194 1195	/* search all fonts and insert each font */1196	for (sf = sflist->fonts; sf; sf = sf->next) {1197		for (cur = sf->zones; cur; cur = cur->next) {1198			if (! cur->mapped && cur->sample == NULL) {1199				/* try again to search the corresponding sample */1200				cur->sample = set_sample(sf, &cur->v);1201				if (cur->sample == NULL)1202					continue;1203			}1204 1205			add_preset(sflist, cur);1206		}1207	}1208}1209 1210 1211/*1212 * add the given zone to preset table1213 */1214static void1215add_preset(struct snd_sf_list *sflist, struct snd_sf_zone *cur)1216{1217	struct snd_sf_zone *zone;1218	int index;1219 1220	zone = search_first_zone(sflist, cur->bank, cur->instr, cur->v.low);1221	if (zone && zone->v.sf_id != cur->v.sf_id) {1222		/* different instrument was already defined */1223		struct snd_sf_zone *p;1224		/* compare the allocated time */1225		for (p = zone; p; p = p->next_zone) {1226			if (p->counter > cur->counter)1227				/* the current is older.. skipped */1228				return;1229		}1230		/* remove old zones */1231		delete_preset(sflist, zone);1232		zone = NULL; /* do not forget to clear this! */1233	}1234 1235	/* prepend this zone */1236	index = get_index(cur->bank, cur->instr, cur->v.low);1237	if (index < 0)1238		return;1239	cur->next_zone = zone; /* zone link */1240	cur->next_instr = sflist->presets[index]; /* preset table link */1241	sflist->presets[index] = cur;1242}1243 1244/*1245 * delete the given zones from preset_table1246 */1247static void1248delete_preset(struct snd_sf_list *sflist, struct snd_sf_zone *zp)1249{1250	int index;1251	struct snd_sf_zone *p;1252 1253	index = get_index(zp->bank, zp->instr, zp->v.low);1254	if (index < 0)1255		return;1256	for (p = sflist->presets[index]; p; p = p->next_instr) {1257		while (p->next_instr == zp) {1258			p->next_instr = zp->next_instr;1259			zp = zp->next_zone;1260			if (zp == NULL)1261				return;1262		}1263	}1264}1265 1266 1267/*1268 * Search matching zones from preset table.1269 * The note can be rewritten by preset mapping (alias).1270 * The found zones are stored on 'table' array.  max_layers defines1271 * the maximum number of elements in this array.1272 * This function returns the number of found zones.  0 if not found.1273 */1274int1275snd_soundfont_search_zone(struct snd_sf_list *sflist, int *notep, int vel,1276			  int preset, int bank,1277			  int def_preset, int def_bank,1278			  struct snd_sf_zone **table, int max_layers)1279{1280	int nvoices;1281	unsigned long flags;1282 1283	/* this function is supposed to be called atomically,1284	 * so we check the lock.  if it's busy, just returns 0 to1285	 * tell the caller the busy state1286	 */1287	spin_lock_irqsave(&sflist->lock, flags);1288	if (sflist->presets_locked) {1289		spin_unlock_irqrestore(&sflist->lock, flags);1290		return 0;1291	}1292	nvoices = search_zones(sflist, notep, vel, preset, bank,1293			       table, max_layers, 0);1294	if (! nvoices) {1295		if (preset != def_preset || bank != def_bank)1296			nvoices = search_zones(sflist, notep, vel,1297					       def_preset, def_bank,1298					       table, max_layers, 0);1299	}1300	spin_unlock_irqrestore(&sflist->lock, flags);1301	return nvoices;1302}1303 1304 1305/*1306 * search the first matching zone1307 */1308static struct snd_sf_zone *1309search_first_zone(struct snd_sf_list *sflist, int bank, int preset, int key)1310{1311	int index;1312	struct snd_sf_zone *zp;1313 1314	index = get_index(bank, preset, key);1315	if (index < 0)1316		return NULL;1317	for (zp = sflist->presets[index]; zp; zp = zp->next_instr) {1318		if (zp->instr == preset && zp->bank == bank)1319			return zp;1320	}1321	return NULL;1322}1323 1324 1325/*1326 * search matching zones from sflist.  can be called recursively.1327 */1328static int1329search_zones(struct snd_sf_list *sflist, int *notep, int vel,1330	     int preset, int bank, struct snd_sf_zone **table,1331	     int max_layers, int level)1332{1333	struct snd_sf_zone *zp;1334	int nvoices;1335 1336	zp = search_first_zone(sflist, bank, preset, *notep);1337	nvoices = 0;1338	for (; zp; zp = zp->next_zone) {1339		if (*notep >= zp->v.low && *notep <= zp->v.high &&1340		    vel >= zp->v.vellow && vel <= zp->v.velhigh) {1341			if (zp->mapped) {1342				/* search preset mapping (aliasing) */1343				int key = zp->v.fixkey;1344				preset = zp->v.start;1345				bank = zp->v.end;1346 1347				if (level > 5) /* too deep alias level */1348					return 0;1349				if (key < 0)1350					key = *notep;1351				nvoices = search_zones(sflist, &key, vel,1352						       preset, bank, table,1353						       max_layers, level + 1);1354				if (nvoices > 0)1355					*notep = key;1356				break;1357			}1358			table[nvoices++] = zp;1359			if (nvoices >= max_layers)1360				break;1361		}1362	}1363 1364	return nvoices;1365}1366 1367 1368/* calculate the index of preset table:1369 * drums are mapped from 128 to 255 according to its note key.1370 * other instruments are mapped from 0 to 127.1371 * if the index is out of range, return -1.1372 */1373static int1374get_index(int bank, int instr, int key)1375{1376	int index;1377	if (SF_IS_DRUM_BANK(bank))1378		index = key + SF_MAX_INSTRUMENTS;1379	else1380		index = instr;1381	index = index % SF_MAX_PRESETS;1382	if (index < 0)1383		return -1;1384	return index;1385}1386 1387/*1388 * Initialise the sflist structure.1389 */1390static void1391snd_sf_init(struct snd_sf_list *sflist)1392{1393	memset(sflist->presets, 0, sizeof(sflist->presets));1394 1395	sflist->mem_used = 0;1396	sflist->currsf = NULL;1397	sflist->open_client = -1;1398	sflist->fonts = NULL;1399	sflist->fonts_size = 0;1400	sflist->zone_counter = 0;1401	sflist->sample_counter = 0;1402	sflist->zone_locked = 0;1403	sflist->sample_locked = 0;1404}1405 1406/*1407 * Release all list records1408 */1409static void1410snd_sf_clear(struct snd_sf_list *sflist)1411{1412	struct snd_soundfont *sf, *nextsf;1413	struct snd_sf_zone *zp, *nextzp;1414	struct snd_sf_sample *sp, *nextsp;1415 1416	for (sf = sflist->fonts; sf; sf = nextsf) {1417		nextsf = sf->next;1418		for (zp = sf->zones; zp; zp = nextzp) {1419			nextzp = zp->next;1420			kfree(zp);1421		}1422		for (sp = sf->samples; sp; sp = nextsp) {1423			nextsp = sp->next;1424			sflist->callback.sample_free(sflist->callback.private_data,1425						     sp, sflist->memhdr);1426			kfree(sp);1427		}1428		kfree(sf);1429	}1430 1431	snd_sf_init(sflist);1432}1433 1434 1435/*1436 * Create a new sflist structure1437 */1438struct snd_sf_list *1439snd_sf_new(struct snd_sf_callback *callback, struct snd_util_memhdr *hdr)1440{1441	struct snd_sf_list *sflist;1442 1443	sflist = kzalloc(sizeof(*sflist), GFP_KERNEL);1444	if (!sflist)1445		return NULL;1446 1447	mutex_init(&sflist->presets_mutex);1448	spin_lock_init(&sflist->lock);1449	sflist->memhdr = hdr;1450 1451	if (callback)1452		sflist->callback = *callback;1453 1454	snd_sf_init(sflist);1455	return sflist;1456}1457 1458 1459/*1460 * Free everything allocated off the sflist structure.1461 */1462void1463snd_sf_free(struct snd_sf_list *sflist)1464{1465	if (sflist == NULL)1466		return;1467	1468	lock_preset(sflist);1469	if (sflist->callback.sample_reset)1470		sflist->callback.sample_reset(sflist->callback.private_data);1471	snd_sf_clear(sflist);1472	unlock_preset(sflist);1473 1474	kfree(sflist);1475}1476 1477/*1478 * Remove all samples1479 * The soundcard should be silent before calling this function.1480 */1481int1482snd_soundfont_remove_samples(struct snd_sf_list *sflist)1483{1484	lock_preset(sflist);1485	if (sflist->callback.sample_reset)1486		sflist->callback.sample_reset(sflist->callback.private_data);1487	snd_sf_clear(sflist);1488	unlock_preset(sflist);1489 1490	return 0;1491}1492 1493/*1494 * Remove unlocked samples.1495 * The soundcard should be silent before calling this function.1496 */1497int1498snd_soundfont_remove_unlocked(struct snd_sf_list *sflist)1499{1500	struct snd_soundfont *sf;1501	struct snd_sf_zone *zp, *nextzp;1502	struct snd_sf_sample *sp, *nextsp;1503 1504	lock_preset(sflist);1505 1506	if (sflist->callback.sample_reset)1507		sflist->callback.sample_reset(sflist->callback.private_data);1508 1509	/* to be sure */1510	memset(sflist->presets, 0, sizeof(sflist->presets));1511 1512	for (sf = sflist->fonts; sf; sf = sf->next) {1513		for (zp = sf->zones; zp; zp = nextzp) {1514			if (zp->counter < sflist->zone_locked)1515				break;1516			nextzp = zp->next;1517			sf->zones = nextzp;1518			kfree(zp);1519		}1520 1521		for (sp = sf->samples; sp; sp = nextsp) {1522			if (sp->counter < sflist->sample_locked)1523				break;1524			nextsp = sp->next;1525			sf->samples = nextsp;1526			sflist->mem_used -= sp->v.truesize;1527			sflist->callback.sample_free(sflist->callback.private_data,1528						     sp, sflist->memhdr);1529			kfree(sp);1530		}1531	}1532 1533	sflist->zone_counter = sflist->zone_locked;1534	sflist->sample_counter = sflist->sample_locked;1535 1536	rebuild_presets(sflist);1537 1538	unlock_preset(sflist);1539	return 0;1540}1541