1139749Simp/*- 2193640Sariff * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org> 3193640Sariff * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org> 450724Scg * All rights reserved. 550724Scg * 650724Scg * Redistribution and use in source and binary forms, with or without 750724Scg * modification, are permitted provided that the following conditions 850724Scg * are met: 950724Scg * 1. Redistributions of source code must retain the above copyright 1050724Scg * notice, this list of conditions and the following disclaimer. 1150724Scg * 2. Redistributions in binary form must reproduce the above copyright 1250724Scg * notice, this list of conditions and the following disclaimer in the 1350724Scg * documentation and/or other materials provided with the distribution. 1450724Scg * 1550724Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1650724Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1750724Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1850724Scg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1950724Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2050724Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2150724Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2250724Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2350724Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2450724Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2550724Scg * SUCH DAMAGE. 2650724Scg */ 2750724Scg 28193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 29193640Sariff#include "opt_snd.h" 30193640Sariff#endif 31193640Sariff 3253465Scg#include <dev/sound/pcm/sound.h> 3350724Scg 3470134Scg#include "feeder_if.h" 3570134Scg 3682180ScgSND_DECLARE_FILE("$FreeBSD$"); 3782180Scg 38227293Sedstatic MALLOC_DEFINE(M_FEEDER, "feeder", "pcm feeder"); 3970134Scg 4066308Scg#define MAXFEEDERS 256 4165645Scg#undef FEEDER_DEBUG 4250724Scg 4364881Scgstruct feedertab_entry { 4464881Scg SLIST_ENTRY(feedertab_entry) link; 4570134Scg struct feeder_class *feederclass; 4664881Scg struct pcm_feederdesc *desc; 4764881Scg 4864881Scg int idx; 4964881Scg}; 5064881Scgstatic SLIST_HEAD(, feedertab_entry) feedertab; 5164881Scg 5250724Scg/*****************************************************************************/ 5350724Scg 5464881Scgvoid 5564881Scgfeeder_register(void *p) 5664881Scg{ 5789834Scg static int feedercnt = 0; 5889834Scg 5970134Scg struct feeder_class *fc = p; 6064881Scg struct feedertab_entry *fte; 6164881Scg int i; 6264881Scg 6364881Scg if (feedercnt == 0) { 6489834Scg KASSERT(fc->desc == NULL, ("first feeder not root: %s", fc->name)); 6589834Scg 6664881Scg SLIST_INIT(&feedertab); 67111909Sorion fte = malloc(sizeof(*fte), M_FEEDER, M_NOWAIT | M_ZERO); 6889834Scg if (fte == NULL) { 6997274Sbde printf("can't allocate memory for root feeder: %s\n", 7097274Sbde fc->name); 7189834Scg 7289834Scg return; 7389834Scg } 7470134Scg fte->feederclass = fc; 7564881Scg fte->desc = NULL; 7664881Scg fte->idx = feedercnt; 7764881Scg SLIST_INSERT_HEAD(&feedertab, fte, link); 7864881Scg feedercnt++; 7989834Scg 80164614Sariff /* initialize global variables */ 81164614Sariff 82170161Sariff if (snd_verbose < 0 || snd_verbose > 4) 83164614Sariff snd_verbose = 1; 84164614Sariff 85170161Sariff /* initialize unit numbering */ 86170161Sariff snd_unit_init(); 87170161Sariff if (snd_unit < 0 || snd_unit > PCMMAXUNIT) 88170884Sariff snd_unit = -1; 89164614Sariff 90164614Sariff if (snd_maxautovchans < 0 || 91164614Sariff snd_maxautovchans > SND_MAXVCHANS) 92164614Sariff snd_maxautovchans = 0; 93164614Sariff 94164614Sariff if (chn_latency < CHN_LATENCY_MIN || 95164614Sariff chn_latency > CHN_LATENCY_MAX) 96164614Sariff chn_latency = CHN_LATENCY_DEFAULT; 97164614Sariff 98164614Sariff if (chn_latency_profile < CHN_LATENCY_PROFILE_MIN || 99164614Sariff chn_latency_profile > CHN_LATENCY_PROFILE_MAX) 100164614Sariff chn_latency_profile = CHN_LATENCY_PROFILE_DEFAULT; 101164614Sariff 102164614Sariff if (feeder_rate_min < FEEDRATE_MIN || 103164614Sariff feeder_rate_max < FEEDRATE_MIN || 104164614Sariff feeder_rate_min > FEEDRATE_MAX || 105164614Sariff feeder_rate_max > FEEDRATE_MAX || 106164614Sariff !(feeder_rate_min < feeder_rate_max)) { 107164614Sariff feeder_rate_min = FEEDRATE_RATEMIN; 108164614Sariff feeder_rate_max = FEEDRATE_RATEMAX; 109164614Sariff } 110164614Sariff 111164614Sariff if (feeder_rate_round < FEEDRATE_ROUNDHZ_MIN || 112164614Sariff feeder_rate_round > FEEDRATE_ROUNDHZ_MAX) 113164614Sariff feeder_rate_round = FEEDRATE_ROUNDHZ; 114164614Sariff 115164614Sariff if (bootverbose) 116164614Sariff printf("%s: snd_unit=%d snd_maxautovchans=%d " 117193640Sariff "latency=%d " 118164614Sariff "feeder_rate_min=%d feeder_rate_max=%d " 119164614Sariff "feeder_rate_round=%d\n", 120164614Sariff __func__, snd_unit, snd_maxautovchans, 121193640Sariff chn_latency, 122164614Sariff feeder_rate_min, feeder_rate_max, 123164614Sariff feeder_rate_round); 124164614Sariff 12589834Scg /* we've got our root feeder so don't veto pcm loading anymore */ 12689834Scg pcm_veto_load = 0; 12789834Scg 12864881Scg return; 12964881Scg } 13064881Scg 13189834Scg KASSERT(fc->desc != NULL, ("feeder '%s' has no descriptor", fc->name)); 13289834Scg 13389834Scg /* beyond this point failure is non-fatal but may result in some translations being unavailable */ 13464881Scg i = 0; 13570134Scg while ((feedercnt < MAXFEEDERS) && (fc->desc[i].type > 0)) { 13675355Scg /* printf("adding feeder %s, %x -> %x\n", fc->name, fc->desc[i].in, fc->desc[i].out); */ 137111909Sorion fte = malloc(sizeof(*fte), M_FEEDER, M_NOWAIT | M_ZERO); 13889834Scg if (fte == NULL) { 13989834Scg printf("can't allocate memory for feeder '%s', %x -> %x\n", fc->name, fc->desc[i].in, fc->desc[i].out); 14089834Scg 14189834Scg return; 14289834Scg } 14370134Scg fte->feederclass = fc; 14470134Scg fte->desc = &fc->desc[i]; 14564881Scg fte->idx = feedercnt; 14664881Scg fte->desc->idx = feedercnt; 14764881Scg SLIST_INSERT_HEAD(&feedertab, fte, link); 14864881Scg i++; 14964881Scg } 15064881Scg feedercnt++; 15164881Scg if (feedercnt >= MAXFEEDERS) 15289834Scg printf("MAXFEEDERS (%d >= %d) exceeded\n", feedercnt, MAXFEEDERS); 15364881Scg} 15464881Scg 15574363Scgstatic void 15674363Scgfeeder_unregisterall(void *p) 15774363Scg{ 15874363Scg struct feedertab_entry *fte, *next; 15974363Scg 16074363Scg next = SLIST_FIRST(&feedertab); 16174363Scg while (next != NULL) { 16274363Scg fte = next; 16374363Scg next = SLIST_NEXT(fte, link); 16474363Scg free(fte, M_FEEDER); 16574363Scg } 16674363Scg} 16774363Scg 16850724Scgstatic int 16964881Scgcmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m) 17050724Scg{ 17166308Scg return ((n->type == m->type) && 17266308Scg ((n->in == 0) || (n->in == m->in)) && 17366308Scg ((n->out == 0) || (n->out == m->out)) && 17466308Scg (n->flags == m->flags)); 17550724Scg} 17650724Scg 17770134Scgstatic void 17874763Scgfeeder_destroy(struct pcm_feeder *f) 17950724Scg{ 18070134Scg FEEDER_FREE(f); 18170134Scg kobj_delete((kobj_t)f, M_FEEDER); 18270134Scg} 18364881Scg 18474763Scgstatic struct pcm_feeder * 18570134Scgfeeder_create(struct feeder_class *fc, struct pcm_feederdesc *desc) 18670134Scg{ 18774763Scg struct pcm_feeder *f; 18870134Scg int err; 18970134Scg 190111909Sorion f = (struct pcm_feeder *)kobj_create((kobj_class_t)fc, M_FEEDER, M_NOWAIT | M_ZERO); 19189834Scg if (f == NULL) 19289834Scg return NULL; 19389834Scg 19489834Scg f->data = fc->data; 19589834Scg f->source = NULL; 19689834Scg f->parent = NULL; 19789834Scg f->class = fc; 19889834Scg f->desc = &(f->desc_static); 19989834Scg 20089834Scg if (desc) { 20170134Scg *(f->desc) = *desc; 20289834Scg } else { 20370134Scg f->desc->type = FEEDER_ROOT; 20470134Scg f->desc->in = 0; 20570134Scg f->desc->out = 0; 20670134Scg f->desc->flags = 0; 20770134Scg f->desc->idx = 0; 20864881Scg } 20989834Scg 21070134Scg err = FEEDER_INIT(f); 21170134Scg if (err) { 21275319Scg printf("feeder_init(%p) on %s returned %d\n", f, fc->name, err); 21370134Scg feeder_destroy(f); 21489834Scg 21570134Scg return NULL; 21689834Scg } 21789834Scg 21889834Scg return f; 21950724Scg} 22050724Scg 22170134Scgstruct feeder_class * 22270134Scgfeeder_getclass(struct pcm_feederdesc *desc) 22350724Scg{ 22464881Scg struct feedertab_entry *fte; 22550724Scg 22664881Scg SLIST_FOREACH(fte, &feedertab, link) { 22770134Scg if ((desc == NULL) && (fte->desc == NULL)) 22870134Scg return fte->feederclass; 22970134Scg if ((fte->desc != NULL) && (desc != NULL) && cmpdesc(desc, fte->desc)) 23070134Scg return fte->feederclass; 23164881Scg } 23264881Scg return NULL; 23350724Scg} 23450724Scg 23550724Scgint 23674763Scgchn_addfeeder(struct pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc) 23766308Scg{ 23874763Scg struct pcm_feeder *nf; 23970134Scg 24070134Scg nf = feeder_create(fc, desc); 24170134Scg if (nf == NULL) 24289834Scg return ENOSPC; 24366308Scg 24470134Scg nf->source = c->feeder; 24566308Scg 246117307Scg if (c->feeder != NULL) 247117307Scg c->feeder->parent = nf; 24866308Scg c->feeder = nf; 24966308Scg 25066308Scg return 0; 25166308Scg} 25266308Scg 25366308Scgint 25474763Scgchn_removefeeder(struct pcm_channel *c) 25550724Scg{ 25674763Scg struct pcm_feeder *f; 25750724Scg 25870134Scg if (c->feeder == NULL) 25964881Scg return -1; 26070134Scg f = c->feeder; 26170134Scg c->feeder = c->feeder->source; 26270134Scg feeder_destroy(f); 26389834Scg 26464881Scg return 0; 26550724Scg} 26650724Scg 26774763Scgstruct pcm_feeder * 26874763Scgchn_findfeeder(struct pcm_channel *c, u_int32_t type) 26966308Scg{ 27074763Scg struct pcm_feeder *f; 27166308Scg 27266308Scg f = c->feeder; 27366308Scg while (f != NULL) { 27466308Scg if (f->desc->type == type) 27566308Scg return f; 27666308Scg f = f->source; 27766308Scg } 27889834Scg 27966308Scg return NULL; 28066308Scg} 28166308Scg 282164614Sariff/* 283164614Sariff * 14bit format scoring 284164614Sariff * -------------------- 285164614Sariff * 286164614Sariff * 13 12 11 10 9 8 2 1 0 offset 287164614Sariff * +---+---+---+---+---+---+-------------+---+---+ 288164614Sariff * | X | X | X | X | X | X | X X X X X X | X | X | 289164614Sariff * +---+---+---+---+---+---+-------------+---+---+ 290164614Sariff * | | | | | | | | | 291164614Sariff * | | | | | | | | +--> signed? 292164614Sariff * | | | | | | | | 293164614Sariff * | | | | | | | +------> bigendian? 294164614Sariff * | | | | | | | 295164614Sariff * | | | | | | +---------------> total channels 296164614Sariff * | | | | | | 297164614Sariff * | | | | | +------------------------> AFMT_A_LAW 298164614Sariff * | | | | | 299164614Sariff * | | | | +----------------------------> AFMT_MU_LAW 300164614Sariff * | | | | 301164614Sariff * | | | +--------------------------------> AFMT_8BIT 302164614Sariff * | | | 303164614Sariff * | | +------------------------------------> AFMT_16BIT 304164614Sariff * | | 305164614Sariff * | +----------------------------------------> AFMT_24BIT 306164614Sariff * | 307164614Sariff * +--------------------------------------------> AFMT_32BIT 308164614Sariff */ 309164614Sariff#define score_signeq(s1, s2) (((s1) & 0x1) == ((s2) & 0x1)) 310164614Sariff#define score_endianeq(s1, s2) (((s1) & 0x2) == ((s2) & 0x2)) 311164614Sariff#define score_cheq(s1, s2) (((s1) & 0xfc) == ((s2) & 0xfc)) 312193640Sariff#define score_chgt(s1, s2) (((s1) & 0xfc) > ((s2) & 0xfc)) 313193640Sariff#define score_chlt(s1, s2) (((s1) & 0xfc) < ((s2) & 0xfc)) 314164614Sariff#define score_val(s1) ((s1) & 0x3f00) 315164614Sariff#define score_cse(s1) ((s1) & 0x7f) 31664881Scg 317164614Sariffu_int32_t 318193640Sariffsnd_fmtscore(u_int32_t fmt) 319154684Sariff{ 320164614Sariff u_int32_t ret; 321164614Sariff 322164614Sariff ret = 0; 323164614Sariff if (fmt & AFMT_SIGNED) 324164614Sariff ret |= 1 << 0; 325164614Sariff if (fmt & AFMT_BIGENDIAN) 326164614Sariff ret |= 1 << 1; 327193640Sariff /*if (fmt & AFMT_STEREO) 328164614Sariff ret |= (2 & 0x3f) << 2; 329164614Sariff else 330193640Sariff ret |= (1 & 0x3f) << 2;*/ 331193640Sariff ret |= (AFMT_CHANNEL(fmt) & 0x3f) << 2; 332154969Sariff if (fmt & AFMT_A_LAW) 333164614Sariff ret |= 1 << 8; 334164614Sariff else if (fmt & AFMT_MU_LAW) 335164614Sariff ret |= 1 << 9; 336164614Sariff else if (fmt & AFMT_8BIT) 337164614Sariff ret |= 1 << 10; 338164614Sariff else if (fmt & AFMT_16BIT) 339164614Sariff ret |= 1 << 11; 340164614Sariff else if (fmt & AFMT_24BIT) 341164614Sariff ret |= 1 << 12; 342164614Sariff else if (fmt & AFMT_32BIT) 343164614Sariff ret |= 1 << 13; 344164614Sariff 345164614Sariff return ret; 346154684Sariff} 347154684Sariff 348164614Sariffstatic u_int32_t 349193640Sariffsnd_fmtbestfunc(u_int32_t fmt, u_int32_t *fmts, int cheq) 350154684Sariff{ 351164614Sariff u_int32_t best, score, score2, oldscore; 352164614Sariff int i; 353154684Sariff 354164614Sariff if (fmt == 0 || fmts == NULL || fmts[0] == 0) 355164614Sariff return 0; 356164614Sariff 357193640Sariff if (snd_fmtvalid(fmt, fmts)) 358164614Sariff return fmt; 359164614Sariff 360154684Sariff best = 0; 361193640Sariff score = snd_fmtscore(fmt); 362154684Sariff oldscore = 0; 363154684Sariff for (i = 0; fmts[i] != 0; i++) { 364193640Sariff score2 = snd_fmtscore(fmts[i]); 365193640Sariff if (cheq && !score_cheq(score, score2) && 366193640Sariff (score_chlt(score2, score) || 367193640Sariff (oldscore != 0 && score_chgt(score2, oldscore)))) 368193640Sariff continue; 369164614Sariff if (oldscore == 0 || 370164614Sariff (score_val(score2) == score_val(score)) || 371164614Sariff (score_val(score2) == score_val(oldscore)) || 372164614Sariff (score_val(score2) > score_val(oldscore) && 373164614Sariff score_val(score2) < score_val(score)) || 374164614Sariff (score_val(score2) < score_val(oldscore) && 375164614Sariff score_val(score2) > score_val(score)) || 376164614Sariff (score_val(oldscore) < score_val(score) && 377164614Sariff score_val(score2) > score_val(oldscore))) { 378164614Sariff if (score_val(oldscore) != score_val(score2) || 379164614Sariff score_cse(score) == score_cse(score2) || 380164614Sariff ((score_cse(oldscore) != score_cse(score) && 381164614Sariff !score_endianeq(score, oldscore) && 382164614Sariff (score_endianeq(score, score2) || 383164614Sariff (!score_signeq(score, oldscore) && 384164614Sariff score_signeq(score, score2)))))) { 385164614Sariff best = fmts[i]; 386164614Sariff oldscore = score2; 387164614Sariff } 388154684Sariff } 389154684Sariff } 390154684Sariff return best; 391154684Sariff} 392154684Sariff 393154684Sariffu_int32_t 394193640Sariffsnd_fmtbestbit(u_int32_t fmt, u_int32_t *fmts) 395164614Sariff{ 396193640Sariff return snd_fmtbestfunc(fmt, fmts, 0); 397164614Sariff} 398164614Sariff 399164614Sariffu_int32_t 400193640Sariffsnd_fmtbestchannel(u_int32_t fmt, u_int32_t *fmts) 401154684Sariff{ 402193640Sariff return snd_fmtbestfunc(fmt, fmts, 1); 403154684Sariff} 404154684Sariff 405154684Sariffu_int32_t 406193640Sariffsnd_fmtbest(u_int32_t fmt, u_int32_t *fmts) 407154684Sariff{ 408154684Sariff u_int32_t best1, best2; 409164614Sariff u_int32_t score, score1, score2; 410154684Sariff 411193640Sariff if (snd_fmtvalid(fmt, fmts)) 412164614Sariff return fmt; 413164614Sariff 414193640Sariff best1 = snd_fmtbestchannel(fmt, fmts); 415193640Sariff best2 = snd_fmtbestbit(fmt, fmts); 416154684Sariff 417164614Sariff if (best1 != 0 && best2 != 0 && best1 != best2) { 418193640Sariff /*if (fmt & AFMT_STEREO)*/ 419193640Sariff if (AFMT_CHANNEL(fmt) > 1) 420154684Sariff return best1; 421154684Sariff else { 422193640Sariff score = score_val(snd_fmtscore(fmt)); 423193640Sariff score1 = score_val(snd_fmtscore(best1)); 424193640Sariff score2 = score_val(snd_fmtscore(best2)); 425154969Sariff if (score1 == score2 || score1 == score) 426154969Sariff return best1; 427154969Sariff else if (score2 == score) 428154684Sariff return best2; 429154969Sariff else if (score1 > score2) 430154684Sariff return best1; 431154684Sariff return best2; 432154684Sariff } 433154684Sariff } else if (best2 == 0) 434154684Sariff return best1; 435155958Sjhb else 436154684Sariff return best2; 437154684Sariff} 438154684Sariff 439117307Scgvoid 440117307Scgfeeder_printchain(struct pcm_feeder *head) 441117307Scg{ 442117307Scg struct pcm_feeder *f; 443117307Scg 444117307Scg printf("feeder chain (head @%p)\n", head); 445117307Scg f = head; 446117307Scg while (f != NULL) { 447117307Scg printf("%s/%d @ %p\n", f->class->name, f->desc->idx, f); 448117307Scg f = f->source; 449117307Scg } 450117307Scg printf("[end]\n\n"); 451117307Scg} 452117307Scg 45366308Scg/*****************************************************************************/ 45466308Scg 45566308Scgstatic int 45674763Scgfeed_root(struct pcm_feeder *feeder, struct pcm_channel *ch, u_int8_t *buffer, u_int32_t count, void *source) 45766308Scg{ 45874763Scg struct snd_dbuf *src = source; 459164614Sariff int l, offset; 46066308Scg 46174763Scg KASSERT(count > 0, ("feed_root: count == 0")); 46266308Scg 463164614Sariff if (++ch->feedcount == 0) 464164614Sariff ch->feedcount = 2; 465164614Sariff 46674763Scg l = min(count, sndbuf_getready(src)); 46766308Scg 468110287Sorion /* When recording only return as much data as available */ 469164614Sariff if (ch->direction == PCMDIR_REC) { 470164614Sariff sndbuf_dispose(src, buffer, l); 471110287Sorion return l; 472164614Sariff } 473110287Sorion 47474763Scg 475164614Sariff offset = count - l; 47674763Scg 477164614Sariff if (offset > 0) { 478164614Sariff if (snd_verbose > 3) 479164614Sariff printf("%s: (%s) %spending %d bytes " 480164614Sariff "(count=%d l=%d feed=%d)\n", 481164614Sariff __func__, 482164614Sariff (ch->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware", 483164614Sariff (ch->feedcount == 1) ? "pre" : "ap", 484164614Sariff offset, count, l, ch->feedcount); 485164614Sariff 486164614Sariff if (ch->feedcount == 1) { 487167644Sariff memset(buffer, 488167644Sariff sndbuf_zerodata(sndbuf_getfmt(src)), 489167644Sariff offset); 490164614Sariff if (l > 0) 491164614Sariff sndbuf_dispose(src, buffer + offset, l); 492164614Sariff else 493164614Sariff ch->feedcount--; 494164614Sariff } else { 495164614Sariff if (l > 0) 496164614Sariff sndbuf_dispose(src, buffer, l); 497167644Sariff memset(buffer + l, 498167644Sariff sndbuf_zerodata(sndbuf_getfmt(src)), 499167644Sariff offset); 500167644Sariff if (!(ch->flags & CHN_F_CLOSING)) 501167644Sariff ch->xruns++; 502164614Sariff } 503164614Sariff } else if (l > 0) 504164614Sariff sndbuf_dispose(src, buffer, l); 505164614Sariff 50666308Scg return count; 50766308Scg} 50870134Scg 50970134Scgstatic kobj_method_t feeder_root_methods[] = { 51070134Scg KOBJMETHOD(feeder_feed, feed_root), 511193640Sariff KOBJMETHOD_END 51266308Scg}; 51370134Scgstatic struct feeder_class feeder_root_class = { 514118473Sdds .name = "feeder_root", 515118473Sdds .methods = feeder_root_methods, 516118473Sdds .size = sizeof(struct pcm_feeder), 517118473Sdds .desc = NULL, 518118473Sdds .data = NULL, 51970134Scg}; 52070134ScgSYSINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_register, &feeder_root_class); 52174363ScgSYSUNINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_unregisterall, NULL); 522