xref: /netbsd-src/sys/dev/midictl.c (revision ba65fde2d7fefa7d39838fa5fa855e62bd606b5e)
1 /* $NetBSD: midictl.c,v 1.7 2011/11/23 23:07:31 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.7 2011/11/23 23:07:31 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, "midictlv");
192 	error = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, store_thread,
193 	    s, NULL, "midictlt");
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 	kmutex_t *lock;
210 
211 	s = mc->store;
212 	lock = s->lock;
213 
214 	mutex_enter(lock);
215 	s->destroy = true;
216 	cv_broadcast(&s->cv);
217 	mutex_exit(lock);
218 }
219 
220 void
221 midictl_change(midictl *mc, uint_fast8_t chan, uint8_t *ctlval)
222 {
223 	class c;
224 	uint_fast16_t key, val;
225 	_Bool islsb, present;
226 
227 	KASSERT(mutex_owned(mc->lock));
228 	KASSERT(!mc->store->destroy);
229 
230 	switch ( ctlval[0] ) {
231 	/*
232 	 * Channel mode messages:
233 	 */
234 	case MIDI_CTRL_OMNI_OFF:
235 	case MIDI_CTRL_OMNI_ON:
236 	case MIDI_CTRL_POLY_OFF:
237 	case MIDI_CTRL_POLY_ON:
238 		if ( chan != mc->base_channel )
239 			return; /* ignored - not on base channel */
240 		else
241 			return; /* XXX ignored anyway - not implemented yet */
242 	case MIDI_CTRL_NOTES_OFF:
243 		mc->notify(mc->cookie, MIDICTL_NOTES_OFF, chan, 0);
244 		return;
245 	case MIDI_CTRL_LOCAL:
246 		mc->notify(mc->cookie, MIDICTL_LOCAL, chan, ctlval[1]);
247 		return;
248 	case MIDI_CTRL_SOUND_OFF:
249 		mc->notify(mc->cookie, MIDICTL_SOUND_OFF, chan, 0);
250 		return;
251 	case MIDI_CTRL_RESET:
252 		reset_all_controllers(mc, chan);
253 		return;
254 	/*
255 	 * Control changes to be handled specially:
256 	 */
257 	case MIDI_CTRL_RPN_LSB:
258 		mc-> rpn &= ~0x7f;
259 		mc-> rpn |=  PN_SET | (0x7f & ctlval[1]);
260 		mc->nrpn &= ~PN_SET;
261 		return;
262 	case MIDI_CTRL_RPN_MSB:
263 		mc-> rpn &= ~0x7f<<7;
264 		mc-> rpn |=  PN_SET | (0x7f & ctlval[1])<<7;
265 		mc->nrpn &= ~PN_SET;
266 		return;
267 	case MIDI_CTRL_NRPN_LSB:
268 		mc->nrpn &= ~0x7f;
269 		mc->nrpn |=  PN_SET | (0x7f & ctlval[1]);
270 		mc-> rpn &= ~PN_SET;
271 		return;
272 	case MIDI_CTRL_NRPN_MSB:
273 		mc->nrpn &= ~0x7f<<7;
274 		mc->nrpn |=  PN_SET | (0x7f & ctlval[1])<<7;
275 		mc-> rpn &= ~PN_SET;
276 		return;
277 	case MIDI_CTRL_DATA_ENTRY_LSB:
278 		islsb = 1;
279 		goto whichparm;
280 	case MIDI_CTRL_DATA_ENTRY_MSB:
281 		islsb = 0;
282 	whichparm:
283 		if ( 0 == ( (mc->rpn ^ mc->nrpn) & PN_SET ) )
284 			return; /* exactly one must be current */
285 		if ( mc->rpn & PN_SET ) {
286 			key = mc->rpn;
287 			c = RPN;
288 		} else {
289 			key = mc->nrpn;
290 			c = NRPN;
291 		}
292 		key &= 0x3fff;
293 		if ( 0x3fff == key ) /* 'null' parm# to lock out changes */
294 			return;
295 		enter14(mc, chan, c, key, islsb, ctlval[1]);
296 		return;
297 	case MIDI_CTRL_RPN_INCREMENT: /* XXX for later - these are a PITA to */
298 	case MIDI_CTRL_RPN_DECREMENT: /* get right - 'right' varies by param */
299 			/* see http://www.midi.org/about-midi/rp18.shtml */
300 		return;
301 	}
302 
303 	/*
304 	 * Channel mode, RPN, and NRPN operations have been ruled out.
305 	 * This is an ordinary control change.
306 	 */
307 
308 	key = ctlval[0];
309 	c = classify(&key, &islsb);
310 
311 	switch ( c ) {
312 	case CTL14:
313 		enter14(mc, chan, c, key, islsb, ctlval[1]);
314 		return;
315 	case CTL7:
316 		present = store_locate(mc->store, c, chan, key);
317 		if ( !mc->accept_any_ctl_rpn ) {
318 			if ( !present )
319 				break;
320 			val = store_extract(mc->store, c, chan, key);
321 			if ( !(val&C7_SET) )
322 				break;
323 		}
324 		store_update(mc->store, c, chan, key,
325 		    C7_SET | (0x7f & ctlval[1]));
326 		mc->notify(mc->cookie, MIDICTL_CTLR, chan, key);
327 		return;
328 	case CTL1:
329 		present = store_locate(mc->store, c, chan, key);
330 		if ( !mc->accept_any_ctl_rpn ) {
331 			if ( !present )
332 				break;
333 			val = store_extract(mc->store, c, chan, key);
334 			if ( !(val&C1_SET) )
335 				break;
336 		}
337 		store_update(mc->store, c, chan, key,
338 		    C1_SET | (ctlval[1]>63));
339 		mc->notify(mc->cookie, MIDICTL_CTLR, chan, key);
340 		return;
341 	case RPN:
342 	case NRPN:
343 		return; /* won't see these - sop for gcc */
344 	}
345 }
346 
347 uint_fast16_t
348 midictl_read(midictl *mc, uint_fast8_t chan, uint_fast8_t ctlr,
349              uint_fast16_t dflt)
350 {
351 	uint_fast16_t key, val;
352 	class c;
353 	_Bool islsb, present;
354 
355 	KASSERT(mutex_owned(mc->lock));
356 	KASSERT(!mc->store->destroy);
357 
358 	key = ctlr;
359 	c = classify(&key, &islsb);
360 	switch ( c ) {
361 	case CTL1:
362 		present = store_locate(mc->store, c, chan, key);
363 		if ( !present ||
364 		    !(C1_SET&(val = store_extract(mc->store, c, chan, key))) ) {
365 			val = C1_SET | (dflt > 63); /* convert to boolean */
366 			store_update(mc->store, c, chan, key, val);
367 		}
368 		return (val & 1) ? 127 : 0;
369 	case CTL7:
370 		present = store_locate(mc->store, c, chan, key);
371 		if ( !present ||
372 		    !(C7_SET&(val = store_extract(mc->store, c, chan, key))) ) {
373 			val = C7_SET | (dflt & 0x7f);
374 			store_update(mc->store, c, chan, key, val);
375 		}
376 		return val & 0x7f;
377 	case CTL14:
378 		KASSERT(!islsb);
379 		return read14(mc, chan, c, key, dflt);
380 	case RPN:
381 	case NRPN:
382 		break; /* sop for gcc */
383 	}
384 	return 0; /* sop for gcc */
385 }
386 
387 uint_fast16_t
388 midictl_rpn_read(midictl *mc, uint_fast8_t chan, uint_fast16_t ctlr,
389                  uint_fast16_t dflt)
390 {
391 
392 	KASSERT(mutex_owned(mc->lock));
393 	KASSERT(!mc->store->destroy);
394 
395 	return read14(mc, chan, RPN, ctlr, dflt);
396 }
397 
398 uint_fast16_t
399 midictl_nrpn_read(midictl *mc, uint_fast8_t chan, uint_fast16_t ctlr,
400                   uint_fast16_t dflt)
401 {
402 
403 	KASSERT(mutex_owned(mc->lock));
404 	KASSERT(!mc->store->destroy);
405 
406 	return read14(mc, chan, NRPN, ctlr, dflt);
407 }
408 
409 static void
410 reset_all_controllers(midictl *mc, uint_fast8_t chan)
411 {
412 	uint_fast16_t ctlr, key;
413 	class c;
414 	_Bool islsb, present;
415 
416 	KASSERT(mutex_owned(mc->lock));
417 
418 	for ( ctlr = 0 ; ; ++ ctlr ) {
419 		switch ( ctlr ) {
420 		/*
421 		 * exempt by http://www.midi.org/about-midi/rp15.shtml:
422 		 */
423 		case MIDI_CTRL_BANK_SELECT_MSB:		/* 0 */
424 		case MIDI_CTRL_CHANNEL_VOLUME_MSB:	/* 7 */
425 		case MIDI_CTRL_PAN_MSB:			/* 10 */
426 			continue;
427 		case MIDI_CTRL_BANK_SELECT_LSB:		/* 32 */
428 			ctlr += 31; /* skip all these LSBs anyway */
429 			continue;
430 		case MIDI_CTRL_SOUND_VARIATION:		/* 70 */
431 			ctlr += 9; /* skip all Sound Controllers */
432 			continue;
433 		case MIDI_CTRL_EFFECT_DEPTH_1:		/* 91 */
434 			goto loop_exit; /* nothing more gets reset */
435 		/*
436 		 * exempt for our own personal reasons:
437 		 */
438 		case MIDI_CTRL_DATA_ENTRY_MSB:		/* 6 */
439 			continue; /* doesn't go to the store */
440 		}
441 
442 		key = ctlr;
443 		c = classify(&key, &islsb);
444 
445 		present = store_locate(mc->store, c, chan, key);
446 		if ( !present )
447 			continue;
448 		store_update(mc->store, c, chan, key, 0); /* no C*SET */
449 	}
450 loop_exit:
451 	mc->notify(mc->cookie, MIDICTL_RESET, chan, 0);
452 }
453 
454 static void
455 enter14(midictl *mc, uint_fast8_t chan, class c, uint_fast16_t key,
456         _Bool islsb, uint8_t val)
457 {
458 	uint16_t stval;
459 	_Bool present;
460 
461 	KASSERT(mutex_owned(mc->lock));
462 
463 	present = store_locate(mc->store, c, chan, key);
464 	stval = (present) ? store_extract(mc->store, c, chan, key) : 0;
465 	if ( !( stval & (C14MSET|C14LSET) ) ) {
466 		if ( !((NRPN==c)? mc->accept_any_nrpn: mc->accept_any_ctl_rpn) )
467 			return;
468 	}
469 	if ( islsb )
470 		stval = C14LSET | val | ( stval & ~0x7f );
471 	else
472 		stval = C14MSET | ( val << 7 ) | ( stval & ~0x3f80 );
473 	store_update(mc->store, c, chan, key, stval);
474 	mc->notify(mc->cookie, CTL14 == c ? MIDICTL_CTLR
475 		             : RPN   == c ? MIDICTL_RPN
476 			     : MIDICTL_NRPN, chan, key);
477 }
478 
479 static uint_fast16_t
480 read14(midictl *mc, uint_fast8_t chan, class c, uint_fast16_t key,
481        uint_fast16_t dflt)
482 {
483 	uint16_t val;
484 	_Bool present;
485 
486 	KASSERT(mutex_owned(mc->lock));
487 
488 	present = store_locate(mc->store, c, chan, key);
489 	if ( !present )
490 		goto neitherset;
491 
492 	val = store_extract(mc->store, c, chan, key);
493 	switch ( val & (C14MSET|C14LSET) ) {
494 	case C14MSET|C14LSET:
495 		return val & 0x3fff;
496 	case C14MSET:
497 		val = C14LSET | (val & ~0x7f) | (dflt & 0x7f);
498 		break;
499 	case C14LSET:
500 		val = C14MSET | (val & ~0x3f8) | (dflt & 0x3f8);
501 		break;
502 neitherset:
503 	case 0:
504 		val = C14MSET|C14LSET | (dflt & 0x3fff);
505 	}
506 	store_update(mc->store, c, chan, key, val);
507 	return val & 0x3fff;
508 }
509 
510 /*
511  * Determine the controller class; ranges based on
512  * http://www.midi.org/about-midi/table3.shtml dated 1995/1999/2002
513  * and viewed 2 June 2006.
514  */
515 static class
516 classify(uint_fast16_t *key, _Bool *islsb) {
517 	if ( *key < 32 ) {
518 		*islsb = 0;
519 		return CTL14;
520 	} else if ( *key < 64 ) {
521 		*islsb = 1;
522 		*key -= 32;
523 		return CTL14;
524 	} else if ( *key < 70 ) {
525 		return CTL1;
526 	}	  	/* 70-84 defined, 85-90 undef'd, 91-95 def'd */
527 	return CTL7;	/* 96-101,120- handled above, 102-119 all undef'd */
528 		  	/* treat them all as CTL7 */
529 }
530 
531 static void
532 notify_no_one(void *cookie, midictl_evt evt,
533     uint_fast8_t chan, uint_fast16_t k)
534 {
535 }
536 
537 #undef PN_SET
538 #undef C14MSET
539 #undef C14LSET
540 #undef C7_SET
541 #undef C1_SET
542 
543 static void
544 store_thread(void *arg)
545 {
546 	midictl_store *s;
547 
548 	s = arg;
549 
550 	mutex_enter(s->lock);
551 	for (;;) {
552 		if (s->destroy) {
553 			mutex_exit(s->lock);
554 			cv_destroy(&s->cv);
555 			kmem_free(s->table, sizeof(*s->table)<<s->lgcapacity);
556 			kmem_free(s, sizeof(*s));
557 			kthread_exit(0);
558 		} else if (NEED_REHASH(s)) {
559 			store_rehash(s);
560 		} else {
561 			cv_wait(&s->cv, s->lock);
562 		}
563 	}
564 }
565 
566 static _Bool
567 store_locate(midictl_store *s, class c, uint_fast8_t chan, uint_fast16_t key)
568 {
569 	uint64_t mask;
570 
571 	KASSERT(mutex_owned(s->lock));
572 
573 	if ( s->used >= 1 << s->lgcapacity )
574 		panic("%s: repeated attempts to expand table failed", __func__);
575 
576 	chan = packing[c] * (chan/packing[c]);
577 
578 	if ( CTL7 == c ) {	/* only 16 bits here (key's only 7) */
579 		s->key = IS_USED | IS_CTL7 | (chan << 7) | key;
580 		mask = 0xffff;
581 	} else {		/* use 23 bits (key could be 14) */
582 		s->key = (c << 20) | (chan << 16) | IS_USED | key;
583 		mask = 0x7fffff;
584 	}
585 
586 	s->idx = store_idx(s->lgcapacity, s->table, s->key, mask);
587 
588 	if ( !(s->table[s->idx] & IS_USED) )
589 		return 0;
590 
591 	return 1;
592 }
593 
594 static uint16_t
595 store_extract(midictl_store *s, class c, uint_fast8_t chan,
596     uint_fast16_t key)
597 {
598 
599 	KASSERT(mutex_owned(s->lock));
600 
601 	chan %= packing[c];
602 	switch ( c ) {
603 	case CTL1:
604 		return 3 & (s->table[s->idx]>>CTL1SHIFT(chan));
605 	case CTL7:
606 		return 0xff & (s->table[s->idx]>>CTL7SHIFT(chan));
607 	case CTL14:
608 	case RPN:
609 	case NRPN:
610 		break;
611 	}
612 	return 0xffff & (s->table[s->idx]>>CTLESHIFT(chan));
613 }
614 
615 static void
616 store_update(midictl_store *s, class c, uint_fast8_t chan,
617     uint_fast16_t key, uint16_t value)
618 {
619 	uint64_t orig;
620 
621 	KASSERT(mutex_owned(s->lock));
622 
623 	orig = s->table[s->idx];
624 	if ( !(orig & IS_USED) ) {
625 		orig = s->key;
626 		++ s->used;
627 	}
628 
629 	chan %= packing[c];
630 
631 	switch ( c ) {
632 	case CTL1:
633 		orig &= ~(((uint64_t)3)<<CTL1SHIFT(chan));
634 		orig |= ((uint64_t)(3 & value)) << CTL1SHIFT(chan);
635 		break;
636 	case CTL7:
637 		orig &= ~(((uint64_t)0xff)<<CTL7SHIFT(chan));
638 		orig |= ((uint64_t)(0xff & value)) << CTL7SHIFT(chan);
639 		break;
640 	case CTL14:
641 	case RPN:
642 	case NRPN:
643 		orig &= ~(((uint64_t)0xffff)<<CTLESHIFT(chan));
644 		orig |= ((uint64_t)value) << CTLESHIFT(chan);
645 		break;
646 	}
647 
648 	s->table[s->idx] = orig;
649 	if (NEED_REHASH(s))
650 		cv_broadcast(&s->cv);
651 }
652 
653 static uint32_t
654 store_idx(uint32_t lgcapacity, uint64_t *table,
655           uint64_t key, uint64_t mask)
656 {
657 	uint32_t val;
658 	uint32_t k, h1, h2;
659 	int32_t idx;
660 
661 	k = key;
662 
663 	h1 = ((k * 0x61c88646) >> (32-lgcapacity)) & ((1<<lgcapacity) - 1);
664 	h2 = ((k * 0x9e3779b9) >> (32-lgcapacity)) & ((1<<lgcapacity) - 1);
665 	h2 |= 1;
666 
667 	for ( idx = h1 ;; idx -= h2 ) {
668 		if ( idx < 0 )
669 			idx += 1<<lgcapacity;
670 		val = (uint32_t)(table[idx] & mask);
671 		if ( val == k )
672 			break;
673 		if ( !(val & IS_USED) )
674 			break;
675 	}
676 
677 	return idx;
678 }
679 
680 static void
681 store_rehash(midictl_store *s)
682 {
683 	uint64_t *newtbl, *oldtbl, mask;
684 	uint32_t oldlgcap, newlgcap, oidx, nidx;
685 
686 	KASSERT(mutex_owned(s->lock));
687 
688 	oldlgcap = s->lgcapacity;
689 	newlgcap = oldlgcap + s->lgcapacity;
690 
691 	mutex_exit(s->lock);
692 	newtbl = kmem_zalloc(sizeof(*newtbl) << newlgcap, KM_SLEEP);
693 	mutex_enter(s->lock);
694 
695 	if (newtbl == NULL) {
696 		kpause("midictls", false, hz, s->lock);
697 		return;
698 	}
699 	/*
700 	 * If s->lgcapacity is changed from what we saved int oldlgcap
701 	 * then someone else has already done this for us.
702 	 * XXXMRG but only function changes s->lgcapacity from its
703 	 * initial value, and it is called singled threaded from the
704 	 * main store_thread(), so this code seems dead to me.
705 	 */
706 	if (oldlgcap != s->lgcapacity) {
707 		KASSERT(FALSE);
708 		mutex_exit(s->lock);
709 		kmem_free(newtbl, sizeof(*newtbl) << newlgcap);
710 		mutex_enter(s->lock);
711 		return;
712 	}
713 
714 	for (oidx = 1 << s->lgcapacity ; oidx-- > 0 ; ) {
715 		if (!(s->table[oidx] & IS_USED))
716 			continue;
717 		if (s->table[oidx] & IS_CTL7)
718 			mask = 0xffff;
719 		else
720 			mask = 0x3fffff;
721 		nidx = store_idx(newlgcap, newtbl,
722 		    s->table[oidx] & mask, mask);
723 		newtbl[nidx] = s->table[oidx];
724 	}
725 	oldtbl = s->table;
726 	s->table = newtbl;
727 	s->lgcapacity = newlgcap;
728 
729 	mutex_exit(s->lock);
730 	kmem_free(oldtbl, sizeof(*oldtbl) << oldlgcap);
731 	mutex_enter(s->lock);
732 }
733