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

操作系统开发

开发平台:

C/C++

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