1/* $NetBSD: midictl.c,v 1.8 2015/08/28 13:04:29 joerg 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.8 2015/08/28 13:04:29 joerg 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
74typedef enum { CTL1, CTL7, CTL14, RPN, NRPN } class;
75
76/*
77 * assert(does_not_apply(KNFNamespaceArgumentAgainstNamesInPrototypes,
78 * PrototypesOfStaticFunctionsWithinNonIncludedFile));
79 */
80static void reset_all_controllers(midictl *mc, uint_fast8_t chan);
81static void enter14(midictl *mc, uint_fast8_t chan, class c,
82 uint_fast16_t key, _Bool islsb, uint8_t val);
83static uint_fast16_t read14(midictl *mc, uint_fast8_t chan, class c,
84 uint_fast16_t key, uint_fast16_t dflt);
85static class classify(uint_fast16_t *key, _Bool *islsb);
86static midictl_notify notify_no_one;
87
88static _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 */
97static uint16_t store_extract(midictl_store *s, class c,
98 uint_fast8_t chan, uint_fast16_t key);
99static 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
134struct 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
155static 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
163static uint32_t store_idx(uint32_t lgcapacity,
164 uint64_t *table,
165 uint64_t key, uint64_t mask);
166static void store_rehash(midictl_store *s);
167static void store_thread(void *);
168
169int
170midictl_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
205void
206midictl_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
220void
221midictl_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 &= ~0x7fU<<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 &= ~0x7fU<<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
347uint_fast16_t
348midictl_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
387uint_fast16_t
388midictl_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
398uint_fast16_t
399midictl_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
409static void
410reset_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 }
450loop_exit:
451 mc->notify(mc->cookie, MIDICTL_RESET, chan, 0);
452}
453
454static void
455enter14(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
479static uint_fast16_t
480read14(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;
502neitherset:
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 */
515static class
516classify(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
531static void
532notify_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
543static void
544store_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
566static _Bool
567store_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
594static uint16_t
595store_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
615static void
616store_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
653static uint32_t
654store_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
680static void
681store_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