The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/midictl.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 662db29b35c4f7438e4d1a70a7704d65


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.