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

操作系统开发

开发平台:

WINDOWS

  1. 12699   /* Send command bytes. */
  2. 12700   for (i = 0; i < outlen; i++) {
  3. 12701         while (in_byte(AHA_STATREG) & AHA_CDF) {}       /* !! timeout */
  4. 12702         out_byte(AHA_DATAREG, *outptr++);
  5. 12703   }
  6. 12704
  7. 12705   /* Receive data bytes. */
  8. 12706   for (i = 0; i < inlen; i++) {
  9. 12707         while (!(in_byte(AHA_STATREG) & AHA_DF)
  10. 12708                 && !(in_byte(AHA_INTRREG) & AHA_HACC)) {}  /* !! timeout */
  11. 12709         *inptr++ = in_byte(AHA_DATAREG);
  12. .Op 149 src/kernel/aha_scsi.c
  13. 12710   }
  14. 12711
  15. 12712   /* Wait for command completion. */
  16. 12713   while (!(in_byte(AHA_INTRREG) & AHA_HACC)) {} /* !! timeout */
  17. 12714   out_byte(AHA_CNTLREG, AHA_IRST);      /* clear interrupt */
  18. 12715   if (aha_irq != 0) enable_irq(aha_irq);
  19. 12716
  20. 12717   /* !! should check status register here for invalid command */
  21. 12718 }
  22. 12721 /*===========================================================================*
  23. 12722  *                              aha_reset                                    *
  24. 12723  *===========================================================================*/
  25. 12724 PRIVATE int aha_reset()
  26. 12725 {
  27. 12726   int stat;
  28. 12727   int irq, bus_on, bus_off, tr_speed;
  29. 12728   unsigned sg_max;
  30. 12729   long v;
  31. 12730   static char aha0_env[] = "AHA0", aha_fmt[] = "x:d:d:x";
  32. 12731   byte cmd[5], haidata[4], getcdata[3], extbios[2];
  33. 12732   struct milli_state ms;
  34. 12733
  35. 12734   /* Get the configuration info from the environment. */
  36. 12735   v = AHA_BASEREG;
  37. 12736   if (env_parse(aha0_env, aha_fmt, 0, &v, 0x000L, 0x3FFL) == EP_OFF) return 0;
  38. 12737   aha_basereg = v;
  39. 12738
  40. 12739   v = 15;
  41. 12740   (void) env_parse(aha0_env, aha_fmt, 1, &v, 2L, 15L);
  42. 12741   bus_on = v;
  43. 12742
  44. 12743   v = 1;
  45. 12744   (void) env_parse(aha0_env, aha_fmt, 2, &v, 1L, 64L);
  46. 12745   bus_off = v;
  47. 12746
  48. 12747   v = 0x00;
  49. 12748   (void) env_parse(aha0_env, aha_fmt, 3, &v, 0x00L, 0xFFL);
  50. 12749   tr_speed = v;
  51. 12750
  52. 12751   /* Reset controller, wait for self test to complete. */
  53. 12752   out_byte(AHA_CNTLREG, AHA_HRST);
  54. 12753   milli_start(&ms);
  55. 12754   while ((stat = in_byte(AHA_STATREG)) & AHA_STST) {
  56. 12755         if (milli_elapsed(&ms) >= AHA_TIMEOUT) {
  57. 12756                 printf("aha0: AHA154x controller not respondingn");
  58. 12757                 return(0);
  59. 12758         }
  60. 12759   }
  61. 12760
  62. 12761   /* Check for self-test failure. */
  63. 12762   if ((stat & (AHA_DIAGF | AHA_INIT | AHA_IDLE | AHA_CDF | AHA_DF))
  64. 12763                                                 != (AHA_INIT | AHA_IDLE)) {
  65. 12764         printf("aha0: AHA154x controller failed self-testn");
  66. 12765         return(0);
  67. 12766   }
  68. 12767
  69. 12768   /* !! maybe a santity check here: make sure IDLE and INIT are set? */
  70. 12769
  71. .Ep 150 src/kernel/aha_scsi.c
  72. 12770   /* Get information about controller type and configuration. */
  73. 12771   cmd[0] = AHACOM_HAINQUIRY;
  74. 12772   aha_command(1, cmd, 4, haidata);
  75. 12773
  76. 12774   cmd[0] = AHACOM_GETCONFIG;
  77. 12775   aha_command(1, cmd, 3, getcdata);
  78. 12776
  79. 12777   /* First inquiry byte tells what type of board. */
  80. 12778   aha_model = haidata[0];
  81. 12779
  82. 12780   /* Unlock the 1540C or 1540CF's mailbox interface.  (This is to keep old
  83. 12781    * drivers from using the adapter if extended features are enabled.)
  84. 12782    */
  85. 12783   if (aha_model >= AHA1540C) {
  86. 12784         cmd[0] = AHACOM_EXTBIOS;        /* get extended BIOS information */
  87. 12785         aha_command(1, cmd, 2, extbios);
  88. 12786         if (extbios[1] != 0) {
  89. 12787                 /* Mailbox interface is locked, so unlock it. */
  90. 12788                 cmd[0] = AHACOM_MBOX_ENABLE;
  91. 12789                 cmd[1] = 0;             /* bit 0 = 0 (enable mailbox) */
  92. 12790                 cmd[2] = extbios[1];    /* lock code to unlock mailbox */
  93. 12791                 aha_command(3, cmd, 0, 0);
  94. 12792         }
  95. 12793   }
  96. 12794
  97. 12795   /* The maximum scatter/gather DMA list length depends on the board model. */
  98. 12796   sg_max = 16;
  99. 12797   if (aha_model == AHA1540) sg_max = 1;         /* 1540 has no s/g */
  100. 12798   if (aha_model >= AHA1540C) sg_max = 255;      /* 1540C has plenty */
  101. 12799
  102. 12800   /* Set up the DMA channel. */
  103. 12801   switch (getcdata[0]) {
  104. 12802   case 0x80:            /* channel 7 */
  105. 12803         out_byte(0xD6, 0xC3);
  106. 12804         out_byte(0xD4, 0x03);
  107. 12805         break;
  108. 12806   case 0x40:            /* channel 6 */
  109. 12807         out_byte(0xD6, 0xC2);
  110. 12808         out_byte(0xD4, 0x02);
  111. 12809         break;
  112. 12810   case 0x20:            /* channel 5 */
  113. 12811         out_byte(0xD6, 0xC1);
  114. 12812         out_byte(0xD4, 0x01);
  115. 12813         break;
  116. 12814   case 0x01:            /* channel 0 */
  117. 12815         out_byte(0x0B, 0x0C);
  118. 12816         out_byte(0x0A, 0x00);
  119. 12817         break;
  120. 12818   default:
  121. 12819         printf("aha0: AHA154x: strange DMA channeln");
  122. 12820         return(0);
  123. 12821   }
  124. 12822
  125. 12823   /* Get the configured IRQ. */
  126. 12824   switch (getcdata[1]) {
  127. 12825   case 0x40:    irq = 15;       break;
  128. 12826   case 0x20:    irq = 14;       break;
  129. 12827   case 0x08:    irq = 12;       break;
  130. 12828   case 0x04:    irq = 11;       break;
  131. 12829   case 0x02:    irq = 10;       break;
  132. .Op 151 src/kernel/aha_scsi.c
  133. 12830   case 0x01:    irq =  9;       break;
  134. 12831   default:
  135. 12832         printf("aha0: strange IRQ settingn");
  136. 12833         return(0);
  137. 12834   }
  138. 12835
  139. 12836   /* Enable interrupts on the given irq. */
  140. 12837   put_irq_handler(irq, s_handler);
  141. 12838   aha_irq = irq;
  142. 12839   enable_irq(irq);
  143. 12840
  144. 12841   /* Initialize request related data: Command Control Block, mailboxes.
  145. 12842    * (We want to have the mailboxes initialized early, because the 1540C
  146. 12843    * wants to know it now.)
  147. 12844    */
  148. 12845
  149. 12846   /* Init ccb. */
  150. 12847   rq->ccb.senselen = CCB_SENSEREQ;      /* always want sense info */
  151. 12848   h2b24(rq->ccb.linkptr, 0L);           /* never link commands */
  152. 12849   rq->ccb.linkid = 0;
  153. 12850   rq->ccb.reserved[0] = 0;
  154. 12851   rq->ccb.reserved[1] = 0;
  155. 12852
  156. 12853   /* Scatter/gather maximum. */
  157. 12854   rq->dmalimit = rq->dmalist + (sg_max < NR_IOREQS ? sg_max : NR_IOREQS);
  158. 12855
  159. 12856   /* Outgoing mailbox. */
  160. 12857   mailbox[0].status = AHA_MBOXFREE;
  161. 12858   h2b24(mailbox[0].ccbptr, vir2phys(&rq->ccb));
  162. 12859
  163. 12860   /* Incoming mailbox. */
  164. 12861   mailbox[1].status = AHA_MBOXFREE;
  165. 12862   /* mailbox[1].ccbptr filled by adapter after command execution. */
  166. 12863
  167. 12864   /* Tell controller where the mailboxes are and how many. */
  168. 12865   cmd[0] = AHACOM_INITBOX;
  169. 12866   cmd[1] = 1;
  170. 12867   h2b24(cmd + 2, vir2phys(mailbox));
  171. 12868   aha_command(5, cmd, 0, 0);
  172. 12869
  173. 12870   /* !! maybe sanity check: check status reg for initialization success */
  174. 12871
  175. 12872   /* Set bus on, bus off and transfer speed. */
  176. 12873   cmd[0] = AHACOM_BUSON;
  177. 12874   cmd[1] = bus_on;
  178. 12875   aha_command(2, cmd, 0, 0);
  179. 12876
  180. 12877   cmd[0] = AHACOM_BUSOFF;
  181. 12878   cmd[1] = bus_off;
  182. 12879   aha_command(2, cmd, 0, 0);
  183. 12880
  184. 12881   cmd[0] = AHACOM_SPEED;
  185. 12882   cmd[1] = tr_speed;
  186. 12883   aha_command(2, cmd, 0, 0);
  187. 12884
  188. 12885   /* Set SCSI selection timeout. */
  189. 12886   cmd[0] = AHACOM_SETIMEOUT;
  190. 12887   cmd[1] = SCSI_TIMEOUT != 0;           /* timeouts on/off */
  191. 12888   cmd[2] = 0;                           /* reserved */
  192. 12889   cmd[3] = SCSI_TIMEOUT / 256;          /* MSB */
  193. .Ep 152 src/kernel/aha_scsi.c
  194. 12890   cmd[4] = SCSI_TIMEOUT % 256;          /* LSB */
  195. 12891   aha_command(5, cmd, 0, 0);
  196. 12892
  197. 12893   return(1);
  198. 12894 }
  199. 12897 /*===========================================================================*
  200. 12898  *                              s_handler                                    *
  201. 12899  *===========================================================================*/
  202. 12900 PRIVATE int s_handler(irq)
  203. 12901 int irq;
  204. 12902 {
  205. 12903 /* Host adapter interrupt, send message to SCSI task and reenable interrupts. */
  206. 12904
  207. 12905   if (in_byte(AHA_INTRREG) & AHA_HACC) {
  208. 12906         /* Simple commands are polled. */
  209. 12907         return 0;
  210. 12908   } else {
  211. 12909         out_byte(AHA_CNTLREG, AHA_IRST);        /* clear interrupt */
  212. 12910         interrupt(SCSI);
  213. 12911         return 1;
  214. 12912   }
  215. 12913 }
  216. 12916 /*===========================================================================*
  217. 12917  *                              h2b16                                        *
  218. 12918  *===========================================================================*/
  219. 12919 PRIVATE void h2b16(b, h)
  220. 12920 big16 b;
  221. 12921 U16_t h;
  222. 12922 {
  223. 12923 /* Host byte order to Big Endian conversion. */
  224. 12924   b[0] = h >> 8;
  225. 12925   b[1] = h >> 0;
  226. 12926 }
  227. 12929 /*===========================================================================*
  228. 12930  *                              h2b24                                        *
  229. 12931  *===========================================================================*/
  230. 12932 PRIVATE void h2b24(b, h)
  231. 12933 big24 b;
  232. 12934 u32_t h;
  233. 12935 {
  234. 12936   b[0] = h >> 16;
  235. 12937   b[1] = h >>  8;
  236. 12938   b[2] = h >>  0;
  237. 12939 }
  238. 12942 /*===========================================================================*
  239. 12943  *                              h2b32                                        *
  240. 12944  *===========================================================================*/
  241. 12945 PRIVATE void h2b32(b, h)
  242. 12946 big32 b;
  243. 12947 u32_t h;
  244. 12948 {
  245. 12949   b[0] = h >> 24;
  246. .Op 153 src/kernel/aha_scsi.c
  247. 12950   b[1] = h >> 16;
  248. 12951   b[2] = h >>  8;
  249. 12952   b[3] = h >>  0;
  250. 12953 }
  251. 12956 /*===========================================================================*
  252. 12957  *                              b2h16                                        *
  253. 12958  *===========================================================================*/
  254. 12959 PRIVATE u16_t b2h16(b)
  255. 12960 big16 b;
  256. 12961 {
  257. 12962   return  ((u16_t) b[0] << 8)
  258. 12963         | ((u16_t) b[1] << 0);
  259. 12964 }
  260. 12967 /*===========================================================================*
  261. 12968  *                              b2h24                                        *
  262. 12969  *===========================================================================*/
  263. 12970 PRIVATE u32_t b2h24(b)
  264. 12971 big24 b;
  265. 12972 {
  266. 12973   return  ((u32_t) b[0] << 16)
  267. 12974         | ((u32_t) b[1] <<  8)
  268. 12975         | ((u32_t) b[2] <<  0);
  269. 12976 }
  270. 12979 /*===========================================================================*
  271. 12980  *                              b2h32                                        *
  272. 12981  *===========================================================================*/
  273. 12982 PRIVATE u32_t b2h32(b)
  274. 12983 big32 b;
  275. 12984 {
  276. 12985   return  ((u32_t) b[0] << 24)
  277. 12986         | ((u32_t) b[1] << 16)
  278. 12987         | ((u32_t) b[2] <<  8)
  279. 12988         | ((u32_t) b[3] <<  0);
  280. 12989 }
  281. 12992 #if AHA_DEBUG & 2
  282. 12993 /*===========================================================================*
  283. 12994  *                              errordump                                    *
  284. 12995  *===========================================================================*/
  285. 12996 PRIVATE void errordump()
  286. 12997 {
  287. 12998   int i;
  288. 12999
  289. 13000   printf("aha ccb dump:");
  290. 13001   for (i = 0; i < sizeof(rq->ccb); i++) {
  291. 13002         if (i % 26 == 0) printf("n");
  292. 13003         printf(" %02x", ((byte *) &rq->ccb)[i]);
  293. 13004   }
  294. 13005   printf("n");
  295. 13006 }
  296. 13007 #endif /* AHA_DEBUG & 2 */
  297. 13008
  298. 13009
  299. .Ep 154 src/kernel/aha_scsi.c
  300. 13010 #if AHA_DEBUG & 4
  301. 13011 /*===========================================================================*
  302. 13012  *                              show_req                                     *
  303. 13013  *===========================================================================*/
  304. 13014 PRIVATE void show_req()
  305. 13015 {
  306. 13016   struct iorequest_s **iopp;
  307. 13017   dma_t *dmap;
  308. 13018   unsigned count, nbytes, len;
  309. 13019
  310. 13020   iopp = rq->iov;
  311. 13021   dmap = rq->dmalist;
  312. 13022   count = rq->count;
  313. 13023   nbytes = 0;
  314. 13024
  315. 13025   printf("%lu:%u", rq->pos, count);
  316. 13026
  317. 13027   while (count > 0) {
  318. 13028         if (iopp == rq->iov || *iopp != iopp[-1])
  319. 13029                 nbytes = (*iopp)->io_nbytes;
  320. 13030
  321. 13031         printf(" (%u,%lx,%u)", nbytes, b2h24(dmap->dataptr),
  322. 13032                                         len = b2h24(dmap->datalen));
  323. 13033         dmap++;
  324. 13034         iopp++;
  325. 13035         count -= len;
  326. 13036         nbytes -= len;
  327. 13037   }
  328. 13038   if (nbytes > 0) printf(" ...(%u)", nbytes);
  329. 13039   printf("n");
  330. 13040 }
  331. 13041 #endif /* AHA_DEBUG & 4 */
  332. 13042
  333. 13043
  334. 13044 #if AHA_DEBUG & 8
  335. 13045 /*===========================================================================*
  336. 13046  *                              dump_scsi_cmd                                *
  337. 13047  *===========================================================================*/
  338. 13048 PRIVATE void dump_scsi_cmd()
  339. 13049 {
  340. 13050   int i;
  341. 13051
  342. 13052   printf("scsi cmd:");
  343. 13053   for (i = 0; i < rq->ccb.cmdlen; i++) printf(" %02x", rq->ccb.cmd[i]);
  344. 13054   printf("n");
  345. 13055 }
  346. 13056 #endif /* AHA_DEBUG & 8 */
  347. 13057
  348. 13058
  349. 13059 /*============================================================================*
  350. 13060  *                              s_geometry                                    *
  351. 13061  *============================================================================*/
  352. 13062 PRIVATE void s_geometry(entry)
  353. 13063 struct partition *entry;
  354. 13064 {
  355. 13065 /* The geometry of a SCSI drive is a complete fake, the Adaptec onboard BIOS
  356. 13066  * makes the drive look like a regular drive on the outside.  A DOS program
  357. 13067  * takes a logical block address, computes cylinder, head and sector like the
  358. 13068  * BIOS int 0x13 call expects, and the Adaptec turns this back into a block
  359. 13069  * address again.  The only reason we care is because some idiot put cylinder,
  360. .Op 155 src/kernel/aha_scsi.c
  361. 13070  * head and sector numbers in the partition table, so fdisk needs to know the
  362. 13071  * geometry.
  363. 13072  */
  364. 13073   unsigned long size = s_sp->part[0].dv_size;
  365. 13074   unsigned heads, sectors;
  366. 13075
  367. 13076   if (size < 1024L * 64 * 32 * 512) {
  368. 13077         /* Small drive. */
  369. 13078         heads = 64;
  370. 13079         sectors = 32;
  371. 13080   } else {
  372. 13081         /* Assume that this BIOS is configured for large drives. */
  373. 13082         heads = 255;
  374. 13083         sectors = 63;
  375. 13084   }
  376. 13085   entry->cylinders = (size >> SECTOR_SHIFT) / (heads * sectors);
  377. 13086   entry->heads = heads;
  378. 13087   entry->sectors = sectors;
  379. 13088 }
  380. 13089 #endif /* !ENABLE_ADAPTEC_SCSI */
  381. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  382. src/kernel/at_wini.c    
  383. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  384. 13100 /* This file contains the device dependent part of a driver for the IBM-AT
  385. 13101  * winchester controller.
  386. 13102  * It was written by Adri Koppes.
  387. 13103  *
  388. 13104  * The file contains one entry point:
  389. 13105  *
  390. 13106  *   at_winchester_task:        main entry when system is brought up
  391. 13107  *
  392. 13108  *
  393. 13109  * Changes:
  394. 13110  *      13 Apr 1992 by Kees J. Bot: device dependent/independent split.
  395. 13111  */
  396. 13112
  397. 13113 #include "kernel.h"
  398. 13114 #include "driver.h"
  399. 13115 #include "drvlib.h"
  400. 13116
  401. 13117 #if ENABLE_AT_WINI
  402. 13118
  403. 13119 /* I/O Ports used by winchester disk controllers. */
  404. 13120
  405. 13121 /* Read and write registers */
  406. 13122 #define REG_BASE0       0x1F0   /* base register of controller 0 */
  407. 13123 #define REG_BASE1       0x170   /* base register of controller 1 */
  408. 13124 #define REG_DATA            0   /* data register (offset from the base reg.) */
  409. 13125 #define REG_PRECOMP         1   /* start of write precompensation */
  410. 13126 #define REG_COUNT           2   /* sectors to transfer */
  411. 13127 #define REG_SECTOR          3   /* sector number */
  412. 13128 #define REG_CYL_LO          4   /* low byte of cylinder number */
  413. 13129 #define REG_CYL_HI          5   /* high byte of cylinder number */
  414. .Ep 156 src/kernel/at_wini.c
  415. 13130 #define REG_LDH             6   /* lba, drive and head */
  416. 13131 #define   LDH_DEFAULT           0xA0    /* ECC enable, 512 bytes per sector */
  417. 13132 #define   LDH_LBA               0x40    /* Use LBA addressing */
  418. 13133 #define   ldh_init(drive)       (LDH_DEFAULT | ((drive) << 4))
  419. 13134
  420. 13135 /* Read only registers */
  421. 13136 #define REG_STATUS          7   /* status */
  422. 13137 #define   STATUS_BSY            0x80    /* controller busy */
  423. 13138 #define   STATUS_RDY            0x40    /* drive ready */
  424. 13139 #define   STATUS_WF             0x20    /* write fault */
  425. 13140 #define   STATUS_SC             0x10    /* seek complete (obsolete) */
  426. 13141 #define   STATUS_DRQ            0x08    /* data transfer request */
  427. 13142 #define   STATUS_CRD            0x04    /* corrected data */
  428. 13143 #define   STATUS_IDX            0x02    /* index pulse */
  429. 13144 #define   STATUS_ERR            0x01    /* error */
  430. 13145 #define REG_ERROR           1   /* error code */
  431. 13146 #define   ERROR_BB              0x80    /* bad block */
  432. 13147 #define   ERROR_ECC             0x40    /* bad ecc bytes */
  433. 13148 #define   ERROR_ID              0x10    /* id not found */
  434. 13149 #define   ERROR_AC              0x04    /* aborted command */
  435. 13150 #define   ERROR_TK              0x02    /* track zero error */
  436. 13151 #define   ERROR_DM              0x01    /* no data address mark */
  437. 13152
  438. 13153 /* Write only registers */
  439. 13154 #define REG_COMMAND         7   /* command */
  440. 13155 #define   CMD_IDLE              0x00    /* for w_command: drive idle */
  441. 13156 #define   CMD_RECALIBRATE       0x10    /* recalibrate drive */
  442. 13157 #define   CMD_READ              0x20    /* read data */
  443. 13158 #define   CMD_WRITE             0x30    /* write data */
  444. 13159 #define   CMD_READVERIFY        0x40    /* read verify */
  445. 13160 #define   CMD_FORMAT            0x50    /* format track */
  446. 13161 #define   CMD_SEEK              0x70    /* seek cylinder */
  447. 13162 #define   CMD_DIAG              0x90    /* execute device diagnostics */
  448. 13163 #define   CMD_SPECIFY           0x91    /* specify parameters */
  449. 13164 #define   ATA_IDENTIFY          0xEC    /* identify drive */
  450. 13165 #define REG_CTL         0x206   /* control register */
  451. 13166 #define   CTL_NORETRY           0x80    /* disable access retry */
  452. 13167 #define   CTL_NOECC             0x40    /* disable ecc retry */
  453. 13168 #define   CTL_EIGHTHEADS        0x08    /* more than eight heads */
  454. 13169 #define   CTL_RESET             0x04    /* reset controller */
  455. 13170 #define   CTL_INTDISABLE        0x02    /* disable interrupts */
  456. 13171
  457. 13172 /* Interrupt request lines. */
  458. 13173 #define AT_IRQ0         14      /* interrupt number for controller 0 */
  459. 13174 #define AT_IRQ1         15      /* interrupt number for controller 1 */
  460. 13175
  461. 13176 /* Common command block */
  462. 13177 struct command {
  463. 13178   u8_t  precomp;        /* REG_PRECOMP, etc. */
  464. 13179   u8_t  count;
  465. 13180   u8_t  sector;
  466. 13181   u8_t  cyl_lo;
  467. 13182   u8_t  cyl_hi;
  468. 13183   u8_t  ldh;
  469. 13184   u8_t  command;
  470. 13185 };
  471. 13186
  472. 13187
  473. 13188 /* Error codes */
  474. 13189 #define ERR              (-1)   /* general error */
  475. .Op 157 src/kernel/at_wini.c
  476. 13190 #define ERR_BAD_SECTOR   (-2)   /* block marked bad detected */
  477. 13191
  478. 13192 /* Some controllers don't interrupt, the clock will wake us up. */
  479. 13193 #define WAKEUP          (32*HZ) /* drive may be out for 31 seconds max */
  480. 13194
  481. 13195 /* Miscellaneous. */
  482. 13196 #define MAX_DRIVES         4    /* this driver supports 4 drives (hd0 - hd19) */
  483. 13197 #if _WORD_SIZE > 2
  484. 13198 #define MAX_SECS         256    /* controller can transfer this many sectors */
  485. 13199 #else
  486. 13200 #define MAX_SECS         127    /* but not to a 16 bit process */
  487. 13201 #endif
  488. 13202 #define MAX_ERRORS         4    /* how often to try rd/wt before quitting */
  489. 13203 #define NR_DEVICES      (MAX_DRIVES * DEV_PER_DRIVE)
  490. 13204 #define SUB_PER_DRIVE   (NR_PARTITIONS * NR_PARTITIONS)
  491. 13205 #define NR_SUBDEVS      (MAX_DRIVES * SUB_PER_DRIVE)
  492. 13206 #define TIMEOUT        32000    /* controller timeout in ms */
  493. 13207 #define RECOVERYTIME     500    /* controller recovery time in ms */
  494. 13208 #define INITIALIZED     0x01    /* drive is initialized */
  495. 13209 #define DEAF            0x02    /* controller must be reset */
  496. 13210 #define SMART           0x04    /* drive supports ATA commands */
  497. 13211
  498. 13212
  499. 13213 /* Variables. */
  500. 13214 PRIVATE struct wini {           /* main drive struct, one entry per drive */
  501. 13215   unsigned state;               /* drive state: deaf, initialized, dead */
  502. 13216   unsigned base;                /* base register of the register file */
  503. 13217   unsigned irq;                 /* interrupt request line */
  504. 13218   unsigned lcylinders;          /* logical number of cylinders (BIOS) */
  505. 13219   unsigned lheads;              /* logical number of heads */
  506. 13220   unsigned lsectors;            /* logical number of sectors per track */
  507. 13221   unsigned pcylinders;          /* physical number of cylinders (translated) */
  508. 13222   unsigned pheads;              /* physical number of heads */
  509. 13223   unsigned psectors;            /* physical number of sectors per track */
  510. 13224   unsigned ldhpref;             /* top four bytes of the LDH (head) register */
  511. 13225   unsigned precomp;             /* write precompensation cylinder / 4 */
  512. 13226   unsigned max_count;           /* max request for this drive */
  513. 13227   unsigned open_ct;             /* in-use count */
  514. 13228   struct device part[DEV_PER_DRIVE];    /* primary partitions: hd[0-4] */
  515. 13229   struct device subpart[SUB_PER_DRIVE]; /* subpartitions: hd[1-4][a-d] */
  516. 13230 } wini[MAX_DRIVES], *w_wn;
  517. 13231
  518. 13232 PRIVATE struct trans {
  519. 13233   struct iorequest_s *iop;      /* belongs to this I/O request */
  520. 13234   unsigned long block;          /* first sector to transfer */
  521. 13235   unsigned count;               /* byte count */
  522. 13236   phys_bytes phys;              /* user physical address */
  523. 13237 } wtrans[NR_IOREQS];
  524. 13238
  525. 13239 PRIVATE struct trans *w_tp;             /* to add transfer requests */
  526. 13240 PRIVATE unsigned w_count;               /* number of bytes to transfer */
  527. 13241 PRIVATE unsigned long w_nextblock;      /* next block on disk to transfer */
  528. 13242 PRIVATE int w_opcode;                   /* DEV_READ or DEV_WRITE */
  529. 13243 PRIVATE int w_command;                  /* current command in execution */
  530. 13244 PRIVATE int w_status;                   /* status after interrupt */
  531. 13245 PRIVATE int w_drive;                    /* selected drive */
  532. 13246 PRIVATE struct device *w_dv;            /* device's base and size */
  533. 13247
  534. 13248 FORWARD _PROTOTYPE( void init_params, (void) );
  535. 13249 FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr) );
  536. .Ep 158 src/kernel/at_wini.c
  537. 13250 FORWARD _PROTOTYPE( struct device *w_prepare, (int device) );
  538. 13251 FORWARD _PROTOTYPE( int w_identify, (void) );
  539. 13252 FORWARD _PROTOTYPE( char *w_name, (void) );
  540. 13253 FORWARD _PROTOTYPE( int w_specify, (void) );
  541. 13254 FORWARD _PROTOTYPE( int w_schedule, (int proc_nr, struct iorequest_s *iop) );
  542. 13255 FORWARD _PROTOTYPE( int w_finish, (void) );
  543. 13256 FORWARD _PROTOTYPE( int com_out, (struct command *cmd) );
  544. 13257 FORWARD _PROTOTYPE( void w_need_reset, (void) );
  545. 13258 FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );
  546. 13259 FORWARD _PROTOTYPE( int com_simple, (struct command *cmd) );
  547. 13260 FORWARD _PROTOTYPE( void w_timeout, (void) );
  548. 13261 FORWARD _PROTOTYPE( int w_reset, (void) );
  549. 13262 FORWARD _PROTOTYPE( int w_intr_wait, (void) );
  550. 13263 FORWARD _PROTOTYPE( int w_waitfor, (int mask, int value) );
  551. 13264 FORWARD _PROTOTYPE( int w_handler, (int irq) );
  552. 13265 FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry) );
  553. 13266
  554. 13267 /* w_waitfor loop unrolled once for speed. */
  555. 13268 #define waitfor(mask, value)    
  556. 13269         ((in_byte(w_wn->base + REG_STATUS) & mask) == value 
  557. 13270                 || w_waitfor(mask, value))
  558. 13271
  559. 13272
  560. 13273 /* Entry points to this driver. */
  561. 13274 PRIVATE struct driver w_dtab = {
  562. 13275   w_name,               /* current device's name */
  563. 13276   w_do_open,            /* open or mount request, initialize device */
  564. 13277   w_do_close,           /* release device */
  565. 13278   do_diocntl,           /* get or set a partition's geometry */
  566. 13279   w_prepare,            /* prepare for I/O on a given minor device */
  567. 13280   w_schedule,           /* precompute cylinder, head, sector, etc. */
  568. 13281   w_finish,             /* do the I/O */
  569. 13282   nop_cleanup,          /* nothing to clean up */
  570. 13283   w_geometry,           /* tell the geometry of the disk */
  571. 13284 };
  572. 13285
  573. 13286 #if ENABLE_ATAPI
  574. 13287 #include "atapi.c"      /* extra code for ATAPI CD-ROM */
  575. 13288 #endif
  576. 13289
  577. 13290
  578. 13291 /*===========================================================================*
  579. 13292  *                              at_winchester_task                           *
  580. 13293  *===========================================================================*/
  581. 13294 PUBLIC void at_winchester_task()
  582. 13295 {
  583. 13296 /* Set special disk parameters then call the generic main loop. */
  584. 13297
  585. 13298   init_params();
  586. 13299
  587. 13300   driver_task(&w_dtab);
  588. 13301 }
  589. 13304 /*============================================================================*
  590. 13305  *                              init_params                                   *
  591. 13306  *============================================================================*/
  592. 13307 PRIVATE void init_params()
  593. 13308 {
  594. 13309 /* This routine is called at startup to initialize the drive parameters. */
  595. .Op 159 src/kernel/at_wini.c
  596. 13310
  597. 13311   u16_t parv[2];
  598. 13312   unsigned int vector;
  599. 13313   int drive, nr_drives, i;
  600. 13314   struct wini *wn;
  601. 13315   u8_t params[16];
  602. 13316   phys_bytes param_phys = vir2phys(params);
  603. 13317
  604. 13318   /* Get the number of drives from the BIOS data area */
  605. 13319   phys_copy(0x475L, param_phys, 1L);
  606. 13320   if ((nr_drives = params[0]) > 2) nr_drives = 2;
  607. 13321
  608. 13322   for (drive = 0, wn = wini; drive < MAX_DRIVES; drive++, wn++) {
  609. 13323         if (drive < nr_drives) {
  610. 13324                 /* Copy the BIOS parameter vector */
  611. 13325                 vector = drive == 0 ? WINI_0_PARM_VEC : WINI_1_PARM_VEC;
  612. 13326                 phys_copy(vector * 4L, vir2phys(parv), 4L);
  613. 13327
  614. 13328                 /* Calculate the address of the parameters and copy them */
  615. 13329                 phys_copy(hclick_to_physb(parv[1]) + parv[0], param_phys, 16L);
  616. 13330
  617. 13331                 /* Copy the parameters to the structures of the drive */
  618. 13332                 wn->lcylinders = bp_cylinders(params);
  619. 13333                 wn->lheads = bp_heads(params);
  620. 13334                 wn->lsectors = bp_sectors(params);
  621. 13335                 wn->precomp = bp_precomp(params) >> 2;
  622. 13336         }
  623. 13337         wn->ldhpref = ldh_init(drive);
  624. 13338         wn->max_count = MAX_SECS << SECTOR_SHIFT;
  625. 13339         if (drive < 2) {
  626. 13340                 /* Controller 0. */
  627. 13341                 wn->base = REG_BASE0;
  628. 13342                 wn->irq = AT_IRQ0;
  629. 13343         } else {
  630. 13344                 /* Controller 1. */
  631. 13345                 wn->base = REG_BASE1;
  632. 13346                 wn->irq = AT_IRQ1;
  633. 13347         }
  634. 13348   }
  635. 13349 }
  636. 13352 /*============================================================================*
  637. 13353  *                              w_do_open                                     *
  638. 13354  *============================================================================*/
  639. 13355 PRIVATE int w_do_open(dp, m_ptr)
  640. 13356 struct driver *dp;
  641. 13357 message *m_ptr;
  642. 13358 {
  643. 13359 /* Device open: Initialize the controller and read the partition table. */
  644. 13360
  645. 13361   int r;
  646. 13362   struct wini *wn;
  647. 13363   struct command cmd;
  648. 13364
  649. 13365   if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
  650. 13366   wn = w_wn;
  651. 13367
  652. 13368   if (wn->state == 0) {
  653. 13369         /* Try to identify the device. */
  654. .Ep 160 src/kernel/at_wini.c
  655. 13370         if (w_identify() != OK) {
  656. 13371                 printf("%s: probe failedn", w_name());
  657. 13372                 if (wn->state & DEAF) w_reset();
  658. 13373                 wn->state = 0;
  659. 13374                 return(ENXIO);
  660. 13375         }
  661. 13376   }
  662. 13377   if (wn->open_ct++ == 0) {
  663. 13378         /* Partition the disk. */
  664. 13379         partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY);
  665. 13380   }
  666. 13381   return(OK);
  667. 13382 }
  668. 13385 /*===========================================================================*
  669. 13386  *                              w_prepare                                    *
  670. 13387  *===========================================================================*/
  671. 13388 PRIVATE struct device *w_prepare(device)
  672. 13389 int device;
  673. 13390 {
  674. 13391 /* Prepare for I/O on a device. */
  675. 13392
  676. 13393   /* Nothing to transfer as yet. */
  677. 13394   w_count = 0;
  678. 13395
  679. 13396   if (device < NR_DEVICES) {                    /* hd0, hd1, ... */
  680. 13397         w_drive = device / DEV_PER_DRIVE;       /* save drive number */
  681. 13398         w_wn = &wini[w_drive];
  682. 13399         w_dv = &w_wn->part[device % DEV_PER_DRIVE];
  683. 13400   } else
  684. 13401   if ((unsigned) (device -= MINOR_hd1a) < NR_SUBDEVS) { /* hd1a, hd1b, ... */
  685. 13402         w_drive = device / SUB_PER_DRIVE;
  686. 13403         w_wn = &wini[w_drive];
  687. 13404         w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
  688. 13405   } else {
  689. 13406         return(NIL_DEV);
  690. 13407   }
  691. 13408   return(w_dv);
  692. 13409 }
  693. 13412 /*===========================================================================*
  694. 13413  *                              w_identify                                   *
  695. 13414  *===========================================================================*/
  696. 13415 PRIVATE int w_identify()
  697. 13416 {
  698. 13417 /* Find out if a device exists, if it is an old AT disk, or a newer ATA
  699. 13418  * drive, a removable media device, etc.
  700. 13419  */
  701. 13420
  702. 13421   struct wini *wn = w_wn;
  703. 13422   struct command cmd;
  704. 13423   char id_string[40];
  705. 13424   int i, r;
  706. 13425   unsigned long size;
  707. 13426 #define id_byte(n)      (&tmp_buf[2 * (n)])
  708. 13427 #define id_word(n)      (((u16_t) id_byte(n)[0] <<  0) 
  709. 13428                         |((u16_t) id_byte(n)[1] <<  8))
  710. 13429 #define id_longword(n)  (((u32_t) id_byte(n)[0] <<  0) 
  711. .Op 161 src/kernel/at_wini.c
  712. 13430                         |((u32_t) id_byte(n)[1] <<  8) 
  713. 13431                         |((u32_t) id_byte(n)[2] << 16) 
  714. 13432                         |((u32_t) id_byte(n)[3] << 24))
  715. 13433
  716. 13434   /* Check if the one of the registers exists. */
  717. 13435   r = in_byte(wn->base + REG_CYL_LO);
  718. 13436   out_byte(wn->base + REG_CYL_LO, ~r);
  719. 13437   if (in_byte(wn->base + REG_CYL_LO) == r) return(ERR);
  720. 13438
  721. 13439   /* Looks OK; register IRQ and try an ATA identify command. */
  722. 13440   put_irq_handler(wn->irq, w_handler);
  723. 13441   enable_irq(wn->irq);
  724. 13442
  725. 13443   cmd.ldh     = wn->ldhpref;
  726. 13444   cmd.command = ATA_IDENTIFY;
  727. 13445   if (com_simple(&cmd) == OK) {
  728. 13446         /* This is an ATA device. */
  729. 13447         wn->state |= SMART;
  730. 13448
  731. 13449         /* Device information. */
  732. 13450         port_read(wn->base + REG_DATA, tmp_phys, SECTOR_SIZE);
  733. 13451
  734. 13452         /* Why are the strings byte swapped??? */
  735. 13453         for (i = 0; i < 40; i++) id_string[i] = id_byte(27)[i^1];
  736. 13454
  737. 13455         /* Preferred CHS translation mode. */
  738. 13456         wn->pcylinders = id_word(1);
  739. 13457         wn->pheads = id_word(3);
  740. 13458         wn->psectors = id_word(6);
  741. 13459         size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
  742. 13460
  743. 13461         if ((id_byte(49)[1] & 0x02) && size > 512L*1024*2) {
  744. 13462                 /* Drive is LBA capable and is big enough to trust it to
  745. 13463                  * not make a mess of it.
  746. 13464                  */
  747. 13465                 wn->ldhpref |= LDH_LBA;
  748. 13466                 size = id_longword(60);
  749. 13467         }
  750. 13468
  751. 13469         if (wn->lcylinders == 0) {
  752. 13470                 /* No BIOS parameters?  Then make some up. */
  753. 13471                 wn->lcylinders = wn->pcylinders;
  754. 13472                 wn->lheads = wn->pheads;
  755. 13473                 wn->lsectors = wn->psectors;
  756. 13474                 while (wn->lcylinders > 1024) {
  757. 13475                         wn->lheads *= 2;
  758. 13476                         wn->lcylinders /= 2;
  759. 13477                 }
  760. 13478         }
  761. 13479   } else {
  762. 13480         /* Not an ATA device; no translations, no special features.  Don't
  763. 13481          * touch it unless the BIOS knows about it.
  764. 13482          */
  765. 13483         if (wn->lcylinders == 0) return(ERR);   /* no BIOS parameters */
  766. 13484         wn->pcylinders = wn->lcylinders;
  767. 13485         wn->pheads = wn->lheads;
  768. 13486         wn->psectors = wn->lsectors;
  769. 13487         size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
  770. 13488   }
  771. 13489   /* The fun ends at 4 GB. */
  772. .Ep 162 src/kernel/at_wini.c
  773. 13490   if (size > ((u32_t) -1) / SECTOR_SIZE) size = ((u32_t) -1) / SECTOR_SIZE;
  774. 13491
  775. 13492   /* Base and size of the whole drive */
  776. 13493   wn->part[0].dv_base = 0;
  777. 13494   wn->part[0].dv_size = size << SECTOR_SHIFT;
  778. 13495
  779. 13496   if (w_specify() != OK && w_specify() != OK) return(ERR);
  780. 13497
  781. 13498   printf("%s: ", w_name());
  782. 13499   if (wn->state & SMART) {
  783. 13500         printf("%.40sn", id_string);
  784. 13501   } else {
  785. 13502         printf("%ux%ux%un", wn->pcylinders, wn->pheads, wn->psectors);
  786. 13503   }
  787. 13504   return(OK);
  788. 13505 }
  789. 13508 /*===========================================================================*
  790. 13509  *                              w_name                                       *
  791. 13510  *===========================================================================*/
  792. 13511 PRIVATE char *w_name()
  793. 13512 {
  794. 13513 /* Return a name for the current device. */
  795. 13514   static char name[] = "at-hd15";
  796. 13515   unsigned device = w_drive * DEV_PER_DRIVE;
  797. 13516
  798. 13517   if (device < 10) {
  799. 13518         name[5] = '0' + device;
  800. 13519         name[6] = 0;
  801. 13520   } else {
  802. 13521         name[5] = '0' + device / 10;
  803. 13522         name[6] = '0' + device % 10;
  804. 13523   }
  805. 13524   return name;
  806. 13525 }
  807. 13528 /*===========================================================================*
  808. 13529  *                              w_specify                                    *
  809. 13530  *===========================================================================*/
  810. 13531 PRIVATE int w_specify()
  811. 13532 {
  812. 13533 /* Routine to initialize the drive after boot or when a reset is needed. */
  813. 13534
  814. 13535   struct wini *wn = w_wn;
  815. 13536   struct command cmd;
  816. 13537
  817. 13538   if ((wn->state & DEAF) && w_reset() != OK) return(ERR);
  818. 13539
  819. 13540   /* Specify parameters: precompensation, number of heads and sectors. */
  820. 13541   cmd.precomp = wn->precomp;
  821. 13542   cmd.count   = wn->psectors;
  822. 13543   cmd.ldh     = w_wn->ldhpref | (wn->pheads - 1);
  823. 13544   cmd.command = CMD_SPECIFY;            /* Specify some parameters */
  824. 13545
  825. 13546   if (com_simple(&cmd) != OK) return(ERR);
  826. 13547
  827. 13548   if (!(wn->state & SMART)) {
  828. 13549         /* Calibrate an old disk. */
  829. .Op 163 src/kernel/at_wini.c
  830. 13550         cmd.sector  = 0;
  831. 13551         cmd.cyl_lo  = 0;
  832. 13552         cmd.cyl_hi  = 0;
  833. 13553         cmd.ldh     = w_wn->ldhpref;
  834. 13554         cmd.command = CMD_RECALIBRATE;
  835. 13555
  836. 13556         if (com_simple(&cmd) != OK) return(ERR);
  837. 13557   }
  838. 13558
  839. 13559   wn->state |= INITIALIZED;
  840. 13560   return(OK);
  841. 13561 }
  842. 13564 /*===========================================================================*
  843. 13565  *                              w_schedule                                   *
  844. 13566  *===========================================================================*/
  845. 13567 PRIVATE int w_schedule(proc_nr, iop)
  846. 13568 int proc_nr;                    /* process doing the request */
  847. 13569 struct iorequest_s *iop;        /* pointer to read or write request */
  848. 13570 {
  849. 13571 /* Gather I/O requests on consecutive blocks so they may be read/written
  850. 13572  * in one controller command.  (There is enough time to compute the next
  851. 13573  * consecutive request while an unwanted block passes by.)
  852. 13574  */
  853. 13575   struct wini *wn = w_wn;
  854. 13576   int r, opcode;
  855. 13577   unsigned long pos;
  856. 13578   unsigned nbytes, count;
  857. 13579   unsigned long block;
  858. 13580   phys_bytes user_phys;
  859. 13581
  860. 13582   /* This many bytes to read/write */
  861. 13583   nbytes = iop->io_nbytes;
  862. 13584   if ((nbytes & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
  863. 13585
  864. 13586   /* From/to this position on the device */
  865. 13587   pos = iop->io_position;
  866. 13588   if ((pos & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
  867. 13589
  868. 13590   /* To/from this user address */
  869. 13591   user_phys = numap(proc_nr, (vir_bytes) iop->io_buf, nbytes);
  870. 13592   if (user_phys == 0) return(iop->io_nbytes = EINVAL);
  871. 13593
  872. 13594   /* Read or write? */
  873. 13595   opcode = iop->io_request & ~OPTIONAL_IO;
  874. 13596
  875. 13597   /* Which block on disk and how close to EOF? */
  876. 13598   if (pos >= w_dv->dv_size) return(OK);         /* At EOF */
  877. 13599   if (pos + nbytes > w_dv->dv_size) nbytes = w_dv->dv_size - pos;
  878. 13600   block = (w_dv->dv_base + pos) >> SECTOR_SHIFT;
  879. 13601
  880. 13602   if (w_count > 0 && block != w_nextblock) {
  881. 13603         /* This new request can't be chained to the job being built */
  882. 13604         if ((r = w_finish()) != OK) return(r);
  883. 13605   }
  884. 13606
  885. 13607   /* The next consecutive block */
  886. 13608   w_nextblock = block + (nbytes >> SECTOR_SHIFT);
  887. 13609
  888. .Ep 164 src/kernel/at_wini.c
  889. 13610   /* While there are "unscheduled" bytes in the request: */
  890. 13611   do {
  891. 13612         count = nbytes;
  892. 13613
  893. 13614         if (w_count == wn->max_count) {
  894. 13615                 /* The drive can't do more then max_count at once */
  895. 13616                 if ((r = w_finish()) != OK) return(r);
  896. 13617         }
  897. 13618
  898. 13619         if (w_count + count > wn->max_count)
  899. 13620                 count = wn->max_count - w_count;
  900. 13621
  901. 13622         if (w_count == 0) {
  902. 13623                 /* The first request in a row, initialize. */
  903. 13624                 w_opcode = opcode;
  904. 13625                 w_tp = wtrans;
  905. 13626         }
  906. 13627
  907. 13628         /* Store I/O parameters */
  908. 13629         w_tp->iop = iop;
  909. 13630         w_tp->block = block;
  910. 13631         w_tp->count = count;
  911. 13632         w_tp->phys = user_phys;
  912. 13633
  913. 13634         /* Update counters */
  914. 13635         w_tp++;
  915. 13636         w_count += count;
  916. 13637         block += count >> SECTOR_SHIFT;
  917. 13638         user_phys += count;
  918. 13639         nbytes -= count;
  919. 13640   } while (nbytes > 0);
  920. 13641
  921. 13642   return(OK);
  922. 13643 }
  923. 13646 /*===========================================================================*
  924. 13647  *                              w_finish                                     *
  925. 13648  *===========================================================================*/
  926. 13649 PRIVATE int w_finish()
  927. 13650 {
  928. 13651 /* Carry out the I/O requests gathered in wtrans[]. */
  929. 13652
  930. 13653   struct trans *tp = wtrans;
  931. 13654   struct wini *wn = w_wn;
  932. 13655   int r, errors;
  933. 13656   struct command cmd;
  934. 13657   unsigned cylinder, head, sector, secspcyl;
  935. 13658
  936. 13659   if (w_count == 0) return(OK); /* Spurious finish. */
  937. 13660
  938. 13661   r = ERR;      /* Trigger the first com_out */
  939. 13662   errors = 0;
  940. 13663
  941. 13664   do {
  942. 13665         if (r != OK) {
  943. 13666                 /* The controller must be (re)programmed. */
  944. 13667
  945. 13668                 /* First check to see if a reinitialization is needed. */
  946. 13669                 if (!(wn->state & INITIALIZED) && w_specify() != OK)
  947. .Op 165 src/kernel/at_wini.c
  948. 13670                         return(tp->iop->io_nbytes = EIO);
  949. 13671
  950. 13672                 /* Tell the controller to transfer w_count bytes */
  951. 13673                 cmd.precomp = wn->precomp;
  952. 13674                 cmd.count   = (w_count >> SECTOR_SHIFT) & BYTE;
  953. 13675                 if (wn->ldhpref & LDH_LBA) {
  954. 13676                         cmd.sector  = (tp->block >>  0) & 0xFF;
  955. 13677                         cmd.cyl_lo  = (tp->block >>  8) & 0xFF;
  956. 13678                         cmd.cyl_hi  = (tp->block >> 16) & 0xFF;
  957. 13679                         cmd.ldh     = wn->ldhpref | ((tp->block >> 24) & 0xF);
  958. 13680                 } else {
  959. 13681                         secspcyl = wn->pheads * wn->psectors;
  960. 13682                         cylinder = tp->block / secspcyl;
  961. 13683                         head = (tp->block % secspcyl) / wn->psectors;
  962. 13684                         sector = tp->block % wn->psectors;
  963. 13685                         cmd.sector  = sector + 1;
  964. 13686                         cmd.cyl_lo  = cylinder & BYTE;
  965. 13687                         cmd.cyl_hi  = (cylinder >> 8) & BYTE;
  966. 13688                         cmd.ldh     = wn->ldhpref | head;
  967. 13689                 }
  968. 13690                 cmd.command = w_opcode == DEV_WRITE ? CMD_WRITE : CMD_READ;
  969. 13691
  970. 13692                 if ((r = com_out(&cmd)) != OK) {
  971. 13693                         if (++errors == MAX_ERRORS) {
  972. 13694                                 w_command = CMD_IDLE;
  973. 13695                                 return(tp->iop->io_nbytes = EIO);
  974. 13696                         }
  975. 13697                         continue;       /* Retry */
  976. 13698                 }
  977. 13699         }
  978. 13700
  979. 13701         /* For each sector, wait for an interrupt and fetch the data (read),
  980. 13702          * or supply data to the controller and wait for an interrupt (write).
  981. 13703          */
  982. 13704
  983. 13705         if (w_opcode == DEV_READ) {
  984. 13706                 if ((r = w_intr_wait()) == OK) {
  985. 13707                         /* Copy data from the device's buffer to user space. */
  986. 13708
  987. 13709                         port_read(wn->base + REG_DATA, tp->phys, SECTOR_SIZE);
  988. 13710
  989. 13711                         tp->phys += SECTOR_SIZE;
  990. 13712                         tp->iop->io_nbytes -= SECTOR_SIZE;
  991. 13713                         w_count -= SECTOR_SIZE;
  992. 13714                         if ((tp->count -= SECTOR_SIZE) == 0) tp++;
  993. 13715                 } else {
  994. 13716                         /* Any faulty data? */
  995. 13717                         if (w_status & STATUS_DRQ) {
  996. 13718                                 port_read(wn->base + REG_DATA, tmp_phys,
  997. 13719                                                                 SECTOR_SIZE);
  998. 13720                         }
  999. 13721                 }
  1000. 13722         } else {
  1001. 13723                 /* Wait for data requested. */
  1002. 13724                 if (!waitfor(STATUS_DRQ, STATUS_DRQ)) {
  1003. 13725                         r = ERR;
  1004. 13726                 } else {
  1005. 13727                         /* Fill the buffer of the drive. */
  1006. 13728
  1007. 13729                         port_write(wn->base + REG_DATA, tp->phys, SECTOR_SIZE);
  1008. .Ep 166 src/kernel/at_wini.c
  1009. 13730                         r = w_intr_wait();
  1010. 13731                 }
  1011. 13732
  1012. 13733                 if (r == OK) {
  1013. 13734                         /* Book the bytes successfully written. */
  1014. 13735
  1015. 13736                         tp->phys += SECTOR_SIZE;
  1016. 13737                         tp->iop->io_nbytes -= SECTOR_SIZE;
  1017. 13738                         w_count -= SECTOR_SIZE;
  1018. 13739                         if ((tp->count -= SECTOR_SIZE) == 0) tp++;
  1019. 13740                 }
  1020. 13741         }
  1021. 13742
  1022. 13743         if (r != OK) {
  1023. 13744                 /* Don't retry if sector marked bad or too many errors */
  1024. 13745                 if (r == ERR_BAD_SECTOR || ++errors == MAX_ERRORS) {
  1025. 13746                         w_command = CMD_IDLE;
  1026. 13747                         return(tp->iop->io_nbytes = EIO);
  1027. 13748                 }
  1028. 13749
  1029. 13750                 /* Reset if halfway, but bail out if optional I/O. */
  1030. 13751                 if (errors == MAX_ERRORS / 2) {
  1031. 13752                         w_need_reset();
  1032. 13753                         if (tp->iop->io_request & OPTIONAL_IO) {
  1033. 13754                                 w_command = CMD_IDLE;
  1034. 13755                                 return(tp->iop->io_nbytes = EIO);
  1035. 13756                         }
  1036. 13757                 }
  1037. 13758                 continue;       /* Retry */
  1038. 13759         }
  1039. 13760         errors = 0;
  1040. 13761   } while (w_count > 0);
  1041. 13762
  1042. 13763   w_command = CMD_IDLE;
  1043. 13764   return(OK);
  1044. 13765 }
  1045. 13768 /*============================================================================*
  1046. 13769  *                              com_out                                       *
  1047. 13770  *============================================================================*/
  1048. 13771 PRIVATE int com_out(cmd)
  1049. 13772 struct command *cmd;            /* Command block */
  1050. 13773 {
  1051. 13774 /* Output the command block to the winchester controller and return status */
  1052. 13775
  1053. 13776   struct wini *wn = w_wn;
  1054. 13777   unsigned base = wn->base;
  1055. 13778
  1056. 13779   if (!waitfor(STATUS_BSY, 0)) {
  1057. 13780         printf("%s: controller not readyn", w_name());
  1058. 13781         return(ERR);
  1059. 13782   }
  1060. 13783
  1061. 13784   /* Select drive. */
  1062. 13785   out_byte(base + REG_LDH, cmd->ldh);
  1063. 13786
  1064. 13787   if (!waitfor(STATUS_BSY, 0)) {
  1065. 13788         printf("%s: drive not readyn", w_name());
  1066. 13789         return(ERR);
  1067. .Op 167 src/kernel/at_wini.c
  1068. 13790   }
  1069. 13791
  1070. 13792   /* Schedule a wakeup call, some controllers are flaky. */
  1071. 13793   clock_mess(WAKEUP, w_timeout);
  1072. 13794
  1073. 13795   out_byte(base + REG_CTL, wn->pheads >= 8 ? CTL_EIGHTHEADS : 0);
  1074. 13796   out_byte(base + REG_PRECOMP, cmd->precomp);
  1075. 13797   out_byte(base + REG_COUNT, cmd->count);
  1076. 13798   out_byte(base + REG_SECTOR, cmd->sector);
  1077. 13799   out_byte(base + REG_CYL_LO, cmd->cyl_lo);
  1078. 13800   out_byte(base + REG_CYL_HI, cmd->cyl_hi);
  1079. 13801   lock();
  1080. 13802   out_byte(base + REG_COMMAND, cmd->command);
  1081. 13803   w_command = cmd->command;
  1082. 13804   w_status = STATUS_BSY;
  1083. 13805   unlock();
  1084. 13806   return(OK);
  1085. 13807 }
  1086. 13810 /*===========================================================================*
  1087. 13811  *                              w_need_reset                                 *
  1088. 13812  *===========================================================================*/
  1089. 13813 PRIVATE void w_need_reset()
  1090. 13814 {
  1091. 13815 /* The controller needs to be reset. */
  1092. 13816   struct wini *wn;
  1093. 13817
  1094. 13818   for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
  1095. 13819         wn->state |= DEAF;
  1096. 13820         wn->state &= ~INITIALIZED;
  1097. 13821   }
  1098. 13822 }
  1099. 13825 /*============================================================================*
  1100. 13826  *                              w_do_close                                    *
  1101. 13827  *============================================================================*/
  1102. 13828 PRIVATE int w_do_close(dp, m_ptr)
  1103. 13829 struct driver *dp;
  1104. 13830 message *m_ptr;
  1105. 13831 {
  1106. 13832 /* Device close: Release a device. */
  1107. 13833
  1108. 13834   if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
  1109. 13835   w_wn->open_ct--;
  1110. 13836   return(OK);
  1111. 13837 }
  1112. 13840 /*============================================================================*
  1113. 13841  *                              com_simple                                    *
  1114. 13842  *============================================================================*/
  1115. 13843 PRIVATE int com_simple(cmd)
  1116. 13844 struct command *cmd;            /* Command block */
  1117. 13845 {
  1118. 13846 /* A simple controller command, only one interrupt and no data-out phase. */
  1119. 13847   int r;
  1120. 13848
  1121. 13849   if ((r = com_out(cmd)) == OK) r = w_intr_wait();
  1122. .Ep 168 src/kernel/at_wini.c
  1123. 13850   w_command = CMD_IDLE;
  1124. 13851   return(r);
  1125. 13852 }
  1126. 13855 /*===========================================================================*
  1127. 13856  *                              w_timeout                                    *
  1128. 13857  *===========================================================================*/
  1129. 13858 PRIVATE void w_timeout()
  1130. 13859 {
  1131. 13860   struct wini *wn = w_wn;
  1132. 13861
  1133. 13862   switch (w_command) {
  1134. 13863   case CMD_IDLE:
  1135. 13864         break;          /* fine */
  1136. 13865   case CMD_READ:
  1137. 13866   case CMD_WRITE:
  1138. 13867         /* Impossible, but not on PC's:  The controller does not respond. */
  1139. 13868
  1140. 13869         /* Limiting multisector I/O seems to help. */
  1141. 13870         if (wn->max_count > 8 * SECTOR_SIZE) {
  1142. 13871                 wn->max_count = 8 * SECTOR_SIZE;
  1143. 13872         } else {
  1144. 13873                 wn->max_count = SECTOR_SIZE;
  1145. 13874         }
  1146. 13875         /*FALL THROUGH*/
  1147. 13876   default:
  1148. 13877         /* Some other command. */
  1149. 13878         printf("%s: timeout on command %02xn", w_name(), w_command);
  1150. 13879         w_need_reset();
  1151. 13880         w_status = 0;
  1152. 13881         interrupt(WINCHESTER);
  1153. 13882   }
  1154. 13883 }
  1155. 13886 /*===========================================================================*
  1156. 13887  *                              w_reset                                      *
  1157. 13888  *===========================================================================*/
  1158. 13889 PRIVATE int w_reset()
  1159. 13890 {
  1160. 13891 /* Issue a reset to the controller.  This is done after any catastrophe,
  1161. 13892  * like the controller refusing to respond.
  1162. 13893  */
  1163. 13894
  1164. 13895   struct wini *wn;
  1165. 13896   int err;
  1166. 13897
  1167. 13898   /* Wait for any internal drive recovery. */
  1168. 13899   milli_delay(RECOVERYTIME);
  1169. 13900
  1170. 13901   /* Strobe reset bit */
  1171. 13902   out_byte(w_wn->base + REG_CTL, CTL_RESET);
  1172. 13903   milli_delay(1);
  1173. 13904   out_byte(w_wn->base + REG_CTL, 0);
  1174. 13905   milli_delay(1);
  1175. 13906
  1176. 13907   /* Wait for controller ready */
  1177. 13908   if (!w_waitfor(STATUS_BSY | STATUS_RDY, STATUS_RDY)) {
  1178. 13909         printf("%s: reset failed, drive busyn", w_name());
  1179. .Op 169 src/kernel/at_wini.c
  1180. 13910         return(ERR);
  1181. 13911   }
  1182. 13912
  1183. 13913   /* The error register should be checked now, but some drives mess it up. */
  1184. 13914
  1185. 13915   for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
  1186. 13916         if (wn->base == w_wn->base) wn->state &= ~DEAF;
  1187. 13917   }
  1188. 13918   return(OK);
  1189. 13919 }
  1190. 13922 /*============================================================================*
  1191. 13923  *                              w_intr_wait                                   *
  1192. 13924  *============================================================================*/
  1193. 13925 PRIVATE int w_intr_wait()
  1194. 13926 {
  1195. 13927 /* Wait for a task completion interrupt and return results. */
  1196. 13928
  1197. 13929   message mess;
  1198. 13930   int r;
  1199. 13931
  1200. 13932   /* Wait for an interrupt that sets w_status to "not busy". */
  1201. 13933   while (w_status & STATUS_BSY) receive(HARDWARE, &mess);
  1202. 13934
  1203. 13935   /* Check status. */
  1204. 13936   lock();
  1205. 13937   if ((w_status & (STATUS_BSY | STATUS_RDY | STATUS_WF | STATUS_ERR))
  1206. 13938                                                         == STATUS_RDY) {
  1207. 13939         r = OK;
  1208. 13940         w_status |= STATUS_BSY; /* assume still busy with I/O */
  1209. 13941   } else
  1210. 13942   if ((w_status & STATUS_ERR) && (in_byte(w_wn->base + REG_ERROR) & ERROR_BB)) {
  1211. 13943         r = ERR_BAD_SECTOR;     /* sector marked bad, retries won't help */
  1212. 13944   } else {
  1213. 13945         r = ERR;                /* any other error */
  1214. 13946   }
  1215. 13947   unlock();
  1216. 13948   return(r);
  1217. 13949 }
  1218. 13952 /*==========================================================================*
  1219. 13953  *                              w_waitfor                                   *
  1220. 13954  *==========================================================================*/
  1221. 13955 PRIVATE int w_waitfor(mask, value)
  1222. 13956 int mask;                       /* status mask */
  1223. 13957 int value;                      /* required status */
  1224. 13958 {
  1225. 13959 /* Wait until controller is in the required state.  Return zero on timeout. */
  1226. 13960
  1227. 13961   struct milli_state ms;
  1228. 13962
  1229. 13963   milli_start(&ms);
  1230. 13964   do {
  1231. 13965        if ((in_byte(w_wn->base + REG_STATUS) & mask) == value) return 1;
  1232. 13966   } while (milli_elapsed(&ms) < TIMEOUT);
  1233. 13967
  1234. 13968   w_need_reset();       /* Controller gone deaf. */
  1235. 13969   return(0);
  1236. .Ep 170 src/kernel/at_wini.c
  1237. 13970 }
  1238. 13973 /*==========================================================================*
  1239. 13974  *                              w_handler                                   *
  1240. 13975  *==========================================================================*/
  1241. 13976 PRIVATE int w_handler(irq)
  1242. 13977 int irq;
  1243. 13978 {
  1244. 13979 /* Disk interrupt, send message to winchester task and reenable interrupts. */
  1245. 13980
  1246. 13981   w_status = in_byte(w_wn->base + REG_STATUS);  /* acknowledge interrupt */
  1247. 13982   interrupt(WINCHESTER);
  1248. 13983   return 1;
  1249. 13984 }
  1250. 13987 /*============================================================================*
  1251. 13988  *                              w_geometry                                    *
  1252. 13989  *============================================================================*/
  1253. 13990 PRIVATE void w_geometry(entry)
  1254. 13991 struct partition *entry;
  1255. 13992 {
  1256. 13993   entry->cylinders = w_wn->lcylinders;
  1257. 13994   entry->heads = w_wn->lheads;
  1258. 13995   entry->sectors = w_wn->lsectors;
  1259. 13996 }
  1260. 13997 #endif /* ENABLE_AT_WINI */
  1261. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1262. src/kernel/bios_wini.c    
  1263. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1264. 14000 /* This file contains the "device dependent" part of a hard disk driver that
  1265. 14001  * uses the ROM BIOS.  It makes a call and just waits for the transfer to
  1266. 14002  * happen.  It is not interrupt driven and thus will (*) have poor performance.
  1267. 14003  * The advantage is that it should work on virtually any PC, XT, 386, PS/2
  1268. 14004  * or clone.  The demo disk uses this driver.  It is suggested that all
  1269. 14005  * MINIX users try the other drivers, and use this one only as a last resort,
  1270. 14006  * if all else fails.
  1271. 14007  *
  1272. 14008  * (*) The performance is within 10% of the AT driver for reads on any disk
  1273. 14009  *     and writes on a 2:1 interleaved disk, it will be DMA_BUF_SIZE bytes
  1274. 14010  *     per revolution for a minimum of 60 kb/s for writes to 1:1 disks.
  1275. 14011  *
  1276. 14012  * The file contains one entry point:
  1277. 14013  *
  1278. 14014  *       bios_winchester_task:  main entry when system is brought up
  1279. 14015  *
  1280. 14016  *
  1281. 14017  * Changes:
  1282. 14018  *      30 Apr 1992 by Kees J. Bot: device dependent/independent split.
  1283. 14019  */
  1284. 14020
  1285. 14021 #include "kernel.h"
  1286. 14022 #include "driver.h"
  1287. 14023 #include "drvlib.h"
  1288. 14024
  1289. .Op 171 src/kernel/bios_wini.c
  1290. 14025 #if ENABLE_BIOS_WINI
  1291. 14026
  1292. 14027 /* If the DMA buffer is large enough then use it always. */
  1293. 14028 #define USE_BUF         (DMA_BUF_SIZE > BLOCK_SIZE)
  1294. 14029
  1295. 14030 /* Error codes */
  1296. 14031 #define ERR              (-1)   /* general error */
  1297. 14032
  1298. 14033 /* Parameters for the disk drive. */
  1299. 14034 #define MAX_DRIVES         4    /* this driver supports 4 drives (hd0 - hd19)*/
  1300. 14035 #define MAX_SECS         255    /* bios can transfer this many sectors */
  1301. 14036 #define NR_DEVICES      (MAX_DRIVES * DEV_PER_DRIVE)
  1302. 14037 #define SUB_PER_DRIVE   (NR_PARTITIONS * NR_PARTITIONS)
  1303. 14038 #define NR_SUBDEVS      (MAX_DRIVES * SUB_PER_DRIVE)
  1304. 14039
  1305. 14040 /* BIOS parameters */
  1306. 14041 #define BIOS_ASK        0x08    /* opcode for asking BIOS for parameters */
  1307. 14042 #define BIOS_RESET      0x00    /* opcode for resetting disk BIOS */
  1308. 14043 #define BIOS_READ       0x02    /* opcode for BIOS read */
  1309. 14044 #define BIOS_WRITE      0x03    /* opcode for BIOS write */
  1310. 14045 #define HD_CODE         0x80    /* BIOS code for hard disk drive 0 */
  1311. 14046
  1312. 14047 /* Variables. */
  1313. 14048 PRIVATE struct wini {           /* main drive struct, one entry per drive */
  1314. 14049   unsigned cylinders;           /* number of cylinders */
  1315. 14050   unsigned heads;               /* number of heads */
  1316. 14051   unsigned sectors;             /* number of sectors per track */
  1317. 14052   unsigned open_ct;             /* in-use count */
  1318. 14053   struct device part[DEV_PER_DRIVE];    /* primary partitions: hd[0-4] */
  1319. 14054   struct device subpart[SUB_PER_DRIVE]; /* subpartitions: hd[1-4][a-d] */
  1320. 14055 } wini[MAX_DRIVES], *w_wn;
  1321. 14056
  1322. 14057 PRIVATE struct trans {
  1323. 14058   struct iorequest_s *iop;      /* belongs to this I/O request */
  1324. 14059   unsigned long block;          /* first sector to transfer */
  1325. 14060   unsigned count;               /* byte count */
  1326. 14061   phys_bytes phys;              /* user physical address */
  1327. 14062   phys_bytes dma;               /* DMA physical address */
  1328. 14063 } wtrans[NR_IOREQS];
  1329. 14064
  1330. 14065 PRIVATE int nr_drives = MAX_DRIVES;     /* Number of drives */
  1331. 14066 PRIVATE struct trans *w_tp;             /* to add transfer requests */
  1332. 14067 PRIVATE unsigned w_count;               /* number of bytes to transfer */
  1333. 14068 PRIVATE unsigned long w_nextblock;      /* next block on disk to transfer */
  1334. 14069 PRIVATE int w_opcode;                   /* DEV_READ or DEV_WRITE */
  1335. 14070 PRIVATE int w_drive;                    /* selected drive */
  1336. 14071 PRIVATE struct device *w_dv;            /* device's base and size */
  1337. 14072 extern unsigned Ax, Bx, Cx, Dx, Es;     /* to hold registers for BIOS calls */
  1338. 14073
  1339. 14074 FORWARD _PROTOTYPE( struct device *w_prepare, (int device) );
  1340. 14075 FORWARD _PROTOTYPE( char *w_name, (void) );
  1341. 14076 FORWARD _PROTOTYPE( int w_schedule, (int proc_nr, struct iorequest_s *iop) );
  1342. 14077 FORWARD _PROTOTYPE( int w_finish, (void) );
  1343. 14078 FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr) );
  1344. 14079 FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );
  1345. 14080 FORWARD _PROTOTYPE( void w_init, (void) );
  1346. 14081 FORWARD _PROTOTYPE( void enable_vectors, (void) );
  1347. 14082 FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry));
  1348. 14083
  1349. 14084
  1350. .Ep 172 src/kernel/bios_wini.c
  1351. 14085 /* Entry points to this driver. */
  1352. 14086 PRIVATE struct driver w_dtab = {
  1353. 14087   w_name,       /* current device's name */
  1354. 14088   w_do_open,    /* open or mount request, initialize device */
  1355. 14089   w_do_close,   /* release device */
  1356. 14090   do_diocntl,   /* get or set a partition's geometry */
  1357. 14091   w_prepare,    /* prepare for I/O on a given minor device */
  1358. 14092   w_schedule,   /* precompute cylinder, head, sector, etc. */
  1359. 14093   w_finish,     /* do the I/O */
  1360. 14094   nop_cleanup,  /* no cleanup needed */
  1361. 14095   w_geometry    /* tell the geometry of the disk */
  1362. 14096 };
  1363. 14097
  1364. 14098
  1365. 14099 /*===========================================================================*
  1366. 14100  *                              bios_winchester_task                         *
  1367. 14101  *===========================================================================*/
  1368. 14102 PUBLIC void bios_winchester_task()
  1369. 14103 {
  1370. 14104   driver_task(&w_dtab);
  1371. 14105 }
  1372. 14108 /*===========================================================================*
  1373. 14109  *                              w_prepare                                    *
  1374. 14110  *===========================================================================*/
  1375. 14111 PRIVATE struct device *w_prepare(device)
  1376. 14112 int device;
  1377. 14113 {
  1378. 14114 /* Prepare for I/O on a device. */
  1379. 14115
  1380. 14116   /* Nothing to transfer as yet. */
  1381. 14117   w_count = 0;
  1382. 14118
  1383. 14119   if (device < NR_DEVICES) {                    /* hd0, hd1, ... */
  1384. 14120         w_drive = device / DEV_PER_DRIVE;       /* save drive number */
  1385. 14121         w_wn = &wini[w_drive];
  1386. 14122         w_dv = &w_wn->part[device % DEV_PER_DRIVE];
  1387. 14123   } else
  1388. 14124   if ((unsigned) (device -= MINOR_hd1a) < NR_SUBDEVS) { /* hd1a, hd1b, ... */
  1389. 14125         w_drive = device / SUB_PER_DRIVE;
  1390. 14126         w_wn = &wini[w_drive];
  1391. 14127         w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
  1392. 14128   } else {
  1393. 14129         return(NIL_DEV);
  1394. 14130   }
  1395. 14131   return(w_drive < nr_drives ? w_dv : NIL_DEV);
  1396. 14132 }
  1397. 14135 /*===========================================================================*
  1398. 14136  *                              w_name                                       *
  1399. 14137  *===========================================================================*/
  1400. 14138 PRIVATE char *w_name()
  1401. 14139 {
  1402. 14140 /* Return a name for the current device. */
  1403. 14141   static char name[] = "bios-hd5";
  1404. 14142
  1405. 14143   name[7] = '0' + w_drive * DEV_PER_DRIVE;
  1406. 14144   return name;
  1407. .Op 173 src/kernel/bios_wini.c
  1408. 14145 }
  1409. 14148 /*===========================================================================*
  1410. 14149  *                              w_schedule                                   *
  1411. 14150  *===========================================================================*/
  1412. 14151 PRIVATE int w_schedule(proc_nr, iop)
  1413. 14152 int proc_nr;                    /* process doing the request */
  1414. 14153 struct iorequest_s *iop;        /* pointer to read or write request */
  1415. 14154 {
  1416. 14155 /* Gather I/O requests on consecutive blocks so they may be read/written
  1417. 14156  * in one bios command if using a buffer.  Check and gather all the requests
  1418. 14157  * and try to finish them as fast as possible if unbuffered.
  1419. 14158  */
  1420. 14159   int r, opcode;
  1421. 14160   unsigned long pos;
  1422. 14161   unsigned nbytes, count, dma_count;
  1423. 14162   unsigned long block;
  1424. 14163   phys_bytes user_phys, dma_phys;
  1425. 14164
  1426. 14165   /* This many bytes to read/write */
  1427. 14166   nbytes = iop->io_nbytes;
  1428. 14167   if ((nbytes & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
  1429. 14168
  1430. 14169   /* From/to this position on the device */
  1431. 14170   pos = iop->io_position;
  1432. 14171   if ((pos & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
  1433. 14172
  1434. 14173   /* To/from this user address */
  1435. 14174   user_phys = numap(proc_nr, (vir_bytes) iop->io_buf, nbytes);
  1436. 14175   if (user_phys == 0) return(iop->io_nbytes = EINVAL);
  1437. 14176
  1438. 14177   /* Read or write? */
  1439. 14178   opcode = iop->io_request & ~OPTIONAL_IO;
  1440. 14179
  1441. 14180   /* Which block on disk and how close to EOF? */
  1442. 14181   if (pos >= w_dv->dv_size) return(OK);         /* At EOF */
  1443. 14182   if (pos + nbytes > w_dv->dv_size) nbytes = w_dv->dv_size - pos;
  1444. 14183   block = (w_dv->dv_base + pos) >> SECTOR_SHIFT;
  1445. 14184
  1446. 14185   if (USE_BUF && w_count > 0 && block != w_nextblock) {
  1447. 14186         /* This new request can't be chained to the job being built */
  1448. 14187         if ((r = w_finish()) != OK) return(r);
  1449. 14188   }
  1450. 14189
  1451. 14190   /* The next consecutive block */
  1452. 14191   if (USE_BUF) w_nextblock = block + (nbytes >> SECTOR_SHIFT);
  1453. 14192
  1454. 14193   /* While there are "unscheduled" bytes in the request: */
  1455. 14194   do {
  1456. 14195         count = nbytes;
  1457. 14196
  1458. 14197         if (USE_BUF) {
  1459. 14198                 if (w_count == DMA_BUF_SIZE) {
  1460. 14199                         /* Can't transfer more than the buffer allows. */
  1461. 14200                         if ((r = w_finish()) != OK) return(r);
  1462. 14201                 }
  1463. 14202
  1464. 14203                 if (w_count + count > DMA_BUF_SIZE)
  1465. 14204                         count = DMA_BUF_SIZE - w_count;
  1466. .Ep 174 src/kernel/bios_wini.c
  1467. 14205         } else {
  1468. 14206                 if (w_tp == wtrans + NR_IOREQS) {
  1469. 14207                         /* All transfer slots in use. */
  1470. 14208                         if ((r = w_finish()) != OK) return(r);
  1471. 14209                 }
  1472. 14210         }
  1473. 14211
  1474. 14212         if (w_count == 0) {
  1475. 14213                 /* The first request in a row, initialize. */
  1476. 14214                 w_opcode = opcode;
  1477. 14215                 w_tp = wtrans;
  1478. 14216         }
  1479. 14217
  1480. 14218         if (USE_BUF) {
  1481. 14219                 dma_phys = tmp_phys + w_count;
  1482. 14220         } else {
  1483. 14221                 /* Memory chunk to DMA. */
  1484. 14222                 dma_phys = user_phys;
  1485. 14223                 dma_count = dma_bytes_left(dma_phys);
  1486. 14224
  1487. 14225                 if (dma_phys >= (1L << 20)) {
  1488. 14226                         /* The BIOS can only address the first megabyte. */
  1489. 14227                         count = SECTOR_SIZE;
  1490. 14228                         dma_phys = tmp_phys;
  1491. 14229                 } else
  1492. 14230                 if (dma_count < count) {
  1493. 14231                         /* Nearing a 64K boundary. */
  1494. 14232                         if (dma_count >= SECTOR_SIZE) {
  1495. 14233                                 /* Can read a few sectors before hitting the
  1496. 14234                                  * boundary.
  1497. 14235                                  */
  1498. 14236                                 count = dma_count & ~SECTOR_MASK;
  1499. 14237                         } else {
  1500. 14238                                 /* Must use the special buffer for this. */
  1501. 14239                                 count = SECTOR_SIZE;
  1502. 14240                                 dma_phys = tmp_phys;
  1503. 14241                         }
  1504. 14242                 }
  1505. 14243         }
  1506. 14244
  1507. 14245         /* Store I/O parameters */
  1508. 14246         w_tp->iop = iop;
  1509. 14247         w_tp->block = block;
  1510. 14248         w_tp->count = count;
  1511. 14249         w_tp->phys = user_phys;
  1512. 14250         w_tp->dma = dma_phys;
  1513. 14251
  1514. 14252         /* Update counters */
  1515. 14253         w_tp++;
  1516. 14254         w_count += count;
  1517. 14255         block += count >> SECTOR_SHIFT;
  1518. 14256         user_phys += count;
  1519. 14257         nbytes -= count;
  1520. 14258   } while (nbytes > 0);
  1521. 14259
  1522. 14260   return(OK);
  1523. 14261 }
  1524. 14264 /*===========================================================================*
  1525. .Op 175 src/kernel/bios_wini.c
  1526. 14265  *                              w_finish                                     *
  1527. 14266  *===========================================================================*/
  1528. 14267 PRIVATE int w_finish()
  1529. 14268 {
  1530. 14269 /* Carry out the I/O requests gathered in wtrans[]. */
  1531. 14270
  1532. 14271   struct trans *tp = wtrans, *tp2;
  1533. 14272   unsigned count, cylinder, sector, head, hicyl, locyl;
  1534. 14273   unsigned secspcyl = w_wn->heads * w_wn->sectors;
  1535. 14274   int many = USE_BUF;
  1536. 14275
  1537. 14276   if (w_count == 0) return(OK); /* Spurious finish. */
  1538. 14277
  1539. 14278   do {
  1540. 14279         if (w_opcode == DEV_WRITE) {
  1541. 14280                 tp2 = tp;
  1542. 14281                 count = 0;
  1543. 14282                 do {
  1544. 14283                         if (USE_BUF || tp2->dma == tmp_phys) {
  1545. 14284                                 phys_copy(tp2->phys, tp2->dma,
  1546. 14285                                                 (phys_bytes) tp2->count);
  1547. 14286                         }
  1548. 14287                         count += tp2->count;
  1549. 14288                         tp2++;
  1550. 14289                 } while (many && count < w_count);
  1551. 14290         } else {
  1552. 14291                 count = many ? w_count : tp->count;
  1553. 14292         }
  1554. 14293
  1555. 14294         /* Do the transfer */
  1556. 14295         cylinder = tp->block / secspcyl;
  1557. 14296         sector = (tp->block % w_wn->sectors) + 1;
  1558. 14297         head = (tp->block % secspcyl) / w_wn->sectors;
  1559. 14298
  1560. 14299         Ax = w_opcode == DEV_WRITE ? BIOS_WRITE : BIOS_READ;
  1561. 14300         Ax = (Ax << 8) | (count >> SECTOR_SHIFT);       /* opcode & count */
  1562. 14301         Bx = (unsigned) tp->dma % HCLICK_SIZE;          /* low order 4 bits */
  1563. 14302         Es = physb_to_hclick(tp->dma);          /* high order 16 bits */
  1564. 14303         hicyl = (cylinder & 0x300) >> 8;        /* two high-order bits */
  1565. 14304         locyl = (cylinder & 0xFF);              /* 8 low-order bits */
  1566. 14305         Cx = sector | (hicyl << 6) | (locyl << 8);
  1567. 14306         Dx = (HD_CODE + w_drive) | (head << 8);
  1568. 14307         level0(bios13);
  1569. 14308         if ((Ax & 0xFF00) != 0) {
  1570. 14309                 /* An error occurred, try again block by block unless */
  1571. 14310                 if (!many) return(tp->iop->io_nbytes = EIO);
  1572. 14311                 many = 0;
  1573. 14312                 continue;
  1574. 14313         }
  1575. 14314
  1576. 14315         w_count -= count;
  1577. 14316
  1578. 14317         do {
  1579. 14318                 if (w_opcode == DEV_READ) {
  1580. 14319                         if (USE_BUF || tp->dma == tmp_phys) {
  1581. 14320                                 phys_copy(tp->dma, tp->phys,
  1582. 14321                                                 (phys_bytes) tp->count);
  1583. 14322                         }
  1584. 14323                 }
  1585. 14324                 tp->iop->io_nbytes -= tp->count;
  1586. .Ep 176 src/kernel/bios_wini.c
  1587. 14325                 count -= tp->count;
  1588. 14326                 tp++;
  1589. 14327         } while (count > 0);
  1590. 14328   } while (w_count > 0);
  1591. 14329
  1592. 14330   return(OK);
  1593. 14331 }
  1594. 14334 /*============================================================================*
  1595. 14335  *                              w_do_open                                     *
  1596. 14336  *============================================================================*/
  1597. 14337 PRIVATE int w_do_open(dp, m_ptr)
  1598. 14338 struct driver *dp;
  1599. 14339 message *m_ptr;
  1600. 14340 {
  1601. 14341 /* Device open: Initialize the controller and read the partition table. */
  1602. 14342
  1603. 14343   static int init_done = FALSE;
  1604. 14344
  1605. 14345   if (!init_done) { w_init(); init_done = TRUE; }
  1606. 14346
  1607. 14347   if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
  1608. 14348
  1609. 14349   if (w_wn->open_ct++ == 0) {
  1610. 14350         /* Partition the disk. */
  1611. 14351         partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY);
  1612. 14352   }
  1613. 14353   return(OK);
  1614. 14354 }
  1615. 14357 /*============================================================================*
  1616. 14358  *                              w_do_close                                    *
  1617. 14359  *============================================================================*/
  1618. 14360 PRIVATE int w_do_close(dp, m_ptr)
  1619. 14361 struct driver *dp;
  1620. 14362 message *m_ptr;
  1621. 14363 {
  1622. 14364 /* Device close: Release a device. */
  1623. 14365
  1624. 14366   if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
  1625. 14367   w_wn->open_ct--;
  1626. 14368   return(OK);
  1627. 14369 }
  1628. 14372 /*===========================================================================*
  1629. 14373  *                              w_init                                       *
  1630. 14374  *===========================================================================*/
  1631. 14375 PRIVATE void w_init()
  1632. 14376 {
  1633. 14377 /* This routine is called at startup to initialize the drive parameters. */
  1634. 14378
  1635. 14379   int drive;
  1636. 14380   struct wini *wn;
  1637. 14381
  1638. 14382   /* Enable real mode BIOS vectors. */
  1639. 14383   enable_vectors();
  1640. 14384
  1641. .Op 177 src/kernel/bios_wini.c
  1642. 14385   /* Set the geometry of the drives */
  1643. 14386   for (drive = 0; drive < nr_drives; drive++) {
  1644. 14387         (void) w_prepare(drive * DEV_PER_DRIVE);
  1645. 14388         wn = w_wn;
  1646. 14389         Dx = drive + HD_CODE;
  1647. 14390         Ax = (BIOS_ASK << 8);
  1648. 14391         level0(bios13);
  1649. 14392         nr_drives = (Ax & 0xFF00) == 0 ? (Dx & 0xFF) : drive;
  1650. 14393         if (nr_drives > MAX_DRIVES) nr_drives = MAX_DRIVES;
  1651. 14394         if (drive >= nr_drives) break;
  1652. 14395
  1653. 14396         wn->heads = (Dx >> 8) + 1;
  1654. 14397         wn->sectors = (Cx & 0x3F);
  1655. 14398         wn->cylinders = ((Cx << 2) & 0x0300) + ((Cx >> 8) & 0x00FF) + 1;
  1656. 14399
  1657. 14400         wn->part[0].dv_size = ((unsigned long) wn->cylinders
  1658. 14401                         * wn->heads * wn->sectors) << SECTOR_SHIFT;
  1659. 14402
  1660. 14403         printf("%s: %d cylinders, %d heads, %d sectors per trackn",
  1661. 14404                 w_name(), wn->cylinders, wn->heads, wn->sectors);
  1662. 14405   }
  1663. 14406 }
  1664. 14409 /*===========================================================================*
  1665. 14410  *                              enable_vectors                               *
  1666. 14411  *===========================================================================*/
  1667. 14412 PRIVATE void enable_vectors()
  1668. 14413 {
  1669. 14414 /* Protected mode Minix has reprogrammed the interrupt controllers to
  1670. 14415  * use different vectors from the BIOS.  This means that the BIOS vectors
  1671. 14416  * must be copied to the Minix locations for use in real mode.  The bios13()
  1672. 14417  * function enables all interrupts that Minix doesn't use, and masks all
  1673. 14418  * interrupts that Minix does use when it makes the "INT 13" call.  Alas
  1674. 14419  * more than one clock tick may occur while the disk is active, so we need
  1675. 14420  * a special real mode clock interrupt handle to gather lost ticks.
  1676. 14421  */
  1677. 14422
  1678. 14423   int vec, irq;
  1679. 14424   static u8_t clock_handler[] = {
  1680. 14425         0x50, 0xB0, 0x20, 0xE6, 0x20, 0xEB, 0x06, 0xE4,
  1681. 14426         0x61, 0x0C, 0x80, 0xE6, 0x61, 0x58, 0x53, 0x1E,
  1682. 14427         0xE8, 0x00, 0x00, 0x5B, 0x2E, 0xC5, 0x5F, 0x0A,
  1683. 14428         0xFF, 0x07, 0x1F, 0x5B, 0xCF,
  1684. 14429         0x00, 0x00, 0x00, 0x00,
  1685. 14430   };
  1686. 14431   u16_t vector[2];
  1687. 14432
  1688. 14433   if (!protected_mode) return;
  1689. 14434
  1690. 14435   for (irq = 0; irq < NR_IRQ_VECTORS; irq++) {
  1691. 14436         phys_copy(BIOS_VECTOR(irq)*4L, VECTOR(irq)*4L, 4L);
  1692. 14437   }
  1693. 14438
  1694. 14439   /* Install a clock interrupt handler to collect clock ticks when the
  1695. 14440    * BIOS disk driver is active.  The handler is a simple bit of 8086 code
  1696. 14441    * that increments "lost_ticks".
  1697. 14442    */
  1698. 14443
  1699. 14444   /* Let the clock interrupt point to the handler. */
  1700. .Ep 178 src/kernel/bios_wini.c
  1701. 14445   vector[0] = vir2phys(clock_handler) % HCLICK_SIZE;
  1702. 14446   vector[1] = vir2phys(clock_handler) / HCLICK_SIZE;
  1703. 14447   phys_copy(vir2phys(vector), VECTOR(CLOCK_IRQ)*4L, 4L);
  1704. 14448
  1705. 14449   /* Store the address of lost_ticks in the handler. */
  1706. 14450   vector[0] = vir2phys(&lost_ticks) % HCLICK_SIZE;
  1707. 14451   vector[1] = vir2phys(&lost_ticks) / HCLICK_SIZE;
  1708. 14452   memcpy(clock_handler + 0x1D, vector, 4);
  1709. 14453
  1710. 14454   if (ps_mca) clock_handler[6]= 0;      /* (PS/2 port B clock ack) */
  1711. 14455 }
  1712. 14458 /*============================================================================*
  1713. 14459  *                              w_geometry                                    *
  1714. 14460  *============================================================================*/
  1715. 14461 PRIVATE void w_geometry(entry)
  1716. 14462 struct partition *entry;
  1717. 14463 {
  1718. 14464   entry->cylinders = w_wn->cylinders;
  1719. 14465   entry->heads = w_wn->heads;
  1720. 14466   entry->sectors = w_wn->sectors;
  1721. 14467 }
  1722. 14468 #endif /* ENABLE_BIOS_WINI */
  1723. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1724. src/kernel/clock.c    
  1725. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1726. 14500 /* This file contains the code and data for the clock task.  The clock task
  1727. 14501  * accepts six message types:
  1728. 14502  *
  1729. 14503  *   HARD_INT:    a clock interrupt has occurred
  1730. 14504  *   GET_UPTIME:  get the time since boot in ticks
  1731. 14505  *   GET_TIME:    a process wants the real time in seconds
  1732. 14506  *   SET_TIME:    a process wants to set the real time in seconds
  1733. 14507  *   SET_ALARM:   a process wants to be alerted after a specified interval
  1734. 14508  *   SET_SYN_AL:  set the sync alarm
  1735. 14509  *
  1736. 14510  *
  1737. 14511  * The input message is format m6.  The parameters are as follows:
  1738. 14512  *
  1739. 14513  *     m_type    CLOCK_PROC   FUNC    NEW_TIME
  1740. 14514  * ---------------------------------------------
  1741. 14515  * | HARD_INT   |          |         |         |
  1742. 14516  * |------------+----------+---------+---------|
  1743. 14517  * | GET_UPTIME |          |         |         |
  1744. 14518  * |------------+----------+---------+---------|
  1745. 14519  * | GET_TIME   |          |         |         |
  1746. 14520  * |------------+----------+---------+---------|
  1747. 14521  * | SET_TIME   |          |         | newtime |
  1748. 14522  * |------------+----------+---------+---------|
  1749. 14523  * | SET_ALARM  | proc_nr  |f to call|  delta  |
  1750. 14524  * |------------+----------+---------+---------|
  1751. 14525  * | SET_SYN_AL | proc_nr  |         |  delta  |
  1752. 14526  * ---------------------------------------------
  1753. 14527  * NEW_TIME, DELTA_CLICKS, and SECONDS_LEFT all refer to the same field in
  1754. 14528  * the message, depending upon the message type.
  1755. 14529  *
  1756. .Op 179 src/kernel/clock.c
  1757. 14530  * Reply messages are of type OK, except in the case of a HARD_INT, to
  1758. 14531  * which no reply is generated. For the GET_* messages the time is returned
  1759. 14532  * in the NEW_TIME field, and for the SET_ALARM and SET_SYN_AL the time
  1760. 14533  * in seconds remaining until the alarm is returned is returned in the same
  1761. 14534  * field.
  1762. 14535  *
  1763. 14536  * When an alarm goes off, if the caller is a user process, a SIGALRM signal
  1764. 14537  * is sent to it.  If it is a task, a function specified by the caller will
  1765. 14538  * be invoked.  This function may, for example, send a message, but only if
  1766. 14539  * it is certain that the task will be blocked when the timer goes off. A
  1767. 14540  * synchronous alarm sends a message to the synchronous alarm task, which
  1768. 14541  * in turn can dispatch a message to another server. This is the only way
  1769. 14542  * to send an alarm to a server, since servers cannot use the function-call
  1770. 14543  * mechanism available to tasks and servers cannot receive signals.
  1771. 14544  */
  1772. 14545
  1773. 14546 #include "kernel.h"
  1774. 14547 #include <signal.h>
  1775. 14548 #include <minix/callnr.h>
  1776. 14549 #include <minix/com.h>
  1777. 14550 #include "proc.h"
  1778. 14551
  1779. 14552 /* Constant definitions. */
  1780. 14553 #define MILLISEC         100    /* how often to call the scheduler (msec) */
  1781. 14554 #define SCHED_RATE (MILLISEC*HZ/1000)   /* number of ticks per schedule */
  1782. 14555
  1783. 14556 /* Clock parameters. */
  1784. 14557 #if (CHIP == INTEL)
  1785. 14558 #define COUNTER_FREQ (2*TIMER_FREQ)     /* counter frequency using sqare wave*/
  1786. 14559 #define LATCH_COUNT     0x00    /* cc00xxxx, c = channel, x = any */
  1787. 14560 #define SQUARE_WAVE     0x36    /* ccaammmb, a = access, m = mode, b = BCD */
  1788. 14561                                 /*   11x11, 11 = LSB then MSB, x11 = sq wave */
  1789. 14562 #define TIMER_COUNT ((unsigned) (TIMER_FREQ/HZ)) /* initial value for counter*/
  1790. 14563 #define TIMER_FREQ  1193182L    /* clock frequency for timer in PC and AT */
  1791. 14564
  1792. 14565 #define CLOCK_ACK_BIT   0x80    /* PS/2 clock interrupt acknowledge bit */
  1793. 14566 #endif
  1794. 14567
  1795. 14568 #if (CHIP == M68000)
  1796. 14569 #define TIMER_FREQ  2457600L    /* timer 3 input clock frequency */
  1797. 14570 #endif
  1798. 14571
  1799. 14572 /* Clock task variables. */
  1800. 14573 PRIVATE clock_t realtime;       /* real time clock */
  1801. 14574 PRIVATE time_t boot_time;       /* time in seconds of system boot */
  1802. 14575 PRIVATE clock_t next_alarm;     /* probable time of next alarm */
  1803. 14576 PRIVATE message mc;             /* message buffer for both input and output */
  1804. 14577 PRIVATE int watchdog_proc;      /* contains proc_nr at call of *watch_dog[]*/
  1805. 14578 PRIVATE watchdog_t watch_dog[NR_TASKS+NR_PROCS];
  1806. 14579
  1807. 14580 /* Variables used by both clock task and synchronous alarm task */
  1808. 14581 PRIVATE int syn_al_alive= TRUE; /* don't wake syn_alrm_task before inited*/
  1809. 14582 PRIVATE int syn_table[NR_TASKS+NR_PROCS]; /* which tasks get CLOCK_INT*/
  1810. 14583
  1811. 14584 /* Variables changed by interrupt handler */
  1812. 14585 PRIVATE clock_t pending_ticks;  /* ticks seen by low level only */
  1813. 14586 PRIVATE int sched_ticks = SCHED_RATE;   /* counter: when 0, call scheduler */
  1814. 14587 PRIVATE struct proc *prev_ptr;  /* last user process run by clock task */
  1815. 14588
  1816. 14589 FORWARD _PROTOTYPE( void common_setalarm, (int proc_nr,
  1817. .Ep 180 src/kernel/clock.c
  1818. 14590                 long delta_ticks, watchdog_t fuction) );
  1819. 14591 FORWARD _PROTOTYPE( void do_clocktick, (void) );
  1820. 14592 FORWARD _PROTOTYPE( void do_get_time, (void) );
  1821. 14593 FORWARD _PROTOTYPE( void do_getuptime, (void) );
  1822. 14594 FORWARD _PROTOTYPE( void do_set_time, (message *m_ptr) );
  1823. 14595 FORWARD _PROTOTYPE( void do_setalarm, (message *m_ptr) );
  1824. 14596 FORWARD _PROTOTYPE( void init_clock, (void) );
  1825. 14597 FORWARD _PROTOTYPE( void cause_alarm, (void) );
  1826. 14598 FORWARD _PROTOTYPE( void do_setsyn_alrm, (message *m_ptr) );
  1827. 14599 FORWARD _PROTOTYPE( int clock_handler, (int irq) );
  1828. 14600
  1829. 14601 /*===========================================================================*
  1830. 14602  *                              clock_task                                   *
  1831. 14603  *===========================================================================*/
  1832. 14604 PUBLIC void clock_task()
  1833. 14605 {
  1834. 14606 /* Main program of clock task.  It corrects realtime by adding pending
  1835. 14607  * ticks seen only by the interrupt service, then it determines which
  1836. 14608  * of the 6 possible calls this is by looking at 'mc.m_type'.  Then
  1837. 14609  * it dispatches.
  1838. 14610  */
  1839. 14611
  1840. 14612   int opcode;
  1841. 14613
  1842. 14614   init_clock();                 /* initialize clock task */
  1843. 14615
  1844. 14616   /* Main loop of the clock task.  Get work, process it, sometimes reply. */
  1845. 14617   while (TRUE) {
  1846. 14618      receive(ANY, &mc);         /* go get a message */
  1847. 14619      opcode = mc.m_type;        /* extract the function code */
  1848. 14620
  1849. 14621      lock();
  1850. 14622      realtime += pending_ticks; /* transfer ticks from low level handler */
  1851. 14623      pending_ticks = 0;         /* so we don't have to worry about them */
  1852. 14624      unlock();
  1853. 14625
  1854. 14626      switch (opcode) {
  1855. 14627         case HARD_INT:   do_clocktick();        break;
  1856. 14628         case GET_UPTIME: do_getuptime();        break;
  1857. 14629         case GET_TIME:   do_get_time();         break;
  1858. 14630         case SET_TIME:   do_set_time(&mc);      break;
  1859. 14631         case SET_ALARM:  do_setalarm(&mc);      break;
  1860. 14632         case SET_SYNC_AL:do_setsyn_alrm(&mc);   break;
  1861. 14633         default: panic("clock task got bad message", mc.m_type);
  1862. 14634      }
  1863. 14635
  1864. 14636     /* Send reply, except for clock tick. */
  1865. 14637     mc.m_type = OK;
  1866. 14638     if (opcode != HARD_INT) send(mc.m_source, &mc);
  1867. 14639   }
  1868. 14640 }
  1869. 14643 /*===========================================================================*
  1870. 14644  *                              do_clocktick                                 *
  1871. 14645  *===========================================================================*/
  1872. 14646 PRIVATE void do_clocktick()
  1873. 14647 {
  1874. 14648 /* Despite its name, this routine is not called on every clock tick. It
  1875. 14649  * is called on those clock ticks when a lot of work needs to be done.
  1876. .Op 181 src/kernel/clock.c
  1877. 14650  */
  1878. 14651
  1879. 14652   register struct proc *rp;
  1880. 14653   register int proc_nr;
  1881. 14654
  1882. 14655   if (next_alarm <= realtime) {
  1883. 14656         /* An alarm may have gone off, but proc may have exited, so check. */
  1884. 14657         next_alarm = LONG_MAX;  /* start computing next alarm */
  1885. 14658         for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) {
  1886. 14659                 if (rp->p_alarm != 0) {
  1887. 14660                         /* See if this alarm time has been reached. */
  1888. 14661                         if (rp->p_alarm <= realtime) {
  1889. 14662                                 /* A timer has gone off.  If it is a user proc,
  1890. 14663                                  * send it a signal.  If it is a task, call the
  1891. 14664                                  * function previously specified by the task.
  1892. 14665                                  */
  1893. 14666                                 proc_nr = proc_number(rp);
  1894. 14667                                 if (watch_dog[proc_nr+NR_TASKS]) {
  1895. 14668                                         watchdog_proc= proc_nr;
  1896. 14669                                         (*watch_dog[proc_nr+NR_TASKS])();
  1897. 14670                                 }
  1898. 14671                                 else
  1899. 14672                                         cause_sig(proc_nr, SIGALRM);
  1900. 14673                                 rp->p_alarm = 0;
  1901. 14674                         }
  1902. 14675
  1903. 14676                         /* Work on determining which alarm is next. */
  1904. 14677                         if (rp->p_alarm != 0 && rp->p_alarm < next_alarm)
  1905. 14678                                 next_alarm = rp->p_alarm;
  1906. 14679                 }
  1907. 14680         }
  1908. 14681   }
  1909. 14682
  1910. 14683   /* If a user process has been running too long, pick another one. */
  1911. 14684   if (--sched_ticks == 0) {
  1912. 14685         if (bill_ptr == prev_ptr) lock_sched(); /* process has run too long */
  1913. 14686         sched_ticks = SCHED_RATE;               /* reset quantum */
  1914. 14687         prev_ptr = bill_ptr;                    /* new previous process */
  1915. 14688   }
  1916. 14689 #if (SHADOWING == 1)
  1917. 14690   if (rdy_head[SHADOW_Q]) unshadow(rdy_head[SHADOW_Q]);
  1918. 14691 #endif
  1919. 14692 }
  1920. 14695 /*===========================================================================*
  1921. 14696  *                              do_getuptime                                 *
  1922. 14697  *===========================================================================*/
  1923. 14698 PRIVATE void do_getuptime()
  1924. 14699 {
  1925. 14700 /* Get and return the current clock uptime in ticks. */
  1926. 14701
  1927. 14702   mc.NEW_TIME = realtime;       /* current uptime */
  1928. 14703 }
  1929. 14706 /*===========================================================================*
  1930. 14707  *                              get_uptime                                   *
  1931. 14708  *===========================================================================*/
  1932. 14709 PUBLIC clock_t get_uptime()
  1933. .Ep 182 src/kernel/clock.c
  1934. 14710 {
  1935. 14711 /* Get and return the current clock uptime in ticks.  This function is
  1936. 14712  * designed to be called from other tasks, so they can get uptime without
  1937. 14713  * the overhead of messages. It has to be careful about pending_ticks.
  1938. 14714  */
  1939. 14715
  1940. 14716   clock_t uptime;
  1941. 14717
  1942. 14718   lock();
  1943. 14719   uptime = realtime + pending_ticks;
  1944. 14720   unlock();
  1945. 14721   return(uptime);
  1946. 14722 }
  1947. 14725 /*===========================================================================*
  1948. 14726  *                              do_get_time                                  *
  1949. 14727  *===========================================================================*/
  1950. 14728 PRIVATE void do_get_time()
  1951. 14729 {
  1952. 14730 /* Get and return the current clock time in seconds. */
  1953. 14731
  1954. 14732   mc.NEW_TIME = boot_time + realtime/HZ;        /* current real time */
  1955. 14733 }
  1956. 14736 /*===========================================================================*
  1957. 14737  *                              do_set_time                                  *
  1958. 14738  *===========================================================================*/
  1959. 14739 PRIVATE void do_set_time(m_ptr)
  1960. 14740 message *m_ptr;                 /* pointer to request message */
  1961. 14741 {
  1962. 14742 /* Set the real time clock.  Only the superuser can use this call. */
  1963. 14743
  1964. 14744   boot_time = m_ptr->NEW_TIME - realtime/HZ;
  1965. 14745 }
  1966. 14748 /*===========================================================================*
  1967. 14749  *                              do_setalarm                                  *
  1968. 14750  *===========================================================================*/
  1969. 14751 PRIVATE void do_setalarm(m_ptr)
  1970. 14752 message *m_ptr;                 /* pointer to request message */
  1971. 14753 {
  1972. 14754 /* A process wants an alarm signal or a task wants a given watch_dog function
  1973. 14755  * called after a specified interval.
  1974. 14756  */
  1975. 14757
  1976. 14758   register struct proc *rp;
  1977. 14759   int proc_nr;                  /* which process wants the alarm */
  1978. 14760   long delta_ticks;             /* in how many clock ticks does he want it? */
  1979. 14761   watchdog_t function;          /* function to call (tasks only) */
  1980. 14762
  1981. 14763   /* Extract the parameters from the message. */
  1982. 14764   proc_nr = m_ptr->CLOCK_PROC_NR;       /* process to interrupt later */
  1983. 14765   delta_ticks = m_ptr->DELTA_TICKS;     /* how many ticks to wait */
  1984. 14766   function = (watchdog_t) m_ptr->FUNC_TO_CALL;
  1985. 14767                                         /* function to call (tasks only) */
  1986. 14768   rp = proc_addr(proc_nr);
  1987. 14769   mc.SECONDS_LEFT = (rp->p_alarm == 0 ? 0 : (rp->p_alarm - realtime)/HZ );
  1988. .Op 183 src/kernel/clock.c
  1989. 14770   if (!istaskp(rp)) function= 0;        /* user processes get signaled */
  1990. 14771   common_setalarm(proc_nr, delta_ticks, function);
  1991. 14772 }
  1992. 14775 /*===========================================================================*
  1993. 14776  *                              do_setsyn_alrm                               *
  1994. 14777  *===========================================================================*/
  1995. 14778 PRIVATE void do_setsyn_alrm(m_ptr)
  1996. 14779 message *m_ptr;                 /* pointer to request message */
  1997. 14780 {
  1998. 14781 /* A process wants a synchronous alarm.
  1999. 14782  */
  2000. 14783
  2001. 14784   register struct proc *rp;
  2002. 14785   int proc_nr;                  /* which process wants the alarm */
  2003. 14786   long delta_ticks;             /* in how many clock ticks does he want it? */
  2004. 14787
  2005. 14788   /* Extract the parameters from the message. */
  2006. 14789   proc_nr = m_ptr->CLOCK_PROC_NR;       /* process to interrupt later */
  2007. 14790   delta_ticks = m_ptr->DELTA_TICKS;     /* how many ticks to wait */
  2008. 14791   rp = proc_addr(proc_nr);
  2009. 14792   mc.SECONDS_LEFT = (rp->p_alarm == 0 ? 0 : (rp->p_alarm - realtime)/HZ );
  2010. 14793   common_setalarm(proc_nr, delta_ticks, cause_alarm);
  2011. 14794 }
  2012. 14797 /*===========================================================================*
  2013. 14798  *                              common_setalarm                              *
  2014. 14799  *===========================================================================*/
  2015. 14800 PRIVATE void common_setalarm(proc_nr, delta_ticks, function)
  2016. 14801 int proc_nr;                    /* which process wants the alarm */
  2017. 14802 long delta_ticks;               /* in how many clock ticks does he want it? */
  2018. 14803 watchdog_t function;            /* function to call (0 if cause_sig is
  2019. 14804                                  * to be called */
  2020. 14805 {
  2021. 14806 /* Finish up work of do_set_alarm and do_setsyn_alrm.  Record an alarm
  2022. 14807  * request and check to see if it is the next alarm needed.
  2023. 14808  */
  2024. 14809
  2025. 14810   register struct proc *rp;
  2026. 14811
  2027. 14812   rp = proc_addr(proc_nr);
  2028. 14813   rp->p_alarm = (delta_ticks == 0 ? 0 : realtime + delta_ticks);
  2029. 14814   watch_dog[proc_nr+NR_TASKS] = function;
  2030. 14815
  2031. 14816   /* Which alarm is next? */
  2032. 14817   next_alarm = LONG_MAX;
  2033. 14818   for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++)
  2034. 14819         if(rp->p_alarm != 0 && rp->p_alarm < next_alarm)next_alarm=rp->p_alarm;
  2035. 14820
  2036. 14821 }
  2037. 14824 /*===========================================================================*
  2038. 14825  *                              cause_alarm                                  *
  2039. 14826  *===========================================================================*/
  2040. 14827 PRIVATE void cause_alarm()
  2041. 14828 {
  2042. 14829 /* Routine called if a timer goes off and the process requested a synchronous
  2043. .Ep 184 src/kernel/clock.c
  2044. 14830  * alarm. The process number is in the global variable watchdog_proc (HACK).
  2045. 14831  */
  2046. 14832   message mess;
  2047. 14833
  2048. 14834   syn_table[watchdog_proc + NR_TASKS]= TRUE;
  2049. 14835   if (!syn_al_alive) send (SYN_ALRM_TASK, &mess);
  2050. 14836 }
  2051. 14839 /*===========================================================================*
  2052. 14840  *                              syn_alrm_task                                *
  2053. 14841  *===========================================================================*/
  2054. 14842 PUBLIC void syn_alrm_task()
  2055. 14843 {
  2056. 14844 /* Main program of the synchronous alarm task.
  2057. 14845  * This task receives messages only from cause_alarm in the clock task.
  2058. 14846  * It sends a CLOCK_INT message to a process that requested a syn_alrm.
  2059. 14847  * Synchronous alarms are so called because, unlike a signals or the
  2060. 14848  * activation of a watchdog, a synchronous alarm is received by a process
  2061. 14849  * when it is in a known part of its code, that is, when it has issued
  2062. 14850  * a call to receive a message.
  2063. 14851  */
  2064. 14852
  2065. 14853   message mess;
  2066. 14854   int work_done;        /* ready to sleep ? */
  2067. 14855   int *al_ptr;          /* pointer in syn_table */
  2068. 14856   int i;
  2069. 14857
  2070. 14858   syn_al_alive= TRUE;
  2071. 14859   for (i= 0, al_ptr= syn_table; i<NR_TASKS+NR_PROCS; i++, al_ptr++)
  2072. 14860         *al_ptr= FALSE;
  2073. 14861
  2074. 14862   while (TRUE) {
  2075. 14863         work_done= TRUE;
  2076. 14864         for (i= 0, al_ptr= syn_table; i<NR_TASKS+NR_PROCS; i++, al_ptr++)
  2077. 14865                 if (*al_ptr) {
  2078. 14866                         *al_ptr= FALSE;
  2079. 14867                         mess.m_type= CLOCK_INT;
  2080. 14868                         send (i-NR_TASKS, &mess);
  2081. 14869                         work_done= FALSE;
  2082. 14870                 }
  2083. 14871         if (work_done) {
  2084. 14872                 syn_al_alive= FALSE;
  2085. 14873                 receive (CLOCK, &mess);
  2086. 14874                 syn_al_alive= TRUE;
  2087. 14875         }
  2088. 14876   }
  2089. 14877 }
  2090. 14880 /*===========================================================================*
  2091. 14881  *                              clock_handler                                *
  2092. 14882  *===========================================================================*/
  2093. 14883 PRIVATE int clock_handler(irq)
  2094. 14884 int irq;
  2095. 14885 {
  2096. 14886 /* This executes on every clock tick (i.e., every time the timer chip
  2097. 14887  * generates an interrupt). It does a little bit of work so the clock
  2098. 14888  * task does not have to be called on every tick.
  2099. 14889  *
  2100. .Op 185 src/kernel/clock.c
  2101. 14890  * Switch context to do_clocktick if an alarm has gone off.
  2102. 14891  * Also switch there to reschedule if the reschedule will do something.
  2103. 14892  * This happens when
  2104. 14893  *      (1) quantum has expired
  2105. 14894  *      (2) current process received full quantum (as clock sampled it!)
  2106. 14895  *      (3) something else is ready to run.
  2107. 14896  * Also call TTY and PRINTER and let them do whatever is necessary.
  2108. 14897  *
  2109. 14898  * Many global global and static variables are accessed here.  The safety
  2110. 14899  * of this must be justified.  Most of them are not changed here:
  2111. 14900  *      k_reenter:
  2112. 14901  *              This safely tells if the clock interrupt is nested.
  2113. 14902  *      proc_ptr, bill_ptr:
  2114. 14903  *              These are used for accounting.  It does not matter if proc.c
  2115. 14904  *              is changing them, provided they are always valid pointers,
  2116. 14905  *              since at worst the previous process would be billed.
  2117. 14906  *      next_alarm, realtime, sched_ticks, bill_ptr, prev_ptr,
  2118. 14907  *      rdy_head[USER_Q]:
  2119. 14908  *              These are tested to decide whether to call interrupt().  It
  2120. 14909  *              does not matter if the test is sometimes (rarely) backwards
  2121. 14910  *              due to a race, since this will only delay the high-level
  2122. 14911  *              processing by one tick, or call the high level unnecessarily.
  2123. 14912  * The variables which are changed require more care:
  2124. 14913  *      rp->user_time, rp->sys_time:
  2125. 14914  *              These are protected by explicit locks in system.c.  They are
  2126. 14915  *              not properly protected in dmp.c (the increment here is not
  2127. 14916  *              atomic) but that hardly matters.
  2128. 14917  *      pending_ticks:
  2129. 14918  *              This is protected by explicit locks in clock.c.  Don't
  2130. 14919  *              update realtime directly, since there are too many
  2131. 14920  *              references to it to guard conveniently.
  2132. 14921  *      lost_ticks:
  2133. 14922  *              Clock ticks counted outside the clock task.
  2134. 14923  *      sched_ticks, prev_ptr:
  2135. 14924  *              Updating these competes with similar code in do_clocktick().
  2136. 14925  *              No lock is necessary, because if bad things happen here
  2137. 14926  *              (like sched_ticks going negative), the code in do_clocktick()
  2138. 14927  *              will restore the variables to reasonable values, and an
  2139. 14928  *              occasional missed or extra sched() is harmless.
  2140. 14929  *
  2141. 14930  * Are these complications worth the trouble?  Well, they make the system 15%
  2142. 14931  * faster on a 5MHz 8088, and make task debugging much easier since there are
  2143. 14932  * no task switches on an inactive system.
  2144. 14933  */
  2145. 14934
  2146. 14935   register struct proc *rp;
  2147. 14936   register unsigned ticks;
  2148. 14937   clock_t now;
  2149. 14938
  2150. 14939   if (ps_mca) {
  2151. 14940         /* Acknowledge the PS/2 clock interrupt. */
  2152. 14941         out_byte(PORT_B, in_byte(PORT_B) | CLOCK_ACK_BIT);
  2153. 14942   }
  2154. 14943
  2155. 14944   /* Update user and system accounting times.
  2156. 14945    * First charge the current process for user time.
  2157. 14946    * If the current process is not the billable process (usually because it
  2158. 14947    * is a task), charge the billable process for system time as well.
  2159. 14948    * Thus the unbillable tasks' user time is the billable users' system time.
  2160. 14949    */
  2161. .Ep 186 src/kernel/clock.c
  2162. 14950   if (k_reenter != 0)
  2163. 14951         rp = proc_addr(HARDWARE);
  2164. 14952   else
  2165. 14953         rp = proc_ptr;
  2166. 14954   ticks = lost_ticks + 1;
  2167. 14955   lost_ticks = 0;
  2168. 14956   rp->user_time += ticks;
  2169. 14957   if (rp != bill_ptr && rp != proc_addr(IDLE)) bill_ptr->sys_time += ticks;
  2170. 14958
  2171. 14959   pending_ticks += ticks;
  2172. 14960   now = realtime + pending_ticks;
  2173. 14961   if (tty_timeout <= now) tty_wakeup(now);      /* possibly wake up TTY */
  2174. 14962 #if (CHIP != M68000)
  2175. 14963   pr_restart();                                 /* possibly restart printer */
  2176. 14964 #endif
  2177. 14965 #if (CHIP == M68000)
  2178. 14966   kb_timer();                                   /* keyboard repeat */
  2179. 14967   if (sched_ticks == 1) fd_timer();             /* floppy deselect */
  2180. 14968 #endif
  2181. 14969
  2182. 14970   if (next_alarm <= now ||
  2183. 14971       sched_ticks == 1 &&
  2184. 14972       bill_ptr == prev_ptr &&
  2185. 14973 #if (SHADOWING == 0)
  2186. 14974       rdy_head[USER_Q] != NIL_PROC) {
  2187. 14975 #else
  2188. 14976       (rdy_head[USER_Q] != NIL_PROC || rdy_head[SHADOW_Q] != NIL_PROC)) {
  2189. 14977 #endif
  2190. 14978         interrupt(CLOCK);
  2191. 14979         return 1;       /* Reenable interrupts */
  2192. 14980   }
  2193. 14981
  2194. 14982   if (--sched_ticks == 0) {
  2195. 14983         /* If bill_ptr == prev_ptr, no ready users so don't need sched(). */
  2196. 14984         sched_ticks = SCHED_RATE;       /* reset quantum */
  2197. 14985         prev_ptr = bill_ptr;            /* new previous process */
  2198. 14986   }
  2199. 14987   return 1;     /* Reenable clock interrupt */
  2200. 14988 }
  2201. 14990 #if (CHIP == INTEL)
  2202. 14991
  2203. 14992 /*===========================================================================*
  2204. 14993  *                              init_clock                                   *
  2205. 14994  *===========================================================================*/
  2206. 14995 PRIVATE void init_clock()
  2207. 14996 {
  2208. 14997 /* Initialize channel 0 of the 8253A timer to e.g. 60 Hz. */
  2209. 14998
  2210. 14999   out_byte(TIMER_MODE, SQUARE_WAVE);    /* set timer to run continuously */
  2211. 15000   out_byte(TIMER0, TIMER_COUNT);        /* load timer low byte */
  2212. 15001   out_byte(TIMER0, TIMER_COUNT >> 8);   /* load timer high byte */
  2213. 15002   put_irq_handler(CLOCK_IRQ, clock_handler);    /* set the interrupt handler */
  2214. 15003   enable_irq(CLOCK_IRQ);                /* ready for clock interrupts */
  2215. 15004 }
  2216. 15007 /*===========================================================================*
  2217. 15008  *                              clock_stop                                   *
  2218. 15009  *===========================================================================*/
  2219. .Op 187 src/kernel/clock.c
  2220. 15010 PUBLIC void clock_stop()
  2221. 15011 {
  2222. 15012 /* Reset the clock to the BIOS rate. (For rebooting) */
  2223. 15013
  2224. 15014   out_byte(TIMER_MODE, 0x36);
  2225. 15015   out_byte(TIMER0, 0);
  2226. 15016   out_byte(TIMER0, 0);
  2227. 15017 }
  2228. 15020 /*==========================================================================*
  2229. 15021  *                              milli_delay                                 *
  2230. 15022  *==========================================================================*/
  2231. 15023 PUBLIC void milli_delay(millisec)
  2232. 15024 unsigned millisec;
  2233. 15025 {
  2234. 15026 /* Delay some milliseconds. */
  2235. 15027
  2236. 15028   struct milli_state ms;
  2237. 15029
  2238. 15030   milli_start(&ms);
  2239. 15031   while (milli_elapsed(&ms) < millisec) {}
  2240. 15032 }
  2241. 15034 /*==========================================================================*
  2242. 15035  *                              milli_start                                 *
  2243. 15036  *==========================================================================*/
  2244. 15037 PUBLIC void milli_start(msp)
  2245. 15038 struct milli_state *msp;
  2246. 15039 {
  2247. 15040 /* Prepare for calls to milli_elapsed(). */
  2248. 15041
  2249. 15042   msp->prev_count = 0;
  2250. 15043   msp->accum_count = 0;
  2251. 15044 }
  2252. 15047 /*==========================================================================*
  2253. 15048  *                              milli_elapsed                               *
  2254. 15049  *==========================================================================*/
  2255. 15050 PUBLIC unsigned milli_elapsed(msp)
  2256. 15051 struct milli_state *msp;
  2257. 15052 {
  2258. 15053 /* Return the number of milliseconds since the call to milli_start().  Must be
  2259. 15054  * polled rapidly.
  2260. 15055  */
  2261. 15056   unsigned count;
  2262. 15057
  2263. 15058   /* Read the counter for channel 0 of the 8253A timer.  The counter
  2264. 15059    * decrements at twice the timer frequency (one full cycle for each
  2265. 15060    * half of square wave).  The counter normally has a value between 0
  2266. 15061    * and TIMER_COUNT, but before the clock task has been initialized,
  2267. 15062    * its maximum value is 65535, as set by the BIOS.
  2268. 15063    */
  2269. 15064   out_byte(TIMER_MODE, LATCH_COUNT);    /* make chip copy count to latch */
  2270. 15065   count = in_byte(TIMER0);      /* countdown continues during 2-step read */
  2271. 15066   count |= in_byte(TIMER0) << 8;
  2272. 15067
  2273. 15068   /* Add difference between previous and new count unless the counter has
  2274. 15069    * increased (restarted its cycle).  We may lose a tick now and then, but
  2275. .Ep 188 src/kernel/clock.c
  2276. 15070    * microsecond precision is not needed.
  2277. 15071    */
  2278. 15072   msp->accum_count += count <= msp->prev_count ? (msp->prev_count - count) : 1;
  2279. 15073   msp->prev_count = count;
  2280. 15074
  2281. 15075   return msp->accum_count / (TIMER_FREQ / 1000);
  2282. 15076 }
  2283. 15077 #endif /* (CHIP == INTEL) */
  2284. 15078
  2285. 15079
  2286. 15080 #if (CHIP == M68000)
  2287. 15081 #include "staddr.h"
  2288. 15082 #include "stmfp.h"
  2289. 15083
  2290. 15084 /*===========================================================================*
  2291. 15085  *                              init_clock                                   *
  2292. 15086  *===========================================================================*/
  2293. 15087 PRIVATE void init_clock()
  2294. 15088 {
  2295. 15089 /* Initialize the timer C in the MFP 68901.
  2296. 15090  * Reducing to HZ is not possible by hardware.  The resulting interrupt
  2297. 15091  * rate is further reduced by software with a factor of 4.
  2298. 15092  * Note that the expression below works for both HZ=50 and HZ=60.
  2299. 15093  */
  2300. 15094   do {
  2301. 15095         MFP->mf_tcdr = TIMER_FREQ/(64*4*HZ);
  2302. 15096   } while ((MFP->mf_tcdr & 0xFF) != TIMER_FREQ/(64*4*HZ));
  2303. 15097   MFP->mf_tcdcr |= (T_Q064<<4);
  2304. 15098 }
  2305. 15099 #endif /* (CHIP == M68000) */
  2306. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2307. src/kernel/console.c    
  2308. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2309. 15100 /* Code and data for the IBM console driver.
  2310. 15101  *
  2311. 15102  * The 6845 video controller used by the IBM PC shares its video memory with
  2312. 15103  * the CPU somewhere in the 0xB0000 memory bank.  To the 6845 this memory
  2313. 15104  * consists of 16-bit words.  Each word has a character code in the low byte
  2314. 15105  * and a so-called attribute byte in the high byte.  The CPU directly modifies
  2315. 15106  * video memory to display characters, and sets two registers on the 6845 that
  2316. 15107  * specify the video origin and the cursor position.  The video origin is the
  2317. 15108  * place in video memory where the first character (upper left corner) can
  2318. 15109  * be found.  Moving the origin is a fast way to scroll the screen.  Some
  2319. 15110  * video adapters wrap around the top of video memory, so the origin can
  2320. 15111  * move without bounds.  For other adapters screen memory must sometimes be
  2321. 15112  * moved to reset the origin.  All computations on video memory use character
  2322. 15113  * (word) addresses for simplicity and assume there is no wrapping.  The
  2323. 15114  * assembly support functions translate the word addresses to byte addresses
  2324. 15115  * and the scrolling function worries about wrapping.
  2325. 15116  */
  2326. 15117
  2327. 15118 #include "kernel.h"
  2328. 15119 #include <termios.h>
  2329. .Op 189 src/kernel/console.c
  2330. 15120 #include <minix/callnr.h>
  2331. 15121 #include <minix/com.h>
  2332. 15122 #include "protect.h"
  2333. 15123 #include "tty.h"
  2334. 15124 #include "proc.h"
  2335. 15125
  2336. 15126 /* Definitions used by the console driver. */
  2337. 15127 #define MONO_BASE    0xB0000L   /* base of mono video memory */
  2338. 15128 #define COLOR_BASE   0xB8000L   /* base of color video memory */
  2339. 15129 #define MONO_SIZE     0x1000    /* 4K mono video memory */
  2340. 15130 #define COLOR_SIZE    0x4000    /* 16K color video memory */
  2341. 15131 #define EGA_SIZE      0x8000    /* EGA & VGA have at least 32K */
  2342. 15132 #define BLANK_COLOR   0x0700    /* determines cursor color on blank screen */
  2343. 15133 #define SCROLL_UP          0    /* scroll forward */
  2344. 15134 #define SCROLL_DOWN        1    /* scroll backward */
  2345. 15135 #define BLANK_MEM ((u16_t *) 0) /* tells mem_vid_copy() to blank the screen */
  2346. 15136 #define CONS_RAM_WORDS    80    /* video ram buffer size */
  2347. 15137 #define MAX_ESC_PARMS      2    /* number of escape sequence params allowed */
  2348. 15138
  2349. 15139 /* Constants relating to the controller chips. */
  2350. 15140 #define M_6845         0x3B4    /* port for 6845 mono */
  2351. 15141 #define C_6845         0x3D4    /* port for 6845 color */
  2352. 15142 #define EGA            0x3C4    /* port for EGA card */
  2353. 15143 #define INDEX              0    /* 6845's index register */
  2354. 15144 #define DATA               1    /* 6845's data register */
  2355. 15145 #define VID_ORG           12    /* 6845's origin register */
  2356. 15146 #define CURSOR            14    /* 6845's cursor register */
  2357. 15147
  2358. 15148 /* Beeper. */
  2359. 15149 #define BEEP_FREQ     0x0533    /* value to put into timer to set beep freq */
  2360. 15150 #define B_TIME             3    /* length of CTRL-G beep is ticks */
  2361. 15151
  2362. 15152 /* definitions used for font management */
  2363. 15153 #define GA_SEQUENCER_INDEX      0x3C4
  2364. 15154 #define GA_SEQUENCER_DATA       0x3C5
  2365. 15155 #define GA_GRAPHICS_INDEX       0x3CE
  2366. 15156 #define GA_GRAPHICS_DATA        0x3CF
  2367. 15157 #define GA_VIDEO_ADDRESS        0xA0000L
  2368. 15158 #define GA_FONT_SIZE            8192
  2369. 15159
  2370. 15160 /* Global variables used by the console driver. */
  2371. 15161 PUBLIC unsigned vid_seg;        /* video ram selector (0xB0000 or 0xB8000) */
  2372. 15162 PUBLIC unsigned vid_size;       /* 0x2000 for color or 0x0800 for mono */
  2373. 15163 PUBLIC unsigned vid_mask;       /* 0x1FFF for color or 0x07FF for mono */
  2374. 15164 PUBLIC unsigned blank_color = BLANK_COLOR; /* display code for blank */
  2375. 15165
  2376. 15166 /* Private variables used by the console driver. */
  2377. 15167 PRIVATE int vid_port;           /* I/O port for accessing 6845 */
  2378. 15168 PRIVATE int wrap;               /* hardware can wrap? */
  2379. 15169 PRIVATE int softscroll;         /* 1 = software scrolling, 0 = hardware */
  2380. 15170 PRIVATE unsigned vid_base;      /* base of video ram (0xB000 or 0xB800) */
  2381. 15171 PRIVATE int beeping;            /* speaker is beeping? */
  2382. 15172 #define scr_width       80      /* # characters on a line */
  2383. 15173 #define scr_lines       25      /* # lines on the screen */
  2384. 15174 #define scr_size        (80*25) /* # characters on the screen */
  2385. 15175
  2386. 15176 /* Per console data. */
  2387. 15177 typedef struct console {
  2388. 15178   tty_t *c_tty;                 /* associated TTY struct */
  2389. 15179   int c_column;                 /* current column number (0-origin) */
  2390. .Ep 190 src/kernel/console.c
  2391. 15180   int c_row;                    /* current row (0 at top of screen) */
  2392. 15181   int c_rwords;                 /* number of WORDS (not bytes) in outqueue */
  2393. 15182   unsigned c_start;             /* start of video memory of this console */
  2394. 15183   unsigned c_limit;             /* limit of this console's video memory */
  2395. 15184   unsigned c_org;               /* location in RAM where 6845 base points */
  2396. 15185   unsigned c_cur;               /* current position of cursor in video RAM */
  2397. 15186   unsigned c_attr;              /* character attribute */
  2398. 15187   unsigned c_blank;             /* blank attribute */
  2399. 15188   char c_esc_state;             /* 0=normal, 1=ESC, 2=ESC[ */
  2400. 15189   char c_esc_intro;             /* Distinguishing character following ESC */
  2401. 15190   int *c_esc_parmp;             /* pointer to current escape parameter */
  2402. 15191   int c_esc_parmv[MAX_ESC_PARMS];       /* list of escape parameters */
  2403. 15192   u16_t c_ramqueue[CONS_RAM_WORDS];     /* buffer for video RAM */
  2404. 15193 } console_t;
  2405. 15194
  2406. 15195 PRIVATE int nr_cons= 1;         /* actual number of consoles */
  2407. 15196 PRIVATE console_t cons_table[NR_CONS];
  2408. 15197 PRIVATE console_t *curcons;     /* currently visible */
  2409. 15198
  2410. 15199 /* Color if using a color controller. */
  2411. 15200 #define color   (vid_port == C_6845)
  2412. 15201
  2413. 15202 /* Map from ANSI colors to the attributes used by the PC */
  2414. 15203 PRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7};
  2415. 15204
  2416. 15205 /* Structure used for font management */
  2417. 15206 struct sequence {
  2418. 15207         unsigned short index;
  2419. 15208         unsigned char port;
  2420. 15209         unsigned char value;
  2421. 15210 };
  2422. 15211
  2423. 15212 FORWARD _PROTOTYPE( void cons_write, (struct tty *tp)                   );
  2424. 15213 FORWARD _PROTOTYPE( void cons_echo, (tty_t *tp, int c)                  );
  2425. 15214 FORWARD _PROTOTYPE( void out_char, (console_t *cons, int c)             );
  2426. 15215 FORWARD _PROTOTYPE( void beep, (void)                                   );
  2427. 15216 FORWARD _PROTOTYPE( void do_escape, (console_t *cons, int c)            );
  2428. 15217 FORWARD _PROTOTYPE( void flush, (console_t *cons)                       );
  2429. 15218 FORWARD _PROTOTYPE( void parse_escape, (console_t *cons, int c)         );
  2430. 15219 FORWARD _PROTOTYPE( void scroll_screen, (console_t *cons, int dir)      );
  2431. 15220 FORWARD _PROTOTYPE( void set_6845, (int reg, unsigned val)              );
  2432. 15221 FORWARD _PROTOTYPE( void stop_beep, (void)                              );
  2433. 15222 FORWARD _PROTOTYPE( void cons_org0, (void)                              );
  2434. 15223 FORWARD _PROTOTYPE( void ga_program, (struct sequence *seq) );
  2435. 15224
  2436. 15225
  2437. 15226 /*===========================================================================*
  2438. 15227  *                              cons_write                                   *
  2439. 15228  *===========================================================================*/
  2440. 15229 PRIVATE void cons_write(tp)
  2441. 15230 register struct tty *tp;        /* tells which terminal is to be used */
  2442. 15231 {
  2443. 15232 /* Copy as much data as possible to the output queue, then start I/O.  On
  2444. 15233  * memory-mapped terminals, such as the IBM console, the I/O will also be
  2445. 15234  * finished, and the counts updated.  Keep repeating until all I/O done.
  2446. 15235  */
  2447. 15236
  2448. 15237   int count;
  2449. 15238   register char *tbuf;
  2450. 15239   char buf[64];
  2451. .Op 191 src/kernel/console.c
  2452. 15240   phys_bytes user_phys;
  2453. 15241   console_t *cons = tp->tty_priv;
  2454. 15242
  2455. 15243   /* Check quickly for nothing to do, so this can be called often without
  2456. 15244    * unmodular tests elsewhere.
  2457. 15245    */
  2458. 15246   if ((count = tp->tty_outleft) == 0 || tp->tty_inhibited) return;
  2459. 15247
  2460. 15248   /* Copy the user bytes to buf[] for decent addressing. Loop over the
  2461. 15249    * copies, since the user buffer may be much larger than buf[].
  2462. 15250    */
  2463. 15251   do {
  2464. 15252         if (count > sizeof(buf)) count = sizeof(buf);
  2465. 15253         user_phys = proc_vir2phys(proc_addr(tp->tty_outproc), tp->tty_out_vir);
  2466. 15254         phys_copy(user_phys, vir2phys(buf), (phys_bytes) count);
  2467. 15255         tbuf = buf;
  2468. 15256
  2469. 15257         /* Update terminal data structure. */
  2470. 15258         tp->tty_out_vir += count;
  2471. 15259         tp->tty_outcum += count;
  2472. 15260         tp->tty_outleft -= count;
  2473. 15261
  2474. 15262         /* Output each byte of the copy to the screen.  Avoid calling
  2475. 15263          * out_char() for the "easy" characters, put them into the buffer
  2476. 15264          * directly.
  2477. 15265          */
  2478. 15266         do {
  2479. 15267                 if ((unsigned) *tbuf < ' ' || cons->c_esc_state > 0
  2480. 15268                         || cons->c_column >= scr_width
  2481. 15269                         || cons->c_rwords >= buflen(cons->c_ramqueue))
  2482. 15270                 {
  2483. 15271                         out_char(cons, *tbuf++);
  2484. 15272                 } else {
  2485. 15273                         cons->c_ramqueue[cons->c_rwords++] =
  2486. 15274                                         cons->c_attr | (*tbuf++ & BYTE);
  2487. 15275                         cons->c_column++;
  2488. 15276                 }
  2489. 15277         } while (--count != 0);
  2490. 15278   } while ((count = tp->tty_outleft) != 0 && !tp->tty_inhibited);
  2491. 15279
  2492. 15280   flush(cons);                  /* transfer anything buffered to the screen */
  2493. 15281
  2494. 15282   /* Reply to the writer if all output is finished. */
  2495. 15283   if (tp->tty_outleft == 0) {
  2496. 15284         tty_reply(tp->tty_outrepcode, tp->tty_outcaller, tp->tty_outproc,
  2497. 15285                                                         tp->tty_outcum);
  2498. 15286         tp->tty_outcum = 0;
  2499. 15287   }
  2500. 15288 }
  2501. 15291 /*===========================================================================*
  2502. 15292  *                              cons_echo                                    *
  2503. 15293  *===========================================================================*/
  2504. 15294 PRIVATE void cons_echo(tp, c)
  2505. 15295 register tty_t *tp;             /* pointer to tty struct */
  2506. 15296 int c;                          /* character to be echoed */
  2507. 15297 {
  2508. 15298 /* Echo keyboard input (print & flush). */
  2509. 15299   console_t *cons = tp->tty_priv;
  2510. .Ep 192 src/kernel/console.c
  2511. 15300
  2512. 15301   out_char(cons, c);
  2513. 15302   flush(cons);
  2514. 15303 }
  2515. 15306 /*===========================================================================*
  2516. 15307  *                              out_char                                     *
  2517. 15308  *===========================================================================*/
  2518. 15309 PRIVATE void out_char(cons, c)
  2519. 15310 register console_t *cons;       /* pointer to console struct */
  2520. 15311 int c;                          /* character to be output */
  2521. 15312 {
  2522. 15313 /* Output a character on the console.  Check for escape sequences first. */
  2523. 15314   if (cons->c_esc_state > 0) {
  2524. 15315         parse_escape(cons, c);
  2525. 15316         return;
  2526. 15317   }
  2527. 15318
  2528. 15319   switch(c) {
  2529. 15320         case 000:               /* null is typically used for padding */
  2530. 15321                 return;         /* better not do anything */
  2531. 15322
  2532. 15323         case 007:               /* ring the bell */
  2533. 15324                 flush(cons);    /* print any chars queued for output */
  2534. 15325                 beep();
  2535. 15326                 return;
  2536. 15327
  2537. 15328         case 'b':              /* backspace */
  2538. 15329                 if (--cons->c_column < 0) {
  2539. 15330                         if (--cons->c_row >= 0) cons->c_column += scr_width;
  2540. 15331                 }
  2541. 15332                 flush(cons);
  2542. 15333                 return;
  2543. 15334
  2544. 15335         case 'n':              /* line feed */
  2545. 15336                 if ((cons->c_tty->tty_termios.c_oflag & (OPOST|ONLCR))
  2546. 15337                                                 == (OPOST|ONLCR)) {
  2547. 15338                         cons->c_column = 0;
  2548. 15339                 }
  2549. 15340                 /*FALL THROUGH*/
  2550. 15341         case 013:               /* CTRL-K */
  2551. 15342         case 014:               /* CTRL-L */
  2552. 15343                 if (cons->c_row == scr_lines-1) {
  2553. 15344                         scroll_screen(cons, SCROLL_UP);
  2554. 15345                 } else {
  2555. 15346                         cons->c_row++;
  2556. 15347                 }
  2557. 15348                 flush(cons);
  2558. 15349                 return;
  2559. 15350
  2560. 15351         case 'r':              /* carriage return */
  2561. 15352                 cons->c_column = 0;
  2562. 15353                 flush(cons);
  2563. 15354                 return;
  2564. 15355
  2565. 15356         case 't':              /* tab */
  2566. 15357                 cons->c_column = (cons->c_column + TAB_SIZE) & ~TAB_MASK;
  2567. 15358                 if (cons->c_column > scr_width) {
  2568. 15359                         cons->c_column -= scr_width;
  2569. .Op 193 src/kernel/console.c
  2570. 15360                         if (cons->c_row == scr_lines-1) {
  2571. 15361                                 scroll_screen(cons, SCROLL_UP);
  2572. 15362                         } else {
  2573. 15363                                 cons->c_row++;
  2574. 15364                         }
  2575. 15365                 }
  2576. 15366                 flush(cons);
  2577. 15367                 return;
  2578. 15368
  2579. 15369         case 033:               /* ESC - start of an escape sequence */
  2580. 15370                 flush(cons);    /* print any chars queued for output */
  2581. 15371                 cons->c_esc_state = 1;  /* mark ESC as seen */
  2582. 15372                 return;
  2583. 15373
  2584. 15374         default:                /* printable chars are stored in ramqueue */
  2585. 15375                 if (cons->c_column >= scr_width) {
  2586. 15376                         if (!LINEWRAP) return;
  2587. 15377                         if (cons->c_row == scr_lines-1) {
  2588. 15378                                 scroll_screen(cons, SCROLL_UP);
  2589. 15379                         } else {
  2590. 15380                                 cons->c_row++;
  2591. 15381                         }
  2592. 15382                         cons->c_column = 0;
  2593. 15383                         flush(cons);
  2594. 15384                 }
  2595. 15385                 if (cons->c_rwords == buflen(cons->c_ramqueue)) flush(cons);
  2596. 15386                 cons->c_ramqueue[cons->c_rwords++] = cons->c_attr | (c & BYTE);
  2597. 15387                 cons->c_column++;                       /* next column */
  2598. 15388                 return;
  2599. 15389   }
  2600. 15390 }
  2601. 15393 /*===========================================================================*
  2602. 15394  *                              scroll_screen                                *
  2603. 15395  *===========================================================================*/
  2604. 15396 PRIVATE void scroll_screen(cons, dir)
  2605. 15397 register console_t *cons;       /* pointer to console struct */
  2606. 15398 int dir;                        /* SCROLL_UP or SCROLL_DOWN */
  2607. 15399 {
  2608. 15400   unsigned new_line, new_org, chars;
  2609. 15401
  2610. 15402   flush(cons);
  2611. 15403   chars = scr_size - scr_width;         /* one screen minus one line */
  2612. 15404
  2613. 15405   /* Scrolling the screen is a real nuisance due to the various incompatible
  2614. 15406    * video cards.  This driver supports software scrolling (Hercules?),
  2615. 15407    * hardware scrolling (mono and CGA cards) and hardware scrolling without
  2616. 15408    * wrapping (EGA cards).  In the latter case we must make sure that
  2617. 15409    *            c_start <= c_org && c_org + scr_size <= c_limit
  2618. 15410    * holds, because EGA doesn't wrap around the end of video memory.
  2619. 15411    */
  2620. 15412   if (dir == SCROLL_UP) {
  2621. 15413         /* Scroll one line up in 3 ways: soft, avoid wrap, use origin. */
  2622. 15414         if (softscroll) {
  2623. 15415                 vid_vid_copy(cons->c_start + scr_width, cons->c_start, chars);
  2624. 15416         } else
  2625. 15417         if (!wrap && cons->c_org + scr_size + scr_width >= cons->c_limit) {
  2626. 15418                 vid_vid_copy(cons->c_org + scr_width, cons->c_start, chars);
  2627. 15419                 cons->c_org = cons->c_start;
  2628. .Ep 194 src/kernel/console.c
  2629. 15420         } else {
  2630. 15421                 cons->c_org = (cons->c_org + scr_width) & vid_mask;
  2631. 15422         }
  2632. 15423         new_line = (cons->c_org + chars) & vid_mask;
  2633. 15424   } else {
  2634. 15425         /* Scroll one line down in 3 ways: soft, avoid wrap, use origin. */
  2635. 15426         if (softscroll) {
  2636. 15427                 vid_vid_copy(cons->c_start, cons->c_start + scr_width, chars);
  2637. 15428         } else
  2638. 15429         if (!wrap && cons->c_org < cons->c_start + scr_width) {
  2639. 15430                 new_org = cons->c_limit - scr_size;
  2640. 15431                 vid_vid_copy(cons->c_org, new_org + scr_width, chars);
  2641. 15432                 cons->c_org = new_org;
  2642. 15433         } else {
  2643. 15434                 cons->c_org = (cons->c_org - scr_width) & vid_mask;
  2644. 15435         }
  2645. 15436         new_line = cons->c_org;
  2646. 15437   }
  2647. 15438   /* Blank the new line at top or bottom. */
  2648. 15439   blank_color = cons->c_blank;
  2649. 15440   mem_vid_copy(BLANK_MEM, new_line, scr_width);
  2650. 15441
  2651. 15442   /* Set the new video origin. */
  2652. 15443   if (cons == curcons) set_6845(VID_ORG, cons->c_org);
  2653. 15444   flush(cons);
  2654. 15445 }
  2655. 15448 /*===========================================================================*
  2656. 15449  *                              flush                                        *
  2657. 15450  *===========================================================================*/
  2658. 15451 PRIVATE void flush(cons)
  2659. 15452 register console_t *cons;       /* pointer to console struct */
  2660. 15453 {
  2661. 15454 /* Send characters buffered in 'ramqueue' to screen memory, check the new
  2662. 15455  * cursor position, compute the new hardware cursor position and set it.
  2663. 15456  */
  2664. 15457   unsigned cur;
  2665. 15458   tty_t *tp = cons->c_tty;
  2666. 15459
  2667. 15460   /* Have the characters in 'ramqueue' transferred to the screen. */
  2668. 15461   if (cons->c_rwords > 0) {
  2669. 15462         mem_vid_copy(cons->c_ramqueue, cons->c_cur, cons->c_rwords);
  2670. 15463         cons->c_rwords = 0;
  2671. 15464
  2672. 15465         /* TTY likes to know the current column and if echoing messed up. */
  2673. 15466         tp->tty_position = cons->c_column;
  2674. 15467         tp->tty_reprint = TRUE;
  2675. 15468   }
  2676. 15469
  2677. 15470   /* Check and update the cursor position. */
  2678. 15471   if (cons->c_column < 0) cons->c_column = 0;
  2679. 15472   if (cons->c_column > scr_width) cons->c_column = scr_width;
  2680. 15473   if (cons->c_row < 0) cons->c_row = 0;
  2681. 15474   if (cons->c_row >= scr_lines) cons->c_row = scr_lines - 1;
  2682. 15475   cur = cons->c_org + cons->c_row * scr_width + cons->c_column;
  2683. 15476   if (cur != cons->c_cur) {
  2684. 15477         if (cons == curcons) set_6845(CURSOR, cur);
  2685. 15478         cons->c_cur = cur;
  2686. 15479   }
  2687. .Op 195 src/kernel/console.c
  2688. 15480 }
  2689. 15483 /*===========================================================================*
  2690. 15484  *                              parse_escape                                 *
  2691. 15485  *===========================================================================*/
  2692. 15486 PRIVATE void parse_escape(cons, c)
  2693. 15487 register console_t *cons;       /* pointer to console struct */
  2694. 15488 char c;                         /* next character in escape sequence */
  2695. 15489 {
  2696. 15490 /* The following ANSI escape sequences are currently supported.
  2697. 15491  * If n and/or m are omitted, they default to 1.
  2698. 15492  *   ESC [nA moves up n lines
  2699. 15493  *   ESC [nB moves down n lines
  2700. 15494  *   ESC [nC moves right n spaces
  2701. 15495  *   ESC [nD moves left n spaces
  2702. 15496  *   ESC [m;nH" moves cursor to (m,n)
  2703. 15497  *   ESC [J clears screen from cursor
  2704. 15498  *   ESC [K clears line from cursor
  2705. 15499  *   ESC [nL inserts n lines ar cursor
  2706. 15500  *   ESC [nM deletes n lines at cursor
  2707. 15501  *   ESC [nP deletes n chars at cursor
  2708. 15502  *   ESC [n@ inserts n chars at cursor
  2709. 15503  *   ESC [nm enables rendition n (0=normal, 4=bold, 5=blinking, 7=reverse)
  2710. 15504  *   ESC M scrolls the screen backwards if the cursor is on the top line
  2711. 15505  */
  2712. 15506
  2713. 15507   switch (cons->c_esc_state) {
  2714. 15508     case 1:                     /* ESC seen */
  2715. 15509         cons->c_esc_intro = '';
  2716. 15510         cons->c_esc_parmp = cons->c_esc_parmv;
  2717. 15511         cons->c_esc_parmv[0] = cons->c_esc_parmv[1] = 0;
  2718. 15512         switch (c) {
  2719. 15513             case '[':   /* Control Sequence Introducer */
  2720. 15514                 cons->c_esc_intro = c;
  2721. 15515                 cons->c_esc_state = 2;
  2722. 15516                 break;
  2723. 15517             case 'M':   /* Reverse Index */
  2724. 15518                 do_escape(cons, c);
  2725. 15519                 break;
  2726. 15520             default:
  2727. 15521                 cons->c_esc_state = 0;
  2728. 15522         }
  2729. 15523         break;
  2730. 15524
  2731. 15525     case 2:                     /* ESC [ seen */
  2732. 15526         if (c >= '0' && c <= '9') {
  2733. 15527                 if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
  2734. 15528                         *cons->c_esc_parmp = *cons->c_esc_parmp * 10 + (c-'0');
  2735. 15529         } else
  2736. 15530         if (c == ';') {
  2737. 15531                 if (++cons->c_esc_parmp < bufend(cons->c_esc_parmv))
  2738. 15532                         *cons->c_esc_parmp = 0;
  2739. 15533         } else {
  2740. 15534                 do_escape(cons, c);
  2741. 15535         }
  2742. 15536         break;
  2743. 15537   }
  2744. 15538 }
  2745. .Ep 196 src/kernel/console.c
  2746. 15541 /*===========================================================================*
  2747. 15542  *                              do_escape                                    *
  2748. 15543  *===========================================================================*/
  2749. 15544 PRIVATE void do_escape(cons, c)
  2750. 15545 register console_t *cons;       /* pointer to console struct */
  2751. 15546 char c;                         /* next character in escape sequence */
  2752. 15547 {
  2753. 15548   int value, n;
  2754. 15549   unsigned src, dst, count;
  2755. 15550
  2756. 15551   /* Some of these things hack on screen RAM, so it had better be up to date */
  2757. 15552   flush(cons);
  2758. 15553
  2759. 15554   if (cons->c_esc_intro == '') {
  2760. 15555         /* Handle a sequence beginning with just ESC */
  2761. 15556         switch (c) {
  2762. 15557             case 'M':           /* Reverse Index */
  2763. 15558                 if (cons->c_row == 0) {
  2764. 15559                         scroll_screen(cons, SCROLL_DOWN);
  2765. 15560                 } else {
  2766. 15561                         cons->c_row--;
  2767. 15562                 }
  2768. 15563                 flush(cons);
  2769. 15564                 break;
  2770. 15565
  2771. 15566             default: break;
  2772. 15567         }
  2773. 15568   } else
  2774. 15569   if (cons->c_esc_intro == '[') {
  2775. 15570         /* Handle a sequence beginning with ESC [ and parameters */
  2776. 15571         value = cons->c_esc_parmv[0];
  2777. 15572         switch (c) {
  2778. 15573             case 'A':           /* ESC [nA moves up n lines */
  2779. 15574                 n = (value == 0 ? 1 : value);
  2780. 15575                 cons->c_row -= n;
  2781. 15576                 flush(cons);
  2782. 15577                 break;
  2783. 15578
  2784. 15579             case 'B':           /* ESC [nB moves down n lines */
  2785. 15580                 n = (value == 0 ? 1 : value);
  2786. 15581                 cons->c_row += n;
  2787. 15582                 flush(cons);
  2788. 15583                 break;
  2789. 15584
  2790. 15585             case 'C':           /* ESC [nC moves right n spaces */
  2791. 15586                 n = (value == 0 ? 1 : value);
  2792. 15587                 cons->c_column += n;
  2793. 15588                 flush(cons);
  2794. 15589                 break;
  2795. 15590
  2796. 15591             case 'D':           /* ESC [nD moves left n spaces */
  2797. 15592                 n = (value == 0 ? 1 : value);
  2798. 15593                 cons->c_column -= n;
  2799. 15594                 flush(cons);
  2800. 15595                 break;
  2801. 15596
  2802. 15597             case 'H':           /* ESC [m;nH" moves cursor to (m,n) */
  2803. 15598                 cons->c_row = cons->c_esc_parmv[0] - 1;
  2804. 15599                 cons->c_column = cons->c_esc_parmv[1] - 1;
  2805. .Op 197 src/kernel/console.c
  2806. 15600                 flush(cons);
  2807. 15601                 break;
  2808. 15602
  2809. 15603             case 'J':           /* ESC [sJ clears in display */
  2810. 15604                 switch (value) {
  2811. 15605                     case 0:     /* Clear from cursor to end of screen */
  2812. 15606                         count = scr_size - (cons->c_cur - cons->c_org);
  2813. 15607                         dst = cons->c_cur;
  2814. 15608                         break;
  2815. 15609                     case 1:     /* Clear from start of screen to cursor */
  2816. 15610                         count = cons->c_cur - cons->c_org;
  2817. 15611                         dst = cons->c_org;
  2818. 15612                         break;
  2819. 15613                     case 2:     /* Clear entire screen */
  2820. 15614                         count = scr_size;
  2821. 15615                         dst = cons->c_org;
  2822. 15616                         break;
  2823. 15617                     default:    /* Do nothing */
  2824. 15618                         count = 0;
  2825. 15619                         dst = cons->c_org;
  2826. 15620                 }
  2827. 15621                 blank_color = cons->c_blank;
  2828. 15622                 mem_vid_copy(BLANK_MEM, dst, count);
  2829. 15623                 break;
  2830. 15624
  2831. 15625             case 'K':           /* ESC [sK clears line from cursor */
  2832. 15626                 switch (value) {