Home | History | Annotate | Line # | Download | only in dev
midictl.c revision 1.6.32.1
      1 /* $NetBSD: midictl.c,v 1.6.32.1 2011/11/19 21:49:35 jmcneill Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2006, 2008 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Chapman Flack, and by Andrew Doran.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 #include <sys/cdefs.h>
     32 __KERNEL_RCSID(0, "$NetBSD: midictl.c,v 1.6.32.1 2011/11/19 21:49:35 jmcneill Exp $");
     33 
     34 /*
     35  * See midictl.h for an overview of the purpose and use of this module.
     36  */
     37 
     38 #include <sys/systm.h>
     39 #include <sys/types.h>
     40 #include <sys/param.h>
     41 #include <sys/kernel.h>
     42 #include <sys/kthread.h>
     43 #include <sys/kmem.h>
     44 
     45 #include "midictl.h"
     46 
     47 /*
     48  * The upper part of this file is MIDI-aware, and deals with things like
     49  * decoding MIDI Control Change messages, dealing with the ones that require
     50  * special handling as mode messages or parameter updates, and so on.
     51  *
     52  * It relies on a "store" layer (implemented in the lower part of this file)
     53  * that only must be able to stash away 2-, 8-, or 16-bit quantities (which
     54  * it may pack into larger units as it sees fit) and find them again given
     55  * a class, channel, and key (controller/parameter number).
     56  *
     57  * The MIDI controllers can have 1-, 7-, or 14-bit values; the parameters are
     58  * also 14-bit. The 14-bit values have to be set in two MIDI messages, 7 bits
     59  * at a time. The MIDI layer uses store-managed 2- or 8-bit slots for the
     60  * smaller types, and uses the free high bit to indicate that it has explicitly
     61  * set the value. (Because the store is allowed to pack things, it may 'find'
     62  * a zero entry for a value we never set, because it shares a word with a
     63  * different value that has been set. We know it is not a real value because
     64  * the high bit is clear.)
     65  *
     66  * The 14-bit values are handled similarly: 16-bit store slots are used to hold
     67  * them, with the two free high bits indicating independently whether the MSB
     68  * and the LSB have been explicitly set--as two separate MIDI messages are
     69  * required. If such a control is queried when only one half has been explicitly
     70  * set, the result is as if it had been set to the specified default value
     71  * before the explicit set.
     72  */
     73 
     74 typedef enum { CTL1, CTL7, CTL14, RPN, NRPN } class;
     75 
     76 /*
     77  * assert(does_not_apply(KNFNamespaceArgumentAgainstNamesInPrototypes,
     78  *    PrototypesOfStaticFunctionsWithinNonIncludedFile));
     79  */
     80 static void reset_all_controllers(midictl *mc, uint_fast8_t chan);
     81 static void enter14(midictl *mc, uint_fast8_t chan, class c,
     82                     uint_fast16_t key, _Bool islsb, uint8_t val);
     83 static uint_fast16_t read14(midictl *mc, uint_fast8_t chan, class c,
     84                             uint_fast16_t key, uint_fast16_t dflt);
     85 static class classify(uint_fast16_t *key, _Bool *islsb);
     86 static midictl_notify notify_no_one;
     87 
     88 static _Bool store_locate(midictl_store *s, class c,
     89                             uint_fast8_t chan, uint_fast16_t key);
     90 /*
     91  * store_extract and store_update operate on the bucket most recently found
     92  * by store_locate on this store. That works because reentrancy of midictl
     93  * functions is limited: they /can/ be reentered during midictl_notify
     94  * callbacks, but not at other arbitrary times. We never call notify /during/
     95  * a locate/extract/update transaction.
     96  */
     97 static uint16_t store_extract(midictl_store *s, class c,
     98                               uint_fast8_t chan, uint_fast16_t key);
     99 static void store_update(midictl_store *s, class c,
    100                          uint_fast8_t chan, uint_fast16_t key, uint16_t value);
    101 
    102 #define PN_SET 0x8000  /* a parameter number has been explicitly set */
    103 #define C14MSET 0x8000 /* MSB of a 14-bit val has been set */
    104 #define C14LSET 0x4000 /* LSB of a 14-bit val has been set */
    105 #define C7_SET 0x80    /* a 7-bit ctl has been set */
    106 #define C1_SET 2       /* a 1-bit ctl has been set */
    107 
    108 /*
    109  *   I M P L E M E N T A T I O N     O F     T H E     S T O R E :
    110  *
    111  * MIDI defines a metric plethora of possible controllers, registered
    112  * parameters, and nonregistered parameters: a bit more than 32k possible words
    113  * to store. The saving grace is that only a handful are likely to appear in
    114  * typical MIDI data, and only a handful are likely implemented by or
    115  * interesting to a typical client. So the store implementation needs to be
    116  * suited to a largish but quite sparse data set.
    117  *
    118  * A double-hashed, open address table is used here. Each slot is a uint64
    119  * that contains the match key (control class|channel|ctl-or-PN-number) as
    120  * well as the values for two or more channels. CTL14s, RPNs, and NRPNs can
    121  * be packed two channels to the slot; CTL7s, six channels; and CTL1s get all
    122  * 16 channels into one slot. The channel value used in the key is the lowest
    123  * channel stored in the slot. Open addressing is appropriate here because the
    124  * link fields in a chained approach would be at least 100% overhead, and also,
    125  * we don't delete (MIDICTL_RESET is the only event that logically deletes
    126  * things, and at the moment it does not remove anything from the table, but
    127  * zeroes the stored value). If wanted, the deletion algorithm for open
    128  * addressing could be used, with shrinking/rehashing when the load factor
    129  * drops below 3/8 (1/2 is the current threshold for expansion), and the
    130  * rehashing would relieve the fills-with-DELETED problem in most cases. But
    131  * for now the table never shrinks while the device is open.
    132  */
    133 
    134 struct midictl_store {
    135 	uint64_t *table;
    136 	uint64_t key;
    137 	uint32_t idx;
    138 	uint32_t lgcapacity;
    139 	uint32_t used;
    140 	kcondvar_t cv;
    141 	kmutex_t *lock;
    142 	bool destroy;
    143 };
    144 
    145 #define INITIALLGCAPACITY 6 /* initial capacity 1<<6 */
    146 #define IS_USED 1<<15
    147 #define IS_CTL7 1<<14
    148 
    149 #define CTL1SHIFT(chan) (23+((chan)<<1))
    150 #define CTL7SHIFT(chan) (16+((chan)<<3))
    151 #define CTLESHIFT(chan) (23+((chan)<<4))
    152 
    153 #define	NEED_REHASH(s)	((s)->used * 2 >= 1 << (s)->lgcapacity)
    154 
    155 static uint_fast8_t const packing[] = {
    156 	[CTL1 ] = 16, /* 16 * 2 bits ==> 32 bits, all chns in one bucket */
    157 	[CTL7 ] =  6, /*  6 * 8 bits ==> 48 bits, 6 chns in one bucket */
    158 	[CTL14] =  2, /*  2 *16 bits ==> 32 bits, 2 chns in one bucket */
    159 	[RPN  ] =  2,
    160 	[NRPN ] =  2
    161 };
    162 
    163 static uint32_t store_idx(uint32_t lgcapacity,
    164 			  uint64_t *table,
    165                           uint64_t key, uint64_t mask);
    166 static void store_rehash(midictl_store *s);
    167 static void store_thread(void *);
    168 
    169 int
    170 midictl_open(midictl *mc)
    171 {
    172 	midictl_store *s;
    173 	int error;
    174 
    175 	if (mc->lock == NULL)
    176 		panic("midictl_open: no lock");
    177 	if (NULL == mc->notify)
    178 		mc->notify = notify_no_one;
    179 	s = kmem_zalloc(sizeof(*s), KM_SLEEP);
    180 	if (s == NULL) {
    181 		return ENOMEM;
    182 	}
    183 	s->lgcapacity = INITIALLGCAPACITY;
    184 	s->table = kmem_zalloc(sizeof(*s->table)<<s->lgcapacity, KM_SLEEP);
    185 	if (s->table == NULL) {
    186 		kmem_free(s->table, sizeof(*s->table)<<s->lgcapacity);
    187 		kmem_free(s, sizeof(*s));
    188 		return ENOMEM;
    189 	}
    190 	s->lock = mc->lock;
    191 	cv_init(&s->cv, "midictl");
    192 	error = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, store_thread,
    193 	    s, NULL, "midictl");
    194 	if (error != 0) {
    195 		printf("midictl: cannot create kthread, error = %d\n", error);
    196 		cv_destroy(&s->cv);
    197 		kmem_free(s->table, sizeof(*s->table)<<s->lgcapacity);
    198 		kmem_free(s, sizeof(*s));
    199 		return error;
    200 	}
    201 	mc->store = s;
    202 	return 0;
    203 }
    204 
    205 void
    206 midictl_close(midictl *mc)
    207 {
    208 	midictl_store *s;
    209 
    210 	s = mc->store;
    211 
    212 	mutex_enter(s->lock);
    213 	s->destroy = true;
    214 	cv_broadcast(&s->cv);
    215 	mutex_exit(s->lock);
    216 }
    217 
    218 void
    219 midictl_change(midictl *mc, uint_fast8_t chan, uint8_t *ctlval)
    220 {
    221 	class c;
    222 	uint_fast16_t key, val;
    223 	_Bool islsb, present;
    224 
    225 	KASSERT(mutex_owned(mc->lock));
    226 
    227 	switch ( ctlval[0] ) {
    228 	/*
    229 	 * Channel mode messages:
    230 	 */
    231 	case MIDI_CTRL_OMNI_OFF:
    232 	case MIDI_CTRL_OMNI_ON:
    233 	case MIDI_CTRL_POLY_OFF:
    234 	case MIDI_CTRL_POLY_ON:
    235 		if ( chan != mc->base_channel )
    236 			return; /* ignored - not on base channel */
    237 		else
    238 			return; /* XXX ignored anyway - not implemented yet */
    239 	case MIDI_CTRL_NOTES_OFF:
    240 		mc->notify(mc->cookie, MIDICTL_NOTES_OFF, chan, 0);
    241 		return;
    242 	case MIDI_CTRL_LOCAL:
    243 		mc->notify(mc->cookie, MIDICTL_LOCAL, chan, ctlval[1]);
    244 		return;
    245 	case MIDI_CTRL_SOUND_OFF:
    246 		mc->notify(mc->cookie, MIDICTL_SOUND_OFF, chan, 0);
    247 		return;
    248 	case MIDI_CTRL_RESET:
    249 		reset_all_controllers(mc, chan);
    250 		return;
    251 	/*
    252 	 * Control changes to be handled specially:
    253 	 */
    254 	case MIDI_CTRL_RPN_LSB:
    255 		mc-> rpn &= ~0x7f;
    256 		mc-> rpn |=  PN_SET | (0x7f & ctlval[1]);
    257 		mc->nrpn &= ~PN_SET;
    258 		return;
    259 	case MIDI_CTRL_RPN_MSB:
    260 		mc-> rpn &= ~0x7f<<7;
    261 		mc-> rpn |=  PN_SET | (0x7f & ctlval[1])<<7;
    262 		mc->nrpn &= ~PN_SET;
    263 		return;
    264 	case MIDI_CTRL_NRPN_LSB:
    265 		mc->nrpn &= ~0x7f;
    266 		mc->nrpn |=  PN_SET | (0x7f & ctlval[1]);
    267 		mc-> rpn &= ~PN_SET;
    268 		return;
    269 	case MIDI_CTRL_NRPN_MSB:
    270 		mc->nrpn &= ~0x7f<<7;
    271 		mc->nrpn |=  PN_SET | (0x7f & ctlval[1])<<7;
    272 		mc-> rpn &= ~PN_SET;
    273 		return;
    274 	case MIDI_CTRL_DATA_ENTRY_LSB:
    275 		islsb = 1;
    276 		goto whichparm;
    277 	case MIDI_CTRL_DATA_ENTRY_MSB:
    278 		islsb = 0;
    279 	whichparm:
    280 		if ( 0 == ( (mc->rpn ^ mc->nrpn) & PN_SET ) )
    281 			return; /* exactly one must be current */
    282 		if ( mc->rpn & PN_SET ) {
    283 			key = mc->rpn;
    284 			c = RPN;
    285 		} else {
    286 			key = mc->nrpn;
    287 			c = NRPN;
    288 		}
    289 		key &= 0x3fff;
    290 		if ( 0x3fff == key ) /* 'null' parm# to lock out changes */
    291 			return;
    292 		enter14(mc, chan, c, key, islsb, ctlval[1]);
    293 		return;
    294 	case MIDI_CTRL_RPN_INCREMENT: /* XXX for later - these are a PITA to */
    295 	case MIDI_CTRL_RPN_DECREMENT: /* get right - 'right' varies by param */
    296 			/* see http://www.midi.org/about-midi/rp18.shtml */
    297 		return;
    298 	}
    299 
    300 	/*
    301 	 * Channel mode, RPN, and NRPN operations have been ruled out.
    302 	 * This is an ordinary control change.
    303 	 */
    304 
    305 	key = ctlval[0];
    306 	c = classify(&key, &islsb);
    307 
    308 	switch ( c ) {
    309 	case CTL14:
    310 		enter14(mc, chan, c, key, islsb, ctlval[1]);
    311 		return;
    312 	case CTL7:
    313 		present = store_locate(mc->store, c, chan, key);
    314 		if ( !mc->accept_any_ctl_rpn ) {
    315 			if ( !present )
    316 				break;
    317 			val = store_extract(mc->store, c, chan, key);
    318 			if ( !(val&C7_SET) )
    319 				break;
    320 		}
    321 		store_update(mc->store, c, chan, key,
    322 		    C7_SET | (0x7f & ctlval[1]));
    323 		mc->notify(mc->cookie, MIDICTL_CTLR, chan, key);
    324 		return;
    325 	case CTL1:
    326 		present = store_locate(mc->store, c, chan, key);
    327 		if ( !mc->accept_any_ctl_rpn ) {
    328 			if ( !present )
    329 				break;
    330 			val = store_extract(mc->store, c, chan, key);
    331 			if ( !(val&C1_SET) )
    332 				break;
    333 		}
    334 		store_update(mc->store, c, chan, key,
    335 		    C1_SET | (ctlval[1]>63));
    336 		mc->notify(mc->cookie, MIDICTL_CTLR, chan, key);
    337 		return;
    338 	case RPN:
    339 	case NRPN:
    340 		return; /* won't see these - sop for gcc */
    341 	}
    342 }
    343 
    344 uint_fast16_t
    345 midictl_read(midictl *mc, uint_fast8_t chan, uint_fast8_t ctlr,
    346              uint_fast16_t dflt)
    347 {
    348 	uint_fast16_t key, val;
    349 	class c;
    350 	_Bool islsb, present;
    351 
    352 	KASSERT(mutex_owned(mc->lock));
    353 
    354 	key = ctlr;
    355 	c = classify(&key, &islsb);
    356 	switch ( c ) {
    357 	case CTL1:
    358 		present = store_locate(mc->store, c, chan, key);
    359 		if ( !present ||
    360 		    !(C1_SET&(val = store_extract(mc->store, c, chan, key))) ) {
    361 			val = C1_SET | (dflt > 63); /* convert to boolean */
    362 			store_update(mc->store, c, chan, key, val);
    363 		}
    364 		return (val & 1) ? 127 : 0;
    365 	case CTL7:
    366 		present = store_locate(mc->store, c, chan, key);
    367 		if ( !present ||
    368 		    !(C7_SET&(val = store_extract(mc->store, c, chan, key))) ) {
    369 			val = C7_SET | (dflt & 0x7f);
    370 			store_update(mc->store, c, chan, key, val);
    371 		}
    372 		return val & 0x7f;
    373 	case CTL14:
    374 		KASSERT(!islsb);
    375 		return read14(mc, chan, c, key, dflt);
    376 	case RPN:
    377 	case NRPN:
    378 		break; /* sop for gcc */
    379 	}
    380 	return 0; /* sop for gcc */
    381 }
    382 
    383 uint_fast16_t
    384 midictl_rpn_read(midictl *mc, uint_fast8_t chan, uint_fast16_t ctlr,
    385                  uint_fast16_t dflt)
    386 {
    387 
    388 	KASSERT(mutex_owned(mc->lock));
    389 
    390 	return read14(mc, chan, RPN, ctlr, dflt);
    391 }
    392 
    393 uint_fast16_t
    394 midictl_nrpn_read(midictl *mc, uint_fast8_t chan, uint_fast16_t ctlr,
    395                   uint_fast16_t dflt)
    396 {
    397 
    398 	KASSERT(mutex_owned(mc->lock));
    399 
    400 	return read14(mc, chan, NRPN, ctlr, dflt);
    401 }
    402 
    403 static void
    404 reset_all_controllers(midictl *mc, uint_fast8_t chan)
    405 {
    406 	uint_fast16_t ctlr, key;
    407 	class c;
    408 	_Bool islsb, present;
    409 
    410 	KASSERT(mutex_owned(mc->lock));
    411 
    412 	for ( ctlr = 0 ; ; ++ ctlr ) {
    413 		switch ( ctlr ) {
    414 		/*
    415 		 * exempt by http://www.midi.org/about-midi/rp15.shtml:
    416 		 */
    417 		case MIDI_CTRL_BANK_SELECT_MSB:		/* 0 */
    418 		case MIDI_CTRL_CHANNEL_VOLUME_MSB:	/* 7 */
    419 		case MIDI_CTRL_PAN_MSB:			/* 10 */
    420 			continue;
    421 		case MIDI_CTRL_BANK_SELECT_LSB:		/* 32 */
    422 			ctlr += 31; /* skip all these LSBs anyway */
    423 			continue;
    424 		case MIDI_CTRL_SOUND_VARIATION:		/* 70 */
    425 			ctlr += 9; /* skip all Sound Controllers */
    426 			continue;
    427 		case MIDI_CTRL_EFFECT_DEPTH_1:		/* 91 */
    428 			goto loop_exit; /* nothing more gets reset */
    429 		/*
    430 		 * exempt for our own personal reasons:
    431 		 */
    432 		case MIDI_CTRL_DATA_ENTRY_MSB:		/* 6 */
    433 			continue; /* doesn't go to the store */
    434 		}
    435 
    436 		key = ctlr;
    437 		c = classify(&key, &islsb);
    438 
    439 		present = store_locate(mc->store, c, chan, key);
    440 		if ( !present )
    441 			continue;
    442 		store_update(mc->store, c, chan, key, 0); /* no C*SET */
    443 	}
    444 loop_exit:
    445 	mc->notify(mc->cookie, MIDICTL_RESET, chan, 0);
    446 }
    447 
    448 static void
    449 enter14(midictl *mc, uint_fast8_t chan, class c, uint_fast16_t key,
    450         _Bool islsb, uint8_t val)
    451 {
    452 	uint16_t stval;
    453 	_Bool present;
    454 
    455 	KASSERT(mutex_owned(mc->lock));
    456 
    457 	present = store_locate(mc->store, c, chan, key);
    458 	stval = (present) ? store_extract(mc->store, c, chan, key) : 0;
    459 	if ( !( stval & (C14MSET|C14LSET) ) ) {
    460 		if ( !((NRPN==c)? mc->accept_any_nrpn: mc->accept_any_ctl_rpn) )
    461 			return;
    462 	}
    463 	if ( islsb )
    464 		stval = C14LSET | val | ( stval & ~0x7f );
    465 	else
    466 		stval = C14MSET | ( val << 7 ) | ( stval & ~0x3f80 );
    467 	store_update(mc->store, c, chan, key, stval);
    468 	mc->notify(mc->cookie, CTL14 == c ? MIDICTL_CTLR
    469 		             : RPN   == c ? MIDICTL_RPN
    470 			     : MIDICTL_NRPN, chan, key);
    471 }
    472 
    473 static uint_fast16_t
    474 read14(midictl *mc, uint_fast8_t chan, class c, uint_fast16_t key,
    475        uint_fast16_t dflt)
    476 {
    477 	uint16_t val;
    478 	_Bool present;
    479 
    480 	KASSERT(mutex_owned(mc->lock));
    481 
    482 	present = store_locate(mc->store, c, chan, key);
    483 	if ( !present )
    484 		goto neitherset;
    485 
    486 	val = store_extract(mc->store, c, chan, key);
    487 	switch ( val & (C14MSET|C14LSET) ) {
    488 	case C14MSET|C14LSET:
    489 		return val & 0x3fff;
    490 	case C14MSET:
    491 		val = C14LSET | (val & ~0x7f) | (dflt & 0x7f);
    492 		break;
    493 	case C14LSET:
    494 		val = C14MSET | (val & ~0x3f8) | (dflt & 0x3f8);
    495 		break;
    496 neitherset:
    497 	case 0:
    498 		val = C14MSET|C14LSET | (dflt & 0x3fff);
    499 	}
    500 	store_update(mc->store, c, chan, key, val);
    501 	return val & 0x3fff;
    502 }
    503 
    504 /*
    505  * Determine the controller class; ranges based on
    506  * http://www.midi.org/about-midi/table3.shtml dated 1995/1999/2002
    507  * and viewed 2 June 2006.
    508  */
    509 static class
    510 classify(uint_fast16_t *key, _Bool *islsb) {
    511 	if ( *key < 32 ) {
    512 		*islsb = 0;
    513 		return CTL14;
    514 	} else if ( *key < 64 ) {
    515 		*islsb = 1;
    516 		*key -= 32;
    517 		return CTL14;
    518 	} else if ( *key < 70 ) {
    519 		return CTL1;
    520 	}	  	/* 70-84 defined, 85-90 undef'd, 91-95 def'd */
    521 	return CTL7;	/* 96-101,120- handled above, 102-119 all undef'd */
    522 		  	/* treat them all as CTL7 */
    523 }
    524 
    525 static void
    526 notify_no_one(void *cookie, midictl_evt evt,
    527     uint_fast8_t chan, uint_fast16_t k)
    528 {
    529 }
    530 
    531 #undef PN_SET
    532 #undef C14MSET
    533 #undef C14LSET
    534 #undef C7_SET
    535 #undef C1_SET
    536 
    537 static void
    538 store_thread(void *arg)
    539 {
    540 	midictl_store *s;
    541 
    542 	s = arg;
    543 
    544 	mutex_enter(s->lock);
    545 	for (;;) {
    546 		if (s->destroy) {
    547 			mutex_exit(s->lock);
    548 			cv_destroy(&s->cv);
    549 			kmem_free(s->table, sizeof(*s->table)<<s->lgcapacity);
    550 			kmem_free(s, sizeof(*s));
    551 			return;
    552 		} else if (NEED_REHASH(s)) {
    553 			store_rehash(s);
    554 		} else {
    555 			cv_wait(&s->cv, s->lock);
    556 		}
    557 	}
    558 }
    559 
    560 static _Bool
    561 store_locate(midictl_store *s, class c, uint_fast8_t chan, uint_fast16_t key)
    562 {
    563 	uint64_t mask;
    564 
    565 	KASSERT(mutex_owned(s->lock));
    566 
    567 	if ( s->used >= 1 << s->lgcapacity )
    568 		panic("%s: repeated attempts to expand table failed", __func__);
    569 
    570 	chan = packing[c] * (chan/packing[c]);
    571 
    572 	if ( CTL7 == c ) {	/* only 16 bits here (key's only 7) */
    573 		s->key = IS_USED | IS_CTL7 | (chan << 7) | key;
    574 		mask = 0xffff;
    575 	} else {		/* use 23 bits (key could be 14) */
    576 		s->key = (c << 20) | (chan << 16) | IS_USED | key;
    577 		mask = 0x7fffff;
    578 	}
    579 
    580 	s->idx = store_idx(s->lgcapacity, s->table, s->key, mask);
    581 
    582 	if ( !(s->table[s->idx] & IS_USED) )
    583 		return 0;
    584 
    585 	return 1;
    586 }
    587 
    588 static uint16_t
    589 store_extract(midictl_store *s, class c, uint_fast8_t chan,
    590     uint_fast16_t key)
    591 {
    592 
    593 	KASSERT(mutex_owned(s->lock));
    594 
    595 	chan %= packing[c];
    596 	switch ( c ) {
    597 	case CTL1:
    598 		return 3 & (s->table[s->idx]>>CTL1SHIFT(chan));
    599 	case CTL7:
    600 		return 0xff & (s->table[s->idx]>>CTL7SHIFT(chan));
    601 	case CTL14:
    602 	case RPN:
    603 	case NRPN:
    604 		break;
    605 	}
    606 	return 0xffff & (s->table[s->idx]>>CTLESHIFT(chan));
    607 }
    608 
    609 static void
    610 store_update(midictl_store *s, class c, uint_fast8_t chan,
    611     uint_fast16_t key, uint16_t value)
    612 {
    613 	uint64_t orig;
    614 
    615 	KASSERT(mutex_owned(s->lock));
    616 
    617 	orig = s->table[s->idx];
    618 	if ( !(orig & IS_USED) ) {
    619 		orig = s->key;
    620 		++ s->used;
    621 	}
    622 
    623 	chan %= packing[c];
    624 
    625 	switch ( c ) {
    626 	case CTL1:
    627 		orig &= ~(((uint64_t)3)<<CTL1SHIFT(chan));
    628 		orig |= ((uint64_t)(3 & value)) << CTL1SHIFT(chan);
    629 		break;
    630 	case CTL7:
    631 		orig &= ~(((uint64_t)0xff)<<CTL7SHIFT(chan));
    632 		orig |= ((uint64_t)(0xff & value)) << CTL7SHIFT(chan);
    633 		break;
    634 	case CTL14:
    635 	case RPN:
    636 	case NRPN:
    637 		orig &= ~(((uint64_t)0xffff)<<CTLESHIFT(chan));
    638 		orig |= ((uint64_t)value) << CTLESHIFT(chan);
    639 		break;
    640 	}
    641 
    642 	s->table[s->idx] = orig;
    643 	if (NEED_REHASH(s))
    644 		cv_broadcast(&s->cv);
    645 }
    646 
    647 static uint32_t
    648 store_idx(uint32_t lgcapacity, uint64_t *table,
    649           uint64_t key, uint64_t mask)
    650 {
    651 	uint32_t val;
    652 	uint32_t k, h1, h2;
    653 	int32_t idx;
    654 
    655 	k = key;
    656 
    657 	h1 = ((k * 0x61c88646) >> (32-lgcapacity)) & ((1<<lgcapacity) - 1);
    658 	h2 = ((k * 0x9e3779b9) >> (32-lgcapacity)) & ((1<<lgcapacity) - 1);
    659 	h2 |= 1;
    660 
    661 	for ( idx = h1 ;; idx -= h2 ) {
    662 		if ( idx < 0 )
    663 			idx += 1<<lgcapacity;
    664 		val = (uint32_t)(table[idx] & mask);
    665 		if ( val == k )
    666 			break;
    667 		if ( !(val & IS_USED) )
    668 			break;
    669 	}
    670 
    671 	return idx;
    672 }
    673 
    674 static void
    675 store_rehash(midictl_store *s)
    676 {
    677 	uint64_t *newtbl, *oldtbl, mask;
    678 	uint32_t oldlgcap, newlgcap, oidx, nidx;
    679 
    680 	KASSERT(mutex_owned(s->lock));
    681 
    682 	oldlgcap = s->lgcapacity;
    683 	newlgcap = oldlgcap + s->lgcapacity;
    684 
    685 	mutex_exit(s->lock);
    686 	newtbl = kmem_zalloc(sizeof(*newtbl) << newlgcap, KM_SLEEP);
    687 	mutex_enter(s->lock);
    688 
    689 	if (newtbl == NULL) {
    690 		kpause("midictl", false, hz, s->lock);
    691 		return;
    692 	}
    693 	if (oldlgcap != s->lgcapacity) {
    694 		mutex_exit(s->lock);
    695 		kmem_free(newtbl, sizeof(*newtbl) << newlgcap);
    696 		mutex_enter(s->lock);
    697 		return;
    698 	}
    699 
    700 	for ( oidx = 1<<s->lgcapacity ; oidx --> 0 ; ) {
    701 		if (!(s->table[oidx] & IS_USED) )
    702 			continue;
    703 		if ( s->table[oidx] & IS_CTL7 )
    704 			mask = 0xffff;
    705 		else
    706 			mask = 0x3fffff;
    707 		nidx = store_idx(newlgcap, newtbl,
    708 		    s->table[oidx] & mask, mask);
    709 		newtbl[nidx] = s->table[oidx];
    710 	}
    711 	oldtbl = s->table;
    712 	s->table = newtbl;
    713 	s->lgcapacity = newlgcap;
    714 
    715 	mutex_exit(s->lock);
    716 	kmem_free(oldtbl, sizeof(*oldtbl) << oldlgcap);
    717 	mutex_enter(s->lock);
    718 }
    719