dbri_driver.c
Upload User: acmefrp
Upload Date: 2010-03-06
Package Size: 23768k
Code Size: 19k
Category:

OS Develop

Development Platform:

C/C++

  1. #ident "@(#) dbri_driver.c 1.1@(#) Copyright (c) 1991-92 Sun Microsystems, Inc."
  2. /*
  3.  * AUDIO/ISDN Chip driver - for ATT T5900FC (DBRI) and MMCODEC
  4.  */
  5. #include <sys/errno.h>
  6. #include <sys/param.h>
  7. #include <sys/user.h>
  8. #include <sys/types.h>
  9. #include <sys/systm.h>
  10. #include <sys/stream.h>
  11. #include <sys/stropts.h>
  12. #include <sys/time.h>
  13. #include <sys/kernel.h>
  14. #include <sys/file.h>
  15. #include <sys/debug.h>
  16. #include <machine/intreg.h>
  17. #include <machine/psl.h>
  18. #include <machine/mmu.h>
  19. #include <sundev/mbvar.h>
  20. #include <sun/audioio.h>
  21. #include <sbusdev/audiovar.h>
  22. #include <sbusdev/dbri_reg.h>
  23. #include <sbusdev/mmcodec_reg.h>
  24. #if !defined(STANDALONE)
  25. #include <sbusdev/aclone.h>
  26. #endif
  27. #include <sun/isdnio.h>
  28. #include <sun/dbriio.h>
  29. #include <sbusdev/dbrivar.h>
  30. #include <sys/callout.h> /* XXX - to debug timers not being cancelled */
  31. #include "audiodebug.h"
  32. /* Local declarations */
  33. dbri_dev_t *Dbri_devices = NULL; /* device ctrlr array */
  34. int Ndbri = 0; /* number of devices found up to now */
  35. int Curdbri = 0; /* current dbri attach unit */
  36. int dbri_identify();
  37. int dbri_attach();
  38. addr_t map_regs();
  39. void report_dev();
  40. /* Declare audio ops vector for DBRI support routines */
  41. struct aud_ops Dbri_audops = {
  42. dbri_close,
  43. dbri_ioctl,
  44. dbri_start,
  45. dbri_stop,
  46. dbri_setflag,
  47. dbri_setinfo,
  48. dbri_queuecmd,
  49. dbri_flushcmd,
  50. };
  51. /*
  52.  * Declare ops vector for auto configuration.
  53.  * It must be named dbri_ops, since the name is constructed from the
  54.  * device name when config writes ioconf.c.
  55.  */
  56. struct dev_ops dbri_ops = {
  57. 1, /* revision */
  58. dbri_identify, /* identify routine */
  59. dbri_attach, /* attach routine */
  60. };
  61. /*
  62.  * Streams declarations
  63.  */
  64. static struct module_info dbri_modinfo = {
  65. 0x6175, /* module ID number */
  66. "dbri", /* module name */
  67. 0, /* min packet size accepted */
  68. DBRI_MAXPACKET, /* max packet size accepted */
  69. DBRI_HIWATER, /* hi-water mark */
  70. DBRI_LOWATER, /* lo-water mark */
  71. };
  72. /*
  73.  * Queue information structure for read queue
  74.  */
  75. static struct qinit dbri_rinit = {
  76. (int(*)())audio_rput, /* put procedure */
  77. (int(*)())audio_rsrv, /* service procedure */
  78. dbri_open, /* called on startup */
  79. (int(*)())audio_close, /* called on finish */
  80. NULL, /* for 3bnet only */
  81. &dbri_modinfo, /* module information structure */
  82. NULL, /* module statistics structure */
  83. };
  84. /*
  85.  * Queue information structure for write queue
  86.  */
  87. static struct qinit dbri_winit = {
  88. (int(*)())audio_wput, /* put procedure */
  89. (int(*)())audio_wsrv, /* service procedure */
  90. NULL, /* called on startup */
  91. NULL, /* called on finish */
  92. NULL, /* for 3bnet only */
  93. &dbri_modinfo, /* module information structure */
  94. NULL, /* module statistics structure */
  95. };
  96. char *dbri_modules[] = {
  97. 0,
  98. };
  99. struct streamtab dbri_info = {
  100. &dbri_rinit, /* qinit for read side */
  101. &dbri_winit, /* qinit for write side */
  102. NULL, /* mux qinit for read */
  103. NULL, /* mux qinit for write */
  104. dbri_modules, /* list of modules to be pushed */
  105. };
  106. /*
  107.  * Called by match_driver() and add_drv_layer() in autoconf.c.  Returns
  108.  * TRUE if the given string refers to this driver, else FALSE.
  109.  */
  110. static int
  111. dbri_identify(name)
  112. char *name;
  113. {
  114. if (strncmp(name, "SUNW,DBRI", 9) != 0)
  115. return (FALSE);
  116. switch (name[9]) {
  117. case 'a':
  118. case 'b':
  119. case 'c':
  120. (void) printf("DBRI: Driver does not support DBRI version %cn",
  121.     name[9]);
  122. return (FALSE);
  123. case 'd':
  124. (void) printf("DBRI: driver will work but upgrade your hardwaren");
  125. break; /* okay, found one */
  126. case 'e':
  127. case 'f':
  128. break;
  129. default:
  130. (void) printf("DBRI: Warning Unknown DBRI version '%c'.n",
  131. name[9]);
  132. break;
  133. }
  134. Ndbri++;
  135. return (TRUE);
  136. } /* dbri_identify */
  137. /*ARGSUSED*/
  138. void
  139. dbri_dont_cache(start, size)
  140. caddr_t start;
  141. int size;
  142. {
  143. #ifdef sun4m
  144. #ifdef SUN4M_35
  145. /* XXX - hack attack - Sunergy 4.1.3 support - never used */
  146. /* Round up size to full pages */
  147. size = mmu_ptob(mmu_btopr(size));
  148. /* Round start down to nearest page start */
  149. start = (caddr_t)((int)start & PAGEMASK);
  150. {
  151. caddr_t end;
  152. for (end = start+size; start <= end; start += MMU_PAGESIZE) {
  153. (void) hat_dontcache((addr_t)start);
  154. }
  155. }
  156. #endif SUN4M_35
  157. #else sun4m
  158. /* Round up size to full pages */
  159. size = mmu_ptob(mmu_btopr(size));
  160. /* Round start down to nearest page start */
  161. start = (caddr_t)((int)start & PAGEMASK);
  162. {
  163. caddr_t end;
  164. for (end = start+size; start <= end; start += MMU_PAGESIZE) {
  165. (void) vac_dontcache((addr_t)start);
  166. }
  167. }
  168. #endif /* sun4m */
  169. return;
  170. }
  171. char *
  172. dbri_mode_name(mode)
  173. dbri_mode_t mode;
  174. {
  175. int i;
  176. static struct {
  177. char *name;
  178. dbri_mode_t value;
  179. } mode_names[] = {
  180. {"DBRI_MODE_UNKNOWN", DBRI_MODE_UNKNOWN},
  181. {"DBRI_MODE_XPRNT", DBRI_MODE_XPRNT},
  182. {"DBRI_MODE_HDLC", DBRI_MODE_HDLC},
  183. {"DBRI_MODE_HDLC_D", DBRI_MODE_HDLC_D},
  184. {"DBRI_MODE_SER", DBRI_MODE_SER},
  185. {"DBRI_MODE_FIXED", DBRI_MODE_FIXED},
  186. {0, (dbri_mode_t)0}
  187. };
  188. static char buf[64];
  189. for (i = 0; mode_names[i].name != NULL; ++i) {
  190. if (mode_names[i].value == mode)
  191. return (mode_names[i].name);
  192. }
  193. (void) sprintf(buf, "unknown mode(0x%x)", (unsigned int)mode);
  194. return (buf);
  195. }
  196. char *
  197. dbri_channel_name(channel)
  198. int channel;
  199. {
  200. int i;
  201. for (i = 0; i < (int)DBRI_LAST_CHNL; ++i) {
  202. if (Chan_tab[i].chan == (dbri_chnl_t)channel)
  203. return (Chan_tab[i].name);
  204. }
  205. if ((dbri_chnl_t)i == DBRI_NO_CHNL)
  206. return ("DBRI_NO_CHNL");
  207. if ((dbri_chnl_t)i == DBRI_HOST_CHNL)
  208. return ("DBRI_HOST_CHNL");
  209. return ("unknown channel");
  210. }
  211. static int
  212. dbri_setup_mem_map(driver, size)
  213. dbri_dev_t *driver;
  214. int size;
  215. {
  216. caddr_t tvaddr;
  217. int i, nb;
  218. dprintf("dbri_setup_mem_map: allocating %d bytesn", size);
  219. size += DBRI_MD_ALIGN;
  220. driver->mem_base = new_kmem_zalloc((u_int) size, KMEM_SLEEP);
  221. if (driver->mem_base == NULL) {
  222. (void) printf("dbri_setup_mem_map: out of memoryn");
  223. return (0);
  224. }
  225. dprintf("dbri_setup_mem_map: mem base is 0x%xn",
  226.     (unsigned int)driver->mem_base);
  227. driver->mem_size = size;
  228. dbri_dont_cache(driver->mem_base, driver->mem_size);
  229. #ifdef sun4m
  230. #ifndef lint /* XXX lint barfs on arg 1 */
  231. driver->sb_addr = (caddr_t)mb_nbmapalloc(dvmamap,
  232. driver->mem_base, driver->mem_size,
  233. MDR_BIGSBUS|MB_CANTWAIT, (func_t)0, (caddr_t)0);
  234. #endif /* lint */
  235. if (driver->sb_addr == (caddr_t)0) {
  236. (void) printf("dbri_setup_mem_map: out of dvma memoryn");
  237. kmem_free(driver->mem_base, (u_int) driver->mem_size);
  238. return (0);
  239. }
  240. dprintf("dbri_setup_mem_map: dvma base is 0x%xn", driver->sb_addr);
  241. driver->addr_offset = (int)(driver->sb_addr - driver->mem_base);
  242. #else /* sun4m */
  243. driver->addr_offset = 0;
  244. #endif /* sun4m */
  245. dprintf("dbri_setup_mem_map: addr_offset is 0x%xn",
  246. (unsigned int)driver->addr_offset);
  247. /*
  248.  * Map is as follows:
  249.  * First is the command queue, then the interrupt queues, then the
  250.  * command descriptors for each minor device
  251.  */
  252. tvaddr = driver->mem_base;
  253. driver->cmdqp = (dbri_chip_cmdq_t *)tvaddr;
  254. tvaddr += sizeof (dbri_chip_cmdq_t);
  255. driver->intq.intq_bp = (dbri_intq_t *)tvaddr;
  256. tvaddr += DBRI_NUM_INTQS * sizeof (dbri_intq_t);
  257. ASSERT ((sizeof(dbri_cmd_t) % DBRI_MD_ALIGN) == 0);
  258. dprintf("old tvaddr = 0x%x    ",tvaddr);
  259. tvaddr = (caddr_t)roundup((u_int)tvaddr, DBRI_MD_ALIGN);
  260. dprintf("new tvaddr = 0x%x  n",tvaddr);
  261. dprintf("dbri_setup_mem_map: starting cmd's at 0x%xn",
  262. (unsigned int)tvaddr);
  263. for (i = 0; i < Nstreams; ++i) {
  264. aud_stream_t *asp;
  265. struct aud_cmdlist *list;
  266. asp = &driver->ioc[i].as;
  267. nb = Chan_tab[i].numbufs;
  268. if (nb > 0) {
  269. dbri_cmd_t *pool;
  270. int j;
  271. j = nb * sizeof (dbri_cmd_t);
  272. pool = (dbri_cmd_t *)tvaddr;
  273. tvaddr += j;
  274. bzero((caddr_t)pool, (unsigned)j);
  275. list = &asp->cmdlist;
  276. list->memory = (caddr_t)pool;
  277. list->size = j;
  278. for (j = 0; j < nb; ++j, ++pool) {
  279. pool->cmd.next = list->free;
  280. list->free = &pool->cmd;
  281. }
  282. } else {
  283. struct aud_cmdlist *bchan_list;
  284. aud_stream_t *bchan_asp;
  285. int redundant_channel = TRUE;
  286. /*
  287.  * kludge for 56kbps and transparent channels
  288.  * so that they point back to the already allocated
  289.  * cmdlists of the base B channels.
  290.  */
  291. switch (i) {
  292. case DBRI_TE_B1_56_OUT:
  293. case DBRI_TE_B1_TR_OUT:
  294. bchan_asp =
  295. &driver->ioc[(int)DBRI_TE_B1_OUT].as;
  296. break;
  297. case DBRI_TE_B2_56_OUT:
  298. case DBRI_TE_B2_TR_OUT:
  299. bchan_asp =
  300. &driver->ioc[(int)DBRI_TE_B2_OUT].as;
  301. break;
  302. case DBRI_TE_B1_56_IN:
  303. case DBRI_TE_B1_TR_IN:
  304. bchan_asp = &driver->ioc[(int)DBRI_TE_B1_IN].as;
  305. break;
  306. case DBRI_TE_B2_56_IN:
  307. case DBRI_TE_B2_TR_IN:
  308. bchan_asp = &driver->ioc[(int)DBRI_TE_B2_IN].as;
  309. break;
  310. case DBRI_NT_B1_56_OUT:
  311. case DBRI_NT_B1_TR_OUT:
  312. bchan_asp =
  313. &driver->ioc[(int)DBRI_NT_B1_OUT].as;
  314. break;
  315. case DBRI_NT_B2_56_OUT:
  316. case DBRI_NT_B2_TR_OUT:
  317. bchan_asp =
  318. &driver->ioc[(int)DBRI_NT_B2_OUT].as;
  319. break;
  320. case DBRI_NT_B1_56_IN:
  321. case DBRI_NT_B1_TR_IN:
  322. bchan_asp = &driver->ioc[(int)DBRI_NT_B1_IN].as;
  323. break;
  324. case DBRI_NT_B2_56_IN:
  325. case DBRI_NT_B2_TR_IN:
  326. bchan_asp = &driver->ioc[(int)DBRI_NT_B2_IN].as;
  327. break;
  328. default:
  329. /* Do nothing for all other channels */
  330. redundant_channel = FALSE;
  331. break;
  332. }
  333. /*
  334.  * If this is a transparent or 56kbps channel then
  335.  * point back to the command lists of the base
  336.  * B channels. Otherwise just zero out the cmdlist
  337.  * pointers.
  338.  */
  339. list = &asp->cmdlist;
  340. if (redundant_channel) {
  341. bchan_list = &bchan_asp->cmdlist;
  342. list->memory = bchan_list->memory;
  343. list->size = bchan_list->size;
  344. list->free = bchan_list->free;
  345. continue;
  346. } else {
  347. list->memory = NULL;
  348. list->size = 0;
  349. }
  350. }
  351. } /* for */
  352. dprintf("dbri_setup_mem_map: ending tvaddr is 0x%xn",
  353. (unsigned int)tvaddr);
  354. return (1);
  355. } /* dbri_setup_mem_map */
  356. /*
  357.  * Attach to the device.
  358.  */
  359. static int
  360. dbri_attach(dev)
  361. struct dev_info *dev;
  362. {
  363. int nb, total_nb;
  364. dbri_dev_t *driver;
  365. int i, tbytes;
  366. extern struct aud_ops Dbri_audops;
  367. extern dbri_chan_tab_t Chan_tab[];
  368. extern void mmcodec_startup_audio();
  369. ATRACEINIT();
  370. ATRACEPRINT("dbri0: debugging version of audio drivern");
  371. /*
  372.  * Each unit has a 'aud_state_t' that contains generic audio
  373.  * device state information.  Also, each unit has a
  374.  * 'dbri_dev_t' that contains device-specific data.
  375.  */
  376. ASSERT(dev != NULL);
  377. ASSERT(Ndbri > 0);
  378. /*
  379.  * Sanity check the configuration tables.
  380.  */
  381. for (i = 0; i < (int)DBRI_LAST_CHNL; ++i) {
  382. if (Chan_tab[i].chan != (dbri_chnl_t)i) {
  383. printf("dbri: %s: Chan_tab[%d].chan = %dn",
  384. ((Chan_tab[i].chan)
  385. ? "Invalid entry"
  386. : "FYI"),
  387. i, Chan_tab[i].chan);
  388. if (Chan_tab[i].chan)
  389. return (-1);
  390. }
  391. }
  392. for (i = 0; i < (int)ISDN_LAST_PORT; ++i) {
  393. if (Port_tab[i].port != (isdn_port_t)i) {
  394. if ((isdn_port_t)i == ISDN_PRI_MGT)
  395. continue;
  396. printf("dbri: %s: Port_tab[%d].port = %dn",
  397. ((Port_tab[i].port == ISDN_PORT_NONE)
  398. ? "Invalid entry"
  399. : "FYI"),
  400. i, Port_tab[i].port);
  401. if (Port_tab[i].port)
  402. return (-1);
  403. }
  404. }
  405. #ifdef sun4c
  406. if (slaveslot(dev->devi_reg->reg_addr) >= 0) {
  407. printf("%s in slave slot will not work.n",
  408. dev->devi_name);
  409. return (-1);
  410. }
  411. #endif sun4c
  412. dev->devi_unit = Curdbri;
  413. dprintf("dbri_attach: attaching device %dn", Curdbri);
  414. if (Dbri_devices == NULL) {
  415. Dbri_devices = ((dbri_dev_t *)
  416. new_kmem_zalloc((u_int)
  417. (Ndbri * sizeof (dbri_dev_t)),
  418. KMEM_SLEEP));
  419. }
  420. /*
  421.  * Identify the audio device and assign a unit number.
  422.  * Get the address of this unit's audio device state structure.
  423.  */
  424. driver = &Dbri_devices[Curdbri];
  425. ASSERT(driver != NULL);
  426. driver->hwi_state.devdata = (void *)driver;
  427. driver->hwi_state.monitor_gain = 0;
  428. driver->hwi_state.output_muted = FALSE;
  429. driver->dbri_dev = dev;
  430. driver->dbri_version = dev->devi_name[9]; /* XXX DIC */
  431. #if !defined(STANDALONE)
  432. {
  433. int status;
  434. status = aclone_register((caddr_t)&dbri_info,
  435. 1 + Curdbri, /* Base for dbri is 1 */
  436. (int)DBRI_MINOR_AUDIO_RW + Nstreams,
  437. (int)DBRI_MINOR_AUDIO_RO + Nstreams,
  438. (int)DBRI_MINOR_AUDIOCTL + Nstreams);
  439. if (status < 0)
  440. printf("dbri: Could not register with aclone!n");
  441. }
  442. #endif /* STANDALONE */
  443. total_nb = 0;
  444. /* Initialize the play info struct */
  445. for (i = 0; i < Nstreams; ++i) {
  446. aud_stream_t *asp;
  447. asp = &driver->ioc[i].as;
  448. ASSERT(asp != NULL);
  449. asp->v = &driver->hwi_state;
  450. asp->info.minordev = (int)Chan_tab[i].minordev;
  451. asp->record_as = &driver->ioc[(int)Chan_tab[i].in_as].as;
  452. asp->play_as = &driver->ioc[(int)Chan_tab[i].out_as].as;
  453. asp->control_as = &driver->ioc[(int)Chan_tab[i].control_as].as;
  454. asp->info.sample_rate = Chan_tab[i].samplerate;
  455. asp->info.channels = Chan_tab[i].channels;
  456. asp->info.precision = Chan_tab[i].len; /* precision */
  457. asp->info.encoding = AUDIO_ENCODING_ULAW;   /* XXX work this */
  458. asp->info.gain = AUDIO_MAX_GAIN;
  459. asp->info.balance = AUDIO_MID_BALANCE;
  460. asp->type = Chan_tab[i].audtype;
  461. AsToDs(asp)->pipe = DBRI_BAD_PIPE;
  462. AsToDs(asp)->recv_eol = FALSE;
  463. AsToDs(asp)->i_info.type = Chan_tab[i].isdntype;
  464. switch (i) { /* adjust special channels */
  465. case DBRI_AUDIO_OUT:
  466. asp->info.port = AUDIO_SPEAKER;
  467. /* XXX - avail_ports needs to be adjusted for Sunergy*/
  468. asp->info.avail_ports =
  469. AUDIO_SPEAKER|AUDIO_HEADPHONE|AUDIO_LINE_OUT;
  470. asp->info.gain = DBRI_DEFAULT_GAIN;
  471. break;
  472. case DBRI_AUDIO_IN:
  473. asp->info.port = AUDIO_MICROPHONE;
  474. /* XXX - avail_ports needs to be adjusted for Sunergy*/
  475. asp->info.avail_ports = AUDIO_MICROPHONE|AUDIO_LINE_IN;
  476. asp->info.gain = DBRI_DEFAULT_GAIN;
  477. break;
  478. case DBRI_AUDIOCTL:
  479. break;
  480. case DBRI_TE_D_IN:
  481. case DBRI_TE_D_OUT:
  482. case DBRI_NT_D_IN:
  483. case DBRI_NT_D_OUT:
  484. asp->info.encoding = AUDIO_ENCODING_NONE;
  485. break;
  486. default:
  487. /*
  488.  * Nothing here currently.
  489.  * Would like to have additional channels added
  490.  * in dbri_conf.c to be sufficiently defined.
  491.  */
  492. break;
  493. } /* switch */
  494. /*
  495.  * Initialize virtual chained DMA command block free
  496.  * lists.  Record channels receive a different number of
  497.  * buffers than play chanels.
  498.  */
  499. asp->input_size = Chan_tab[i].input_size;
  500. AsToDs(asp)->i_var.t101 = Default_T101_timer;
  501. AsToDs(asp)->i_var.t102 = Default_T102_timer;
  502. AsToDs(asp)->i_var.t103 = Default_T103_timer;
  503. AsToDs(asp)->i_var.t104 = Default_T104_timer;
  504. AsToDs(asp)->i_var.asmb = Default_asmb;
  505. AsToDs(asp)->i_var.power = Default_power;
  506. nb = Chan_tab[i].numbufs;
  507. total_nb += nb;
  508. } /* for */
  509. tbytes = sizeof (dbri_chip_cmdq_t);
  510. tbytes += DBRI_NUM_INTQS * sizeof (dbri_intq_t);
  511. tbytes += total_nb * sizeof (dbri_cmd_t);
  512. (void) dbri_setup_mem_map(driver, tbytes);
  513. dprintf("dbri_attach: intq = 0x%x   cmdq = 0x%xn",
  514.     (unsigned int)driver->intq.intq_bp,
  515.     (unsigned int)driver->cmdqp);
  516. dprintf("dbri_attach: serialp = 0x%xn",
  517.     (unsigned int)&driver->ser_sts);
  518. /*
  519.  * Init the ops vector and back-pointers to the audio struct
  520.  */
  521. driver->hwi_state.ops = &Dbri_audops;
  522. /*
  523.  * Map in the registers for this device.
  524.  */
  525. driver->chip = (dbri_reg_t *)map_regs(dev->devi_reg->reg_addr,
  526.     dev->devi_reg->reg_size, dev->devi_reg->reg_bustype);
  527. #if 1 /* XXX */
  528. {
  529. int oldlevel = dev->devi_intr->int_pri;
  530. switch (dev->devi_name[9]) {
  531. case 'a':
  532. panic("dbri: Found version 'a' where it couldn't be.");
  533. break;
  534. case 'c':
  535. #ifdef sun4m
  536. dev->devi_intr->int_pri = 57; /* XXX - C2 Specific */
  537. #endif
  538. break;
  539. default:
  540. break;
  541. }
  542. if (oldlevel != dev->devi_intr->int_pri) {
  543. printf("dbri: Changed int_pri from %d to %d!!!n",
  544. oldlevel, dev->devi_intr->int_pri);
  545. }
  546. }
  547. #endif /* XXX3 */
  548. /*
  549.  * Add the interrupt for this device.
  550.  */
  551. driver->intrlevel = ipltospl(dev->devi_intr->int_pri);
  552. if (Curdbri == 0) {
  553. dprintf("dbri_attach: before addintr dev->pri=0x%x ilev=0x%xn",
  554.     (unsigned int)dev->devi_intr->int_pri,
  555.     (unsigned int)driver->intrlevel);
  556. addintr(dev->devi_intr->int_pri, dbri_intr, dev->devi_name,
  557.     dev->devi_unit);
  558. adddma(dev->devi_intr->int_pri);
  559. }
  560. report_dev(dev);
  561. dbri_initchip(driver); /* Initialize the chip */
  562. /* Allow users to use this unit */
  563. driver->openinhibit = FALSE;
  564. /* Start up audio functionality */
  565. mmcodec_startup_audio(driver);
  566. Curdbri++;  /* Attach succeeded, increment unit number counter. */
  567. return (0);
  568. } /* dbri_attach */
  569. #if defined(DBRI_LOADABLE)
  570. #include <sys/conf.h>
  571. #include <sun/autoconf.h>
  572. #include <sun/vddrv.h>
  573. struct cdevsw dbri_cdevsw = {
  574. /* open, close, read, write, */
  575. 0, 0, 0, 0,
  576. /* ioctl, reset, select, mmap, */
  577. 0, 0, 0, 0,
  578. /* str, segmap */
  579. &dbri_info, 0,
  580. };
  581. extern char dbri_version[];
  582. /*
  583.  * struct vdldrv is different in sun4m and sun4c, -Dsun4m or -Dsun4c is
  584.  * required for proper compilation. The new sun4m fields are at the end of
  585.  * the structure and are therefore initialized to zeros here.
  586.  */
  587. struct vdldrv Dbri_driver = {
  588. VDMAGIC_DRV, /* Drv_magic */
  589. dbri_version, /* Drv_name */
  590. &dbri_ops, /* Drv_dev_ops */
  591. NULL, /* Drv_bdevsw */
  592. &dbri_cdevsw, /* Drv_cdevsw */
  593. 0, /* Drv_blockmajor, 0 means let system choose */
  594. 0, /* Drv_charmajor, 0 means let system choose */
  595. };
  596. /*
  597.  * dbri_init - Entry point routine, modload/unload support.
  598.  */
  599. int
  600. dbri_init(function_code, vdp, vdi, vds)
  601. unsigned  function_code;
  602. struct vddrv *vdp;
  603. addr_t vdi;
  604. struct vdstat *vds;
  605. {
  606. int status;
  607. int dbri_unattach();
  608. #ifdef lint
  609. (void) dbri_init(0, vdp, vdi, vds);
  610. #endif
  611. switch (function_code) {
  612. case VDLOAD:
  613. vdp->vdd_vdtab = (struct vdlinkage*)&Dbri_driver;
  614. dprintf("dbri_init: loading drivern");
  615. Ndbri = 0;
  616. Curdbri = 0;
  617. Dbri_devices = NULL;
  618. return (0);
  619. case VDUNLOAD:
  620. if (Dbri_devices == NULL)
  621. return (0);
  622. #if !defined(STANDALONE)
  623. /*
  624.  * Removing audioclone mappings
  625.  */
  626. aclone_unregister((caddr_t)&dbri_info);
  627. #endif /* STANDALONE */
  628. status = dbri_unattach(vdp);
  629. return (status);
  630. case VDSTAT:
  631. return (0);
  632. }
  633. return (EINVAL);
  634. } /* dbri_init */
  635. /*ARGSUSED*/
  636. static int
  637. dbri_unattach(vdp)
  638. struct vddrv *vdp;
  639. {
  640. dbri_dev_t *driver;
  641. int busy = 0;
  642. int i, dev;
  643. int s;
  644. /*
  645.  * Cycle through devices and if any minor device is open then the
  646.  * driver cannot be unloaded.
  647.  */
  648. for (dev = 0; dev < Ndbri; ++dev) {
  649. driver = &Dbri_devices[dev];
  650. s = splr(driver->intrlevel);
  651. for (i = 0; i < Nstreams; ++i) {
  652. aud_stream_t *asp;
  653. asp = &driver->ioc[i].as;
  654. if (asp->info.open != 0)
  655. ++busy;
  656. }
  657. if (busy) {
  658. (void) splx(s);
  659. return (EBUSY);
  660. }
  661. /* Set DBRI back to initial state */
  662. dbri_initchip(driver);
  663. remintr(driver->dbri_dev->devi_intr->int_pri, dbri_intr);
  664. (void) splx(s);
  665. } /* for */
  666. #if 1 /* XXX */
  667. {
  668. struct callout *p1,
  669. *p2;
  670. extern void mmcodec_watchdog();
  671. char *fn = 0;
  672. /* already spl'ed above clock? */
  673. for (p1 = &calltodo; (p2 = p1->c_next) != 0; p1 = p2) {
  674. if (p2->c_func == (int(*)())dbri_keep_alive) {
  675. fn = "dbri_keep_alive";
  676. } else if (p2->c_func == (int(*)())dbri_nt_timer) {
  677. fn = "dbri_nt_timer";
  678. } else if (p2->c_func == (int(*)())dbri_te_timer) {
  679. fn = "dbri_te_timer";
  680. } else if (p2->c_func == (int(*)())mmcodec_watchdog) {
  681. fn = "mmcodec_watchdog";
  682. } else {
  683. continue;
  684. }
  685. dprintf("dbri: callout queue = %s(0x%x) time=%d.n",
  686.     fn, (unsigned int)p2->c_arg, p2->c_time);
  687. untimeout(p2->c_func, p2->c_arg); /* XXX */
  688. }
  689. }
  690. #endif
  691. /* cycle through devices releasing memory */
  692. for (dev = 0; dev < Ndbri; ++dev) {
  693. driver = &Dbri_devices[dev];
  694. /*
  695.  * Deallocate per minor device resources.
  696.  */
  697. dprintf("dbri_init: deallocating memoryn");
  698. #ifdef sun4m
  699. mb_mapfree(dvmamap, &driver->sb_addr);
  700. #endif /* sun4m */
  701. kmem_free(driver->mem_base, (u_int) driver->mem_size);
  702. }
  703. /* Now release main driver structure */
  704. kmem_free((caddr_t)Dbri_devices, (u_int) (Ndbri * sizeof (dbri_dev_t)));
  705. Ndbri = 0;
  706. Dbri_devices = NULL;
  707. return (0);
  708. }
  709. #endif /* DBRI_LOADABLE */