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

操作系统开发

开发平台:

WINDOWS

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