COMPLETE.T
上传用户:datang2001
上传日期:2007-02-01
资源大小:53269k
文件大小:2535k
源码类别:

操作系统开发

开发平台:

C/C++

  1. 25109 /*==========================================================================*
  2. 25110  *                              lock_ready                                  *
  3. 25111  *==========================================================================*/
  4. 25112 PUBLIC void lock_ready(rp)
  5. 25113 struct proc *rp;                /* this process is now runnable */
  6. 25114 {
  7. .Ep 344 src/kernel/proc.c
  8. 25115 /* Safe gateway to ready() for tasks. */
  9. 25116
  10. 25117   switching = TRUE;
  11. 25118   ready(rp);
  12. 25119   switching = FALSE;
  13. 25120 }
  14. 25122 /*==========================================================================*
  15. 25123  *                              lock_unready                                *
  16. 25124  *==========================================================================*/
  17. 25125 PUBLIC void lock_unready(rp)
  18. 25126 struct proc *rp;                /* this process is no longer runnable */
  19. 25127 {
  20. 25128 /* Safe gateway to unready() for tasks. */
  21. 25129
  22. 25130   switching = TRUE;
  23. 25131   unready(rp);
  24. 25132   switching = FALSE;
  25. 25133 }
  26. 25135 /*==========================================================================*
  27. 25136  *                              lock_sched                                  *
  28. 25137  *==========================================================================*/
  29. 25138 PUBLIC void lock_sched()
  30. 25139 {
  31. 25140 /* Safe gateway to sched() for tasks. */
  32. 25141
  33. 25142   switching = TRUE;
  34. 25143   sched();
  35. 25144   switching = FALSE;
  36. 25145 }
  37. 25147 /*==========================================================================*
  38. 25148  *                              unhold                                      *
  39. 25149  *==========================================================================*/
  40. 25150 PUBLIC void unhold()
  41. 25151 {
  42. 25152 /* Flush any held-up interrupts.  k_reenter must be 0.  held_head must not
  43. 25153  * be NIL_PROC.  Interrupts must be disabled.  They will be enabled but will
  44. 25154  * be disabled when this returns.
  45. 25155  */
  46. 25156
  47. 25157   register struct proc *rp;     /* current head of held queue */
  48. 25158
  49. 25159   if (switching) return;
  50. 25160   rp = held_head;
  51. 25161   do {
  52. 25162         if ( (held_head = rp->p_nextheld) == NIL_PROC) held_tail = NIL_PROC;
  53. 25163         rp->p_int_held = FALSE;
  54. 25164         unlock();               /* reduce latency; held queue may change! */
  55. 25165         interrupt(proc_number(rp));
  56. 25166         lock();                 /* protect the held queue again */
  57. 25167   }
  58. 25168   while ( (rp = held_head) != NIL_PROC);
  59. 25169 }
  60. 25171 #if (CHIP == M68000)
  61. 25172 /*==========================================================================*
  62. 25173  *                              cp_mess                                     *
  63. 25174  *==========================================================================*/
  64. .Op 345 src/kernel/proc.c
  65. 25175 PRIVATE void cp_mess(src, src_p, src_m, dst_p, dst_m)
  66. 25176 int src;                        /* sender process */
  67. 25177 register struct proc *src_p;    /* source proc entry */
  68. 25178 message *src_m;                 /* source message */
  69. 25179 register struct proc *dst_p;    /* destination proc entry */
  70. 25180 message *dst_m;                 /* destination buffer */
  71. 25181 {
  72. 25182 #if (SHADOWING == 0)
  73. 25183   /* convert virtual address to physical address */
  74. 25184   /* The caller has already checked if all addresses are within bounds */
  75. 25185   
  76. 25186   src_m = (message *)((char *)src_m + (((phys_bytes)src_p->p_map[D].mem_phys
  77. 25187                                 - src_p->p_map[D].mem_vir) << CLICK_SHIFT));
  78. 25188   dst_m = (message *)((char *)dst_m + (((phys_bytes)dst_p->p_map[D].mem_phys
  79. 25189                                 - dst_p->p_map[D].mem_vir) << CLICK_SHIFT));
  80. 25190 #else
  81. 25191   register phys_bytes correction;
  82. 25192
  83. 25193   if (correction = src_p->p_shadow) {
  84. 25194         correction = (correction - src_p->p_map[D].mem_phys) << CLICK_SHIFT;
  85. 25195         src_m = (message *)((char *)src_m + correction);
  86. 25196   }
  87. 25197   if (correction = dst_p->p_shadow) {
  88. 25198         correction = (correction - dst_p->p_map[D].mem_phys) << CLICK_SHIFT;
  89. 25199         dst_m = (message *)((char *)dst_m + correction);
  90. 25200   }
  91. 25201 #endif
  92. 25202 #ifdef NEEDFSTRUCOPY
  93. 25203   phys_copy(src_m,dst_m,(phys_bytes) sizeof(message));
  94. 25204 #else
  95. 25205   *dst_m = *src_m;
  96. 25206 #endif
  97. 25207   dst_m->m_source = src;
  98. 25208 }
  99. 25209 #endif
  100. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  101. src/kernel/protect.c    
  102. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  103. 25300 /* This file contains code for initialization of protected mode, to initialize
  104. 25301  * code and data segment descriptors, and to initialize global descriptors
  105. 25302  * for local descriptors in the process table.
  106. 25303  */
  107. 25304
  108. 25305 #include "kernel.h"
  109. 25306 #include "proc.h"
  110. 25307 #include "protect.h"
  111. 25308
  112. 25309 #if _WORD_SIZE == 4
  113. 25310 #define INT_GATE_TYPE   (INT_286_GATE | DESC_386_BIT)
  114. 25311 #define TSS_TYPE        (AVL_286_TSS  | DESC_386_BIT)
  115. 25312 #else
  116. 25313 #define INT_GATE_TYPE   INT_286_GATE
  117. 25314 #define TSS_TYPE        AVL_286_TSS
  118. .Ep 346 src/kernel/protect.c
  119. 25315 #endif
  120. 25316
  121. 25317 struct desctableptr_s {
  122. 25318   char limit[sizeof(u16_t)];
  123. 25319   char base[sizeof(u32_t)];             /* really u24_t + pad for 286 */
  124. 25320 };
  125. 25321
  126. 25322 struct gatedesc_s {
  127. 25323   u16_t offset_low;
  128. 25324   u16_t selector;
  129. 25325   u8_t pad;                     /* |000|XXXXX| ig & trpg, |XXXXXXXX| task g */
  130. 25326   u8_t p_dpl_type;              /* |P|DL|0|TYPE| */
  131. 25327 #if _WORD_SIZE == 4
  132. 25328   u16_t offset_high;
  133. 25329 #else
  134. 25330   u16_t reserved;
  135. 25331 #endif
  136. 25332 };
  137. 25333
  138. 25334 struct tss_s {
  139. 25335   reg_t backlink;
  140. 25336   reg_t sp0;                    /* stack pointer to use during interrupt */
  141. 25337   reg_t ss0;                    /*   "   segment  "  "    "        "     */
  142. 25338   reg_t sp1;
  143. 25339   reg_t ss1;
  144. 25340   reg_t sp2;
  145. 25341   reg_t ss2;
  146. 25342 #if _WORD_SIZE == 4
  147. 25343   reg_t cr3;
  148. 25344 #endif
  149. 25345   reg_t ip;
  150. 25346   reg_t flags;
  151. 25347   reg_t ax;
  152. 25348   reg_t cx;
  153. 25349   reg_t dx;
  154. 25350   reg_t bx;
  155. 25351   reg_t sp;
  156. 25352   reg_t bp;
  157. 25353   reg_t si;
  158. 25354   reg_t di;
  159. 25355   reg_t es;
  160. 25356   reg_t cs;
  161. 25357   reg_t ss;
  162. 25358   reg_t ds;
  163. 25359 #if _WORD_SIZE == 4
  164. 25360   reg_t fs;
  165. 25361   reg_t gs;
  166. 25362 #endif
  167. 25363   reg_t ldt;
  168. 25364 #if _WORD_SIZE == 4
  169. 25365   u16_t trap;
  170. 25366   u16_t iobase;
  171. 25367 /* u8_t iomap[0]; */
  172. 25368 #endif
  173. 25369 };
  174. 25370
  175. 25371 PUBLIC struct segdesc_s gdt[GDT_SIZE];
  176. 25372 PRIVATE struct gatedesc_s idt[IDT_SIZE];        /* zero-init so none present */
  177. 25373 PUBLIC struct tss_s tss;        /* zero init */
  178. 25374
  179. .Op 347 src/kernel/protect.c
  180. 25375 FORWARD _PROTOTYPE( void int_gate, (unsigned vec_nr, phys_bytes base,
  181. 25376                 unsigned dpl_type) );
  182. 25377 FORWARD _PROTOTYPE( void sdesc, (struct segdesc_s *segdp, phys_bytes base,
  183. 25378                 phys_bytes size) );
  184. 25379
  185. 25380 /*=========================================================================*
  186. 25381  *                              prot_init                                  *
  187. 25382  *=========================================================================*/
  188. 25383 PUBLIC void prot_init()
  189. 25384 {
  190. 25385 /* Set up tables for protected mode.
  191. 25386  * All GDT slots are allocated at compile time.
  192. 25387  */
  193. 25388
  194. 25389   phys_bytes code_bytes;
  195. 25390   phys_bytes data_bytes;
  196. 25391   struct gate_table_s *gtp;
  197. 25392   struct desctableptr_s *dtp;
  198. 25393   unsigned ldt_selector;
  199. 25394   register struct proc *rp;
  200. 25395
  201. 25396   static struct gate_table_s {
  202. 25397         _PROTOTYPE( void (*gate), (void) );
  203. 25398         unsigned char vec_nr;
  204. 25399         unsigned char privilege;
  205. 25400   }
  206. 25401   gate_table[] = {
  207. 25402         divide_error, DIVIDE_VECTOR, INTR_PRIVILEGE,
  208. 25403         single_step_exception, DEBUG_VECTOR, INTR_PRIVILEGE,
  209. 25404         nmi, NMI_VECTOR, INTR_PRIVILEGE,
  210. 25405         breakpoint_exception, BREAKPOINT_VECTOR, USER_PRIVILEGE,
  211. 25406         overflow, OVERFLOW_VECTOR, USER_PRIVILEGE,
  212. 25407         bounds_check, BOUNDS_VECTOR, INTR_PRIVILEGE,
  213. 25408         inval_opcode, INVAL_OP_VECTOR, INTR_PRIVILEGE,
  214. 25409         copr_not_available, COPROC_NOT_VECTOR, INTR_PRIVILEGE,
  215. 25410         double_fault, DOUBLE_FAULT_VECTOR, INTR_PRIVILEGE,
  216. 25411         copr_seg_overrun, COPROC_SEG_VECTOR, INTR_PRIVILEGE,
  217. 25412         inval_tss, INVAL_TSS_VECTOR, INTR_PRIVILEGE,
  218. 25413         segment_not_present, SEG_NOT_VECTOR, INTR_PRIVILEGE,
  219. 25414         stack_exception, STACK_FAULT_VECTOR, INTR_PRIVILEGE,
  220. 25415         general_protection, PROTECTION_VECTOR, INTR_PRIVILEGE,
  221. 25416 #if _WORD_SIZE == 4
  222. 25417         page_fault, PAGE_FAULT_VECTOR, INTR_PRIVILEGE,
  223. 25418         copr_error, COPROC_ERR_VECTOR, INTR_PRIVILEGE,
  224. 25419 #endif
  225. 25420         { hwint00, VECTOR( 0), INTR_PRIVILEGE },
  226. 25421         { hwint01, VECTOR( 1), INTR_PRIVILEGE },
  227. 25422         { hwint02, VECTOR( 2), INTR_PRIVILEGE },
  228. 25423         { hwint03, VECTOR( 3), INTR_PRIVILEGE },
  229. 25424         { hwint04, VECTOR( 4), INTR_PRIVILEGE },
  230. 25425         { hwint05, VECTOR( 5), INTR_PRIVILEGE },
  231. 25426         { hwint06, VECTOR( 6), INTR_PRIVILEGE },
  232. 25427         { hwint07, VECTOR( 7), INTR_PRIVILEGE },
  233. 25428         { hwint08, VECTOR( 8), INTR_PRIVILEGE },
  234. 25429         { hwint09, VECTOR( 9), INTR_PRIVILEGE },
  235. 25430         { hwint10, VECTOR(10), INTR_PRIVILEGE },
  236. 25431         { hwint11, VECTOR(11), INTR_PRIVILEGE },
  237. 25432         { hwint12, VECTOR(12), INTR_PRIVILEGE },
  238. 25433         { hwint13, VECTOR(13), INTR_PRIVILEGE },
  239. 25434         { hwint14, VECTOR(14), INTR_PRIVILEGE },
  240. .Ep 348 src/kernel/protect.c
  241. 25435         { hwint15, VECTOR(15), INTR_PRIVILEGE },
  242. 25436   };
  243. 25437
  244. 25438   /* This is called early and can't use tables set up by main(). */
  245. 25439   data_bytes = (phys_bytes) sizes[1] << CLICK_SHIFT;
  246. 25440   if (sizes[0] == 0)
  247. 25441         code_bytes = data_bytes;        /* common I&D */
  248. 25442   else
  249. 25443         code_bytes = (phys_bytes) sizes[0] << CLICK_SHIFT;
  250. 25444
  251. 25445   /* Build gdt and idt pointers in GDT where the BIOS expects them. */
  252. 25446   dtp= (struct desctableptr_s *) &gdt[GDT_INDEX];
  253. 25447   * (u16_t *) dtp->limit = (sizeof gdt) - 1;
  254. 25448   * (u32_t *) dtp->base = vir2phys(gdt);
  255. 25449
  256. 25450   dtp= (struct desctableptr_s *) &gdt[IDT_INDEX];
  257. 25451   * (u16_t *) dtp->limit = (sizeof idt) - 1;
  258. 25452   * (u32_t *) dtp->base = vir2phys(idt);
  259. 25453
  260. 25454   /* Build segment descriptors for tasks and interrupt handlers. */
  261. 25455   init_codeseg(&gdt[CS_INDEX], code_base, code_bytes, INTR_PRIVILEGE);
  262. 25456   init_dataseg(&gdt[DS_INDEX], data_base, data_bytes, INTR_PRIVILEGE);
  263. 25457   init_dataseg(&gdt[ES_INDEX], 0L, 0L, TASK_PRIVILEGE);
  264. 25458
  265. 25459   /* Build scratch descriptors for functions in klib88. */
  266. 25460   init_dataseg(&gdt[DS_286_INDEX], (phys_bytes) 0,
  267. 25461                (phys_bytes) MAX_286_SEG_SIZE, TASK_PRIVILEGE);
  268. 25462   init_dataseg(&gdt[ES_286_INDEX], (phys_bytes) 0,
  269. 25463                (phys_bytes) MAX_286_SEG_SIZE, TASK_PRIVILEGE);
  270. 25464
  271. 25465   /* Build local descriptors in GDT for LDT's in process table.
  272. 25466    * The LDT's are allocated at compile time in the process table, and
  273. 25467    * initialized whenever a process' map is initialized or changed.
  274. 25468    */
  275. 25469   for (rp = BEG_PROC_ADDR, ldt_selector = FIRST_LDT_INDEX * DESC_SIZE;
  276. 25470        rp < END_PROC_ADDR; ++rp, ldt_selector += DESC_SIZE) {
  277. 25471         init_dataseg(&gdt[ldt_selector / DESC_SIZE], vir2phys(rp->p_ldt),
  278. 25472                      (phys_bytes) sizeof rp->p_ldt, INTR_PRIVILEGE);
  279. 25473         gdt[ldt_selector / DESC_SIZE].access = PRESENT | LDT;
  280. 25474         rp->p_ldt_sel = ldt_selector;
  281. 25475   }
  282. 25476
  283. 25477   /* Build main TSS.
  284. 25478    * This is used only to record the stack pointer to be used after an
  285. 25479    * interrupt.
  286. 25480    * The pointer is set up so that an interrupt automatically saves the
  287. 25481    * current process's registers ip:cs:f:sp:ss in the correct slots in the
  288. 25482    * process table.
  289. 25483    */
  290. 25484   tss.ss0 = DS_SELECTOR;
  291. 25485   init_dataseg(&gdt[TSS_INDEX], vir2phys(&tss), (phys_bytes) sizeof tss,
  292. 25486                                                         INTR_PRIVILEGE);
  293. 25487   gdt[TSS_INDEX].access = PRESENT | (INTR_PRIVILEGE << DPL_SHIFT) | TSS_TYPE;
  294. 25488
  295. 25489   /* Build descriptors for interrupt gates in IDT. */
  296. 25490   for (gtp = &gate_table[0];
  297. 25491        gtp < &gate_table[sizeof gate_table / sizeof gate_table[0]]; ++gtp) {
  298. 25492         int_gate(gtp->vec_nr, (phys_bytes) (vir_bytes) gtp->gate,
  299. 25493                  PRESENT | INT_GATE_TYPE | (gtp->privilege << DPL_SHIFT));
  300. 25494   }
  301. .Op 349 src/kernel/protect.c
  302. 25495   int_gate(SYS_VECTOR, (phys_bytes) (vir_bytes) p_s_call,
  303. 25496            PRESENT | (USER_PRIVILEGE << DPL_SHIFT) | INT_GATE_TYPE);
  304. 25497   int_gate(LEVEL0_VECTOR, (phys_bytes) (vir_bytes) level0_call,
  305. 25498            PRESENT | (TASK_PRIVILEGE << DPL_SHIFT) | INT_GATE_TYPE);
  306. 25499
  307. 25500 #if _WORD_SIZE == 4
  308. 25501   /* Complete building of main TSS. */
  309. 25502   tss.iobase = sizeof tss;      /* empty i/o permissions map */
  310. 25503
  311. 25504   /* Complete building of interrupt gates. */
  312. 25505   int_gate(SYS386_VECTOR, (phys_bytes) (vir_bytes) s_call,
  313. 25506            PRESENT | (USER_PRIVILEGE << DPL_SHIFT) | INT_GATE_TYPE);
  314. 25507 #endif
  315. 25508 }
  316. 25510 /*=========================================================================*
  317. 25511  *                              init_codeseg                               *
  318. 25512  *=========================================================================*/
  319. 25513 PUBLIC void init_codeseg(segdp, base, size, privilege)
  320. 25514 register struct segdesc_s *segdp;
  321. 25515 phys_bytes base;
  322. 25516 phys_bytes size;
  323. 25517 int privilege;
  324. 25518 {
  325. 25519 /* Build descriptor for a code segment. */
  326. 25520
  327. 25521   sdesc(segdp, base, size);
  328. 25522   segdp->access = (privilege << DPL_SHIFT)
  329. 25523                 | (PRESENT | SEGMENT | EXECUTABLE | READABLE);
  330. 25524                 /* CONFORMING = 0, ACCESSED = 0 */
  331. 25525 }
  332. 25527 /*=========================================================================*
  333. 25528  *                              init_dataseg                               *
  334. 25529  *=========================================================================*/
  335. 25530 PUBLIC void init_dataseg(segdp, base, size, privilege)
  336. 25531 register struct segdesc_s *segdp;
  337. 25532 phys_bytes base;
  338. 25533 phys_bytes size;
  339. 25534 int privilege;
  340. 25535 {
  341. 25536 /* Build descriptor for a data segment. */
  342. 25537
  343. 25538   sdesc(segdp, base, size);
  344. 25539   segdp->access = (privilege << DPL_SHIFT) | (PRESENT | SEGMENT | WRITEABLE);
  345. 25540                 /* EXECUTABLE = 0, EXPAND_DOWN = 0, ACCESSED = 0 */
  346. 25541 }
  347. 25543 /*=========================================================================*
  348. 25544  *                              sdesc                                      *
  349. 25545  *=========================================================================*/
  350. 25546 PRIVATE void sdesc(segdp, base, size)
  351. 25547 register struct segdesc_s *segdp;
  352. 25548 phys_bytes base;
  353. 25549 phys_bytes size;
  354. 25550 {
  355. 25551 /* Fill in the size fields (base, limit and granularity) of a descriptor. */
  356. 25552
  357. 25553   segdp->base_low = base;
  358. 25554   segdp->base_middle = base >> BASE_MIDDLE_SHIFT;
  359. .Ep 350 src/kernel/protect.c
  360. 25555
  361. 25556 #if _WORD_SIZE == 4
  362. 25557   segdp->base_high = base >> BASE_HIGH_SHIFT;
  363. 25558   --size;                       /* convert to a limit, 0 size means 4G */
  364. 25559   if (size > BYTE_GRAN_MAX) {
  365. 25560         segdp->limit_low = size >> PAGE_GRAN_SHIFT;
  366. 25561         segdp->granularity = GRANULAR | (size >>
  367. 25562                                      (PAGE_GRAN_SHIFT + GRANULARITY_SHIFT));
  368. 25563   } else {
  369. 25564         segdp->limit_low = size;
  370. 25565         segdp->granularity = size >> GRANULARITY_SHIFT;
  371. 25566   }
  372. 25567   segdp->granularity |= DEFAULT;        /* means BIG for data seg */
  373. 25568 #else
  374. 25569   segdp->limit_low = size - 1;
  375. 25570 #endif
  376. 25571 }
  377. 25573 /*=========================================================================*
  378. 25574  *                              seg2phys                                   *
  379. 25575  *=========================================================================*/
  380. 25576 PUBLIC phys_bytes seg2phys(seg)
  381. 25577 U16_t seg;
  382. 25578 {
  383. 25579 /* Return the base address of a segment, with seg being either a 8086 segment
  384. 25580  * register, or a 286/386 segment selector.
  385. 25581  */
  386. 25582   phys_bytes base;
  387. 25583   struct segdesc_s *segdp;
  388. 25584
  389. 25585   if (!protected_mode) {
  390. 25586         base = hclick_to_physb(seg);
  391. 25587   } else {
  392. 25588         segdp = &gdt[seg >> 3];
  393. 25589         base = segdp->base_low | ((u32_t) segdp->base_middle << 16);
  394. 25590 #if _WORD_SIZE == 4
  395. 25591         base |= ((u32_t) segdp->base_high << 24);
  396. 25592 #endif
  397. 25593   }
  398. 25594   return base;
  399. 25595 }
  400. 25597 /*=========================================================================*
  401. 25598  *                              int_gate                                   *
  402. 25599  *=========================================================================*/
  403. 25600 PRIVATE void int_gate(vec_nr, base, dpl_type)
  404. 25601 unsigned vec_nr;
  405. 25602 phys_bytes base;
  406. 25603 unsigned dpl_type;
  407. 25604 {
  408. 25605 /* Build descriptor for an interrupt gate. */
  409. 25606
  410. 25607   register struct gatedesc_s *idp;
  411. 25608
  412. 25609   idp = &idt[vec_nr];
  413. 25610   idp->offset_low = base;
  414. 25611   idp->selector = CS_SELECTOR;
  415. 25612   idp->p_dpl_type = dpl_type;
  416. 25613 #if _WORD_SIZE == 4
  417. 25614   idp->offset_high = base >> OFFSET_HIGH_SHIFT;
  418. .Op 351 src/kernel/protect.c
  419. 25615 #endif
  420. 25616 }
  421. 25618 /*=========================================================================*
  422. 25619  *                              enable_iop                                 *
  423. 25620  *=========================================================================*/
  424. 25621 PUBLIC void enable_iop(pp)
  425. 25622 struct proc *pp;
  426. 25623 {
  427. 25624 /* Allow a user process to use I/O instructions.  Change the I/O Permission
  428. 25625  * Level bits in the psw. These specify least-privileged Current Permission
  429. 25626  * Level allowed to execute I/O instructions. Users and servers have CPL 3. 
  430. 25627  * You can't have less privilege than that. Kernel has CPL 0, tasks CPL 1.
  431. 25628  */
  432. 25629   pp->p_reg.psw |= 0x3000;
  433. 25630 }
  434. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  435. src/kernel/pty.c    
  436. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  437. 25700 /*      pty.c - pseudo terminal driver                  Author: Kees J. Bot
  438. 25701  *                                                              30 Dec 1995
  439. 25702  * PTYs can be seen as a bidirectional pipe with TTY
  440. 25703  * input and output processing.  For example a simple rlogin session:
  441. 25704  *
  442. 25705  *      keyboard -> rlogin -> in.rld -> /dev/ptypX -> /dev/ttypX -> shell
  443. 25706  *      shell -> /dev/ttypX -> /dev/ptypX -> in.rld -> rlogin -> screen
  444. 25707  *
  445. 25708  * This file takes care of copying data between the tty/pty device pairs and
  446. 25709  * the open/read/write/close calls on the pty devices.  The TTY task takes
  447. 25710  * care of the input and output processing (interrupt, backspace, raw I/O,
  448. 25711  * etc.) using the pty_read() and pty_write() functions as the "keyboard" and
  449. 25712  * "screen" functions of the ttypX devices.
  450. 25713  * Be careful when reading this code, the terms "reading" and "writing" are
  451. 25714  * used both for the tty and the pty end of the pseudo tty.  Writes to one
  452. 25715  * end are to be read at the other end and vice-versa.
  453. 25716  */
  454. 25717
  455. 25718 #include "kernel.h"
  456. 25719 #include <termios.h>
  457. 25720 #include <signal.h>
  458. 25721 #include <minix/com.h>
  459. 25722 #include <minix/callnr.h>
  460. 25723 #include "tty.h"
  461. 25724 #include "proc.h"
  462. 25725
  463. 25726 #if NR_PTYS > 0
  464. 25727
  465. 25728 /* PTY bookkeeping structure, one per pty/tty pair. */
  466. 25729 typedef struct pty {
  467. 25730   tty_t         *tty;           /* associated TTY structure */
  468. 25731   char          state;          /* flags: busy, closed, ... */
  469. 25732
  470. 25733   /* Read call on /dev/ptypX. */
  471. 25734   char          rdrepcode;      /* reply code, TASK_REPLY or REVIVE */
  472. .Ep 352 src/kernel/pty.c
  473. 25735   char          rdcaller;       /* process making the call (usually FS) */
  474. 25736   char          rdproc;         /* process that wants to read from the pty */
  475. 25737   vir_bytes     rdvir;          /* virtual address in readers address space */
  476. 25738   int           rdleft;         /* # bytes yet to be read */
  477. 25739   int           rdcum;          /* # bytes written so far */
  478. 25740
  479. 25741   /* Write call to /dev/ptypX. */
  480. 25742   char          wrrepcode;      /* reply code, TASK_REPLY or REVIVE */
  481. 25743   char          wrcaller;       /* process making the call (usually FS) */
  482. 25744   char          wrproc;         /* process that wants to write to the pty */
  483. 25745   vir_bytes     wrvir;          /* virtual address in writers address space */
  484. 25746   int           wrleft;         /* # bytes yet to be written */
  485. 25747   int           wrcum;          /* # bytes written so far */
  486. 25748
  487. 25749   /* Output buffer. */
  488. 25750   int           ocount;         /* # characters in the buffer */
  489. 25751   char          *ohead, *otail; /* head and tail of the circular buffer */
  490. 25752   char          obuf[128];      /* buffer for bytes going to the pty reader */
  491. 25753 } pty_t;
  492. 25754
  493. 25755 #define PTY_ACTIVE      0x01    /* pty is open/active */
  494. 25756 #define TTY_CLOSED      0x02    /* tty side has closed down */
  495. 25757 #define PTY_CLOSED      0x04    /* pty side has closed down */
  496. 25758
  497. 25759 PRIVATE pty_t pty_table[NR_PTYS];       /* PTY bookkeeping */
  498. 25760
  499. 25761
  500. 25762 FORWARD _PROTOTYPE( void pty_write, (tty_t *tp)                         );
  501. 25763 FORWARD _PROTOTYPE( void pty_echo, (tty_t *tp, int c)                   );
  502. 25764 FORWARD _PROTOTYPE( void pty_start, (pty_t *pp)                         );
  503. 25765 FORWARD _PROTOTYPE( void pty_finish, (pty_t *pp)                        );
  504. 25766 FORWARD _PROTOTYPE( void pty_read, (tty_t *tp)                          );
  505. 25767 FORWARD _PROTOTYPE( void pty_close, (tty_t *tp)                         );
  506. 25768 FORWARD _PROTOTYPE( void pty_icancel, (tty_t *tp)                       );
  507. 25769 FORWARD _PROTOTYPE( void pty_ocancel, (tty_t *tp)                       );
  508. 25770
  509. 25771
  510. 25772 /*==========================================================================*
  511. 25773  *                              do_pty                                      *
  512. 25774  *==========================================================================*/
  513. 25775 PUBLIC void do_pty(tp, m_ptr)
  514. 25776 tty_t *tp;
  515. 25777 message *m_ptr;
  516. 25778 {
  517. 25779 /* Perform an open/close/read/write call on a /dev/ptypX device. */
  518. 25780   pty_t *pp = tp->tty_priv;
  519. 25781   int r;
  520. 25782
  521. 25783   switch (m_ptr->m_type) {
  522. 25784     case DEV_READ:
  523. 25785         /* Check, store information on the reader, do I/O. */
  524. 25786         if (pp->state & TTY_CLOSED) {
  525. 25787                 r = 0;
  526. 25788                 break;
  527. 25789         }
  528. 25790         if (pp->rdleft != 0) {
  529. 25791                 r = EIO;
  530. 25792                 break;
  531. 25793         }
  532. 25794         if (m_ptr->COUNT <= 0) {
  533. .Op 353 src/kernel/pty.c
  534. 25795                 r = EINVAL;
  535. 25796                 break;
  536. 25797         }
  537. 25798         if (numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
  538. 25799                                                         m_ptr->COUNT) == 0) {
  539. 25800                 r = EFAULT;
  540. 25801                 break;
  541. 25802         }
  542. 25803         pp->rdrepcode = TASK_REPLY;
  543. 25804         pp->rdcaller = m_ptr->m_source;
  544. 25805         pp->rdproc = m_ptr->PROC_NR;
  545. 25806         pp->rdvir = (vir_bytes) m_ptr->ADDRESS;
  546. 25807         pp->rdleft = m_ptr->COUNT;
  547. 25808         pty_start(pp);
  548. 25809         handle_events(tp);
  549. 25810         if (pp->rdleft == 0) return;                    /* already done */
  550. 25811
  551. 25812         if (m_ptr->TTY_FLAGS & O_NONBLOCK) {
  552. 25813                 r = EAGAIN;                             /* don't suspend */
  553. 25814                 pp->rdleft = pp->rdcum = 0;
  554. 25815         } else {
  555. 25816                 r = SUSPEND;                            /* do suspend */
  556. 25817                 pp->rdrepcode = REVIVE;
  557. 25818         }
  558. 25819         break;
  559. 25820
  560. 25821     case DEV_WRITE:
  561. 25822         /* Check, store information on the writer, do I/O. */
  562. 25823         if (pp->state & TTY_CLOSED) {
  563. 25824                 r = EIO;
  564. 25825                 break;
  565. 25826         }
  566. 25827         if (pp->wrleft != 0) {
  567. 25828                 r = EIO;
  568. 25829                 break;
  569. 25830         }
  570. 25831         if (m_ptr->COUNT <= 0) {
  571. 25832                 r = EINVAL;
  572. 25833                 break;
  573. 25834         }
  574. 25835         if (numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
  575. 25836                                                         m_ptr->COUNT) == 0) {
  576. 25837                 r = EFAULT;
  577. 25838                 break;
  578. 25839         }
  579. 25840         pp->wrrepcode = TASK_REPLY;
  580. 25841         pp->wrcaller = m_ptr->m_source;
  581. 25842         pp->wrproc = m_ptr->PROC_NR;
  582. 25843         pp->wrvir = (vir_bytes) m_ptr->ADDRESS;
  583. 25844         pp->wrleft = m_ptr->COUNT;
  584. 25845         handle_events(tp);
  585. 25846         if (pp->wrleft == 0) return;                    /* already done */
  586. 25847
  587. 25848         if (m_ptr->TTY_FLAGS & O_NONBLOCK) {            /* don't suspend */
  588. 25849                 r = pp->wrcum > 0 ? pp->wrcum : EAGAIN;
  589. 25850                 pp->wrleft = pp->wrcum = 0;
  590. 25851         } else {
  591. 25852                 pp->wrrepcode = REVIVE;                 /* do suspend */
  592. 25853                 r = SUSPEND;
  593. 25854         }
  594. .Ep 354 src/kernel/pty.c
  595. 25855         break;
  596. 25856
  597. 25857     case DEV_IOCTL:
  598. 25858         /* No ioctl's allowed on the pty side. */
  599. 25859         r = ENOTTY;
  600. 25860         break;
  601. 25861
  602. 25862     case DEV_OPEN:
  603. 25863         r = pp->state != 0 ? EIO : OK;
  604. 25864         pp->state |= PTY_ACTIVE;
  605. 25865         break;
  606. 25866
  607. 25867     case DEV_CLOSE:
  608. 25868         r = OK;
  609. 25869         if (pp->state & TTY_CLOSED) {
  610. 25870                 pp->state = 0;
  611. 25871         } else {
  612. 25872                 pp->state |= PTY_CLOSED;
  613. 25873                 sigchar(tp, SIGHUP);
  614. 25874         }
  615. 25875         break;
  616. 25876
  617. 25877     case CANCEL:
  618. 25878         if (m_ptr->PROC_NR == pp->rdproc) {
  619. 25879                 /* Cancel a read from a PTY. */
  620. 25880                 pp->rdleft = pp->rdcum = 0;
  621. 25881         }
  622. 25882         if (m_ptr->PROC_NR == pp->wrproc) {
  623. 25883                 /* Cancel a write to a PTY. */
  624. 25884                 pp->wrleft = pp->wrcum = 0;
  625. 25885         }
  626. 25886         r = EINTR;
  627. 25887         break;
  628. 25888
  629. 25889     default:
  630. 25890         r = EINVAL;
  631. 25891   }
  632. 25892   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
  633. 25893 }
  634. 25896 /*==========================================================================*
  635. 25897  *                              pty_write                                   *
  636. 25898  *==========================================================================*/
  637. 25899 PRIVATE void pty_write(tp)
  638. 25900 tty_t *tp;
  639. 25901 {
  640. 25902 /* (*dev_write)() routine for PTYs.  Transfer bytes from the writer on
  641. 25903  * /dev/ttypX to the output buffer.
  642. 25904  */
  643. 25905   pty_t *pp = tp->tty_priv;
  644. 25906   int count, ocount;
  645. 25907   phys_bytes user_phys;
  646. 25908
  647. 25909   /* PTY closed down? */
  648. 25910   if (pp->state & PTY_CLOSED) {
  649. 25911         if (tp->tty_outleft > 0) {
  650. 25912                 tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
  651. 25913                                                         tp->tty_outproc, EIO);
  652. 25914                 tp->tty_outleft = tp->tty_outcum = 0;
  653. .Op 355 src/kernel/pty.c
  654. 25915         }
  655. 25916         return;
  656. 25917   }
  657. 25918
  658. 25919   /* While there is something to do. */
  659. 25920   for (;;) {
  660. 25921         ocount = buflen(pp->obuf) - pp->ocount;
  661. 25922         count = bufend(pp->obuf) - pp->ohead;
  662. 25923         if (count > ocount) count = ocount;
  663. 25924         if (count > tp->tty_outleft) count = tp->tty_outleft;
  664. 25925         if (count == 0 || tp->tty_inhibited) break;
  665. 25926
  666. 25927         /* Copy from user space to the PTY output buffer. */
  667. 25928         user_phys = proc_vir2phys(proc_addr(tp->tty_outproc), tp->tty_out_vir);
  668. 25929         phys_copy(user_phys, vir2phys(pp->ohead), (phys_bytes) count);
  669. 25930
  670. 25931         /* Perform output processing on the output buffer. */
  671. 25932         out_process(tp, pp->obuf, pp->ohead, bufend(pp->obuf), &count, &ocount);
  672. 25933         if (count == 0) break;
  673. 25934
  674. 25935         /* Assume echoing messed up by output. */
  675. 25936         tp->tty_reprint = TRUE;
  676. 25937
  677. 25938         /* Bookkeeping. */
  678. 25939         pp->ocount += ocount;
  679. 25940         if ((pp->ohead += ocount) >= bufend(pp->obuf))
  680. 25941                 pp->ohead -= buflen(pp->obuf);
  681. 25942         pty_start(pp);
  682. 25943         tp->tty_out_vir += count;
  683. 25944         tp->tty_outcum += count;
  684. 25945         if ((tp->tty_outleft -= count) == 0) {
  685. 25946                 /* Output is finished, reply to the writer. */
  686. 25947                 tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
  687. 25948                                         tp->tty_outproc, tp->tty_outcum);
  688. 25949                 tp->tty_outcum = 0;
  689. 25950         }
  690. 25951   }
  691. 25952   pty_finish(pp);
  692. 25953 }
  693. 25956 /*==========================================================================*
  694. 25957  *                              pty_echo                                    *
  695. 25958  *==========================================================================*/
  696. 25959 PRIVATE void pty_echo(tp, c)
  697. 25960 tty_t *tp;
  698. 25961 int c;
  699. 25962 {
  700. 25963 /* Echo one character.  (Like pty_write, but only one character, optionally.) */
  701. 25964
  702. 25965   pty_t *pp = tp->tty_priv;
  703. 25966   int count, ocount;
  704. 25967
  705. 25968   ocount = buflen(pp->obuf) - pp->ocount;
  706. 25969   if (ocount == 0) return;              /* output buffer full */
  707. 25970   count = 1;
  708. 25971   *pp->ohead = c;                       /* add one character */
  709. 25972
  710. 25973   out_process(tp, pp->obuf, pp->ohead, bufend(pp->obuf), &count, &ocount);
  711. 25974   if (count == 0) return;
  712. .Ep 356 src/kernel/pty.c
  713. 25975
  714. 25976   pp->ocount += ocount;
  715. 25977   if ((pp->ohead += ocount) >= bufend(pp->obuf)) pp->ohead -= buflen(pp->obuf);
  716. 25978   pty_start(pp);
  717. 25979 }
  718. 25982 /*==========================================================================*
  719. 25983  *                              pty_start                                   *
  720. 25984  *==========================================================================*/
  721. 25985 PRIVATE void pty_start(pp)
  722. 25986 pty_t *pp;
  723. 25987 {
  724. 25988 /* Transfer bytes written to the output buffer to the PTY reader. */
  725. 25989   int count;
  726. 25990   phys_bytes user_phys;
  727. 25991
  728. 25992   /* While there are things to do. */
  729. 25993   for (;;) {
  730. 25994         count = bufend(pp->obuf) - pp->otail;
  731. 25995         if (count > pp->ocount) count = pp->ocount;
  732. 25996         if (count > pp->rdleft) count = pp->rdleft;
  733. 25997         if (count == 0) break;
  734. 25998
  735. 25999         /* Copy from the output buffer to the readers address space. */
  736. 26000         user_phys = proc_vir2phys(proc_addr(pp->rdproc), pp->rdvir);
  737. 26001         phys_copy(vir2phys(pp->otail), user_phys, (phys_bytes) count);
  738. 26002
  739. 26003         /* Bookkeeping. */
  740. 26004         pp->ocount -= count;
  741. 26005         if ((pp->otail += count) == bufend(pp->obuf)) pp->otail = pp->obuf;
  742. 26006         pp->rdvir += count;
  743. 26007         pp->rdcum += count;
  744. 26008         pp->rdleft -= count;
  745. 26009   }
  746. 26010 }
  747. 26013 /*==========================================================================*
  748. 26014  *                              pty_finish                                  *
  749. 26015  *==========================================================================*/
  750. 26016 PRIVATE void pty_finish(pp)
  751. 26017 pty_t *pp;
  752. 26018 {
  753. 26019 /* Finish the read request of a PTY reader if there is at least one byte
  754. 26020  * transferred.
  755. 26021  */
  756. 26022
  757. 26023   if (pp->rdcum > 0) {
  758. 26024         tty_reply(pp->rdrepcode, pp->rdcaller, pp->rdproc, pp->rdcum);
  759. 26025         pp->rdleft = pp->rdcum = 0;
  760. 26026   }
  761. 26027 }
  762. 26030 /*==========================================================================*
  763. 26031  *                              pty_read                                    *
  764. 26032  *==========================================================================*/
  765. 26033 PRIVATE void pty_read(tp)
  766. 26034 tty_t *tp;
  767. .Op 357 src/kernel/pty.c
  768. 26035 {
  769. 26036 /* Offer bytes from the PTY writer for input on the TTY.  (Do it one byte at
  770. 26037  * a time, 99% of the writes will be for one byte, so no sense in being smart.)
  771. 26038  */
  772. 26039   pty_t *pp = tp->tty_priv;
  773. 26040   phys_bytes user_phys;
  774. 26041   char c;
  775. 26042
  776. 26043   if (pp->state & PTY_CLOSED) {
  777. 26044         if (tp->tty_inleft > 0) {
  778. 26045                 tty_reply(tp->tty_inrepcode, tp->tty_incaller, tp->tty_inproc,
  779. 26046                                                                 tp->tty_incum);
  780. 26047                 tp->tty_inleft = tp->tty_incum = 0;
  781. 26048         }
  782. 26049         return;
  783. 26050   }
  784. 26051
  785. 26052   while (pp->wrleft > 0) {
  786. 26053         /* Transfer one character to 'c'. */
  787. 26054         user_phys = proc_vir2phys(proc_addr(pp->wrproc), pp->wrvir);
  788. 26055         phys_copy(user_phys, vir2phys(&c), 1L);
  789. 26056
  790. 26057         /* Input processing. */
  791. 26058         if (in_process(tp, &c, 1) == 0) break;
  792. 26059
  793. 26060         /* PTY writer bookkeeping. */
  794. 26061         pp->wrvir++;
  795. 26062         pp->wrcum++;
  796. 26063         if (--pp->wrleft == 0) {
  797. 26064                 tty_reply(pp->wrrepcode, pp->wrcaller, pp->wrproc, pp->wrcum);
  798. 26065                 pp->wrcum = 0;
  799. 26066         }
  800. 26067   }
  801. 26068 }
  802. 26071 /*==========================================================================*
  803. 26072  *                              pty_close                                   *
  804. 26073  *==========================================================================*/
  805. 26074 PRIVATE void pty_close(tp)
  806. 26075 tty_t *tp;
  807. 26076 {
  808. 26077 /* The tty side has closed, so shut down the pty side. */
  809. 26078   pty_t *pp = tp->tty_priv;
  810. 26079
  811. 26080   if (!(pp->state & PTY_ACTIVE)) return;
  812. 26081
  813. 26082   if (pp->rdleft > 0) {
  814. 26083         tty_reply(pp->rdrepcode, pp->rdcaller, pp->rdproc, 0);
  815. 26084         pp->rdleft = pp->rdcum = 0;
  816. 26085   }
  817. 26086
  818. 26087   if (pp->wrleft > 0) {
  819. 26088         tty_reply(pp->wrrepcode, pp->wrcaller, pp->wrproc, EIO);
  820. 26089         pp->wrleft = pp->wrcum = 0;
  821. 26090   }
  822. 26091
  823. 26092   if (pp->state & PTY_CLOSED) pp->state = 0; else pp->state |= TTY_CLOSED;
  824. 26093 }
  825. .Ep 358 src/kernel/pty.c
  826. 26096 /*==========================================================================*
  827. 26097  *                              pty_icancel                                 *
  828. 26098  *==========================================================================*/
  829. 26099 PRIVATE void pty_icancel(tp)
  830. 26100 tty_t *tp;
  831. 26101 {
  832. 26102 /* Discard waiting input. */
  833. 26103   pty_t *pp = tp->tty_priv;
  834. 26104
  835. 26105   if (pp->wrleft > 0) {
  836. 26106         tty_reply(pp->wrrepcode, pp->wrcaller, pp->wrproc,
  837. 26107                                                 pp->wrcum + pp->wrleft);
  838. 26108         pp->wrleft = pp->wrcum = 0;
  839. 26109   }
  840. 26110 }
  841. 26113 /*==========================================================================*
  842. 26114  *                              pty_ocancel                                 *
  843. 26115  *==========================================================================*/
  844. 26116 PRIVATE void pty_ocancel(tp)
  845. 26117 tty_t *tp;
  846. 26118 {
  847. 26119 /* Drain the output buffer. */
  848. 26120   pty_t *pp = tp->tty_priv;
  849. 26121
  850. 26122   pp->ocount = 0;
  851. 26123   pp->otail = pp->ohead;
  852. 26124 }
  853. 26127 /*==========================================================================*
  854. 26128  *                              pty_init                                    *
  855. 26129  *==========================================================================*/
  856. 26130 PUBLIC void pty_init(tp)
  857. 26131 tty_t *tp;
  858. 26132 {
  859. 26133   pty_t *pp;
  860. 26134   int line;
  861. 26135
  862. 26136   /* Associate PTY and TTY structures. */
  863. 26137   line = tp - &tty_table[NR_CONS + NR_RS_LINES];
  864. 26138   pp = tp->tty_priv = &pty_table[line];
  865. 26139   pp->tty = tp;
  866. 26140
  867. 26141   /* Set up output queue. */
  868. 26142   pp->ohead = pp->otail = pp->obuf;
  869. 26143
  870. 26144   /* Fill in TTY function hooks. */
  871. 26145   tp->tty_devread = pty_read;
  872. 26146   tp->tty_devwrite = pty_write;
  873. 26147   tp->tty_echo = pty_echo;
  874. 26148   tp->tty_icancel = pty_icancel;
  875. 26149   tp->tty_ocancel = pty_ocancel;
  876. 26150   tp->tty_close = pty_close;
  877. 26151 }
  878. 26152 #endif /* NR_PTYS > 0 */
  879. .Op 359 src/kernel/rs232.c
  880. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  881. src/kernel/rs232.c    
  882. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  883. 26200 /*==========================================================================*
  884. 26201  *              rs232.c - serial driver for 8250 and 16450 UARTs            *
  885. 26202  *              Added support for Atari ST M68901 and YM-2149   --kub       *
  886. 26203  *==========================================================================*/
  887. 26204
  888. 26205 #include "kernel.h"
  889. 26206 #include <termios.h>
  890. 26207 #include <signal.h>
  891. 26208 #include "tty.h"
  892. 26209 #include "proc.h"
  893. 26210
  894. 26211 #if NR_RS_LINES > 0
  895. 26212
  896. 26213 #if (MACHINE != IBM_PC) && (MACHINE != ATARI)
  897. 26214 #error                          /* rs232.c only supports PC and Atari ST */
  898. 26215 #endif
  899. 26216
  900. 26217 #if (MACHINE == ATARI)
  901. 26218 #include "staddr.h"
  902. 26219 #include "stsound.h"
  903. 26220 #include "stmfp.h"
  904. 26221 #if (NR_RS_LINES > 1)
  905. 26222 #error                          /* Only one physical RS232 line available */
  906. 26223 #endif
  907. 26224 #endif
  908. 26225
  909. 26226 #if (MACHINE == IBM_PC)         /* PC/AT 8250/16450 chip combination */
  910. 26227
  911. 26228 /* 8250 constants. */
  912. 26229 #define UART_FREQ         115200L       /* timer frequency */
  913. 26230
  914. 26231 /* Interrupt enable bits. */
  915. 26232 #define IE_RECEIVER_READY       1
  916. 26233 #define IE_TRANSMITTER_READY    2
  917. 26234 #define IE_LINE_STATUS_CHANGE   4
  918. 26235 #define IE_MODEM_STATUS_CHANGE  8
  919. 26236
  920. 26237 /* Interrupt status bits. */
  921. 26238 #define IS_MODEM_STATUS_CHANGE  0
  922. 26239 #define IS_TRANSMITTER_READY    2
  923. 26240 #define IS_RECEIVER_READY       4
  924. 26241 #define IS_LINE_STATUS_CHANGE   6
  925. 26242
  926. 26243 /* Line control bits. */
  927. 26244 #define LC_2STOP_BITS        0x04
  928. 26245 #define LC_PARITY            0x08
  929. 26246 #define LC_PAREVEN           0x10
  930. 26247 #define LC_BREAK             0x40
  931. 26248 #define LC_ADDRESS_DIVISOR   0x80
  932. 26249
  933. 26250 /* Line status bits. */
  934. 26251 #define LS_OVERRUN_ERR          2
  935. 26252 #define LS_PARITY_ERR           4
  936. 26253 #define LS_FRAMING_ERR          8
  937. 26254 #define LS_BREAK_INTERRUPT   0x10
  938. .Ep 360 src/kernel/rs232.c
  939. 26255 #define LS_TRANSMITTER_READY 0x20
  940. 26256
  941. 26257 /* Modem control bits. */
  942. 26258 #define MC_DTR                  1
  943. 26259 #define MC_RTS                  2
  944. 26260 #define MC_OUT2                 8       /* required for PC & AT interrupts */
  945. 26261
  946. 26262 /* Modem status bits. */
  947. 26263 #define MS_CTS               0x10
  948. 26264 #define MS_RLSD              0x80       /* Received Line Signal Detect */
  949. 26265 #define MS_DRLSD             0x08       /* RLSD Delta */
  950. 26266
  951. 26267 #else /* MACHINE == ATARI */            /* Atari ST 68901 USART */
  952. 26268
  953. 26269 /* Most of the USART constants are already defined in stmfp.h . The local
  954. 26270  * definitions made here are for keeping C code changes smaller.   --kub
  955. 26271  */
  956. 26272
  957. 26273 #define UART_FREQ          19200L       /* timer frequency */
  958. 26274
  959. 26275 /* Line status bits. */
  960. 26276 #define LS_OVERRUN_ERR       R_OE
  961. 26277 #define LS_PARITY_ERR        R_PE
  962. 26278 #define LS_FRAMING_ERR       R_FE
  963. 26279 #define LS_BREAK_INTERRUPT   R_BREAK
  964. 26280
  965. 26281 /* Modem status bits. */
  966. 26282 #define MS_CTS               IO_SCTS    /* 0x04 */
  967. 26283
  968. 26284 #endif /* MACHINE == ATARI */
  969. 26285
  970. 26286 #define DATA_BITS_SHIFT         8       /* amount data bits shifted in mode */
  971. 26287 #define DEF_BAUD             1200       /* default baud rate */
  972. 26288
  973. 26289 #define RS_IBUFSIZE          1024       /* RS232 input buffer size */
  974. 26290 #define RS_OBUFSIZE          1024       /* RS232 output buffer size */
  975. 26291
  976. 26292 /* Input buffer watermarks.
  977. 26293  * The external device is asked to stop sending when the buffer
  978. 26294  * exactly reaches high water, or when TTY requests it.  Sending restarts
  979. 26295  * when the input buffer empties below the low watermark.
  980. 26296  */
  981. 26297 #define RS_ILOWWATER    (1 * RS_IBUFSIZE / 4)
  982. 26298 #define RS_IHIGHWATER   (3 * RS_IBUFSIZE / 4)
  983. 26299
  984. 26300 /* Output buffer low watermark.
  985. 26301  * TTY is notified when the output buffer empties below the low watermark, so
  986. 26302  * it may continue filling the buffer if doing a large write.
  987. 26303  */
  988. 26304 #define RS_OLOWWATER    (1 * RS_OBUFSIZE / 4)
  989. 26305
  990. 26306 #if (MACHINE == IBM_PC)
  991. 26307
  992. 26308 /* Macros to handle flow control.
  993. 26309  * Interrupts must be off when they are used.
  994. 26310  * Time is critical - already the function call for out_byte() is annoying.
  995. 26311  * If out_byte() can be done in-line, tests to avoid it can be dropped.
  996. 26312  * istart() tells external device we are ready by raising RTS.
  997. 26313  * istop() tells external device we are not ready by dropping RTS.
  998. 26314  * DTR is kept high all the time (it probably should be raised by open and
  999. .Op 361 src/kernel/rs232.c
  1000. 26315  * dropped by close of the device).
  1001. 26316  * OUT2 is also kept high all the time.
  1002. 26317  */
  1003. 26318 #define istart(rs) 
  1004. 26319         (out_byte((rs)->modem_ctl_port, MC_OUT2 | MC_RTS | MC_DTR), 
  1005. 26320                 (rs)->idevready = TRUE)
  1006. 26321 #define istop(rs) 
  1007. 26322         (out_byte((rs)->modem_ctl_port, MC_OUT2 | MC_DTR), 
  1008. 26323                 (rs)->idevready = FALSE)
  1009. 26324
  1010. 26325 /* Macro to tell if device is ready.  The rs->cts field is set to MS_CTS if
  1011. 26326  * CLOCAL is in effect for a line without a CTS wire.
  1012. 26327  */
  1013. 26328 #define devready(rs) ((in_byte(rs->modem_status_port) | rs->cts) & MS_CTS)
  1014. 26329
  1015. 26330 /* Macro to tell if transmitter is ready. */
  1016. 26331 #define txready(rs) (in_byte(rs->line_status_port) & LS_TRANSMITTER_READY)
  1017. 26332
  1018. 26333 /* Macro to tell if carrier has dropped.
  1019. 26334  * The RS232 Carrier Detect (CD) line is usually connected to the 8250
  1020. 26335  * Received Line Signal Detect pin, reflected by bit MS_RLSD in the Modem
  1021. 26336  * Status Register.  The MS_DRLSD bit tells if MS_RLSD has just changed state.
  1022. 26337  * So if MS_DRLSD is set and MS_RLSD cleared, we know that carrier has just
  1023. 26338  * dropped.
  1024. 26339  */
  1025. 26340 #define devhup(rs)      
  1026. 26341         (in_byte(rs->modem_status_port) & (MS_RLSD|MS_DRLSD) == MS_DRLSD)
  1027. 26342
  1028. 26343 #else /* MACHINE == ATARI */
  1029. 26344
  1030. 26345 /* Macros to handle flow control.
  1031. 26346  * Time is critical - already the function call for lock()/restore() is
  1032. 26347  * annoying.
  1033. 26348  * istart() tells external device we are ready by raising RTS.
  1034. 26349  * istop() tells external device we are not ready by dropping RTS.
  1035. 26350  * DTR is kept high all the time (it probably should be raised by open and
  1036. 26351  * dropped by close of the device). NOTE: The modem lines are active low.
  1037. 26352  */
  1038. 26353 #define set_porta(msk,val) { register int s = lock();           
  1039. 26354                              SOUND->sd_selr = YM_IOA;           
  1040. 26355                              SOUND->sd_wdat =                   
  1041. 26356                                 SOUND->sd_rdat & (msk) | (val); 
  1042. 26357                              restore(s);        }
  1043. 26358 #define istart(rs)         { set_porta( ~(PA_SRTS|PA_SDTR),0 ); 
  1044. 26359                              (rs)->idevready = TRUE;    }
  1045. 26360 #define istop(rs)          { set_porta( ~PA_SDTR, PA_SRTS );    
  1046. 26361                              (rs)->idevready = FALSE;   }
  1047. 26362
  1048. 26363 /* Macro to tell if device is ready.  The rs->cts field is set to MS_CTS if
  1049. 26364  * CLOCAL is in effect for a line without a CTS wire.
  1050. 26365  */
  1051. 26366 #define devready(rs)         ((~MFP->mf_gpip | rs->cts) & MS_CTS)
  1052. 26367
  1053. 26368 /* Transmitter ready test */
  1054. 26369 #define txready(rs)          (MFP->mf_tsr & (T_EMPTY | T_UE))
  1055. 26370
  1056. 26371 #endif /* MACHINE == ATARI */
  1057. 26372
  1058. 26373 /* Types. */
  1059. 26374 typedef unsigned char bool_t;   /* boolean */
  1060. .Ep 362 src/kernel/rs232.c
  1061. 26375
  1062. 26376 /* RS232 device structure, one per device. */
  1063. 26377 typedef struct rs232 {
  1064. 26378   tty_t *tty;                   /* associated TTY structure */
  1065. 26379
  1066. 26380   int icount;                   /* number of bytes in the input buffer */
  1067. 26381   char *ihead;                  /* next free spot in input buffer */
  1068. 26382   char *itail;                  /* first byte to give to TTY */
  1069. 26383   bool_t idevready;             /* nonzero if we are ready to receive (RTS) */
  1070. 26384   char cts;                     /* normally 0, but MS_CTS if CLOCAL is set */
  1071. 26385
  1072. 26386   unsigned char ostate;         /* combination of flags: */
  1073. 26387 #define ODONE          1        /* output completed (< output enable bits) */
  1074. 26388 #define ORAW           2        /* raw mode for xoff disable (< enab. bits) */
  1075. 26389 #define OWAKEUP        4        /* tty_wakeup() pending (asm code only) */
  1076. 26390 #define ODEVREADY MS_CTS        /* external device hardware ready (CTS) */
  1077. 26391 #define OQUEUED     0x20        /* output buffer not empty */
  1078. 26392 #define OSWREADY    0x40        /* external device software ready (no xoff) */
  1079. 26393 #define ODEVHUP  MS_RLSD        /* external device has dropped carrier */
  1080. 26394 #define OSOFTBITS  (ODONE | ORAW | OWAKEUP | OQUEUED | OSWREADY)
  1081. 26395                                 /* user-defined bits */
  1082. 26396 #if (OSOFTBITS | ODEVREADY | ODEVHUP) == OSOFTBITS
  1083. 26397                                 /* a weak sanity check */
  1084. 26398 #error                          /* bits are not unique */
  1085. 26399 #endif
  1086. 26400   unsigned char oxoff;          /* char to stop output */
  1087. 26401   bool_t inhibited;             /* output inhibited? (follows tty_inhibited) */
  1088. 26402   bool_t drain;                 /* if set drain output and reconfigure line */
  1089. 26403   int ocount;                   /* number of bytes in the output buffer */
  1090. 26404   char *ohead;                  /* next free spot in output buffer */
  1091. 26405   char *otail;                  /* next char to output */
  1092. 26406
  1093. 26407 #if (MACHINE == IBM_PC)
  1094. 26408   port_t xmit_port;             /* i/o ports */
  1095. 26409   port_t recv_port;
  1096. 26410   port_t div_low_port;
  1097. 26411   port_t div_hi_port;
  1098. 26412   port_t int_enab_port;
  1099. 26413   port_t int_id_port;
  1100. 26414   port_t line_ctl_port;
  1101. 26415   port_t modem_ctl_port;
  1102. 26416   port_t line_status_port;
  1103. 26417   port_t modem_status_port;
  1104. 26418 #endif
  1105. 26419
  1106. 26420   unsigned char lstatus;        /* last line status */
  1107. 26421   unsigned char pad;            /* ensure alignment for 16-bit ints */
  1108. 26422   unsigned framing_errors;      /* error counts (no reporting yet) */
  1109. 26423   unsigned overrun_errors;
  1110. 26424   unsigned parity_errors;
  1111. 26425   unsigned break_interrupts;
  1112. 26426
  1113. 26427   char ibuf[RS_IBUFSIZE];       /* input buffer */
  1114. 26428   char obuf[RS_OBUFSIZE];       /* output buffer */
  1115. 26429 } rs232_t;
  1116. 26430
  1117. 26431 PUBLIC rs232_t rs_lines[NR_RS_LINES];
  1118. 26432
  1119. 26433 /* Table and macro to translate an RS232 line number to its rs_lines entry. */
  1120. 26434 PRIVATE rs232_t *p_rs_addr[NR_RS_LINES];
  1121. .Op 363 src/kernel/rs232.c
  1122. 26435
  1123. 26436 #define rs_addr(line)   (p_rs_addr[line])
  1124. 26437
  1125. 26438 #if (MACHINE == IBM_PC)
  1126. 26439 /* 8250 base addresses. */
  1127. 26440 PRIVATE port_t addr_8250[] = {
  1128. 26441   0x3F8,                        /* COM1: (line 0); COM3 might be at 0x3E8 */
  1129. 26442   0x2F8,                        /* COM2: (line 1); COM4 might be at 0x2E8 */
  1130. 26443 };
  1131. 26444 #endif
  1132. 26445
  1133. 26446 FORWARD _PROTOTYPE( int rs232_1handler, (int irq)                       );
  1134. 26447 FORWARD _PROTOTYPE( int rs232_2handler, (int irq)                       );
  1135. 26448 FORWARD _PROTOTYPE( void in_int, (rs232_t *rs)                          );
  1136. 26449 FORWARD _PROTOTYPE( void line_int, (rs232_t *rs)                        );
  1137. 26450 FORWARD _PROTOTYPE( void modem_int, (rs232_t *rs)                       );
  1138. 26451 FORWARD _PROTOTYPE( void rs_write, (tty_t *tp)                          );
  1139. 26452 FORWARD _PROTOTYPE( void rs_echo, (tty_t *tp, int c)                    );
  1140. 26453 FORWARD _PROTOTYPE( void rs_ioctl, (tty_t *tp)                          );
  1141. 26454 FORWARD _PROTOTYPE( void rs_config, (rs232_t *rs)                       );
  1142. 26455 FORWARD _PROTOTYPE( void rs_read, (tty_t *tp)                           );
  1143. 26456 FORWARD _PROTOTYPE( void rs_icancel, (tty_t *tp)                        );
  1144. 26457 FORWARD _PROTOTYPE( void rs_ocancel, (tty_t *tp)                        );
  1145. 26458 FORWARD _PROTOTYPE( void rs_ostart, (rs232_t *rs)                       );
  1146. 26459 FORWARD _PROTOTYPE( void rs_break, (tty_t *tp)                          );
  1147. 26460 FORWARD _PROTOTYPE( void out_int, (rs232_t *rs)                         );
  1148. 26461
  1149. 26462
  1150. 26463 /*==========================================================================*
  1151. 26464  *                              rs_write                                    *
  1152. 26465  *==========================================================================*/
  1153. 26466 PRIVATE void rs_write(tp)
  1154. 26467 register tty_t *tp;
  1155. 26468 {
  1156. 26469 /* (*devwrite)() routine for RS232. */
  1157. 26470
  1158. 26471   rs232_t *rs = tp->tty_priv;
  1159. 26472   int count, ocount;
  1160. 26473   phys_bytes user_phys;
  1161. 26474
  1162. 26475   if (rs->inhibited != tp->tty_inhibited) {
  1163. 26476         /* Inhibition state has changed. */
  1164. 26477         lock();
  1165. 26478         rs->ostate |= OSWREADY;
  1166. 26479         if (tp->tty_inhibited) rs->ostate &= ~OSWREADY;
  1167. 26480         unlock();
  1168. 26481         rs->inhibited = tp->tty_inhibited;
  1169. 26482   }
  1170. 26483
  1171. 26484   if (rs->drain) {
  1172. 26485         /* Wait for the line to drain then reconfigure and continue output. */
  1173. 26486         if (rs->ocount > 0) return;
  1174. 26487         rs->drain = FALSE;
  1175. 26488         rs_config(rs);
  1176. 26489   }
  1177. 26490
  1178. 26491   /* While there is something to do. */
  1179. 26492   for (;;) {
  1180. 26493         ocount = buflen(rs->obuf) - rs->ocount;
  1181. 26494         count = bufend(rs->obuf) - rs->ohead;
  1182. .Ep 364 src/kernel/rs232.c
  1183. 26495         if (count > ocount) count = ocount;
  1184. 26496         if (count > tp->tty_outleft) count = tp->tty_outleft;
  1185. 26497         if (count == 0 || tp->tty_inhibited) return;
  1186. 26498
  1187. 26499         /* Copy from user space to the RS232 output buffer. */
  1188. 26500         user_phys = proc_vir2phys(proc_addr(tp->tty_outproc), tp->tty_out_vir);
  1189. 26501         phys_copy(user_phys, vir2phys(rs->ohead), (phys_bytes) count);
  1190. 26502
  1191. 26503         /* Perform output processing on the output buffer. */
  1192. 26504         out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count, &ocount);
  1193. 26505         if (count == 0) break;
  1194. 26506
  1195. 26507         /* Assume echoing messed up by output. */
  1196. 26508         tp->tty_reprint = TRUE;
  1197. 26509
  1198. 26510         /* Bookkeeping. */
  1199. 26511         lock();                 /* protect interrupt sensitive rs->ocount */
  1200. 26512         rs->ocount += ocount;
  1201. 26513         rs_ostart(rs);
  1202. 26514         unlock();
  1203. 26515         if ((rs->ohead += ocount) >= bufend(rs->obuf))
  1204. 26516                 rs->ohead -= buflen(rs->obuf);
  1205. 26517         tp->tty_out_vir += count;
  1206. 26518         tp->tty_outcum += count;
  1207. 26519         if ((tp->tty_outleft -= count) == 0) {
  1208. 26520                 /* Output is finished, reply to the writer. */
  1209. 26521                 tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
  1210. 26522                                         tp->tty_outproc, tp->tty_outcum);
  1211. 26523                 tp->tty_outcum = 0;
  1212. 26524         }
  1213. 26525   }
  1214. 26526 }
  1215. 26529 /*==========================================================================*
  1216. 26530  *                              rs_echo                                     *
  1217. 26531  *==========================================================================*/
  1218. 26532 PRIVATE void rs_echo(tp, c)
  1219. 26533 tty_t *tp;                      /* which TTY */
  1220. 26534 int c;                          /* character to echo */
  1221. 26535 {
  1222. 26536 /* Echo one character.  (Like rs_write, but only one character, optionally.) */
  1223. 26537
  1224. 26538   rs232_t *rs = tp->tty_priv;
  1225. 26539   int count, ocount;
  1226. 26540
  1227. 26541   ocount = buflen(rs->obuf) - rs->ocount;
  1228. 26542   if (ocount == 0) return;              /* output buffer full */
  1229. 26543   count = 1;
  1230. 26544   *rs->ohead = c;                       /* add one character */
  1231. 26545
  1232. 26546   out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count, &ocount);
  1233. 26547   if (count == 0) return;
  1234. 26548
  1235. 26549   lock();
  1236. 26550   rs->ocount += ocount;
  1237. 26551   rs_ostart(rs);
  1238. 26552   unlock();
  1239. 26553   if ((rs->ohead += ocount) >= bufend(rs->obuf)) rs->ohead -= buflen(rs->obuf);
  1240. 26554 }
  1241. .Op 365 src/kernel/rs232.c
  1242. 26557 /*==========================================================================*
  1243. 26558  *                              rs_ioctl                                    *
  1244. 26559  *==========================================================================*/
  1245. 26560 PRIVATE void rs_ioctl(tp)
  1246. 26561 tty_t *tp;                      /* which TTY */
  1247. 26562 {
  1248. 26563 /* Reconfigure the line as soon as the output has drained. */
  1249. 26564   rs232_t *rs = tp->tty_priv;
  1250. 26565
  1251. 26566   rs->drain = TRUE;
  1252. 26567 }
  1253. 26570 /*==========================================================================*
  1254. 26571  *                              rs_config                                   *
  1255. 26572  *==========================================================================*/
  1256. 26573 PRIVATE void rs_config(rs)
  1257. 26574 rs232_t *rs;                    /* which line */
  1258. 26575 {
  1259. 26576 /* Set various line control parameters for RS232 I/O.
  1260. 26577  * If DataBits == 5 and StopBits == 2, 8250 will generate 1.5 stop bits.
  1261. 26578  * The 8250 can't handle split speed, so we use the input speed.
  1262. 26579  */
  1263. 26580
  1264. 26581   tty_t *tp = rs->tty;
  1265. 26582   int divisor;
  1266. 26583   int line_controls;
  1267. 26584   static struct speed2divisor {
  1268. 26585         speed_t speed;
  1269. 26586         int     divisor;
  1270. 26587   } s2d[] = {
  1271. 26588 #if (MACHINE == IBM_PC)
  1272. 26589         { B50,          UART_FREQ / 50          },
  1273. 26590 #endif
  1274. 26591         { B75,          UART_FREQ / 75          },
  1275. 26592         { B110,         UART_FREQ / 110         },
  1276. 26593         { B134,         UART_FREQ * 10 / 1345   },
  1277. 26594         { B150,         UART_FREQ / 150         },
  1278. 26595         { B200,         UART_FREQ / 200         },
  1279. 26596         { B300,         UART_FREQ / 300         },
  1280. 26597         { B600,         UART_FREQ / 600         },
  1281. 26598         { B1200,        UART_FREQ / 1200        },
  1282. 26599 #if (MACHINE == IBM_PC)
  1283. 26600         { B1800,        UART_FREQ / 1800        },
  1284. 26601 #endif
  1285. 26602         { B2400,        UART_FREQ / 2400        },
  1286. 26603         { B4800,        UART_FREQ / 4800        },
  1287. 26604         { B9600,        UART_FREQ / 9600        },
  1288. 26605         { B19200,       UART_FREQ / 19200       },
  1289. 26606 #if (MACHINE == IBM_PC)
  1290. 26607         { B38400,       UART_FREQ / 38400       },
  1291. 26608         { B57600,       UART_FREQ / 57600       },
  1292. 26609         { B115200,      UART_FREQ / 115200L     },
  1293. 26610 #endif
  1294. 26611   };
  1295. 26612   struct speed2divisor *s2dp;
  1296. 26613
  1297. 26614   /* RS232 needs to know the xoff character, and if CTS works. */
  1298. .Ep 366 src/kernel/rs232.c
  1299. 26615   rs->oxoff = tp->tty_termios.c_cc[VSTOP];
  1300. 26616   rs->cts = (tp->tty_termios.c_cflag & CLOCAL) ? MS_CTS : 0;
  1301. 26617
  1302. 26618   /* Look up the 8250 rate divisor from the output speed. */
  1303. 26619   divisor = 0;
  1304. 26620   for (s2dp = s2d; s2dp < s2d + sizeof(s2d)/sizeof(s2d[0]); s2dp++) {
  1305. 26621         if (s2dp->speed == tp->tty_termios.c_ospeed) divisor = s2dp->divisor;
  1306. 26622   }
  1307. 26623   if (divisor == 0) return;     /* B0? */
  1308. 26624
  1309. 26625 #if (MACHINE == IBM_PC)
  1310. 26626   /* Compute line control flag bits. */
  1311. 26627   line_controls = 0;
  1312. 26628   if (tp->tty_termios.c_cflag & PARENB) {
  1313. 26629         line_controls |= LC_PARITY;
  1314. 26630         if (!(tp->tty_termios.c_cflag & PARODD)) line_controls |= LC_PAREVEN;
  1315. 26631   }
  1316. 26632   if (divisor >= (UART_FREQ / 110)) line_controls |= LC_2STOP_BITS;
  1317. 26633   line_controls |= (tp->tty_termios.c_cflag & CSIZE) >> 2;
  1318. 26634
  1319. 26635   /* Lock out interrupts while setting the speed. The receiver register is
  1320. 26636    * going to be hidden by the div_low register, but the input interrupt
  1321. 26637    * handler relies on reading it to clear the interrupt and avoid looping
  1322. 26638    * forever.
  1323. 26639    */
  1324. 26640   lock();
  1325. 26641
  1326. 26642   /* Select the baud rate divisor registers and change the rate. */
  1327. 26643   out_byte(rs->line_ctl_port, LC_ADDRESS_DIVISOR);
  1328. 26644   out_byte(rs->div_low_port, divisor);
  1329. 26645   out_byte(rs->div_hi_port, divisor >> 8);
  1330. 26646
  1331. 26647   /* Change the line controls and reselect the usual registers. */
  1332. 26648   out_byte(rs->line_ctl_port, line_controls);
  1333. 26649
  1334. 26650   rs->ostate |= ORAW;
  1335. 26651   if ((tp->tty_termios.c_lflag & IXON) && rs->oxoff != _POSIX_VDISABLE)
  1336. 26652         rs->ostate &= ~ORAW;
  1337. 26653
  1338. 26654   unlock();
  1339. 26655
  1340. 26656 #else /* MACHINE == ATARI */
  1341. 26657
  1342. 26658   line_controls = U_Q16;
  1343. 26659   if (tp->tty_termios.c_cflag & PARENB) {
  1344. 26660         line_controls |= U_PAR;
  1345. 26661         if (!(tp->tty_termios.c_cflag & PARODD)) line_controls |= U_EVEN;
  1346. 26662   }
  1347. 26663   line_controls |= (divisor >= (UART_FREQ / 110)) ? U_ST2 : U_ST1;
  1348. 26664
  1349. 26665   switch (tp->tty_termios.c_cflag & CSIZE) {    /* XXX - are U_Dn like CSn? */
  1350. 26666         case CS5:       line_controls |= U_D5; break;
  1351. 26667         case CS5:       line_controls |= U_D6; break;
  1352. 26668         case CS5:       line_controls |= U_D7; break;
  1353. 26669         case CS5:       line_controls |= U_D8; break;
  1354. 26670   }
  1355. 26671   lock();
  1356. 26672   MFP->mf_ucr = line_controls;
  1357. 26673   MFP->mf_tddr = divisor;
  1358. 26674   unlock();
  1359. .Op 367 src/kernel/rs232.c
  1360. 26675 #endif /* MACHINE == ATARI */
  1361. 26676 }
  1362. 26679 /*==========================================================================*
  1363. 26680  *                              rs_init                                     *
  1364. 26681  *==========================================================================*/
  1365. 26682 PUBLIC void rs_init(tp)
  1366. 26683 tty_t *tp;                      /* which TTY */
  1367. 26684 {
  1368. 26685 /* Initialize RS232 for one line. */
  1369. 26686
  1370. 26687   register rs232_t *rs;
  1371. 26688   int line;
  1372. 26689 #if (MACHINE == IBM_PC)
  1373. 26690   port_t this_8250;
  1374. 26691   int irq;
  1375. 26692   long v;
  1376. 26693 #endif
  1377. 26694
  1378. 26695   /* Associate RS232 and TTY structures. */
  1379. 26696   line = tp - &tty_table[NR_CONS];
  1380. 26697   rs = tp->tty_priv = &rs_lines[line];
  1381. 26698   rs->tty = tp;
  1382. 26699
  1383. 26700   /* Set up input queue. */
  1384. 26701   rs->ihead = rs->itail = rs->ibuf;
  1385. 26702
  1386. 26703 #if (MACHINE == IBM_PC)
  1387. 26704   /* Precalculate port numbers for speed. Magic numbers in the code (once). */
  1388. 26705   this_8250 = addr_8250[line];
  1389. 26706   rs->xmit_port = this_8250 + 0;
  1390. 26707   rs->recv_port = this_8250 + 0;
  1391. 26708   rs->div_low_port = this_8250 + 0;
  1392. 26709   rs->div_hi_port = this_8250 + 1;
  1393. 26710   rs->int_enab_port = this_8250 + 1;
  1394. 26711   rs->int_id_port = this_8250 + 2;
  1395. 26712   rs->line_ctl_port = this_8250 + 3;
  1396. 26713   rs->modem_ctl_port = this_8250 + 4;
  1397. 26714   rs->line_status_port = this_8250 + 5;
  1398. 26715   rs->modem_status_port = this_8250 + 6;
  1399. 26716 #endif
  1400. 26717
  1401. 26718   /* Set up the hardware to a base state, in particular
  1402. 26719    *    o turn off DTR (MC_DTR) to try to stop the external device.
  1403. 26720    *    o be careful about the divisor latch.  Some BIOS's leave it enabled
  1404. 26721    *      here and that caused trouble (no interrupts) in version 1.5 by
  1405. 26722    *      hiding the interrupt enable port in the next step, and worse trouble
  1406. 26723    *      (continual interrupts) in an old version by hiding the receiver
  1407. 26724    *      port in the first interrupt.  Call rs_ioctl() early to avoid this.
  1408. 26725    *    o disable interrupts at the chip level, to force an edge transition
  1409. 26726    *      on the 8259 line when interrupts are next enabled and active.
  1410. 26727    *      RS232 interrupts are guaranteed to be disabled now by the 8259
  1411. 26728    *      mask, but there used to be trouble if the mask was set without
  1412. 26729    *      handling a previous interrupt.
  1413. 26730    */
  1414. 26731   istop(rs);                    /* sets modem_ctl_port */
  1415. 26732   rs_config(rs);
  1416. 26733 #if (MACHINE == IBM_PC)
  1417. 26734   out_byte(rs->int_enab_port, 0);
  1418. .Ep 368 src/kernel/rs232.c
  1419. 26735 #endif
  1420. 26736
  1421. 26737   /* Clear any harmful leftover interrupts.  An output interrupt is harmless
  1422. 26738    * and will occur when interrupts are enabled anyway.  Set up the output
  1423. 26739    * queue using the status from clearing the modem status interrupt.
  1424. 26740    */
  1425. 26741 #if (MACHINE == IBM_PC)
  1426. 26742   in_byte(rs->line_status_port);
  1427. 26743   in_byte(rs->recv_port);
  1428. 26744 #endif
  1429. 26745   rs->ostate = devready(rs) | ORAW | OSWREADY;  /* reads modem_ctl_port */
  1430. 26746   rs->ohead = rs->otail = rs->obuf;
  1431. 26747
  1432. 26748 #if (MACHINE == IBM_PC)
  1433. 26749   /* Enable interrupts for both interrupt controller and device. */
  1434. 26750   irq = (line & 1) ? SECONDARY_IRQ : RS232_IRQ;
  1435. 26751
  1436. 26752 #if ENABLE_NETWORKING
  1437. 26753   /* The ethernet driver may steal the IRQ of an RS232 line. */
  1438. 26754   v = ETHER_IRQ;
  1439. 26755   switch (env_parse("DPETH0", "x:d:x", 1, &v, 0L, (long) NR_IRQ_VECTORS-1)) {
  1440. 26756   case EP_ON:
  1441. 26757   case EP_SET:
  1442. 26758         if (v == irq) return;           /* IRQ in use, don't configure line */
  1443. 26759   }
  1444. 26760 #endif
  1445. 26761
  1446. 26762   put_irq_handler(irq, (line & 1) ? rs232_2handler : rs232_1handler);
  1447. 26763   enable_irq(irq);
  1448. 26764   out_byte(rs->int_enab_port, IE_LINE_STATUS_CHANGE | IE_MODEM_STATUS_CHANGE
  1449. 26765                                 | IE_RECEIVER_READY | IE_TRANSMITTER_READY);
  1450. 26766 #else /* MACHINE == ATARI */
  1451. 26767   /* Initialize the 68901 chip, then enable interrupts. */
  1452. 26768   MFP->mf_scr = 0x00;
  1453. 26769   MFP->mf_tcdcr |= T_Q004;
  1454. 26770   MFP->mf_rsr = R_ENA;
  1455. 26771   MFP->mf_tsr = T_ENA;
  1456. 26772   MFP->mf_aer = (MFP->mf_aer | (IO_SCTS|IO_SDCD)) ^
  1457. 26773                  (MFP->mf_gpip & (IO_SCTS|IO_SDCD));
  1458. 26774   MFP->mf_ddr = (MFP->mf_ddr & ~ (IO_SCTS|IO_SDCD));
  1459. 26775   MFP->mf_iera |= (IA_RRDY|IA_RERR|IA_TRDY|IA_TERR);
  1460. 26776   MFP->mf_imra |= (IA_RRDY|IA_RERR|IA_TRDY|IA_TERR);
  1461. 26777   MFP->mf_ierb |= (IB_SCTS|IB_SDCD);
  1462. 26778   MFP->mf_imrb |= (IB_SCTS|IB_SDCD);
  1463. 26779 #endif /* MACHINE == ATARI */
  1464. 26780
  1465. 26781   /* Fill in TTY function hooks. */
  1466. 26782   tp->tty_devread = rs_read;
  1467. 26783   tp->tty_devwrite = rs_write;
  1468. 26784   tp->tty_echo = rs_echo;
  1469. 26785   tp->tty_icancel = rs_icancel;
  1470. 26786   tp->tty_ocancel = rs_ocancel;
  1471. 26787   tp->tty_ioctl = rs_ioctl;
  1472. 26788   tp->tty_break = rs_break;
  1473. 26789
  1474. 26790   /* Tell external device we are ready. */
  1475. 26791   istart(rs);
  1476. 26792 }
  1477. .Op 369 src/kernel/rs232.c
  1478. 26795 /*==========================================================================*
  1479. 26796  *                              rs_icancel                                  *
  1480. 26797  *==========================================================================*/
  1481. 26798 PRIVATE void rs_icancel(tp)
  1482. 26799 tty_t *tp;                      /* which TTY */
  1483. 26800 {
  1484. 26801 /* Cancel waiting input. */
  1485. 26802   rs232_t *rs = tp->tty_priv;
  1486. 26803
  1487. 26804   lock();
  1488. 26805   rs->icount = 0;
  1489. 26806   rs->itail = rs->ihead;
  1490. 26807   istart(rs);
  1491. 26808   unlock();
  1492. 26809 }
  1493. 26812 /*==========================================================================*
  1494. 26813  *                              rs_ocancel                                  *
  1495. 26814  *==========================================================================*/
  1496. 26815 PRIVATE void rs_ocancel(tp)
  1497. 26816 tty_t *tp;                      /* which TTY */
  1498. 26817 {
  1499. 26818 /* Cancel pending output. */
  1500. 26819   rs232_t *rs = tp->tty_priv;
  1501. 26820
  1502. 26821   lock();
  1503. 26822   rs->ostate &= ~(ODONE | OQUEUED);
  1504. 26823   rs->ocount = 0;
  1505. 26824   rs->otail = rs->ohead;
  1506. 26825   unlock();
  1507. 26826 }
  1508. 26829 /*==========================================================================*
  1509. 26830  *                              rs_read                                     *
  1510. 26831  *==========================================================================*/
  1511. 26832 PRIVATE void rs_read(tp)
  1512. 26833 tty_t *tp;                      /* which tty */
  1513. 26834 {
  1514. 26835 /* Process characters from the circular input buffer. */
  1515. 26836
  1516. 26837   rs232_t *rs = tp->tty_priv;
  1517. 26838   int icount, count, ostate;
  1518. 26839
  1519. 26840   if (!(tp->tty_termios.c_cflag & CLOCAL)) {
  1520. 26841         /* Send a SIGHUP if hangup detected. */
  1521. 26842         lock();
  1522. 26843         ostate = rs->ostate;
  1523. 26844         rs->ostate &= ~ODEVHUP;         /* save ostate, clear DEVHUP */
  1524. 26845         unlock();
  1525. 26846         if (ostate & ODEVHUP) { sigchar(tp, SIGHUP); return; }
  1526. 26847   }
  1527. 26848
  1528. 26849   while ((count = rs->icount) > 0) {
  1529. 26850         icount = bufend(rs->ibuf) - rs->itail;
  1530. 26851         if (count > icount) count = icount;
  1531. 26852
  1532. 26853         /* Perform input processing on (part of) the input buffer. */
  1533. 26854         if ((count = in_process(tp, rs->itail, count)) == 0) break;
  1534. .Ep 370 src/kernel/rs232.c
  1535. 26855
  1536. 26856         lock();                 /* protect interrupt sensitive variables */
  1537. 26857         rs->icount -= count;
  1538. 26858         if (!rs->idevready && rs->icount < RS_ILOWWATER) istart(rs);
  1539. 26859         unlock();
  1540. 26860         if ((rs->itail += count) == bufend(rs->ibuf)) rs->itail = rs->ibuf;
  1541. 26861   }
  1542. 26862 }
  1543. 26865 /*==========================================================================*
  1544. 26866  *                              rs_ostart                                   *
  1545. 26867  *==========================================================================*/
  1546. 26868 PRIVATE void rs_ostart(rs)
  1547. 26869 rs232_t *rs;                    /* which rs line */
  1548. 26870 {
  1549. 26871 /* Tell RS232 there is something waiting in the output buffer. */
  1550. 26872
  1551. 26873   rs->ostate |= OQUEUED;
  1552. 26874   if (txready(rs)) out_int(rs);
  1553. 26875 }
  1554. 26878 /*==========================================================================*
  1555. 26879  *                              rs_break                                    *
  1556. 26880  *==========================================================================*/
  1557. 26881 PRIVATE void rs_break(tp)
  1558. 26882 tty_t *tp;                      /* which tty */
  1559. 26883 {
  1560. 26884 /* Generate a break condition by setting the BREAK bit for 0.4 sec. */
  1561. 26885   rs232_t *rs = tp->tty_priv;
  1562. 26886   int line_controls;
  1563. 26887
  1564. 26888   line_controls = in_byte(rs->line_ctl_port);
  1565. 26889   out_byte(rs->line_ctl_port, line_controls | LC_BREAK);
  1566. 26890   milli_delay(400);                                             /* ouch */
  1567. 26891   out_byte(rs->line_ctl_port, line_controls);
  1568. 26892 }
  1569. 26895 /* Low level (interrupt) routines. */
  1570. 26896
  1571. 26897 #if (MACHINE == IBM_PC)
  1572. 26898 /*==========================================================================*
  1573. 26899  *                              rs232_1handler                              *
  1574. 26900  *==========================================================================*/
  1575. 26901 PRIVATE int rs232_1handler(irq)
  1576. 26902 int irq;
  1577. 26903 {
  1578. 26904 /* Interrupt hander for IRQ4.
  1579. 26905  * Only 1 line (usually COM1) should use it.
  1580. 26906  */
  1581. 26907
  1582. 26908   register rs232_t *rs = &rs_lines[0];
  1583. 26909
  1584. 26910   while (TRUE) {
  1585. 26911         /* Loop to pick up ALL pending interrupts for device.
  1586. 26912          * This usually just wastes time unless the hardware has a buffer
  1587. 26913          * (and then we have to worry about being stuck in the loop too long).
  1588. 26914          * Unfortunately, some serial cards lock up without this.
  1589. .Op 371 src/kernel/rs232.c
  1590. 26915          */
  1591. 26916         switch (in_byte(rs->int_id_port)) {
  1592. 26917         case IS_RECEIVER_READY:
  1593. 26918                 in_int(rs);
  1594. 26919                 continue;
  1595. 26920         case IS_TRANSMITTER_READY:
  1596. 26921                 out_int(rs);
  1597. 26922                 continue;
  1598. 26923         case IS_MODEM_STATUS_CHANGE:
  1599. 26924                 modem_int(rs);
  1600. 26925                 continue;
  1601. 26926         case IS_LINE_STATUS_CHANGE:
  1602. 26927                 line_int(rs);
  1603. 26928                 continue;
  1604. 26929         }
  1605. 26930         return(1);      /* reenable serial interrupt */
  1606. 26931   }
  1607. 26932 }
  1608. 26935 /*==========================================================================*
  1609. 26936  *                              rs232_2handler                              *
  1610. 26937  *==========================================================================*/
  1611. 26938 PRIVATE int rs232_2handler(irq)
  1612. 26939 int irq;
  1613. 26940 {
  1614. 26941 /* Interrupt hander for IRQ3.
  1615. 26942  * Only 1 line (usually COM2) should use it.
  1616. 26943  */
  1617. 26944
  1618. 26945   register rs232_t *rs = &rs_lines[1];
  1619. 26946
  1620. 26947   while (TRUE) {
  1621. 26948         switch (in_byte(rs->int_id_port)) {
  1622. 26949         case IS_RECEIVER_READY:
  1623. 26950                 in_int(rs);
  1624. 26951                 continue;
  1625. 26952         case IS_TRANSMITTER_READY:
  1626. 26953                 out_int(rs);
  1627. 26954                 continue;
  1628. 26955         case IS_MODEM_STATUS_CHANGE:
  1629. 26956                 modem_int(rs);
  1630. 26957                 continue;
  1631. 26958         case IS_LINE_STATUS_CHANGE:
  1632. 26959                 line_int(rs);
  1633. 26960                 continue;
  1634. 26961         }
  1635. 26962         return(1);      /* reenable serial interrupt */
  1636. 26963   }
  1637. 26964 }
  1638. 26965 #else /* MACHINE == ATARI */
  1639. 26966 /*==========================================================================*
  1640. 26967  *                              siaint                                      *
  1641. 26968  *==========================================================================*/
  1642. 26969 PRIVATE void siaint(type)
  1643. 26970 int    type;           /* interrupt type */
  1644. 26971 {
  1645. 26972 /* siaint is the rs232 interrupt procedure for Atari ST's. For ST there are
  1646. 26973  * as much as 5 interrupt lines used for rs232. The trap type byte left on the
  1647. 26974  * stack by the assembler interrupt handler identifies the interrupt cause.
  1648. .Ep 372 src/kernel/rs232.c
  1649. 26975  */
  1650. 26976
  1651. 26977   register unsigned char  code;
  1652. 26978   register rs232_t *rs = &rs_lines[0];
  1653. 26979   int s = lock();
  1654. 26980
  1655. 26981   switch (type & 0x00FF)
  1656. 26982   {
  1657. 26983         case 0x00:             /* receive buffer full */
  1658. 26984                 in_int(rs);
  1659. 26985                 break;
  1660. 26986         case 0x01:             /* receive error */
  1661. 26987                 line_int(rs);
  1662. 26988                 break;
  1663. 26989         case 0x02:             /* transmit buffer empty */
  1664. 26990                 out_int(rs);
  1665. 26991                 break;
  1666. 26992         case 0x03:             /* transmit error */
  1667. 26993                 code = MFP->mf_tsr;
  1668. 26994                 if (code & ~(T_ENA | T_UE | T_EMPTY))
  1669. 26995                 {
  1670. 26996                     printf("sia: transmit error: status=%xrn", code);
  1671. 26997                     /* MFP->mf_udr = lastchar; */ /* retry */
  1672. 26998                 }
  1673. 26999                 break;
  1674. 27000         case 0x04:              /* modem lines change */
  1675. 27001                 modem_int(rs);
  1676. 27002                 break;
  1677. 27003   }
  1678. 27004   restore(s);
  1679. 27005 }
  1680. 27006 #endif /* MACHINE == ATARI */
  1681. 27007
  1682. 27008
  1683. 27009 /*==========================================================================*
  1684. 27010  *                              in_int                                      *
  1685. 27011  *==========================================================================*/
  1686. 27012 PRIVATE void in_int(rs)
  1687. 27013 register rs232_t *rs;           /* line with input interrupt */
  1688. 27014 {
  1689. 27015 /* Read the data which just arrived.
  1690. 27016  * If it is the oxoff char, clear OSWREADY, else if OSWREADY was clear, set
  1691. 27017  * it and restart output (any char does this, not just xon).
  1692. 27018  * Put data in the buffer if room, otherwise discard it.
  1693. 27019  * Set a flag for the clock interrupt handler to eventually notify TTY.
  1694. 27020  */
  1695. 27021
  1696. 27022   int c;
  1697. 27023
  1698. 27024 #if (MACHINE == IBM_PC)
  1699. 27025   c = in_byte(rs->recv_port);
  1700. 27026 #else /* MACHINE == ATARI */
  1701. 27027   c = MFP->mf_udr;
  1702. 27028 #endif
  1703. 27029
  1704. 27030   if (!(rs->ostate & ORAW)) {
  1705. 27031         if (c == rs->oxoff) {
  1706. 27032                 rs->ostate &= ~OSWREADY;
  1707. 27033         } else
  1708. 27034         if (!(rs->ostate & OSWREADY)) {
  1709. .Op 373 src/kernel/rs232.c
  1710. 27035                 rs->ostate |= OSWREADY;
  1711. 27036                 if (txready(rs)) out_int(rs);
  1712. 27037         }
  1713. 27038   }
  1714. 27039
  1715. 27040   if (rs->icount == buflen(rs->ibuf)) return;   /* input buffer full, discard */
  1716. 27041
  1717. 27042   if (++rs->icount == RS_IHIGHWATER && rs->idevready) istop(rs);
  1718. 27043   *rs->ihead = c;
  1719. 27044   if (++rs->ihead == bufend(rs->ibuf)) rs->ihead = rs->ibuf;
  1720. 27045   if (rs->icount == 1) {
  1721. 27046         rs->tty->tty_events = 1;
  1722. 27047         force_timeout();
  1723. 27048   }
  1724. 27049 }
  1725. 27052 /*==========================================================================*
  1726. 27053  *                              line_int                                    *
  1727. 27054  *==========================================================================*/
  1728. 27055 PRIVATE void line_int(rs)
  1729. 27056 register rs232_t *rs;           /* line with line status interrupt */
  1730. 27057 {
  1731. 27058 /* Check for and record errors. */
  1732. 27059
  1733. 27060 #if (MACHINE == IBM_PC)
  1734. 27061   rs->lstatus = in_byte(rs->line_status_port);
  1735. 27062 #else /* MACHINE == ATARI */
  1736. 27063   rs->lstatus = MFP->mf_rsr;
  1737. 27064   MFP->mf_rsr &= R_ENA;
  1738. 27065   rs->pad = MFP->mf_udr;        /* discard char in case of LS_OVERRUN_ERR */
  1739. 27066 #endif /* MACHINE == ATARI */
  1740. 27067   if (rs->lstatus & LS_FRAMING_ERR) ++rs->framing_errors;
  1741. 27068   if (rs->lstatus & LS_OVERRUN_ERR) ++rs->overrun_errors;
  1742. 27069   if (rs->lstatus & LS_PARITY_ERR) ++rs->parity_errors;
  1743. 27070   if (rs->lstatus & LS_BREAK_INTERRUPT) ++rs->break_interrupts;
  1744. 27071 }
  1745. 27074 /*==========================================================================*
  1746. 27075  *                              modem_int                                   *
  1747. 27076  *==========================================================================*/
  1748. 27077 PRIVATE void modem_int(rs)
  1749. 27078 register rs232_t *rs;           /* line with modem interrupt */
  1750. 27079 {
  1751. 27080 /* Get possibly new device-ready status, and clear ODEVREADY if necessary.
  1752. 27081  * If the device just became ready, restart output.
  1753. 27082  */
  1754. 27083
  1755. 27084 #if (MACHINE == ATARI)
  1756. 27085   /* Set active edge interrupt so that next change causes a new interrupt */
  1757. 27086   MFP->mf_aer = (MFP->mf_aer | (IO_SCTS|IO_SDCD)) ^
  1758. 27087                  (MFP->mf_gpip & (IO_SCTS|IO_SDCD));
  1759. 27088 #endif
  1760. 27089
  1761. 27090   if (devhup(rs)) {
  1762. 27091         rs->ostate |= ODEVHUP;
  1763. 27092         rs->tty->tty_events = 1;
  1764. 27093         force_timeout();
  1765. 27094   }
  1766. .Ep 374 src/kernel/rs232.c
  1767. 27095
  1768. 27096   if (!devready(rs))
  1769. 27097         rs->ostate &= ~ODEVREADY;
  1770. 27098   else if (!(rs->ostate & ODEVREADY)) {
  1771. 27099         rs->ostate |= ODEVREADY;
  1772. 27100         if (txready(rs)) out_int(rs);
  1773. 27101   }
  1774. 27102 }
  1775. 27105 /*==========================================================================*
  1776. 27106  *                              out_int                                     *
  1777. 27107  *==========================================================================*/
  1778. 27108 PRIVATE void out_int(rs)
  1779. 27109 register rs232_t *rs;           /* line with output interrupt */
  1780. 27110 {
  1781. 27111 /* If there is output to do and everything is ready, do it (local device is
  1782. 27112  * known ready).
  1783. 27113  * Notify TTY when the buffer goes empty.
  1784. 27114  */
  1785. 27115
  1786. 27116   if (rs->ostate >= (ODEVREADY | OQUEUED | OSWREADY)) {
  1787. 27117         /* Bit test allows ORAW and requires the others. */
  1788. 27118 #if (MACHINE == IBM_PC)
  1789. 27119         out_byte(rs->xmit_port, *rs->otail);
  1790. 27120 #else /* MACHINE == ATARI */
  1791. 27121         MFP->mf_udr = *rs->otail;
  1792. 27122 #endif
  1793. 27123         if (++rs->otail == bufend(rs->obuf)) rs->otail = rs->obuf;
  1794. 27124         if (--rs->ocount == 0) {
  1795. 27125                 rs->ostate ^= (ODONE | OQUEUED);  /* ODONE on, OQUEUED off */
  1796. 27126                 rs->tty->tty_events = 1;
  1797. 27127                 force_timeout();
  1798. 27128         } else
  1799. 27129         if (rs->ocount == RS_OLOWWATER) {       /* running low? */
  1800. 27130                 rs->tty->tty_events = 1;
  1801. 27131                 force_timeout();
  1802. 27132         }
  1803. 27133   }
  1804. 27134 }
  1805. 27135 #endif /* NR_RS_LINES > 0 */
  1806. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1807. src/kernel/sb16_dsp.c    
  1808. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1809. 27200 /* This file contains the driver for a DSP (Digital Sound Processor) on
  1810. 27201  * a SoundBlaster 16 (ASP) soundcard.
  1811. 27202  *
  1812. 27203  * The driver supports the following operations (using message format m2):
  1813. 27204  *
  1814. 27205  *    m_type      DEVICE    PROC_NR     COUNT    POSITION  ADRRESS
  1815. 27206  * ----------------------------------------------------------------
  1816. 27207  * |  DEV_OPEN  | device  | proc nr |         |         |         |
  1817. 27208  * |------------+---------+---------+---------+---------+---------|
  1818. 27209  * |  DEV_CLOSE | device  | proc nr |         |         |         |
  1819. .Op 375 src/kernel/sb16_dsp.c
  1820. 27210  * |------------+---------+---------+---------+---------+---------|
  1821. 27211  * |  DEV_READ  | device  | proc nr |  bytes  |         | buf ptr |
  1822. 27212  * |------------+---------+---------+---------+---------+---------|
  1823. 27213  * |  DEV_WRITE | device  | proc nr |  bytes  |         | buf ptr |
  1824. 27214  * |------------+---------+---------+---------+---------+---------|
  1825. 27215  * |  DEV_IOCTL | device  | proc nr |func code|         | buf ptr |
  1826. 27216  * ----------------------------------------------------------------
  1827. 27217  *
  1828. 27218  * The file contains one entry point:
  1829. 27219  *
  1830. 27220  *   dsp_task:  main entry when system is brought up
  1831. 27221  *
  1832. 27222  *  May 20 1995                 Author: Michel R. Prevenier 
  1833. 27223  */
  1834. 27224
  1835. 27225
  1836. 27226 #include "kernel.h"
  1837. 27227 #include <minix/com.h> 
  1838. 27228 #include <minix/callnr.h> 
  1839. 27229 #include <sys/ioctl.h>
  1840. 27230 #if __minix_vmd
  1841. 27231 #include "proc.h"
  1842. 27232 #include "config.h"
  1843. 27233 #endif
  1844. 27234 #include "sb16.h"
  1845. 27235
  1846. 27236 #if ENABLE_SB_AUDIO
  1847. 27237
  1848. 27238 /* prototypes */
  1849. 27239 FORWARD _PROTOTYPE( void init_buffer, (void));
  1850. 27240 FORWARD _PROTOTYPE( int dsp_init, (void)); 
  1851. 27241 FORWARD _PROTOTYPE( int dsp_handler, (int irq));
  1852. 27242 FORWARD _PROTOTYPE( int dsp_open, (message *m_ptr));
  1853. 27243 FORWARD _PROTOTYPE( int dsp_close, (message *m_ptr));
  1854. 27244 FORWARD _PROTOTYPE( int dsp_ioctl, (message *m_ptr));
  1855. 27245 FORWARD _PROTOTYPE( int dsp_write, (message *m_ptr));
  1856. 27246 FORWARD _PROTOTYPE( int dsp_read, (message *m_ptr));
  1857. 27247 FORWARD _PROTOTYPE( int dsp_reset, (void)); 
  1858. 27248 FORWARD _PROTOTYPE( int dsp_command, (int value));
  1859. 27249 FORWARD _PROTOTYPE( int dsp_set_speed, (unsigned int speed));
  1860. 27250 FORWARD _PROTOTYPE( int dsp_set_size, (unsigned int size));
  1861. 27251 FORWARD _PROTOTYPE( int dsp_set_stereo, (unsigned int stereo));
  1862. 27252 FORWARD _PROTOTYPE( int dsp_set_bits, (unsigned int bits));
  1863. 27253 FORWARD _PROTOTYPE( int dsp_set_sign, (unsigned int sign));
  1864. 27254 FORWARD _PROTOTYPE( void dsp_dma_setup, (phys_bytes address, int count));
  1865. 27255 FORWARD _PROTOTYPE( void dsp_setup, (void));
  1866. 27256
  1867. 27257 /* globals */
  1868. 27258 #if __minix_vmd
  1869. 27259 PRIVATE int DspTasknr = ANY;
  1870. 27260 #endif
  1871. 27261 PRIVATE int DspVersion[2]; 
  1872. 27262 PRIVATE unsigned int DspStereo = DEFAULT_STEREO;
  1873. 27263 PRIVATE unsigned int DspSpeed = DEFAULT_SPEED; 
  1874. 27264 PRIVATE unsigned int DspBits = DEFAULT_BITS;
  1875. 27265 PRIVATE unsigned int DspSign = DEFAULT_SIGN;
  1876. 27266 PRIVATE unsigned int DspFragmentSize = DSP_MAX_FRAGMENT_SIZE;
  1877. 27267 PRIVATE int DspAvail = 0;
  1878. 27268 PRIVATE int DspBusy = 0;
  1879. 27269 PRIVATE int DmaBusy = 0;
  1880. .Ep 376 src/kernel/sb16_dsp.c
  1881. 27270 PRIVATE int DmaDone = 1;
  1882. 27271 PRIVATE int DmaMode = 0;
  1883. 27272
  1884. 27273 PRIVATE char DmaBuffer[(long)2 * DMA_SIZE];
  1885. 27274 PRIVATE char *DmaPtr;
  1886. 27275 PRIVATE phys_bytes DmaPhys;
  1887. 27276
  1888. 27277
  1889. 27278 /*=========================================================================*
  1890. 27279  *                              dsp_task                                   *
  1891. 27280  *=========================================================================*/
  1892. 27281 PUBLIC void dsp_task()
  1893. 27282 {
  1894. 27283   message mess;
  1895. 27284   int err, caller, proc_nr;
  1896. 27285
  1897. 27286 #if __minix_vmd
  1898. 27287   DspTasknr = proc_number(proc_ptr);
  1899. 27288 #endif
  1900. 27289
  1901. 27290   /* initialize the DMA buffer */
  1902. 27291   init_buffer();
  1903. 27292
  1904. 27293   /* Here is the main loop of the sound task. It waits for a message, carries
  1905. 27294    * it out, and sends a reply.
  1906. 27295    */
  1907. 27296   while (TRUE) 
  1908. 27297   {
  1909. 27298         receive(ANY, &mess);
  1910. 27299
  1911. 27300         caller = mess.m_source;
  1912. 27301         proc_nr = mess.PROC_NR;
  1913. 27302
  1914. 27303         switch (caller) 
  1915. 27304         {
  1916. 27305           case HARDWARE:
  1917. 27306                 /* Leftover interrupt. */
  1918. 27307                 continue;
  1919. 27308           case FS_PROC_NR:
  1920. 27309                 /* The only legitimate caller. */
  1921. 27310                 break;
  1922. 27311           default:
  1923. 27312                 printf("sb16: got message from %dn", caller);
  1924. 27313                 continue;
  1925. 27314         }
  1926. 27315
  1927. 27316         /* Now carry out the work. */
  1928. 27317         switch(mess.m_type) 
  1929. 27318         {
  1930. 27319             case DEV_OPEN:      err = dsp_open(&mess);break;    
  1931. 27320             case DEV_CLOSE:     err = dsp_close(&mess);break; 
  1932. 27321             case DEV_IOCTL:     err = dsp_ioctl(&mess);break;
  1933. 27322             case DEV_READ:      err = dsp_read(&mess);break;  
  1934. 27323             case DEV_WRITE:     err = dsp_write(&mess);break;
  1935. 27324             default:            err = EINVAL;break;
  1936. 27325         }
  1937. 27326
  1938. 27327         /* Finally, prepare and send the reply message. */
  1939. 27328         mess.m_type = TASK_REPLY;
  1940. 27329         mess.REP_PROC_NR = proc_nr;
  1941. .Op 377 src/kernel/sb16_dsp.c
  1942. 27330
  1943. 27331         mess.REP_STATUS = err;  /* #bytes transfered or error code */
  1944. 27332         send(caller, &mess);    /* send reply to caller */
  1945. 27333   }
  1946. 27334 }
  1947. 27337 /*===========================================================================*
  1948. 27338  *                              init_buffer                                  *
  1949. 27339  *===========================================================================*/
  1950. 27340 PRIVATE void init_buffer()
  1951. 27341 {
  1952. 27342 /* Select a buffer that can safely be used for dma transfers.  
  1953. 27343  * Its absolute address is 'DmaPhys', the normal address is 'DmaPtr'.
  1954. 27344  */
  1955. 27345
  1956. 27346   DmaPtr = DmaBuffer;
  1957. 27347   DmaPhys = vir2phys(DmaBuffer);
  1958. 27348
  1959. 27349   if (dma_bytes_left(DmaPhys) < DMA_SIZE) {
  1960. 27350         /* First half of buffer crosses a 64K boundary, can't DMA into that */
  1961. 27351         DmaPtr += DMA_SIZE;
  1962. 27352         DmaPhys += DMA_SIZE;
  1963. 27353   }
  1964. 27354 }
  1965. 27357 /*=========================================================================*
  1966. 27358  *                              dsp_open                                   *    
  1967. 27359  *=========================================================================*/
  1968. 27360 PRIVATE int dsp_open(m_ptr)
  1969. 27361 message *m_ptr;
  1970. 27362 {
  1971. 27363
  1972. 27364 #if SB_DEBUG
  1973. 27365   printf("sb16_openn");
  1974. 27366 #endif
  1975. 27367
  1976. 27368   /* try to detect SoundBlaster card */
  1977. 27369   if (!DspAvail && dsp_init() != OK) return EIO;
  1978. 27370
  1979. 27371   /* Only one open at a time with soundcards */
  1980. 27372   if (DspBusy) return EBUSY;
  1981. 27373  
  1982. 27374   /* Start with a clean DSP */
  1983. 27375   if (dsp_reset() != OK) return EIO;
  1984. 27376
  1985. 27377   /* Setup default values */
  1986. 27378   DspStereo = DEFAULT_STEREO;
  1987. 27379   DspSpeed = DEFAULT_SPEED;
  1988. 27380   DspBits = DEFAULT_BITS;
  1989. 27381   DspSign = DEFAULT_SIGN;
  1990. 27382   DspFragmentSize = DMA_SIZE;
  1991. 27383   
  1992. 27384   DspBusy = 1;
  1993. 27385   DmaBusy = 0;
  1994. 27386
  1995. 27387   return OK;
  1996. 27388 }
  1997. .Ep 378 src/kernel/sb16_dsp.c
  1998. 27391 /*=========================================================================*
  1999. 27392  *                              dsp_close                                  *    
  2000. 27393  *=========================================================================*/
  2001. 27394 PRIVATE int dsp_close(m_ptr)
  2002. 27395 message *m_ptr;
  2003. 27396 {
  2004. 27397
  2005. 27398 #if SB_DEBUG
  2006. 27399   printf("dsp_closen");
  2007. 27400 #endif
  2008. 27401
  2009. 27402   DspBusy = 0;                  /* soundcard available again */
  2010. 27403   DmaBusy = 0;
  2011. 27404
  2012. 27405   return OK;
  2013. 27406 }
  2014. 27409 /*=========================================================================*
  2015. 27410  *                              dsp_ioctl                                  *    
  2016. 27411  *=========================================================================*/
  2017. 27412 PRIVATE int dsp_ioctl(m_ptr)
  2018. 27413 message *m_ptr;
  2019. 27414 {
  2020. 27415   int status;
  2021. 27416   phys_bytes user_phys;
  2022. 27417   unsigned int val;
  2023. 27418
  2024. 27419   /* Cannot change parameters during play or recording */
  2025. 27420   if (DmaBusy) return EBUSY;
  2026. 27421
  2027. 27422   /* Get user data */
  2028. 27423   if (m_ptr->REQUEST != DSPIORESET)
  2029. 27424   {
  2030. 27425     user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, 
  2031. 27426                                                    sizeof(unsigned int));
  2032. 27427     if (user_phys == 0) return(EFAULT);
  2033. 27428     phys_copy(user_phys, vir2phys(&val), (phys_bytes) sizeof(val));
  2034. 27429   }
  2035. 27430
  2036. 27431 #if SB_DEBUG
  2037. 27432   printf("dsp_ioctl: got ioctl %d, argument: %dn", m_ptr->REQUEST, val);
  2038. 27433 #endif
  2039. 27434
  2040. 27435   switch(m_ptr->REQUEST)
  2041. 27436   {
  2042. 27437     case DSPIORATE:     status = dsp_set_speed(val);break;
  2043. 27438     case DSPIOSTEREO:   status = dsp_set_stereo(val);break;
  2044. 27439     case DSPIOBITS:     status = dsp_set_bits(val);break;
  2045. 27440     case DSPIOSIZE:     status = dsp_set_size(val);break;
  2046. 27441     case DSPIOSIGN:     status = dsp_set_sign(val);break;
  2047. 27442     case DSPIOMAX:      { 
  2048. 27443                            val = DMA_SIZE;
  2049. 27444                            phys_copy(vir2phys(&val), user_phys, 
  2050. 27445                                            (phys_bytes) sizeof(val));
  2051. 27446                            status = OK;
  2052. 27447                         };break;
  2053. 27448     case DSPIORESET:    status = dsp_reset();break;
  2054. 27449     default:            status = ENOTTY;break;
  2055. .Op 379 src/kernel/sb16_dsp.c
  2056. 27450   }
  2057. 27451
  2058. 27452   return status;
  2059. 27453 }
  2060. 27456 /*=========================================================================*
  2061. 27457  *                              dsp_init                                   *
  2062. 27458  *=========================================================================*/
  2063. 27459 PRIVATE int dsp_init()
  2064. 27460 {
  2065. 27461   int i;
  2066. 27462
  2067. 27463   if (dsp_reset () != OK) 
  2068. 27464   { 
  2069. 27465     printf("sb16: No SoundBlaster card detectedn");
  2070. 27466     return -1;
  2071. 27467   }
  2072. 27468
  2073. 27469   DspVersion[0] = DspVersion[1] = 0;
  2074. 27470   dsp_command(DSP_GET_VERSION); /* Get DSP version bytes */
  2075. 27471
  2076. 27472   for (i = 1000; i; i--)
  2077. 27473   {
  2078. 27474     if (in_byte (DSP_DATA_AVL) & 0x80)
  2079. 27475     {           
  2080. 27476       if (DspVersion[0] == 0)
  2081. 27477         DspVersion[0] = in_byte (DSP_READ);
  2082. 27478       else
  2083. 27479       {
  2084. 27480         DspVersion[1] = in_byte (DSP_READ);
  2085. 27481         break;
  2086. 27482       }
  2087. 27483     }
  2088. 27484   }
  2089. 27485
  2090. 27486   if (DspVersion[0] < 4)
  2091. 27487   {
  2092. 27488     printf("sb16: No SoundBlaster 16 compatible card detectedn");
  2093. 27489     return -1;
  2094. 27490   }
  2095. 27491   else
  2096. 27492     printf ("sb16: SoundBlaster DSP version %d.%d detectedn", 
  2097. 27493           DspVersion[0], DspVersion[1]);
  2098. 27494
  2099. 27495   /* set IRQ and DMA channels */
  2100. 27496   mixer_set(MIXER_SET_IRQ, (1 << (SB_IRQ / 2 - 1)));
  2101. 27497   mixer_set(MIXER_SET_DMA, (1 << SB_DMA_8 | 1 << SB_DMA_16)); 
  2102. 27498
  2103. 27499   /* register interrupt vector and enable irq */
  2104. 27500   put_irq_handler(SB_IRQ, dsp_handler);
  2105. 27501   enable_irq(SB_IRQ);
  2106. 27502
  2107. 27503   DspAvail = 1;
  2108. 27504   return OK;
  2109. 27505 }
  2110. 27508 /*=========================================================================*
  2111. 27509  *                              dsp_handler                                *
  2112. .Ep 380 src/kernel/sb16_dsp.c
  2113. 27510  *=========================================================================*/
  2114. 27511 PRIVATE int dsp_handler(irq)
  2115. 27512 int irq;
  2116. 27513 {
  2117. 27514
  2118. 27515 #if SB_DEBUG2
  2119. 27516   printf("SoundBlaster interrupt %dn", irq);
  2120. 27517 #endif 
  2121. 27518
  2122. 27519   if (DmaDone)     /* Dma transfer is done */
  2123. 27520   {
  2124. 27521     /* Send DSP command to stop dma */
  2125. 27522     dsp_command((DspBits == 8 ? DSP_CMD_DMA8HALT : DSP_CMD_DMA16HALT));
  2126. 27523
  2127. 27524     DmaBusy = 0;  /* Dma available again */
  2128. 27525   }
  2129. 27526
  2130. 27527   /* Send interrupt to audio task and enable again */
  2131. 27528 #if __minix_vmd
  2132. 27529   interrupt(DspTasknr);
  2133. 27530 #else
  2134. 27531   interrupt(AUDIO);
  2135. 27532 #endif
  2136. 27533
  2137. 27534   /* Acknowledge the interrupt on the DSP */
  2138. 27535   (void) in_byte((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL));
  2139. 27536
  2140. 27537   return 1;
  2141. 27538 }
  2142. 27541 /*=========================================================================*
  2143. 27542  *                              dsp_command                                *
  2144. 27543  *=========================================================================*/
  2145. 27544 PRIVATE int dsp_command(value)
  2146. 27545 int value;
  2147. 27546 {
  2148. 27547   int             i;
  2149. 27548
  2150. 27549   for (i = 0; i < SB_TIMEOUT; i++)
  2151. 27550   {
  2152. 27551     if ((in_byte (DSP_STATUS) & 0x80) == 0)
  2153. 27552     {
  2154. 27553       out_byte (DSP_COMMAND, value);
  2155. 27554       return OK;
  2156. 27555     }
  2157. 27556   }
  2158. 27557
  2159. 27558   printf ("sb16: SoundBlaster: DSP Command(%x) timeoutn", value);
  2160. 27559   return -1;
  2161. 27560 }
  2162. 27563 /*=========================================================================*
  2163. 27564  *                              dsp_reset                                  *
  2164. 27565  *=========================================================================*/
  2165. 27566 PRIVATE int dsp_reset(void)
  2166. 27567 {
  2167. 27568   int i;
  2168. 27569
  2169. .Op 381 src/kernel/sb16_dsp.c
  2170. 27570   out_byte (DSP_RESET, 1);
  2171. 27571   for(i =0; i<1000; i++); /* wait a while */
  2172. 27572   out_byte (DSP_RESET, 0);
  2173. 27573
  2174. 27574   for (i = 0; i < 1000 && !(in_byte (DSP_DATA_AVL) & 0x80); i++);       
  2175. 27575
  2176. 27576   if (in_byte (DSP_READ) != 0xAA) return EIO; /* No SoundBlaster */                     
  2177. 27577
  2178. 27578   DmaBusy = 0;
  2179. 27579   DmaDone = 1;
  2180. 27580
  2181. 27581   return OK;
  2182. 27582 }
  2183. 27585 /*=========================================================================*
  2184. 27586  *                              dsp_set_speed                              *
  2185. 27587  *=========================================================================*/
  2186. 27588 static int dsp_set_speed(speed)
  2187. 27589 unsigned int speed;
  2188. 27590 {
  2189. 27591 #if SB_DEBUG
  2190. 27592   printf("sb16: setting speed to %u, stereo = %dn", speed, DspStereo);
  2191. 27593 #endif
  2192. 27594
  2193. 27595   if (speed < DSP_MIN_SPEED || speed > DSP_MAX_SPEED)
  2194. 27596     return EPERM;
  2195. 27597
  2196. 27598   /* Soundblaster 16 can be programmed with real sample rates
  2197. 27599    * instead of time constants
  2198. 27600    *
  2199. 27601    * Since you cannot sample and play at the same time
  2200. 27602    * we set in- and output rate to the same value 
  2201. 27603    */
  2202. 27604
  2203. 27605    lock();                                      /* disable interrupts */
  2204. 27606    dsp_command(DSP_INPUT_RATE);                 /* set input rate */
  2205. 27607    dsp_command(speed >> 8);                     /* high byte of speed */
  2206. 27608    dsp_command(speed);                          /* low byte of speed */
  2207. 27609    dsp_command(DSP_OUTPUT_RATE);                /* same for output rate */
  2208. 27610    dsp_command(speed >> 8);     
  2209. 27611    dsp_command(speed); 
  2210. 27612    unlock();                                    /* enable interrupts */
  2211. 27613
  2212. 27614    DspSpeed = speed;
  2213. 27615
  2214. 27616    return OK;
  2215. 27617 }
  2216. 27620 /*=========================================================================*
  2217. 27621  *                              dsp_set_stereo                             *
  2218. 27622  *=========================================================================*/
  2219. 27623 static int dsp_set_stereo(stereo)
  2220. 27624 unsigned int stereo;
  2221. 27625 {
  2222. 27626   if (stereo) 
  2223. 27627     DspStereo = 1;
  2224. 27628   else 
  2225. 27629     DspStereo = 0;
  2226. .Ep 382 src/kernel/sb16_dsp.c
  2227. 27630
  2228. 27631   return OK;
  2229. 27632 }
  2230. 27635 /*=========================================================================*
  2231. 27636  *                              dsp_set_bits                               *
  2232. 27637  *=========================================================================*/
  2233. 27638 static int dsp_set_bits(bits)
  2234. 27639 unsigned int bits;
  2235. 27640 {
  2236. 27641   /* Sanity checks */
  2237. 27642   if (bits != 8 && bits != 16) return EINVAL;
  2238. 27643
  2239. 27644   DspBits = bits; 
  2240. 27645
  2241. 27646   return OK;
  2242. 27647 }
  2243. 27650 /*=========================================================================*
  2244. 27651  *                              dsp_set_size                               *
  2245. 27652  *=========================================================================*/
  2246. 27653 static int dsp_set_size(size)
  2247. 27654 unsigned int size;
  2248. 27655 {
  2249. 27656
  2250. 27657 #if SB_DEBUG
  2251. 27658   printf("sb16: set fragment size to %un", size);
  2252. 27659 #endif
  2253. 27660  
  2254. 27661   /* Sanity checks */
  2255. 27662   if (size < DSP_MIN_FRAGMENT_SIZE || 
  2256. 27663       size > DSP_MAX_FRAGMENT_SIZE || 
  2257. 27664       size % 2 != 0)
  2258. 27665     return EINVAL;
  2259. 27666
  2260. 27667   DspFragmentSize = size; 
  2261. 27668
  2262. 27669   return OK;
  2263. 27670 }
  2264. 27673 /*=========================================================================*
  2265. 27674  *                              dsp_set_sign                               *
  2266. 27675  *=========================================================================*/
  2267. 27676 static int dsp_set_sign(sign)
  2268. 27677 unsigned int sign;
  2269. 27678 {
  2270. 27679
  2271. 27680 #if SB_DEBUG
  2272. 27681   printf("sb16: set sign to %un", sign);
  2273. 27682 #endif
  2274. 27683  
  2275. 27684   DspSign = (sign > 0 ? 1 : 0); 
  2276. 27685
  2277. 27686   return OK;
  2278. 27687 }
  2279. .Op 383 src/kernel/sb16_dsp.c
  2280. 27690 /*===========================================================================*
  2281. 27691  *                              dsp_dma_setup                                *
  2282. 27692  *===========================================================================*/
  2283. 27693 PRIVATE void dsp_dma_setup(address, count)
  2284. 27694 phys_bytes address;
  2285. 27695 int count;
  2286. 27696
  2287. 27697 {
  2288. 27698 #if SB_DEBUG
  2289. 27699   printf("Setting up %d bit DMAn", DspBits);
  2290. 27700 #endif
  2291. 27701
  2292. 27702   if (DspBits == 8)    /* 8 bit sound */
  2293. 27703   {
  2294. 27704     count--;     
  2295. 27705
  2296. 27706     lock();
  2297. 27707     out_byte(DMA8_MASK, SB_DMA_8 | 0x04);      /* Disable DMA channel */
  2298. 27708     out_byte(DMA8_CLEAR, 0x00);                /* Clear flip flop */
  2299. 27709
  2300. 27710     /* set DMA mode */
  2301. 27711     out_byte(DMA8_MODE, 
  2302. 27712                (DmaMode == DEV_WRITE ? DMA8_AUTO_PLAY : DMA8_AUTO_REC)); 
  2303. 27713
  2304. 27714     out_byte(DMA8_ADDR, address >>  0);        /* Low_byte of address */
  2305. 27715     out_byte(DMA8_ADDR, address >>  8);        /* High byte of address */
  2306. 27716     out_byte(DMA8_PAGE, address >> 16);        /* 64K page number */
  2307. 27717     out_byte(DMA8_COUNT, count >> 0);          /* Low byte of count */
  2308. 27718     out_byte(DMA8_COUNT, count >> 8);          /* High byte of count */
  2309. 27719     out_byte(DMA8_MASK, SB_DMA_8);             /* Enable DMA channel */
  2310. 27720     unlock();
  2311. 27721   }
  2312. 27722   else  /* 16 bit sound */
  2313. 27723   {
  2314. 27724     count-= 2;
  2315. 27725
  2316. 27726     lock();
  2317. 27727     out_byte(DMA16_MASK, (SB_DMA_16 & 3) | 0x04); /* Disable DMA channel */
  2318. 27728     out_byte(DMA16_CLEAR, 0x00);                  /* Clear flip flop */
  2319. 27729
  2320. 27730     /* Set dma mode */
  2321. 27731     out_byte(DMA16_MODE, 
  2322. 27732                (DmaMode == DEV_WRITE ? DMA16_AUTO_PLAY : DMA16_AUTO_REC));        
  2323. 27733
  2324. 27734     out_byte(DMA16_ADDR, (address >> 1) & 0xFF);  /* Low_byte of address */
  2325. 27735     out_byte(DMA16_ADDR, (address >> 9) & 0xFF);  /* High byte of address */
  2326. 27736     out_byte(DMA16_PAGE, (address >> 16) & 0xFE); /* 128K page number */
  2327. 27737     out_byte(DMA16_COUNT, count >> 1);            /* Low byte of count */
  2328. 27738     out_byte(DMA16_COUNT, count >> 9);            /* High byte of count */
  2329. 27739     out_byte(DMA16_MASK, SB_DMA_16 & 3);          /* Enable DMA channel */
  2330. 27740     unlock();
  2331. 27741   }
  2332. 27742 }
  2333. 27745 /*===========================================================================*
  2334. 27746  *                              dsp_setup                                    *
  2335. 27747  *===========================================================================*/
  2336. 27748 PRIVATE void dsp_setup()
  2337. 27749 { 
  2338. .Ep 384 src/kernel/sb16_dsp.c
  2339. 27750   /* Set current sample speed */
  2340. 27751   dsp_set_speed(DspSpeed);
  2341. 27752
  2342. 27753   /* Put the speaker on */
  2343. 27754    if (DmaMode == DEV_WRITE)
  2344. 27755    {
  2345. 27756      dsp_command (DSP_CMD_SPKON); /* put speaker on */
  2346. 27757
  2347. 27758       /* Program DSP with dma mode */
  2348. 27759       dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_OUT : DSP_CMD_16BITAUTO_OUT));     
  2349. 27760    }
  2350. 27761    else
  2351. 27762    {
  2352. 27763      dsp_command (DSP_CMD_SPKOFF); /* put speaker off */
  2353. 27764
  2354. 27765      /* Program DSP with dma mode */
  2355. 27766      dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_IN : DSP_CMD_16BITAUTO_IN));     
  2356. 27767    }
  2357. 27768
  2358. 27769   /* Program DSP with transfer mode */
  2359. 27770   if (!DspSign)
  2360. 27771     dsp_command((DspStereo == 1 ? DSP_MODE_STEREO_US : DSP_MODE_MONO_US));
  2361. 27772   else
  2362. 27773     dsp_command((DspStereo == 1 ? DSP_MODE_STEREO_S : DSP_MODE_MONO_S));
  2363. 27774
  2364. 27775   /* Give length of fragment to DSP */
  2365. 27776   if (DspBits == 8) /* 8 bit transfer */
  2366. 27777   {
  2367. 27778     /* #bytes - 1 */
  2368. 27779     dsp_command((DspFragmentSize - 1) >> 0); 
  2369. 27780     dsp_command((DspFragmentSize - 1) >> 8);
  2370. 27781   }
  2371. 27782   else              /* 16 bit transfer */
  2372. 27783   {
  2373. 27784     /* #words - 1 */
  2374. 27785     dsp_command((DspFragmentSize - 1) >> 1);
  2375. 27786     dsp_command((DspFragmentSize - 1) >> 9);
  2376. 27787   }
  2377. 27788 }
  2378. 27789       
  2379. 27790
  2380. 27791 /*===========================================================================*
  2381. 27792  *                              dsp_write                                    *
  2382. 27793  *===========================================================================*/
  2383. 27794 PRIVATE int dsp_write(m_ptr)
  2384. 27795 message *m_ptr;
  2385. 27796 {
  2386. 27797   phys_bytes user_phys;
  2387. 27798   message mess;
  2388. 27799
  2389. 27800   if (m_ptr->COUNT != DspFragmentSize) return EINVAL;
  2390. 27801
  2391. 27802   /* From this user address */
  2392. 27803   user_phys = numap(m_ptr->PROC_NR, (vir_bytes)m_ptr->ADDRESS, DspFragmentSize);
  2393. 27804   if (user_phys == 0) return EINVAL;
  2394. 27805
  2395. 27806   if (DmaBusy)    /* Dma already started */
  2396. 27807   {
  2397. 27808     if (DmaMode != m_ptr->m_type) return EBUSY;
  2398. 27809
  2399. .Op 385 src/kernel/sb16_dsp.c
  2400. 27810     DmaDone = 0;  /* No, we're not done yet */
  2401. 27811
  2402. 27812     /* Wait for next block to become free */
  2403. 27813     receive(HARDWARE, &mess); 
  2404. 27814
  2405. 27815     /* Copy first block to dma buffer */
  2406. 27816     phys_copy(user_phys, DmaPhys, (phys_bytes) DspFragmentSize);
  2407. 27817
  2408. 27818   }
  2409. 27819   else /* A new dma transfer has started */    
  2410. 27820   {
  2411. 27821     DmaMode = DEV_WRITE;           /* Dma mode is writing */
  2412. 27822
  2413. 27823     /* Copy fragment to dma buffer */    
  2414. 27824     phys_copy(user_phys, DmaPhys, (phys_bytes) DspFragmentSize);
  2415. 27825
  2416. 27826     /* Set up the dma chip */
  2417. 27827     dsp_dma_setup(DmaPhys, DspFragmentSize);  
  2418. 27828
  2419. 27829     /* Set up the DSP */
  2420. 27830     dsp_setup();
  2421. 27831       
  2422. 27832     DmaBusy = 1;         /* Dma is busy */
  2423. 27833   }
  2424. 27834
  2425. 27835   DmaDone = 1;            /* dma done for now */
  2426. 27836
  2427. 27837   return(DspFragmentSize);
  2428. 27838 }
  2429. 27841 /*===========================================================================*
  2430. 27842  *                              dsp_read                                     *
  2431. 27843  *===========================================================================*/
  2432. 27844 PRIVATE int dsp_read(m_ptr)
  2433. 27845 message *m_ptr;
  2434. 27846 {
  2435. 27847   phys_bytes user_phys;
  2436. 27848   message mess;
  2437. 27849  
  2438. 27850   if (m_ptr->COUNT != DspFragmentSize) return EINVAL;
  2439. 27851
  2440. 27852   /* To this user address */
  2441. 27853   user_phys = numap(m_ptr->PROC_NR, (vir_bytes)m_ptr->ADDRESS, DspFragmentSize);
  2442. 27854   if (user_phys == 0) return EINVAL;
  2443. 27855
  2444. 27856   if (DmaBusy)     /* Dma already started */
  2445. 27857   {
  2446. 27858     if (DmaMode != m_ptr->m_type) return EBUSY;
  2447. 27859
  2448. 27860     DmaDone = 0;   /* No, we're not done yet */ 
  2449. 27861
  2450. 27862     /* Wait for a full dma buffer */
  2451. 27863     receive(HARDWARE, &mess); 
  2452. 27864
  2453. 27865     /* Copy the buffer */
  2454. 27866     phys_copy(DmaPhys, user_phys, (phys_bytes) DspFragmentSize);
  2455. 27867   }
  2456. 27868   else  /* A new dma transfer has started */
  2457. 27869   {
  2458. .Ep 386 src/kernel/sb16_dsp.c
  2459. 27870     DmaMode = DEV_READ;                /* Dma mode is reading */
  2460. 27871
  2461. 27872     /* Set up the dma chip */
  2462. 27873     dsp_dma_setup(DmaPhys, DspFragmentSize);  
  2463. 27874  
  2464. 27875     /* Set up the DSP */
  2465. 27876     dsp_setup();
  2466. 27877
  2467. 27878     DmaBusy = 1;       /* Dma has started */
  2468. 27879     DmaDone = 0;       /* Dma not done */
  2469. 27880
  2470. 27881     /* Wait for dma to finish with first block */
  2471. 27882     receive(HARDWARE, &mess);
  2472. 27883
  2473. 27884     /* Copy dma buffer to user */
  2474. 27885     phys_copy(DmaPhys, user_phys, (phys_bytes) DspFragmentSize);
  2475. 27886   }
  2476. 27887
  2477. 27888   DmaDone = 1;   /* dma done for now */
  2478. 27889
  2479. 27890   return(DspFragmentSize);
  2480. 27891 }
  2481. 27892 #endif /* ENABLE_AUDIO */
  2482. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2483. src/kernel/sb16_mixer.c    
  2484. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2485. 27900 /* This file contains the driver for the mixer on
  2486. 27901  * a SoundBlaster 16 (ASP) soundcard.
  2487. 27902  *
  2488. 27903  * The driver supports the following operations (using message format m2):
  2489. 27904  *
  2490. 27905  *    m_type      DEVICE    PROC_NR     COUNT    POSITION  ADRRESS
  2491. 27906  * ----------------------------------------------------------------
  2492. 27907  * |  DEV_OPEN  | device  | proc nr |         |         |         |
  2493. 27908  * |------------+---------+---------+---------+---------+---------|
  2494. 27909  * |  DEV_CLOSE | device  | proc nr |         |         |         |
  2495. 27910  * |------------+---------+---------+---------+---------+---------|
  2496. 27911  * |  DEV_IOCTL | device  | proc nr |func code|         | buf_ptr |
  2497. 27912  * ----------------------------------------------------------------
  2498. 27913  *
  2499. 27914  * The file contains one entry point:
  2500. 27915  *
  2501. 27916  *   mixer_task:  main entry when system is brought up
  2502. 27917  *
  2503. 27918  *  May 20 1995                 Author: Michel R. Prevenier 
  2504. 27919  */
  2505. 27920
  2506. 27921
  2507. 27922 #include "kernel.h"
  2508. 27923 #include <minix/com.h> 
  2509. 27924 #include <minix/callnr.h> 
  2510. 27925 #include <sys/ioctl.h>
  2511. 27926 #include <minix/sound.h>
  2512. 27927 #if __minix_vmd
  2513. 27928 #include "config.h"
  2514. 27929 #endif
  2515. .Op 387 src/kernel/sb16_mixer.c
  2516. 27930 #include "sb16.h"
  2517. 27931
  2518. 27932 #if ENABLE_SB_AUDIO
  2519. 27933
  2520. 27934 /* Function prototypes */
  2521. 27935 FORWARD _PROTOTYPE( int mixer_init, (void)); 
  2522. 27936 FORWARD _PROTOTYPE( int mixer_open, (message *m_ptr));
  2523. 27937 FORWARD _PROTOTYPE( int mixer_close, (message *m_ptr));
  2524. 27938 FORWARD _PROTOTYPE( int mixer_ioctl, (message *m_ptr));
  2525. 27939 FORWARD _PROTOTYPE( int mixer_get, (int reg));
  2526. 27940 FORWARD _PROTOTYPE( int get_set_volume, (message *m_ptr, int flag));
  2527. 27941 FORWARD _PROTOTYPE( int get_set_input, (message *m_ptr, int flag, int channel));
  2528. 27942 FORWARD _PROTOTYPE( int get_set_output, (message *m_ptr, int flag));
  2529. 27943
  2530. 27944 PRIVATE int mixer_avail = 0;    /* Mixer exists? */
  2531. 27945
  2532. 27946
  2533. 27947 /*=========================================================================*
  2534. 27948  *                              mixer_task                                 *
  2535. 27949  *=========================================================================*/
  2536. 27950 PUBLIC void mixer_task()
  2537. 27951 {
  2538. 27952   message mess;
  2539. 27953   int err, caller, proc_nr;
  2540. 27954
  2541. 27955   /* Here is the main loop of the mixer task. It waits for a message, carries
  2542. 27956    * it out, and sends a reply.
  2543. 27957    */
  2544. 27958   while (TRUE) 
  2545. 27959   {
  2546. 27960         receive(ANY, &mess);
  2547. 27961
  2548. 27962         caller = mess.m_source;
  2549. 27963         proc_nr = mess.PROC_NR;
  2550. 27964
  2551. 27965         switch (caller) 
  2552. 27966         {
  2553. 27967           case HARDWARE:
  2554. 27968                 /* Leftover interrupt. */
  2555. 27969                 continue;
  2556. 27970           case FS_PROC_NR:
  2557. 27971                 /* The only legitimate caller. */
  2558. 27972                 break;
  2559. 27973           default:
  2560. 27974                 printf("sb16: got message from %dn", caller);
  2561. 27975                 continue;
  2562. 27976         }
  2563. 27977
  2564. 27978         /* Now carry out the work. */
  2565. 27979         switch(mess.m_type) 
  2566. 27980         {
  2567. 27981             case DEV_OPEN:      err = mixer_open(&mess);break;  
  2568. 27982             case DEV_CLOSE:     err = mixer_close(&mess);break; 
  2569. 27983             case DEV_IOCTL:     err = mixer_ioctl(&mess);break;
  2570. 27984             default:            err = EINVAL;break;
  2571. 27985         }
  2572. 27986
  2573. 27987         /* Finally, prepare and send the reply message. */
  2574. 27988         mess.m_type = TASK_REPLY;
  2575. 27989         mess.REP_PROC_NR = proc_nr;
  2576. .Ep 388 src/kernel/sb16_mixer.c
  2577. 27990
  2578. 27991         mess.REP_STATUS = err;  /* error code */
  2579. 27992         send(caller, &mess);    /* send reply to caller */
  2580. 27993   }
  2581. 27994 }
  2582. 27997 /*=========================================================================*
  2583. 27998  *                              mixer_open                                 *    
  2584. 27999  *=========================================================================*/
  2585. 28000 PRIVATE int mixer_open(m_ptr)
  2586. 28001 message *m_ptr;
  2587. 28002 {
  2588. 28003
  2589. 28004 #if SB_DEBUG
  2590. 28005   printf("mixer_openn");
  2591. 28006 #endif
  2592. 28007
  2593. 28008   /* try to detect the mixer type */
  2594. 28009   if (!mixer_avail && !mixer_init() != OK) return EIO;
  2595. 28010
  2596. 28011   return OK;
  2597. 28012 }
  2598. 28015 /*=========================================================================*
  2599. 28016  *                              mixer_close                                *    
  2600. 28017  *=========================================================================*/
  2601. 28018 PRIVATE int mixer_close(m_ptr)
  2602. 28019 message *m_ptr;
  2603. 28020 {
  2604. 28021
  2605. 28022 #if SB_DEBUG
  2606. 28023   printf("mixer_closen");
  2607. 28024 #endif
  2608. 28025
  2609. 28026   return OK;
  2610. 28027 }
  2611. 28030 /*=========================================================================*
  2612. 28031  *                              mixer_ioctl                                *    
  2613. 28032  *=========================================================================*/
  2614. 28033 PRIVATE int mixer_ioctl(m_ptr)
  2615. 28034 message *m_ptr;
  2616. 28035 {
  2617. 28036   int status;
  2618. 28037
  2619. 28038 #if SB_DEBUG
  2620. 28039   printf("mixer: got ioctl %dn", m_ptr->REQUEST);
  2621. 28040 #endif
  2622. 28041
  2623. 28042
  2624. 28043   switch(m_ptr->REQUEST)
  2625. 28044   {
  2626. 28045     case MIXIOGETVOLUME:      status = get_set_volume(m_ptr, 0);break;
  2627. 28046     case MIXIOSETVOLUME:      status = get_set_volume(m_ptr, 1);break;
  2628. 28047     case MIXIOGETINPUTLEFT:   status = get_set_input(m_ptr, 0, 0);break;
  2629. 28048     case MIXIOGETINPUTRIGHT:  status = get_set_input(m_ptr, 0, 1);break;
  2630. 28049     case MIXIOGETOUTPUT:      status = get_set_output(m_ptr, 0);break;
  2631. .Op 389 src/kernel/sb16_mixer.c
  2632. 28050     case MIXIOSETINPUTLEFT:   status = get_set_input(m_ptr, 1, 0);break;
  2633. 28051     case MIXIOSETINPUTRIGHT:  status = get_set_input(m_ptr, 1, 1);break;
  2634. 28052     case MIXIOSETOUTPUT:      status = get_set_output(m_ptr, 1);break;
  2635. 28053     default:                  status = ENOTTY;
  2636. 28054   }
  2637. 28055
  2638. 28056   return status;
  2639. 28057 }
  2640. 28060 /*=========================================================================*
  2641. 28061  *                              mixer_init                                 *
  2642. 28062  *=========================================================================*/
  2643. 28063 PRIVATE int mixer_init()
  2644. 28064 {
  2645. 28065   /* Try to detect the mixer by writing to MIXER_DAC_LEVEL if the
  2646. 28066    * value written can be read back the mixer is there
  2647. 28067    */
  2648. 28068
  2649. 28069   mixer_set(MIXER_DAC_LEVEL, 0x10);       /* write something to it */
  2650. 28070   if (mixer_get(MIXER_DAC_LEVEL) != 0x10)
  2651. 28071   {
  2652. 28072     printf("sb16: Mixer not detectedn");
  2653. 28073     return EIO;
  2654. 28074   }
  2655. 28075
  2656. 28076   /* Enable Automatic Gain Control */
  2657. 28077   mixer_set(MIXER_AGC, 0x01);
  2658. 28078
  2659. 28079 #if SB_DEBUG 
  2660. 28080   printf("Mixer detectedn");
  2661. 28081 #endif
  2662. 28082
  2663. 28083   mixer_avail = 1;
  2664. 28084   return OK;
  2665. 28085 }
  2666. 28088 /*=========================================================================*
  2667. 28089  *                              mixer_set                                  *
  2668. 28090  *=========================================================================*/
  2669. 28091 PUBLIC int mixer_set(reg, data)
  2670. 28092 int reg;
  2671. 28093 int data;
  2672. 28094 {
  2673. 28095   int i;
  2674. 28096
  2675. 28097   out_byte(MIXER_REG, reg);
  2676. 28098   for(i=0;i<100;i++);
  2677. 28099   out_byte(MIXER_DATA, data);
  2678. 28100
  2679. 28101   return OK;
  2680. 28102 }  
  2681. 28103
  2682. 28104
  2683. 28105 /*=========================================================================*
  2684. 28106  *                              mixer_get                                  *
  2685. 28107  *=========================================================================*/
  2686. 28108 PRIVATE int mixer_get(reg)
  2687. 28109 int reg;
  2688. .Ep 390 src/kernel/sb16_mixer.c
  2689. 28110 {
  2690. 28111   int i;
  2691. 28112
  2692. 28113   out_byte(MIXER_REG, reg);
  2693. 28114   for(i=0;i<100;i++);
  2694. 28115   return (in_byte(MIXER_DATA) & 0xff);
  2695. 28116 }  
  2696. 28117
  2697. 28118
  2698. 28119 /*=========================================================================*
  2699. 28120  *                              get_set_volume                             *
  2700. 28121  *=========================================================================*/
  2701. 28122 PRIVATE int get_set_volume(m_ptr, flag)
  2702. 28123 message *m_ptr;
  2703. 28124 int flag;       /* 0 = get, 1 = set */
  2704. 28125 {
  2705. 28126   phys_bytes user_phys;
  2706. 28127   struct volume_level level;
  2707. 28128   int cmd_left, cmd_right, shift, max_level;
  2708. 28129
  2709. 28130   user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, 
  2710. 28131                                          sizeof(struct volume_level));
  2711. 28132   if (user_phys == 0) return(EFAULT);
  2712. 28133   phys_copy(user_phys, vir2phys(&level), (phys_bytes) sizeof(level));
  2713. 28134
  2714. 28135   shift = 3;
  2715. 28136   max_level = 0x1F;
  2716. 28137
  2717. 28138   switch (level.device)
  2718. 28139   {
  2719. 28140     case Master:  { cmd_left = MIXER_MASTER_LEFT;
  2720. 28141                     cmd_right = MIXER_MASTER_RIGHT;
  2721. 28142                   };break;
  2722. 28143     case Dac:     { cmd_left = MIXER_DAC_LEFT;
  2723. 28144                     cmd_right = MIXER_DAC_RIGHT;
  2724. 28145                   };break;
  2725. 28146     case Fm:      { cmd_left = MIXER_FM_LEFT;
  2726. 28147                     cmd_right = MIXER_FM_RIGHT;
  2727. 28148                   };break;
  2728. 28149     case Cd:      { cmd_left = MIXER_CD_LEFT;
  2729. 28150                     cmd_right = MIXER_CD_RIGHT;
  2730. 28151                   };break;
  2731. 28152     case Line:    { cmd_left = MIXER_LINE_LEFT;
  2732. 28153                     cmd_right = MIXER_LINE_RIGHT;
  2733. 28154                   };break;
  2734. 28155     case Mic:     { cmd_left = cmd_right = MIXER_MIC_LEVEL;
  2735. 28156                   };break;
  2736. 28157     case Speaker: { cmd_left = cmd_right = MIXER_PC_LEVEL;
  2737. 28158                     shift = 6;
  2738. 28159                     max_level = 0x03;
  2739. 28160                   };break;
  2740. 28161     case Treble:  { cmd_left = MIXER_TREBLE_LEFT;
  2741. 28162                     cmd_right = MIXER_TREBLE_RIGHT;
  2742. 28163                     shift = 4;
  2743. 28164                     max_level = 0x0F;
  2744. 28165                   };break;
  2745. 28166     case Bass:    { cmd_left = MIXER_BASS_LEFT;
  2746. 28167                     cmd_right = MIXER_BASS_RIGHT;
  2747. 28168                     shift = 4;
  2748. 28169                     max_level = 0x0F;
  2749. .Op 391 src/kernel/sb16_mixer.c
  2750. 28170                   };break;
  2751. 28171     default:     return EINVAL;
  2752. 28172   }
  2753. 28173
  2754. 28174   if (flag)  /* Set volume level */
  2755. 28175   {
  2756. 28176     if (level.right < 0) level.right = 0;
  2757. 28177     else if (level.right > max_level) level.right = max_level;
  2758. 28178     if (level.left < 0) level.left = 0;
  2759. 28179     else if (level.left > max_level) level.left = max_level;
  2760. 28180
  2761. 28181     mixer_set(cmd_right, (level.right << shift));
  2762. 28182     mixer_set(cmd_left, (level.left << shift));
  2763. 28183   }
  2764. 28184   else       /* Get volume level */
  2765. 28185   {
  2766. 28186     level.left = mixer_get(cmd_left);
  2767. 28187     level.right = mixer_get(cmd_right);
  2768. 28188
  2769. 28189     level.left >>= shift;
  2770. 28190     level.right >>= shift;
  2771. 28191
  2772. 28192     /* Copy back to user */
  2773. 28193     phys_copy(vir2phys(&level), user_phys, (phys_bytes) sizeof(level));
  2774. 28194   }
  2775. 28195         
  2776. 28196   return OK;
  2777. 28197 }
  2778. 28200 /*=========================================================================*
  2779. 28201  *                              get_set_input                              *
  2780. 28202  *=========================================================================*/
  2781. 28203 PRIVATE int get_set_input(m_ptr, flag, channel)
  2782. 28204 message *m_ptr;
  2783. 28205 int flag;       /* 0 = get, 1 = set */
  2784. 28206 int channel;    /* 0 = left, 1 = right */
  2785. 28207 {
  2786. 28208   phys_bytes user_phys;
  2787. 28209   struct inout_ctrl input;
  2788. 28210   int input_cmd, input_mask, mask, del_mask, shift;
  2789. 28211
  2790. 28212   user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, 
  2791. 28213                                          sizeof(struct inout_ctrl));
  2792. 28214   if (user_phys == 0) return(EFAULT);
  2793. 28215   phys_copy(user_phys, vir2phys(&input), (phys_bytes) sizeof(input));
  2794. 28216
  2795. 28217   input_cmd = (channel == 0 ? MIXER_IN_LEFT : MIXER_IN_RIGHT);
  2796. 28218
  2797. 28219   mask = mixer_get(input_cmd); 
  2798. 28220
  2799. 28221   switch (input.device)
  2800. 28222   {
  2801. 28223     case Fm:   { shift = 5;
  2802. 28224                  del_mask = 0x1F; 
  2803. 28225                };break;
  2804. 28226     case Cd:   { shift = 1;
  2805. 28227                  del_mask = 0x79;
  2806. 28228                };break;
  2807. 28229     case Line: { shift = 3;
  2808. .Ep 392 src/kernel/sb16_mixer.c
  2809. 28230                  del_mask = 0x67;
  2810. 28231                };break;
  2811. 28232     case Mic:  { shift = 0;
  2812. 28233                  del_mask = 0x7E;
  2813. 28234                };break;
  2814. 28235     default:   return EINVAL;
  2815. 28236   }
  2816. 28237
  2817. 28238   if (flag)  /* Set input */
  2818. 28239   {
  2819. 28240     input_mask = 
  2820. 28241            ((input.left == ON ? 1 : 0) << 1) | (input.right == ON ? 1 : 0);
  2821. 28242
  2822. 28243     if (shift > 0)
  2823. 28244      input_mask <<= shift;
  2824. 28245     else
  2825. 28246      input_mask >>= 1;
  2826. 28247
  2827. 28248     mask &= del_mask;   
  2828. 28249     mask |= input_mask;
  2829. 28250
  2830. 28251     mixer_set(input_cmd, mask);
  2831. 28252   }
  2832. 28253   else      /* Get input */
  2833. 28254   {
  2834. 28255     if (shift > 0)
  2835. 28256     {
  2836. 28257       input.left = ((mask >> (shift+1)) & 1 == 1 ? ON : OFF);
  2837. 28258       input.right = ((mask >> shift) & 1 == 1 ? ON : OFF);
  2838. 28259     }
  2839. 28260     else
  2840. 28261       input.left = ((mask & 1) == 1 ? ON : OFF);
  2841. 28262