COMPLETE.TXT
资源名称:os_source.zip [点击查看]
上传用户:datang2001
上传日期:2007-02-01
资源大小:53269k
文件大小:2565k
源码类别:
操作系统开发
开发平台:
C/C++
- 12818 default:
- 12819 printf("aha0: AHA154x: strange DMA channeln");
- 12820 return(0);
- 12821 }
- 12822
- 12823 /* Get the configured IRQ. */
- 12824 switch (getcdata[1]) {
- 12825 case 0x40: irq = 15; break;
- 12826 case 0x20: irq = 14; break;
- 12827 case 0x08: irq = 12; break;
- 12828 case 0x04: irq = 11; break;
- 12829 case 0x02: irq = 10; break;
- 12830 case 0x01: irq = 9; break;
- 12831 default:
- 12832 printf("aha0: strange IRQ settingn");
- 12833 return(0);
- 12834 }
- 12835
- 12836 /* Enable interrupts on the given irq. */
- 12837 put_irq_handler(irq, s_handler);
- 12838 aha_irq = irq;
- 12839 enable_irq(irq);
- 12840
- 12841 /* Initialize request related data: Command Control Block, mailboxes.
- 12842 * (We want to have the mailboxes initialized early, because the 1540C
- 12843 * wants to know it now.)
- 12844 */
- 12845
- 12846 /* Init ccb. */
- 12847 rq->ccb.senselen = CCB_SENSEREQ; /* always want sense info */
- 12848 h2b24(rq->ccb.linkptr, 0L); /* never link commands */
- 12849 rq->ccb.linkid = 0;
- 12850 rq->ccb.reserved[0] = 0;
- 12851 rq->ccb.reserved[1] = 0;
- 12852
- 12853 /* Scatter/gather maximum. */
- 12854 rq->dmalimit = rq->dmalist + (sg_max < NR_IOREQS ? sg_max : NR_IOREQS);
- 12855
- 12856 /* Outgoing mailbox. */
- 12857 mailbox[0].status = AHA_MBOXFREE;
- 12858 h2b24(mailbox[0].ccbptr, vir2phys(&rq->ccb));
- 12859
- 12860 /* Incoming mailbox. */
- 12861 mailbox[1].status = AHA_MBOXFREE;
- 12862 /* mailbox[1].ccbptr filled by adapter after command execution. */
- 12863
- 12864 /* Tell controller where the mailboxes are and how many. */
- 12865 cmd[0] = AHACOM_INITBOX;
- 12866 cmd[1] = 1;
- 12867 h2b24(cmd + 2, vir2phys(mailbox));
- 12868 aha_command(5, cmd, 0, 0);
- 12869
- 12870 /* !! maybe sanity check: check status reg for initialization success */
- 12871
- 12872 /* Set bus on, bus off and transfer speed. */
- 12873 cmd[0] = AHACOM_BUSON;
- 12874 cmd[1] = bus_on;
- 12875 aha_command(2, cmd, 0, 0);
- 12876
- 12877 cmd[0] = AHACOM_BUSOFF;
- 12878 cmd[1] = bus_off;
- 12879 aha_command(2, cmd, 0, 0);
- 12880
- 12881 cmd[0] = AHACOM_SPEED;
- 12882 cmd[1] = tr_speed;
- 12883 aha_command(2, cmd, 0, 0);
- 12884
- 12885 /* Set SCSI selection timeout. */
- 12886 cmd[0] = AHACOM_SETIMEOUT;
- 12887 cmd[1] = SCSI_TIMEOUT != 0; /* timeouts on/off */
- 12888 cmd[2] = 0; /* reserved */
- 12889 cmd[3] = SCSI_TIMEOUT / 256; /* MSB */
- 12890 cmd[4] = SCSI_TIMEOUT % 256; /* LSB */
- 12891 aha_command(5, cmd, 0, 0);
- 12892
- 12893 return(1);
- 12894 }
- 12897 /*===========================================================================*
- 12898 * s_handler *
- 12899 *===========================================================================*/
- 12900 PRIVATE int s_handler(irq)
- 12901 int irq;
- 12902 {
- 12903 /* Host adapter interrupt, send message to SCSI task and reenable interrupts. */
- 12904
- 12905 if (in_byte(AHA_INTRREG) & AHA_HACC) {
- 12906 /* Simple commands are polled. */
- 12907 return 0;
- 12908 } else {
- 12909 out_byte(AHA_CNTLREG, AHA_IRST); /* clear interrupt */
- 12910 interrupt(SCSI);
- 12911 return 1;
- 12912 }
- 12913 }
- 12916 /*===========================================================================*
- 12917 * h2b16 *
- 12918 *===========================================================================*/
- 12919 PRIVATE void h2b16(b, h)
- 12920 big16 b;
- 12921 U16_t h;
- 12922 {
- 12923 /* Host byte order to Big Endian conversion. */
- 12924 b[0] = h >> 8;
- 12925 b[1] = h >> 0;
- 12926 }
- 12929 /*===========================================================================*
- 12930 * h2b24 *
- 12931 *===========================================================================*/
- 12932 PRIVATE void h2b24(b, h)
- 12933 big24 b;
- 12934 u32_t h;
- 12935 {
- 12936 b[0] = h >> 16;
- 12937 b[1] = h >> 8;
- 12938 b[2] = h >> 0;
- 12939 }
- 12942 /*===========================================================================*
- 12943 * h2b32 *
- 12944 *===========================================================================*/
- 12945 PRIVATE void h2b32(b, h)
- 12946 big32 b;
- 12947 u32_t h;
- 12948 {
- 12949 b[0] = h >> 24;
- 12950 b[1] = h >> 16;
- 12951 b[2] = h >> 8;
- 12952 b[3] = h >> 0;
- 12953 }
- 12956 /*===========================================================================*
- 12957 * b2h16 *
- 12958 *===========================================================================*/
- 12959 PRIVATE u16_t b2h16(b)
- 12960 big16 b;
- 12961 {
- 12962 return ((u16_t) b[0] << 8)
- 12963 | ((u16_t) b[1] << 0);
- 12964 }
- 12967 /*===========================================================================*
- 12968 * b2h24 *
- 12969 *===========================================================================*/
- 12970 PRIVATE u32_t b2h24(b)
- 12971 big24 b;
- 12972 {
- 12973 return ((u32_t) b[0] << 16)
- 12974 | ((u32_t) b[1] << 8)
- 12975 | ((u32_t) b[2] << 0);
- 12976 }
- 12979 /*===========================================================================*
- 12980 * b2h32 *
- 12981 *===========================================================================*/
- 12982 PRIVATE u32_t b2h32(b)
- 12983 big32 b;
- 12984 {
- 12985 return ((u32_t) b[0] << 24)
- 12986 | ((u32_t) b[1] << 16)
- 12987 | ((u32_t) b[2] << 8)
- 12988 | ((u32_t) b[3] << 0);
- 12989 }
- 12992 #if AHA_DEBUG & 2
- 12993 /*===========================================================================*
- 12994 * errordump *
- 12995 *===========================================================================*/
- 12996 PRIVATE void errordump()
- 12997 {
- 12998 int i;
- 12999
- 13000 printf("aha ccb dump:");
- 13001 for (i = 0; i < sizeof(rq->ccb); i++) {
- 13002 if (i % 26 == 0) printf("n");
- 13003 printf(" %02x", ((byte *) &rq->ccb)[i]);
- 13004 }
- 13005 printf("n");
- 13006 }
- 13007 #endif /* AHA_DEBUG & 2 */
- 13008
- 13009
- 13010 #if AHA_DEBUG & 4
- 13011 /*===========================================================================*
- 13012 * show_req *
- 13013 *===========================================================================*/
- 13014 PRIVATE void show_req()
- 13015 {
- 13016 struct iorequest_s **iopp;
- 13017 dma_t *dmap;
- 13018 unsigned count, nbytes, len;
- 13019
- 13020 iopp = rq->iov;
- 13021 dmap = rq->dmalist;
- 13022 count = rq->count;
- 13023 nbytes = 0;
- 13024
- 13025 printf("%lu:%u", rq->pos, count);
- 13026
- 13027 while (count > 0) {
- 13028 if (iopp == rq->iov || *iopp != iopp[-1])
- 13029 nbytes = (*iopp)->io_nbytes;
- 13030
- 13031 printf(" (%u,%lx,%u)", nbytes, b2h24(dmap->dataptr),
- 13032 len = b2h24(dmap->datalen));
- 13033 dmap++;
- 13034 iopp++;
- 13035 count -= len;
- 13036 nbytes -= len;
- 13037 }
- 13038 if (nbytes > 0) printf(" ...(%u)", nbytes);
- 13039 printf("n");
- 13040 }
- 13041 #endif /* AHA_DEBUG & 4 */
- 13042
- 13043
- 13044 #if AHA_DEBUG & 8
- 13045 /*===========================================================================*
- 13046 * dump_scsi_cmd *
- 13047 *===========================================================================*/
- 13048 PRIVATE void dump_scsi_cmd()
- 13049 {
- 13050 int i;
- 13051
- 13052 printf("scsi cmd:");
- 13053 for (i = 0; i < rq->ccb.cmdlen; i++) printf(" %02x", rq->ccb.cmd[i]);
- 13054 printf("n");
- 13055 }
- 13056 #endif /* AHA_DEBUG & 8 */
- 13057
- 13058
- 13059 /*============================================================================*
- 13060 * s_geometry *
- 13061 *============================================================================*/
- 13062 PRIVATE void s_geometry(entry)
- 13063 struct partition *entry;
- 13064 {
- 13065 /* The geometry of a SCSI drive is a complete fake, the Adaptec onboard BIOS
- 13066 * makes the drive look like a regular drive on the outside. A DOS program
- 13067 * takes a logical block address, computes cylinder, head and sector like the
- 13068 * BIOS int 0x13 call expects, and the Adaptec turns this back into a block
- 13069 * address again. The only reason we care is because some idiot put cylinder,
- 13070 * head and sector numbers in the partition table, so fdisk needs to know the
- 13071 * geometry.
- 13072 */
- 13073 unsigned long size = s_sp->part[0].dv_size;
- 13074 unsigned heads, sectors;
- 13075
- 13076 if (size < 1024L * 64 * 32 * 512) {
- 13077 /* Small drive. */
- 13078 heads = 64;
- 13079 sectors = 32;
- 13080 } else {
- 13081 /* Assume that this BIOS is configured for large drives. */
- 13082 heads = 255;
- 13083 sectors = 63;
- 13084 }
- 13085 entry->cylinders = (size >> SECTOR_SHIFT) / (heads * sectors);
- 13086 entry->heads = heads;
- 13087 entry->sectors = sectors;
- 13088 }
- 13089 #endif /* !ENABLE_ADAPTEC_SCSI */
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/at_wini.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 13100 /* This file contains the device dependent part of a driver for the IBM-AT
- 13101 * winchester controller.
- 13102 * It was written by Adri Koppes.
- 13103 *
- 13104 * The file contains one entry point:
- 13105 *
- 13106 * at_winchester_task: main entry when system is brought up
- 13107 *
- 13108 *
- 13109 * Changes:
- 13110 * 13 Apr 1992 by Kees J. Bot: device dependent/independent split.
- 13111 */
- 13112
- 13113 #include "kernel.h"
- 13114 #include "driver.h"
- 13115 #include "drvlib.h"
- 13116
- 13117 #if ENABLE_AT_WINI
- 13118
- 13119 /* I/O Ports used by winchester disk controllers. */
- 13120
- 13121 /* Read and write registers */
- 13122 #define REG_BASE0 0x1F0 /* base register of controller 0 */
- 13123 #define REG_BASE1 0x170 /* base register of controller 1 */
- 13124 #define REG_DATA 0 /* data register (offset from the base reg.) */
- 13125 #define REG_PRECOMP 1 /* start of write precompensation */
- 13126 #define REG_COUNT 2 /* sectors to transfer */
- 13127 #define REG_SECTOR 3 /* sector number */
- 13128 #define REG_CYL_LO 4 /* low byte of cylinder number */
- 13129 #define REG_CYL_HI 5 /* high byte of cylinder number */
- 13130 #define REG_LDH 6 /* lba, drive and head */
- 13131 #define LDH_DEFAULT 0xA0 /* ECC enable, 512 bytes per sector */
- 13132 #define LDH_LBA 0x40 /* Use LBA addressing */
- 13133 #define ldh_init(drive) (LDH_DEFAULT | ((drive) << 4))
- 13134
- 13135 /* Read only registers */
- 13136 #define REG_STATUS 7 /* status */
- 13137 #define STATUS_BSY 0x80 /* controller busy */
- 13138 #define STATUS_RDY 0x40 /* drive ready */
- 13139 #define STATUS_WF 0x20 /* write fault */
- 13140 #define STATUS_SC 0x10 /* seek complete (obsolete) */
- 13141 #define STATUS_DRQ 0x08 /* data transfer request */
- 13142 #define STATUS_CRD 0x04 /* corrected data */
- 13143 #define STATUS_IDX 0x02 /* index pulse */
- 13144 #define STATUS_ERR 0x01 /* error */
- 13145 #define REG_ERROR 1 /* error code */
- 13146 #define ERROR_BB 0x80 /* bad block */
- 13147 #define ERROR_ECC 0x40 /* bad ecc bytes */
- 13148 #define ERROR_ID 0x10 /* id not found */
- 13149 #define ERROR_AC 0x04 /* aborted command */
- 13150 #define ERROR_TK 0x02 /* track zero error */
- 13151 #define ERROR_DM 0x01 /* no data address mark */
- 13152
- 13153 /* Write only registers */
- 13154 #define REG_COMMAND 7 /* command */
- 13155 #define CMD_IDLE 0x00 /* for w_command: drive idle */
- 13156 #define CMD_RECALIBRATE 0x10 /* recalibrate drive */
- 13157 #define CMD_READ 0x20 /* read data */
- 13158 #define CMD_WRITE 0x30 /* write data */
- 13159 #define CMD_READVERIFY 0x40 /* read verify */
- 13160 #define CMD_FORMAT 0x50 /* format track */
- 13161 #define CMD_SEEK 0x70 /* seek cylinder */
- 13162 #define CMD_DIAG 0x90 /* execute device diagnostics */
- 13163 #define CMD_SPECIFY 0x91 /* specify parameters */
- 13164 #define ATA_IDENTIFY 0xEC /* identify drive */
- 13165 #define REG_CTL 0x206 /* control register */
- 13166 #define CTL_NORETRY 0x80 /* disable access retry */
- 13167 #define CTL_NOECC 0x40 /* disable ecc retry */
- 13168 #define CTL_EIGHTHEADS 0x08 /* more than eight heads */
- 13169 #define CTL_RESET 0x04 /* reset controller */
- 13170 #define CTL_INTDISABLE 0x02 /* disable interrupts */
- 13171
- 13172 /* Interrupt request lines. */
- 13173 #define AT_IRQ0 14 /* interrupt number for controller 0 */
- 13174 #define AT_IRQ1 15 /* interrupt number for controller 1 */
- 13175
- 13176 /* Common command block */
- 13177 struct command {
- 13178 u8_t precomp; /* REG_PRECOMP, etc. */
- 13179 u8_t count;
- 13180 u8_t sector;
- 13181 u8_t cyl_lo;
- 13182 u8_t cyl_hi;
- 13183 u8_t ldh;
- 13184 u8_t command;
- 13185 };
- 13186
- 13187
- 13188 /* Error codes */
- 13189 #define ERR (-1) /* general error */
- 13190 #define ERR_BAD_SECTOR (-2) /* block marked bad detected */
- 13191
- 13192 /* Some controllers don't interrupt, the clock will wake us up. */
- 13193 #define WAKEUP (32*HZ) /* drive may be out for 31 seconds max */
- 13194
- 13195 /* Miscellaneous. */
- 13196 #define MAX_DRIVES 4 /* this driver supports 4 drives (hd0 - hd19) */
- 13197 #if _WORD_SIZE > 2
- 13198 #define MAX_SECS 256 /* controller can transfer this many sectors */
- 13199 #else
- 13200 #define MAX_SECS 127 /* but not to a 16 bit process */
- 13201 #endif
- 13202 #define MAX_ERRORS 4 /* how often to try rd/wt before quitting */
- 13203 #define NR_DEVICES (MAX_DRIVES * DEV_PER_DRIVE)
- 13204 #define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS)
- 13205 #define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE)
- 13206 #define TIMEOUT 32000 /* controller timeout in ms */
- 13207 #define RECOVERYTIME 500 /* controller recovery time in ms */
- 13208 #define INITIALIZED 0x01 /* drive is initialized */
- 13209 #define DEAF 0x02 /* controller must be reset */
- 13210 #define SMART 0x04 /* drive supports ATA commands */
- 13211
- 13212
- 13213 /* Variables. */
- 13214 PRIVATE struct wini { /* main drive struct, one entry per drive */
- 13215 unsigned state; /* drive state: deaf, initialized, dead */
- 13216 unsigned base; /* base register of the register file */
- 13217 unsigned irq; /* interrupt request line */
- 13218 unsigned lcylinders; /* logical number of cylinders (BIOS) */
- 13219 unsigned lheads; /* logical number of heads */
- 13220 unsigned lsectors; /* logical number of sectors per track */
- 13221 unsigned pcylinders; /* physical number of cylinders (translated) */
- 13222 unsigned pheads; /* physical number of heads */
- 13223 unsigned psectors; /* physical number of sectors per track */
- 13224 unsigned ldhpref; /* top four bytes of the LDH (head) register */
- 13225 unsigned precomp; /* write precompensation cylinder / 4 */
- 13226 unsigned max_count; /* max request for this drive */
- 13227 unsigned open_ct; /* in-use count */
- 13228 struct device part[DEV_PER_DRIVE]; /* primary partitions: hd[0-4] */
- 13229 struct device subpart[SUB_PER_DRIVE]; /* subpartitions: hd[1-4][a-d] */
- 13230 } wini[MAX_DRIVES], *w_wn;
- 13231
- 13232 PRIVATE struct trans {
- 13233 struct iorequest_s *iop; /* belongs to this I/O request */
- 13234 unsigned long block; /* first sector to transfer */
- 13235 unsigned count; /* byte count */
- 13236 phys_bytes phys; /* user physical address */
- 13237 } wtrans[NR_IOREQS];
- 13238
- 13239 PRIVATE struct trans *w_tp; /* to add transfer requests */
- 13240 PRIVATE unsigned w_count; /* number of bytes to transfer */
- 13241 PRIVATE unsigned long w_nextblock; /* next block on disk to transfer */
- 13242 PRIVATE int w_opcode; /* DEV_READ or DEV_WRITE */
- 13243 PRIVATE int w_command; /* current command in execution */
- 13244 PRIVATE int w_status; /* status after interrupt */
- 13245 PRIVATE int w_drive; /* selected drive */
- 13246 PRIVATE struct device *w_dv; /* device's base and size */
- 13247
- 13248 FORWARD _PROTOTYPE( void init_params, (void) );
- 13249 FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr) );
- 13250 FORWARD _PROTOTYPE( struct device *w_prepare, (int device) );
- 13251 FORWARD _PROTOTYPE( int w_identify, (void) );
- 13252 FORWARD _PROTOTYPE( char *w_name, (void) );
- 13253 FORWARD _PROTOTYPE( int w_specify, (void) );
- 13254 FORWARD _PROTOTYPE( int w_schedule, (int proc_nr, struct iorequest_s *iop) );
- 13255 FORWARD _PROTOTYPE( int w_finish, (void) );
- 13256 FORWARD _PROTOTYPE( int com_out, (struct command *cmd) );
- 13257 FORWARD _PROTOTYPE( void w_need_reset, (void) );
- 13258 FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );
- 13259 FORWARD _PROTOTYPE( int com_simple, (struct command *cmd) );
- 13260 FORWARD _PROTOTYPE( void w_timeout, (void) );
- 13261 FORWARD _PROTOTYPE( int w_reset, (void) );
- 13262 FORWARD _PROTOTYPE( int w_intr_wait, (void) );
- 13263 FORWARD _PROTOTYPE( int w_waitfor, (int mask, int value) );
- 13264 FORWARD _PROTOTYPE( int w_handler, (int irq) );
- 13265 FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry) );
- 13266
- 13267 /* w_waitfor loop unrolled once for speed. */
- 13268 #define waitfor(mask, value)
- 13269 ((in_byte(w_wn->base + REG_STATUS) & mask) == value
- 13270 || w_waitfor(mask, value))
- 13271
- 13272
- 13273 /* Entry points to this driver. */
- 13274 PRIVATE struct driver w_dtab = {
- 13275 w_name, /* current device's name */
- 13276 w_do_open, /* open or mount request, initialize device */
- 13277 w_do_close, /* release device */
- 13278 do_diocntl, /* get or set a partition's geometry */
- 13279 w_prepare, /* prepare for I/O on a given minor device */
- 13280 w_schedule, /* precompute cylinder, head, sector, etc. */
- 13281 w_finish, /* do the I/O */
- 13282 nop_cleanup, /* nothing to clean up */
- 13283 w_geometry, /* tell the geometry of the disk */
- 13284 };
- 13285
- 13286 #if ENABLE_ATAPI
- 13287 #include "atapi.c" /* extra code for ATAPI CD-ROM */
- 13288 #endif
- 13289
- 13290
- 13291 /*===========================================================================*
- 13292 * at_winchester_task *
- 13293 *===========================================================================*/
- 13294 PUBLIC void at_winchester_task()
- 13295 {
- 13296 /* Set special disk parameters then call the generic main loop. */
- 13297
- 13298 init_params();
- 13299
- 13300 driver_task(&w_dtab);
- 13301 }
- 13304 /*============================================================================*
- 13305 * init_params *
- 13306 *============================================================================*/
- 13307 PRIVATE void init_params()
- 13308 {
- 13309 /* This routine is called at startup to initialize the drive parameters. */
- 13310
- 13311 u16_t parv[2];
- 13312 unsigned int vector;
- 13313 int drive, nr_drives, i;
- 13314 struct wini *wn;
- 13315 u8_t params[16];
- 13316 phys_bytes param_phys = vir2phys(params);
- 13317
- 13318 /* Get the number of drives from the BIOS data area */
- 13319 phys_copy(0x475L, param_phys, 1L);
- 13320 if ((nr_drives = params[0]) > 2) nr_drives = 2;
- 13321
- 13322 for (drive = 0, wn = wini; drive < MAX_DRIVES; drive++, wn++) {
- 13323 if (drive < nr_drives) {
- 13324 /* Copy the BIOS parameter vector */
- 13325 vector = drive == 0 ? WINI_0_PARM_VEC : WINI_1_PARM_VEC;
- 13326 phys_copy(vector * 4L, vir2phys(parv), 4L);
- 13327
- 13328 /* Calculate the address of the parameters and copy them */
- 13329 phys_copy(hclick_to_physb(parv[1]) + parv[0], param_phys, 16L);
- 13330
- 13331 /* Copy the parameters to the structures of the drive */
- 13332 wn->lcylinders = bp_cylinders(params);
- 13333 wn->lheads = bp_heads(params);
- 13334 wn->lsectors = bp_sectors(params);
- 13335 wn->precomp = bp_precomp(params) >> 2;
- 13336 }
- 13337 wn->ldhpref = ldh_init(drive);
- 13338 wn->max_count = MAX_SECS << SECTOR_SHIFT;
- 13339 if (drive < 2) {
- 13340 /* Controller 0. */
- 13341 wn->base = REG_BASE0;
- 13342 wn->irq = AT_IRQ0;
- 13343 } else {
- 13344 /* Controller 1. */
- 13345 wn->base = REG_BASE1;
- 13346 wn->irq = AT_IRQ1;
- 13347 }
- 13348 }
- 13349 }
- 13352 /*============================================================================*
- 13353 * w_do_open *
- 13354 *============================================================================*/
- 13355 PRIVATE int w_do_open(dp, m_ptr)
- 13356 struct driver *dp;
- 13357 message *m_ptr;
- 13358 {
- 13359 /* Device open: Initialize the controller and read the partition table. */
- 13360
- 13361 int r;
- 13362 struct wini *wn;
- 13363 struct command cmd;
- 13364
- 13365 if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
- 13366 wn = w_wn;
- 13367
- 13368 if (wn->state == 0) {
- 13369 /* Try to identify the device. */
- 13370 if (w_identify() != OK) {
- 13371 printf("%s: probe failedn", w_name());
- 13372 if (wn->state & DEAF) w_reset();
- 13373 wn->state = 0;
- 13374 return(ENXIO);
- 13375 }
- 13376 }
- 13377 if (wn->open_ct++ == 0) {
- 13378 /* Partition the disk. */
- 13379 partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY);
- 13380 }
- 13381 return(OK);
- 13382 }
- 13385 /*===========================================================================*
- 13386 * w_prepare *
- 13387 *===========================================================================*/
- 13388 PRIVATE struct device *w_prepare(device)
- 13389 int device;
- 13390 {
- 13391 /* Prepare for I/O on a device. */
- 13392
- 13393 /* Nothing to transfer as yet. */
- 13394 w_count = 0;
- 13395
- 13396 if (device < NR_DEVICES) { /* hd0, hd1, ... */
- 13397 w_drive = device / DEV_PER_DRIVE; /* save drive number */
- 13398 w_wn = &wini[w_drive];
- 13399 w_dv = &w_wn->part[device % DEV_PER_DRIVE];
- 13400 } else
- 13401 if ((unsigned) (device -= MINOR_hd1a) < NR_SUBDEVS) { /* hd1a, hd1b, ... */
- 13402 w_drive = device / SUB_PER_DRIVE;
- 13403 w_wn = &wini[w_drive];
- 13404 w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
- 13405 } else {
- 13406 return(NIL_DEV);
- 13407 }
- 13408 return(w_dv);
- 13409 }
- 13412 /*===========================================================================*
- 13413 * w_identify *
- 13414 *===========================================================================*/
- 13415 PRIVATE int w_identify()
- 13416 {
- 13417 /* Find out if a device exists, if it is an old AT disk, or a newer ATA
- 13418 * drive, a removable media device, etc.
- 13419 */
- 13420
- 13421 struct wini *wn = w_wn;
- 13422 struct command cmd;
- 13423 char id_string[40];
- 13424 int i, r;
- 13425 unsigned long size;
- 13426 #define id_byte(n) (&tmp_buf[2 * (n)])
- 13427 #define id_word(n) (((u16_t) id_byte(n)[0] << 0)
- 13428 |((u16_t) id_byte(n)[1] << 8))
- 13429 #define id_longword(n) (((u32_t) id_byte(n)[0] << 0)
- 13430 |((u32_t) id_byte(n)[1] << 8)
- 13431 |((u32_t) id_byte(n)[2] << 16)
- 13432 |((u32_t) id_byte(n)[3] << 24))
- 13433
- 13434 /* Check if the one of the registers exists. */
- 13435 r = in_byte(wn->base + REG_CYL_LO);
- 13436 out_byte(wn->base + REG_CYL_LO, ~r);
- 13437 if (in_byte(wn->base + REG_CYL_LO) == r) return(ERR);
- 13438
- 13439 /* Looks OK; register IRQ and try an ATA identify command. */
- 13440 put_irq_handler(wn->irq, w_handler);
- 13441 enable_irq(wn->irq);
- 13442
- 13443 cmd.ldh = wn->ldhpref;
- 13444 cmd.command = ATA_IDENTIFY;
- 13445 if (com_simple(&cmd) == OK) {
- 13446 /* This is an ATA device. */
- 13447 wn->state |= SMART;
- 13448
- 13449 /* Device information. */
- 13450 port_read(wn->base + REG_DATA, tmp_phys, SECTOR_SIZE);
- 13451
- 13452 /* Why are the strings byte swapped??? */
- 13453 for (i = 0; i < 40; i++) id_string[i] = id_byte(27)[i^1];
- 13454
- 13455 /* Preferred CHS translation mode. */
- 13456 wn->pcylinders = id_word(1);
- 13457 wn->pheads = id_word(3);
- 13458 wn->psectors = id_word(6);
- 13459 size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
- 13460
- 13461 if ((id_byte(49)[1] & 0x02) && size > 512L*1024*2) {
- 13462 /* Drive is LBA capable and is big enough to trust it to
- 13463 * not make a mess of it.
- 13464 */
- 13465 wn->ldhpref |= LDH_LBA;
- 13466 size = id_longword(60);
- 13467 }
- 13468
- 13469 if (wn->lcylinders == 0) {
- 13470 /* No BIOS parameters? Then make some up. */
- 13471 wn->lcylinders = wn->pcylinders;
- 13472 wn->lheads = wn->pheads;
- 13473 wn->lsectors = wn->psectors;
- 13474 while (wn->lcylinders > 1024) {
- 13475 wn->lheads *= 2;
- 13476 wn->lcylinders /= 2;
- 13477 }
- 13478 }
- 13479 } else {
- 13480 /* Not an ATA device; no translations, no special features. Don't
- 13481 * touch it unless the BIOS knows about it.
- 13482 */
- 13483 if (wn->lcylinders == 0) return(ERR); /* no BIOS parameters */
- 13484 wn->pcylinders = wn->lcylinders;
- 13485 wn->pheads = wn->lheads;
- 13486 wn->psectors = wn->lsectors;
- 13487 size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
- 13488 }
- 13489 /* The fun ends at 4 GB. */
- 13490 if (size > ((u32_t) -1) / SECTOR_SIZE) size = ((u32_t) -1) / SECTOR_SIZE;
- 13491
- 13492 /* Base and size of the whole drive */
- 13493 wn->part[0].dv_base = 0;
- 13494 wn->part[0].dv_size = size << SECTOR_SHIFT;
- 13495
- 13496 if (w_specify() != OK && w_specify() != OK) return(ERR);
- 13497
- 13498 printf("%s: ", w_name());
- 13499 if (wn->state & SMART) {
- 13500 printf("%.40sn", id_string);
- 13501 } else {
- 13502 printf("%ux%ux%un", wn->pcylinders, wn->pheads, wn->psectors);
- 13503 }
- 13504 return(OK);
- 13505 }
- 13508 /*===========================================================================*
- 13509 * w_name *
- 13510 *===========================================================================*/
- 13511 PRIVATE char *w_name()
- 13512 {
- 13513 /* Return a name for the current device. */
- 13514 static char name[] = "at-hd15";
- 13515 unsigned device = w_drive * DEV_PER_DRIVE;
- 13516
- 13517 if (device < 10) {
- 13518 name[5] = '0' + device;
- 13519 name[6] = 0;
- 13520 } else {
- 13521 name[5] = '0' + device / 10;
- 13522 name[6] = '0' + device % 10;
- 13523 }
- 13524 return name;
- 13525 }
- 13528 /*===========================================================================*
- 13529 * w_specify *
- 13530 *===========================================================================*/
- 13531 PRIVATE int w_specify()
- 13532 {
- 13533 /* Routine to initialize the drive after boot or when a reset is needed. */
- 13534
- 13535 struct wini *wn = w_wn;
- 13536 struct command cmd;
- 13537
- 13538 if ((wn->state & DEAF) && w_reset() != OK) return(ERR);
- 13539
- 13540 /* Specify parameters: precompensation, number of heads and sectors. */
- 13541 cmd.precomp = wn->precomp;
- 13542 cmd.count = wn->psectors;
- 13543 cmd.ldh = w_wn->ldhpref | (wn->pheads - 1);
- 13544 cmd.command = CMD_SPECIFY; /* Specify some parameters */
- 13545
- 13546 if (com_simple(&cmd) != OK) return(ERR);
- 13547
- 13548 if (!(wn->state & SMART)) {
- 13549 /* Calibrate an old disk. */
- 13550 cmd.sector = 0;
- 13551 cmd.cyl_lo = 0;
- 13552 cmd.cyl_hi = 0;
- 13553 cmd.ldh = w_wn->ldhpref;
- 13554 cmd.command = CMD_RECALIBRATE;
- 13555
- 13556 if (com_simple(&cmd) != OK) return(ERR);
- 13557 }
- 13558
- 13559 wn->state |= INITIALIZED;
- 13560 return(OK);
- 13561 }
- 13564 /*===========================================================================*
- 13565 * w_schedule *
- 13566 *===========================================================================*/
- 13567 PRIVATE int w_schedule(proc_nr, iop)
- 13568 int proc_nr; /* process doing the request */
- 13569 struct iorequest_s *iop; /* pointer to read or write request */
- 13570 {
- 13571 /* Gather I/O requests on consecutive blocks so they may be read/written
- 13572 * in one controller command. (There is enough time to compute the next
- 13573 * consecutive request while an unwanted block passes by.)
- 13574 */
- 13575 struct wini *wn = w_wn;
- 13576 int r, opcode;
- 13577 unsigned long pos;
- 13578 unsigned nbytes, count;
- 13579 unsigned long block;
- 13580 phys_bytes user_phys;
- 13581
- 13582 /* This many bytes to read/write */
- 13583 nbytes = iop->io_nbytes;
- 13584 if ((nbytes & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
- 13585
- 13586 /* From/to this position on the device */
- 13587 pos = iop->io_position;
- 13588 if ((pos & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
- 13589
- 13590 /* To/from this user address */
- 13591 user_phys = numap(proc_nr, (vir_bytes) iop->io_buf, nbytes);
- 13592 if (user_phys == 0) return(iop->io_nbytes = EINVAL);
- 13593
- 13594 /* Read or write? */
- 13595 opcode = iop->io_request & ~OPTIONAL_IO;
- 13596
- 13597 /* Which block on disk and how close to EOF? */
- 13598 if (pos >= w_dv->dv_size) return(OK); /* At EOF */
- 13599 if (pos + nbytes > w_dv->dv_size) nbytes = w_dv->dv_size - pos;
- 13600 block = (w_dv->dv_base + pos) >> SECTOR_SHIFT;
- 13601
- 13602 if (w_count > 0 && block != w_nextblock) {
- 13603 /* This new request can't be chained to the job being built */
- 13604 if ((r = w_finish()) != OK) return(r);
- 13605 }
- 13606
- 13607 /* The next consecutive block */
- 13608 w_nextblock = block + (nbytes >> SECTOR_SHIFT);
- 13609
- 13610 /* While there are "unscheduled" bytes in the request: */
- 13611 do {
- 13612 count = nbytes;
- 13613
- 13614 if (w_count == wn->max_count) {
- 13615 /* The drive can't do more then max_count at once */
- 13616 if ((r = w_finish()) != OK) return(r);
- 13617 }
- 13618
- 13619 if (w_count + count > wn->max_count)
- 13620 count = wn->max_count - w_count;
- 13621
- 13622 if (w_count == 0) {
- 13623 /* The first request in a row, initialize. */
- 13624 w_opcode = opcode;
- 13625 w_tp = wtrans;
- 13626 }
- 13627
- 13628 /* Store I/O parameters */
- 13629 w_tp->iop = iop;
- 13630 w_tp->block = block;
- 13631 w_tp->count = count;
- 13632 w_tp->phys = user_phys;
- 13633
- 13634 /* Update counters */
- 13635 w_tp++;
- 13636 w_count += count;
- 13637 block += count >> SECTOR_SHIFT;
- 13638 user_phys += count;
- 13639 nbytes -= count;
- 13640 } while (nbytes > 0);
- 13641
- 13642 return(OK);
- 13643 }
- 13646 /*===========================================================================*
- 13647 * w_finish *
- 13648 *===========================================================================*/
- 13649 PRIVATE int w_finish()
- 13650 {
- 13651 /* Carry out the I/O requests gathered in wtrans[]. */
- 13652
- 13653 struct trans *tp = wtrans;
- 13654 struct wini *wn = w_wn;
- 13655 int r, errors;
- 13656 struct command cmd;
- 13657 unsigned cylinder, head, sector, secspcyl;
- 13658
- 13659 if (w_count == 0) return(OK); /* Spurious finish. */
- 13660
- 13661 r = ERR; /* Trigger the first com_out */
- 13662 errors = 0;
- 13663
- 13664 do {
- 13665 if (r != OK) {
- 13666 /* The controller must be (re)programmed. */
- 13667
- 13668 /* First check to see if a reinitialization is needed. */
- 13669 if (!(wn->state & INITIALIZED) && w_specify() != OK)
- 13670 return(tp->iop->io_nbytes = EIO);
- 13671
- 13672 /* Tell the controller to transfer w_count bytes */
- 13673 cmd.precomp = wn->precomp;
- 13674 cmd.count = (w_count >> SECTOR_SHIFT) & BYTE;
- 13675 if (wn->ldhpref & LDH_LBA) {
- 13676 cmd.sector = (tp->block >> 0) & 0xFF;
- 13677 cmd.cyl_lo = (tp->block >> 8) & 0xFF;
- 13678 cmd.cyl_hi = (tp->block >> 16) & 0xFF;
- 13679 cmd.ldh = wn->ldhpref | ((tp->block >> 24) & 0xF);
- 13680 } else {
- 13681 secspcyl = wn->pheads * wn->psectors;
- 13682 cylinder = tp->block / secspcyl;
- 13683 head = (tp->block % secspcyl) / wn->psectors;
- 13684 sector = tp->block % wn->psectors;
- 13685 cmd.sector = sector + 1;
- 13686 cmd.cyl_lo = cylinder & BYTE;
- 13687 cmd.cyl_hi = (cylinder >> 8) & BYTE;
- 13688 cmd.ldh = wn->ldhpref | head;
- 13689 }
- 13690 cmd.command = w_opcode == DEV_WRITE ? CMD_WRITE : CMD_READ;
- 13691
- 13692 if ((r = com_out(&cmd)) != OK) {
- 13693 if (++errors == MAX_ERRORS) {
- 13694 w_command = CMD_IDLE;
- 13695 return(tp->iop->io_nbytes = EIO);
- 13696 }
- 13697 continue; /* Retry */
- 13698 }
- 13699 }
- 13700
- 13701 /* For each sector, wait for an interrupt and fetch the data (read),
- 13702 * or supply data to the controller and wait for an interrupt (write).
- 13703 */
- 13704
- 13705 if (w_opcode == DEV_READ) {
- 13706 if ((r = w_intr_wait()) == OK) {
- 13707 /* Copy data from the device's buffer to user space. */
- 13708
- 13709 port_read(wn->base + REG_DATA, tp->phys, SECTOR_SIZE);
- 13710
- 13711 tp->phys += SECTOR_SIZE;
- 13712 tp->iop->io_nbytes -= SECTOR_SIZE;
- 13713 w_count -= SECTOR_SIZE;
- 13714 if ((tp->count -= SECTOR_SIZE) == 0) tp++;
- 13715 } else {
- 13716 /* Any faulty data? */
- 13717 if (w_status & STATUS_DRQ) {
- 13718 port_read(wn->base + REG_DATA, tmp_phys,
- 13719 SECTOR_SIZE);
- 13720 }
- 13721 }
- 13722 } else {
- 13723 /* Wait for data requested. */
- 13724 if (!waitfor(STATUS_DRQ, STATUS_DRQ)) {
- 13725 r = ERR;
- 13726 } else {
- 13727 /* Fill the buffer of the drive. */
- 13728
- 13729 port_write(wn->base + REG_DATA, tp->phys, SECTOR_SIZE);
- 13730 r = w_intr_wait();
- 13731 }
- 13732
- 13733 if (r == OK) {
- 13734 /* Book the bytes successfully written. */
- 13735
- 13736 tp->phys += SECTOR_SIZE;
- 13737 tp->iop->io_nbytes -= SECTOR_SIZE;
- 13738 w_count -= SECTOR_SIZE;
- 13739 if ((tp->count -= SECTOR_SIZE) == 0) tp++;
- 13740 }
- 13741 }
- 13742
- 13743 if (r != OK) {
- 13744 /* Don't retry if sector marked bad or too many errors */
- 13745 if (r == ERR_BAD_SECTOR || ++errors == MAX_ERRORS) {
- 13746 w_command = CMD_IDLE;
- 13747 return(tp->iop->io_nbytes = EIO);
- 13748 }
- 13749
- 13750 /* Reset if halfway, but bail out if optional I/O. */
- 13751 if (errors == MAX_ERRORS / 2) {
- 13752 w_need_reset();
- 13753 if (tp->iop->io_request & OPTIONAL_IO) {
- 13754 w_command = CMD_IDLE;
- 13755 return(tp->iop->io_nbytes = EIO);
- 13756 }
- 13757 }
- 13758 continue; /* Retry */
- 13759 }
- 13760 errors = 0;
- 13761 } while (w_count > 0);
- 13762
- 13763 w_command = CMD_IDLE;
- 13764 return(OK);
- 13765 }
- 13768 /*============================================================================*
- 13769 * com_out *
- 13770 *============================================================================*/
- 13771 PRIVATE int com_out(cmd)
- 13772 struct command *cmd; /* Command block */
- 13773 {
- 13774 /* Output the command block to the winchester controller and return status */
- 13775
- 13776 struct wini *wn = w_wn;
- 13777 unsigned base = wn->base;
- 13778
- 13779 if (!waitfor(STATUS_BSY, 0)) {
- 13780 printf("%s: controller not readyn", w_name());
- 13781 return(ERR);
- 13782 }
- 13783
- 13784 /* Select drive. */
- 13785 out_byte(base + REG_LDH, cmd->ldh);
- 13786
- 13787 if (!waitfor(STATUS_BSY, 0)) {
- 13788 printf("%s: drive not readyn", w_name());
- 13789 return(ERR);
- 13790 }
- 13791
- 13792 /* Schedule a wakeup call, some controllers are flaky. */
- 13793 clock_mess(WAKEUP, w_timeout);
- 13794
- 13795 out_byte(base + REG_CTL, wn->pheads >= 8 ? CTL_EIGHTHEADS : 0);
- 13796 out_byte(base + REG_PRECOMP, cmd->precomp);
- 13797 out_byte(base + REG_COUNT, cmd->count);
- 13798 out_byte(base + REG_SECTOR, cmd->sector);
- 13799 out_byte(base + REG_CYL_LO, cmd->cyl_lo);
- 13800 out_byte(base + REG_CYL_HI, cmd->cyl_hi);
- 13801 lock();
- 13802 out_byte(base + REG_COMMAND, cmd->command);
- 13803 w_command = cmd->command;
- 13804 w_status = STATUS_BSY;
- 13805 unlock();
- 13806 return(OK);
- 13807 }
- 13810 /*===========================================================================*
- 13811 * w_need_reset *
- 13812 *===========================================================================*/
- 13813 PRIVATE void w_need_reset()
- 13814 {
- 13815 /* The controller needs to be reset. */
- 13816 struct wini *wn;
- 13817
- 13818 for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
- 13819 wn->state |= DEAF;
- 13820 wn->state &= ~INITIALIZED;
- 13821 }
- 13822 }
- 13825 /*============================================================================*
- 13826 * w_do_close *
- 13827 *============================================================================*/
- 13828 PRIVATE int w_do_close(dp, m_ptr)
- 13829 struct driver *dp;
- 13830 message *m_ptr;
- 13831 {
- 13832 /* Device close: Release a device. */
- 13833
- 13834 if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
- 13835 w_wn->open_ct--;
- 13836 return(OK);
- 13837 }
- 13840 /*============================================================================*
- 13841 * com_simple *
- 13842 *============================================================================*/
- 13843 PRIVATE int com_simple(cmd)
- 13844 struct command *cmd; /* Command block */
- 13845 {
- 13846 /* A simple controller command, only one interrupt and no data-out phase. */
- 13847 int r;
- 13848
- 13849 if ((r = com_out(cmd)) == OK) r = w_intr_wait();
- 13850 w_command = CMD_IDLE;
- 13851 return(r);
- 13852 }
- 13855 /*===========================================================================*
- 13856 * w_timeout *
- 13857 *===========================================================================*/
- 13858 PRIVATE void w_timeout()
- 13859 {
- 13860 struct wini *wn = w_wn;
- 13861
- 13862 switch (w_command) {
- 13863 case CMD_IDLE:
- 13864 break; /* fine */
- 13865 case CMD_READ:
- 13866 case CMD_WRITE:
- 13867 /* Impossible, but not on PC's: The controller does not respond. */
- 13868
- 13869 /* Limiting multisector I/O seems to help. */
- 13870 if (wn->max_count > 8 * SECTOR_SIZE) {
- 13871 wn->max_count = 8 * SECTOR_SIZE;
- 13872 } else {
- 13873 wn->max_count = SECTOR_SIZE;
- 13874 }
- 13875 /*FALL THROUGH*/
- 13876 default:
- 13877 /* Some other command. */
- 13878 printf("%s: timeout on command %02xn", w_name(), w_command);
- 13879 w_need_reset();
- 13880 w_status = 0;
- 13881 interrupt(WINCHESTER);
- 13882 }
- 13883 }
- 13886 /*===========================================================================*
- 13887 * w_reset *
- 13888 *===========================================================================*/
- 13889 PRIVATE int w_reset()
- 13890 {
- 13891 /* Issue a reset to the controller. This is done after any catastrophe,
- 13892 * like the controller refusing to respond.
- 13893 */
- 13894
- 13895 struct wini *wn;
- 13896 int err;
- 13897
- 13898 /* Wait for any internal drive recovery. */
- 13899 milli_delay(RECOVERYTIME);
- 13900
- 13901 /* Strobe reset bit */
- 13902 out_byte(w_wn->base + REG_CTL, CTL_RESET);
- 13903 milli_delay(1);
- 13904 out_byte(w_wn->base + REG_CTL, 0);
- 13905 milli_delay(1);
- 13906
- 13907 /* Wait for controller ready */
- 13908 if (!w_waitfor(STATUS_BSY | STATUS_RDY, STATUS_RDY)) {
- 13909 printf("%s: reset failed, drive busyn", w_name());
- 13910 return(ERR);
- 13911 }
- 13912
- 13913 /* The error register should be checked now, but some drives mess it up. */
- 13914
- 13915 for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
- 13916 if (wn->base == w_wn->base) wn->state &= ~DEAF;
- 13917 }
- 13918 return(OK);
- 13919 }
- 13922 /*============================================================================*
- 13923 * w_intr_wait *
- 13924 *============================================================================*/
- 13925 PRIVATE int w_intr_wait()
- 13926 {
- 13927 /* Wait for a task completion interrupt and return results. */
- 13928
- 13929 message mess;
- 13930 int r;
- 13931
- 13932 /* Wait for an interrupt that sets w_status to "not busy". */
- 13933 while (w_status & STATUS_BSY) receive(HARDWARE, &mess);
- 13934
- 13935 /* Check status. */
- 13936 lock();
- 13937 if ((w_status & (STATUS_BSY | STATUS_RDY | STATUS_WF | STATUS_ERR))
- 13938 == STATUS_RDY) {
- 13939 r = OK;
- 13940 w_status |= STATUS_BSY; /* assume still busy with I/O */
- 13941 } else
- 13942 if ((w_status & STATUS_ERR) && (in_byte(w_wn->base + REG_ERROR) & ERROR_BB)) {
- 13943 r = ERR_BAD_SECTOR; /* sector marked bad, retries won't help */
- 13944 } else {
- 13945 r = ERR; /* any other error */
- 13946 }
- 13947 unlock();
- 13948 return(r);
- 13949 }
- 13952 /*==========================================================================*
- 13953 * w_waitfor *
- 13954 *==========================================================================*/
- 13955 PRIVATE int w_waitfor(mask, value)
- 13956 int mask; /* status mask */
- 13957 int value; /* required status */
- 13958 {
- 13959 /* Wait until controller is in the required state. Return zero on timeout. */
- 13960
- 13961 struct milli_state ms;
- 13962
- 13963 milli_start(&ms);
- 13964 do {
- 13965 if ((in_byte(w_wn->base + REG_STATUS) & mask) == value) return 1;
- 13966 } while (milli_elapsed(&ms) < TIMEOUT);
- 13967
- 13968 w_need_reset(); /* Controller gone deaf. */
- 13969 return(0);
- 13970 }
- 13973 /*==========================================================================*
- 13974 * w_handler *
- 13975 *==========================================================================*/
- 13976 PRIVATE int w_handler(irq)
- 13977 int irq;
- 13978 {
- 13979 /* Disk interrupt, send message to winchester task and reenable interrupts. */
- 13980
- 13981 w_status = in_byte(w_wn->base + REG_STATUS); /* acknowledge interrupt */
- 13982 interrupt(WINCHESTER);
- 13983 return 1;
- 13984 }
- 13987 /*============================================================================*
- 13988 * w_geometry *
- 13989 *============================================================================*/
- 13990 PRIVATE void w_geometry(entry)
- 13991 struct partition *entry;
- 13992 {
- 13993 entry->cylinders = w_wn->lcylinders;
- 13994 entry->heads = w_wn->lheads;
- 13995 entry->sectors = w_wn->lsectors;
- 13996 }
- 13997 #endif /* ENABLE_AT_WINI */
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/bios_wini.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 14000 /* This file contains the "device dependent" part of a hard disk driver that
- 14001 * uses the ROM BIOS. It makes a call and just waits for the transfer to
- 14002 * happen. It is not interrupt driven and thus will (*) have poor performance.
- 14003 * The advantage is that it should work on virtually any PC, XT, 386, PS/2
- 14004 * or clone. The demo disk uses this driver. It is suggested that all
- 14005 * MINIX users try the other drivers, and use this one only as a last resort,
- 14006 * if all else fails.
- 14007 *
- 14008 * (*) The performance is within 10% of the AT driver for reads on any disk
- 14009 * and writes on a 2:1 interleaved disk, it will be DMA_BUF_SIZE bytes
- 14010 * per revolution for a minimum of 60 kb/s for writes to 1:1 disks.
- 14011 *
- 14012 * The file contains one entry point:
- 14013 *
- 14014 * bios_winchester_task: main entry when system is brought up
- 14015 *
- 14016 *
- 14017 * Changes:
- 14018 * 30 Apr 1992 by Kees J. Bot: device dependent/independent split.
- 14019 */
- 14020
- 14021 #include "kernel.h"
- 14022 #include "driver.h"
- 14023 #include "drvlib.h"
- 14024
- 14025 #if ENABLE_BIOS_WINI
- 14026
- 14027 /* If the DMA buffer is large enough then use it always. */
- 14028 #define USE_BUF (DMA_BUF_SIZE > BLOCK_SIZE)
- 14029
- 14030 /* Error codes */
- 14031 #define ERR (-1) /* general error */
- 14032
- 14033 /* Parameters for the disk drive. */
- 14034 #define MAX_DRIVES 4 /* this driver supports 4 drives (hd0 - hd19)*/
- 14035 #define MAX_SECS 255 /* bios can transfer this many sectors */
- 14036 #define NR_DEVICES (MAX_DRIVES * DEV_PER_DRIVE)
- 14037 #define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS)
- 14038 #define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE)
- 14039
- 14040 /* BIOS parameters */
- 14041 #define BIOS_ASK 0x08 /* opcode for asking BIOS for parameters */
- 14042 #define BIOS_RESET 0x00 /* opcode for resetting disk BIOS */
- 14043 #define BIOS_READ 0x02 /* opcode for BIOS read */
- 14044 #define BIOS_WRITE 0x03 /* opcode for BIOS write */
- 14045 #define HD_CODE 0x80 /* BIOS code for hard disk drive 0 */
- 14046
- 14047 /* Variables. */
- 14048 PRIVATE struct wini { /* main drive struct, one entry per drive */
- 14049 unsigned cylinders; /* number of cylinders */
- 14050 unsigned heads; /* number of heads */
- 14051 unsigned sectors; /* number of sectors per track */
- 14052 unsigned open_ct; /* in-use count */
- 14053 struct device part[DEV_PER_DRIVE]; /* primary partitions: hd[0-4] */
- 14054 struct device subpart[SUB_PER_DRIVE]; /* subpartitions: hd[1-4][a-d] */
- 14055 } wini[MAX_DRIVES], *w_wn;
- 14056
- 14057 PRIVATE struct trans {
- 14058 struct iorequest_s *iop; /* belongs to this I/O request */
- 14059 unsigned long block; /* first sector to transfer */
- 14060 unsigned count; /* byte count */
- 14061 phys_bytes phys; /* user physical address */
- 14062 phys_bytes dma; /* DMA physical address */
- 14063 } wtrans[NR_IOREQS];
- 14064
- 14065 PRIVATE int nr_drives = MAX_DRIVES; /* Number of drives */
- 14066 PRIVATE struct trans *w_tp; /* to add transfer requests */
- 14067 PRIVATE unsigned w_count; /* number of bytes to transfer */
- 14068 PRIVATE unsigned long w_nextblock; /* next block on disk to transfer */
- 14069 PRIVATE int w_opcode; /* DEV_READ or DEV_WRITE */
- 14070 PRIVATE int w_drive; /* selected drive */
- 14071 PRIVATE struct device *w_dv; /* device's base and size */
- 14072 extern unsigned Ax, Bx, Cx, Dx, Es; /* to hold registers for BIOS calls */
- 14073
- 14074 FORWARD _PROTOTYPE( struct device *w_prepare, (int device) );
- 14075 FORWARD _PROTOTYPE( char *w_name, (void) );
- 14076 FORWARD _PROTOTYPE( int w_schedule, (int proc_nr, struct iorequest_s *iop) );
- 14077 FORWARD _PROTOTYPE( int w_finish, (void) );
- 14078 FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr) );
- 14079 FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );
- 14080 FORWARD _PROTOTYPE( void w_init, (void) );
- 14081 FORWARD _PROTOTYPE( void enable_vectors, (void) );
- 14082 FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry));
- 14083
- 14084
- 14085 /* Entry points to this driver. */
- 14086 PRIVATE struct driver w_dtab = {
- 14087 w_name, /* current device's name */
- 14088 w_do_open, /* open or mount request, initialize device */
- 14089 w_do_close, /* release device */
- 14090 do_diocntl, /* get or set a partition's geometry */
- 14091 w_prepare, /* prepare for I/O on a given minor device */
- 14092 w_schedule, /* precompute cylinder, head, sector, etc. */
- 14093 w_finish, /* do the I/O */
- 14094 nop_cleanup, /* no cleanup needed */
- 14095 w_geometry /* tell the geometry of the disk */
- 14096 };
- 14097
- 14098
- 14099 /*===========================================================================*
- 14100 * bios_winchester_task *
- 14101 *===========================================================================*/
- 14102 PUBLIC void bios_winchester_task()
- 14103 {
- 14104 driver_task(&w_dtab);
- 14105 }
- 14108 /*===========================================================================*
- 14109 * w_prepare *
- 14110 *===========================================================================*/
- 14111 PRIVATE struct device *w_prepare(device)
- 14112 int device;
- 14113 {
- 14114 /* Prepare for I/O on a device. */
- 14115
- 14116 /* Nothing to transfer as yet. */
- 14117 w_count = 0;
- 14118
- 14119 if (device < NR_DEVICES) { /* hd0, hd1, ... */
- 14120 w_drive = device / DEV_PER_DRIVE; /* save drive number */
- 14121 w_wn = &wini[w_drive];
- 14122 w_dv = &w_wn->part[device % DEV_PER_DRIVE];
- 14123 } else
- 14124 if ((unsigned) (device -= MINOR_hd1a) < NR_SUBDEVS) { /* hd1a, hd1b, ... */
- 14125 w_drive = device / SUB_PER_DRIVE;
- 14126 w_wn = &wini[w_drive];
- 14127 w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
- 14128 } else {
- 14129 return(NIL_DEV);
- 14130 }
- 14131 return(w_drive < nr_drives ? w_dv : NIL_DEV);
- 14132 }
- 14135 /*===========================================================================*
- 14136 * w_name *
- 14137 *===========================================================================*/
- 14138 PRIVATE char *w_name()
- 14139 {
- 14140 /* Return a name for the current device. */
- 14141 static char name[] = "bios-hd5";
- 14142
- 14143 name[7] = '0' + w_drive * DEV_PER_DRIVE;
- 14144 return name;
- 14145 }
- 14148 /*===========================================================================*
- 14149 * w_schedule *
- 14150 *===========================================================================*/
- 14151 PRIVATE int w_schedule(proc_nr, iop)
- 14152 int proc_nr; /* process doing the request */
- 14153 struct iorequest_s *iop; /* pointer to read or write request */
- 14154 {
- 14155 /* Gather I/O requests on consecutive blocks so they may be read/written
- 14156 * in one bios command if using a buffer. Check and gather all the requests
- 14157 * and try to finish them as fast as possible if unbuffered.
- 14158 */
- 14159 int r, opcode;
- 14160 unsigned long pos;
- 14161 unsigned nbytes, count, dma_count;
- 14162 unsigned long block;
- 14163 phys_bytes user_phys, dma_phys;
- 14164
- 14165 /* This many bytes to read/write */
- 14166 nbytes = iop->io_nbytes;
- 14167 if ((nbytes & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
- 14168
- 14169 /* From/to this position on the device */
- 14170 pos = iop->io_position;
- 14171 if ((pos & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
- 14172
- 14173 /* To/from this user address */
- 14174 user_phys = numap(proc_nr, (vir_bytes) iop->io_buf, nbytes);
- 14175 if (user_phys == 0) return(iop->io_nbytes = EINVAL);
- 14176
- 14177 /* Read or write? */
- 14178 opcode = iop->io_request & ~OPTIONAL_IO;
- 14179
- 14180 /* Which block on disk and how close to EOF? */
- 14181 if (pos >= w_dv->dv_size) return(OK); /* At EOF */
- 14182 if (pos + nbytes > w_dv->dv_size) nbytes = w_dv->dv_size - pos;
- 14183 block = (w_dv->dv_base + pos) >> SECTOR_SHIFT;
- 14184
- 14185 if (USE_BUF && w_count > 0 && block != w_nextblock) {
- 14186 /* This new request can't be chained to the job being built */
- 14187 if ((r = w_finish()) != OK) return(r);
- 14188 }
- 14189
- 14190 /* The next consecutive block */
- 14191 if (USE_BUF) w_nextblock = block + (nbytes >> SECTOR_SHIFT);
- 14192
- 14193 /* While there are "unscheduled" bytes in the request: */
- 14194 do {
- 14195 count = nbytes;
- 14196
- 14197 if (USE_BUF) {
- 14198 if (w_count == DMA_BUF_SIZE) {
- 14199 /* Can't transfer more than the buffer allows. */
- 14200 if ((r = w_finish()) != OK) return(r);
- 14201 }
- 14202
- 14203 if (w_count + count > DMA_BUF_SIZE)
- 14204 count = DMA_BUF_SIZE - w_count;
- 14205 } else {
- 14206 if (w_tp == wtrans + NR_IOREQS) {
- 14207 /* All transfer slots in use. */
- 14208 if ((r = w_finish()) != OK) return(r);
- 14209 }
- 14210 }
- 14211
- 14212 if (w_count == 0) {
- 14213 /* The first request in a row, initialize. */
- 14214 w_opcode = opcode;
- 14215 w_tp = wtrans;
- 14216 }
- 14217
- 14218 if (USE_BUF) {
- 14219 dma_phys = tmp_phys + w_count;
- 14220 } else {
- 14221 /* Memory chunk to DMA. */
- 14222 dma_phys = user_phys;
- 14223 dma_count = dma_bytes_left(dma_phys);
- 14224
- 14225 if (dma_phys >= (1L << 20)) {
- 14226 /* The BIOS can only address the first megabyte. */
- 14227 count = SECTOR_SIZE;
- 14228 dma_phys = tmp_phys;
- 14229 } else
- 14230 if (dma_count < count) {
- 14231 /* Nearing a 64K boundary. */
- 14232 if (dma_count >= SECTOR_SIZE) {
- 14233 /* Can read a few sectors before hitting the
- 14234 * boundary.
- 14235 */
- 14236 count = dma_count & ~SECTOR_MASK;
- 14237 } else {
- 14238 /* Must use the special buffer for this. */
- 14239 count = SECTOR_SIZE;
- 14240 dma_phys = tmp_phys;
- 14241 }
- 14242 }
- 14243 }
- 14244
- 14245 /* Store I/O parameters */
- 14246 w_tp->iop = iop;
- 14247 w_tp->block = block;
- 14248 w_tp->count = count;
- 14249 w_tp->phys = user_phys;
- 14250 w_tp->dma = dma_phys;
- 14251
- 14252 /* Update counters */
- 14253 w_tp++;
- 14254 w_count += count;
- 14255 block += count >> SECTOR_SHIFT;
- 14256 user_phys += count;
- 14257 nbytes -= count;
- 14258 } while (nbytes > 0);
- 14259
- 14260 return(OK);
- 14261 }
- 14264 /*===========================================================================*
- 14265 * w_finish *
- 14266 *===========================================================================*/
- 14267 PRIVATE int w_finish()
- 14268 {
- 14269 /* Carry out the I/O requests gathered in wtrans[]. */
- 14270
- 14271 struct trans *tp = wtrans, *tp2;
- 14272 unsigned count, cylinder, sector, head, hicyl, locyl;
- 14273 unsigned secspcyl = w_wn->heads * w_wn->sectors;
- 14274 int many = USE_BUF;
- 14275
- 14276 if (w_count == 0) return(OK); /* Spurious finish. */
- 14277
- 14278 do {
- 14279 if (w_opcode == DEV_WRITE) {
- 14280 tp2 = tp;
- 14281 count = 0;
- 14282 do {
- 14283 if (USE_BUF || tp2->dma == tmp_phys) {
- 14284 phys_copy(tp2->phys, tp2->dma,
- 14285 (phys_bytes) tp2->count);
- 14286 }
- 14287 count += tp2->count;
- 14288 tp2++;
- 14289 } while (many && count < w_count);
- 14290 } else {
- 14291 count = many ? w_count : tp->count;
- 14292 }
- 14293
- 14294 /* Do the transfer */
- 14295 cylinder = tp->block / secspcyl;
- 14296 sector = (tp->block % w_wn->sectors) + 1;
- 14297 head = (tp->block % secspcyl) / w_wn->sectors;
- 14298
- 14299 Ax = w_opcode == DEV_WRITE ? BIOS_WRITE : BIOS_READ;
- 14300 Ax = (Ax << 8) | (count >> SECTOR_SHIFT); /* opcode & count */
- 14301 Bx = (unsigned) tp->dma % HCLICK_SIZE; /* low order 4 bits */
- 14302 Es = physb_to_hclick(tp->dma); /* high order 16 bits */
- 14303 hicyl = (cylinder & 0x300) >> 8; /* two high-order bits */
- 14304 locyl = (cylinder & 0xFF); /* 8 low-order bits */
- 14305 Cx = sector | (hicyl << 6) | (locyl << 8);
- 14306 Dx = (HD_CODE + w_drive) | (head << 8);
- 14307 level0(bios13);
- 14308 if ((Ax & 0xFF00) != 0) {
- 14309 /* An error occurred, try again block by block unless */
- 14310 if (!many) return(tp->iop->io_nbytes = EIO);
- 14311 many = 0;
- 14312 continue;
- 14313 }
- 14314
- 14315 w_count -= count;
- 14316
- 14317 do {
- 14318 if (w_opcode == DEV_READ) {
- 14319 if (USE_BUF || tp->dma == tmp_phys) {
- 14320 phys_copy(tp->dma, tp->phys,
- 14321 (phys_bytes) tp->count);
- 14322 }
- 14323 }
- 14324 tp->iop->io_nbytes -= tp->count;
- 14325 count -= tp->count;
- 14326 tp++;
- 14327 } while (count > 0);
- 14328 } while (w_count > 0);
- 14329
- 14330 return(OK);
- 14331 }
- 14334 /*============================================================================*
- 14335 * w_do_open *
- 14336 *============================================================================*/
- 14337 PRIVATE int w_do_open(dp, m_ptr)
- 14338 struct driver *dp;
- 14339 message *m_ptr;
- 14340 {
- 14341 /* Device open: Initialize the controller and read the partition table. */
- 14342
- 14343 static int init_done = FALSE;
- 14344
- 14345 if (!init_done) { w_init(); init_done = TRUE; }
- 14346
- 14347 if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
- 14348
- 14349 if (w_wn->open_ct++ == 0) {
- 14350 /* Partition the disk. */
- 14351 partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY);
- 14352 }
- 14353 return(OK);
- 14354 }
- 14357 /*============================================================================*
- 14358 * w_do_close *
- 14359 *============================================================================*/
- 14360 PRIVATE int w_do_close(dp, m_ptr)
- 14361 struct driver *dp;
- 14362 message *m_ptr;
- 14363 {
- 14364 /* Device close: Release a device. */
- 14365
- 14366 if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
- 14367 w_wn->open_ct--;
- 14368 return(OK);
- 14369 }
- 14372 /*===========================================================================*
- 14373 * w_init *
- 14374 *===========================================================================*/
- 14375 PRIVATE void w_init()
- 14376 {
- 14377 /* This routine is called at startup to initialize the drive parameters. */
- 14378
- 14379 int drive;
- 14380 struct wini *wn;
- 14381
- 14382 /* Enable real mode BIOS vectors. */
- 14383 enable_vectors();
- 14384
- 14385 /* Set the geometry of the drives */
- 14386 for (drive = 0; drive < nr_drives; drive++) {
- 14387 (void) w_prepare(drive * DEV_PER_DRIVE);
- 14388 wn = w_wn;
- 14389 Dx = drive + HD_CODE;
- 14390 Ax = (BIOS_ASK << 8);
- 14391 level0(bios13);
- 14392 nr_drives = (Ax & 0xFF00) == 0 ? (Dx & 0xFF) : drive;
- 14393 if (nr_drives > MAX_DRIVES) nr_drives = MAX_DRIVES;
- 14394 if (drive >= nr_drives) break;
- 14395
- 14396 wn->heads = (Dx >> 8) + 1;
- 14397 wn->sectors = (Cx & 0x3F);
- 14398 wn->cylinders = ((Cx << 2) & 0x0300) + ((Cx >> 8) & 0x00FF) + 1;
- 14399
- 14400 wn->part[0].dv_size = ((unsigned long) wn->cylinders
- 14401 * wn->heads * wn->sectors) << SECTOR_SHIFT;
- 14402
- 14403 printf("%s: %d cylinders, %d heads, %d sectors per trackn",
- 14404 w_name(), wn->cylinders, wn->heads, wn->sectors);
- 14405 }
- 14406 }
- 14409 /*===========================================================================*
- 14410 * enable_vectors *
- 14411 *===========================================================================*/
- 14412 PRIVATE void enable_vectors()
- 14413 {
- 14414 /* Protected mode Minix has reprogrammed the interrupt controllers to
- 14415 * use different vectors from the BIOS. This means that the BIOS vectors
- 14416 * must be copied to the Minix locations for use in real mode. The bios13()
- 14417 * function enables all interrupts that Minix doesn't use, and masks all
- 14418 * interrupts that Minix does use when it makes the "INT 13" call. Alas
- 14419 * more than one clock tick may occur while the disk is active, so we need
- 14420 * a special real mode clock interrupt handle to gather lost ticks.
- 14421 */
- 14422
- 14423 int vec, irq;
- 14424 static u8_t clock_handler[] = {
- 14425 0x50, 0xB0, 0x20, 0xE6, 0x20, 0xEB, 0x06, 0xE4,
- 14426 0x61, 0x0C, 0x80, 0xE6, 0x61, 0x58, 0x53, 0x1E,
- 14427 0xE8, 0x00, 0x00, 0x5B, 0x2E, 0xC5, 0x5F, 0x0A,
- 14428 0xFF, 0x07, 0x1F, 0x5B, 0xCF,
- 14429 0x00, 0x00, 0x00, 0x00,
- 14430 };
- 14431 u16_t vector[2];
- 14432
- 14433 if (!protected_mode) return;
- 14434
- 14435 for (irq = 0; irq < NR_IRQ_VECTORS; irq++) {
- 14436 phys_copy(BIOS_VECTOR(irq)*4L, VECTOR(irq)*4L, 4L);
- 14437 }
- 14438
- 14439 /* Install a clock interrupt handler to collect clock ticks when the
- 14440 * BIOS disk driver is active. The handler is a simple bit of 8086 code
- 14441 * that increments "lost_ticks".
- 14442 */
- 14443
- 14444 /* Let the clock interrupt point to the handler. */
- 14445 vector[0] = vir2phys(clock_handler) % HCLICK_SIZE;
- 14446 vector[1] = vir2phys(clock_handler) / HCLICK_SIZE;
- 14447 phys_copy(vir2phys(vector), VECTOR(CLOCK_IRQ)*4L, 4L);
- 14448
- 14449 /* Store the address of lost_ticks in the handler. */
- 14450 vector[0] = vir2phys(&lost_ticks) % HCLICK_SIZE;
- 14451 vector[1] = vir2phys(&lost_ticks) / HCLICK_SIZE;
- 14452 memcpy(clock_handler + 0x1D, vector, 4);
- 14453
- 14454 if (ps_mca) clock_handler[6]= 0; /* (PS/2 port B clock ack) */
- 14455 }
- 14458 /*============================================================================*
- 14459 * w_geometry *
- 14460 *============================================================================*/
- 14461 PRIVATE void w_geometry(entry)
- 14462 struct partition *entry;
- 14463 {
- 14464 entry->cylinders = w_wn->cylinders;
- 14465 entry->heads = w_wn->heads;
- 14466 entry->sectors = w_wn->sectors;
- 14467 }
- 14468 #endif /* ENABLE_BIOS_WINI */
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/clock.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 14500 /* This file contains the code and data for the clock task. The clock task
- 14501 * accepts six message types:
- 14502 *
- 14503 * HARD_INT: a clock interrupt has occurred
- 14504 * GET_UPTIME: get the time since boot in ticks
- 14505 * GET_TIME: a process wants the real time in seconds
- 14506 * SET_TIME: a process wants to set the real time in seconds
- 14507 * SET_ALARM: a process wants to be alerted after a specified interval
- 14508 * SET_SYN_AL: set the sync alarm
- 14509 *
- 14510 *
- 14511 * The input message is format m6. The parameters are as follows:
- 14512 *
- 14513 * m_type CLOCK_PROC FUNC NEW_TIME
- 14514 * ---------------------------------------------
- 14515 * | HARD_INT | | | |
- 14516 * |------------+----------+---------+---------|
- 14517 * | GET_UPTIME | | | |
- 14518 * |------------+----------+---------+---------|
- 14519 * | GET_TIME | | | |
- 14520 * |------------+----------+---------+---------|
- 14521 * | SET_TIME | | | newtime |
- 14522 * |------------+----------+---------+---------|
- 14523 * | SET_ALARM | proc_nr |f to call| delta |
- 14524 * |------------+----------+---------+---------|
- 14525 * | SET_SYN_AL | proc_nr | | delta |
- 14526 * ---------------------------------------------
- 14527 * NEW_TIME, DELTA_CLICKS, and SECONDS_LEFT all refer to the same field in
- 14528 * the message, depending upon the message type.
- 14529 *
- 14530 * Reply messages are of type OK, except in the case of a HARD_INT, to
- 14531 * which no reply is generated. For the GET_* messages the time is returned
- 14532 * in the NEW_TIME field, and for the SET_ALARM and SET_SYN_AL the time
- 14533 * in seconds remaining until the alarm is returned is returned in the same
- 14534 * field.
- 14535 *
- 14536 * When an alarm goes off, if the caller is a user process, a SIGALRM signal
- 14537 * is sent to it. If it is a task, a function specified by the caller will
- 14538 * be invoked. This function may, for example, send a message, but only if
- 14539 * it is certain that the task will be blocked when the timer goes off. A
- 14540 * synchronous alarm sends a message to the synchronous alarm task, which
- 14541 * in turn can dispatch a message to another server. This is the only way
- 14542 * to send an alarm to a server, since servers cannot use the function-call
- 14543 * mechanism available to tasks and servers cannot receive signals.
- 14544 */
- 14545
- 14546 #include "kernel.h"
- 14547 #include <signal.h>
- 14548 #include <minix/callnr.h>
- 14549 #include <minix/com.h>
- 14550 #include "proc.h"
- 14551
- 14552 /* Constant definitions. */
- 14553 #define MILLISEC 100 /* how often to call the scheduler (msec) */
- 14554 #define SCHED_RATE (MILLISEC*HZ/1000) /* number of ticks per schedule */
- 14555
- 14556 /* Clock parameters. */
- 14557 #if (CHIP == INTEL)
- 14558 #define COUNTER_FREQ (2*TIMER_FREQ) /* counter frequency using sqare wave*/
- 14559 #define LATCH_COUNT 0x00 /* cc00xxxx, c = channel, x = any */
- 14560 #define SQUARE_WAVE 0x36 /* ccaammmb, a = access, m = mode, b = BCD */
- 14561 /* 11x11, 11 = LSB then MSB, x11 = sq wave */
- 14562 #define TIMER_COUNT ((unsigned) (TIMER_FREQ/HZ)) /* initial value for counter*/
- 14563 #define TIMER_FREQ 1193182L /* clock frequency for timer in PC and AT */
- 14564
- 14565 #define CLOCK_ACK_BIT 0x80 /* PS/2 clock interrupt acknowledge bit */
- 14566 #endif
- 14567
- 14568 #if (CHIP == M68000)
- 14569 #define TIMER_FREQ 2457600L /* timer 3 input clock frequency */
- 14570 #endif
- 14571
- 14572 /* Clock task variables. */
- 14573 PRIVATE clock_t realtime; /* real time clock */
- 14574 PRIVATE time_t boot_time; /* time in seconds of system boot */
- 14575 PRIVATE clock_t next_alarm; /* probable time of next alarm */
- 14576 PRIVATE message mc; /* message buffer for both input and output */
- 14577 PRIVATE int watchdog_proc; /* contains proc_nr at call of *watch_dog[]*/
- 14578 PRIVATE watchdog_t watch_dog[NR_TASKS+NR_PROCS];
- 14579
- 14580 /* Variables used by both clock task and synchronous alarm task */
- 14581 PRIVATE int syn_al_alive= TRUE; /* don't wake syn_alrm_task before inited*/
- 14582 PRIVATE int syn_table[NR_TASKS+NR_PROCS]; /* which tasks get CLOCK_INT*/
- 14583
- 14584 /* Variables changed by interrupt handler */
- 14585 PRIVATE clock_t pending_ticks; /* ticks seen by low level only */
- 14586 PRIVATE int sched_ticks = SCHED_RATE; /* counter: when 0, call scheduler */
- 14587 PRIVATE struct proc *prev_ptr; /* last user process run by clock task */
- 14588
- 14589 FORWARD _PROTOTYPE( void common_setalarm, (int proc_nr,
- 14590 long delta_ticks, watchdog_t fuction) );
- 14591 FORWARD _PROTOTYPE( void do_clocktick, (void) );
- 14592 FORWARD _PROTOTYPE( void do_get_time, (void) );
- 14593 FORWARD _PROTOTYPE( void do_getuptime, (void) );
- 14594 FORWARD _PROTOTYPE( void do_set_time, (message *m_ptr) );
- 14595 FORWARD _PROTOTYPE( void do_setalarm, (message *m_ptr) );
- 14596 FORWARD _PROTOTYPE( void init_clock, (void) );
- 14597 FORWARD _PROTOTYPE( void cause_alarm, (void) );
- 14598 FORWARD _PROTOTYPE( void do_setsyn_alrm, (message *m_ptr) );
- 14599 FORWARD _PROTOTYPE( int clock_handler, (int irq) );
- 14600
- 14601 /*===========================================================================*
- 14602 * clock_task *
- 14603 *===========================================================================*/
- 14604 PUBLIC void clock_task()
- 14605 {
- 14606 /* Main program of clock task. It corrects realtime by adding pending
- 14607 * ticks seen only by the interrupt service, then it determines which
- 14608 * of the 6 possible calls this is by looking at 'mc.m_type'. Then
- 14609 * it dispatches.
- 14610 */
- 14611
- 14612 int opcode;
- 14613
- 14614 init_clock(); /* initialize clock task */
- 14615
- 14616 /* Main loop of the clock task. Get work, process it, sometimes reply. */
- 14617 while (TRUE) {
- 14618 receive(ANY, &mc); /* go get a message */
- 14619 opcode = mc.m_type; /* extract the function code */
- 14620
- 14621 lock();
- 14622 realtime += pending_ticks; /* transfer ticks from low level handler */
- 14623 pending_ticks = 0; /* so we don't have to worry about them */
- 14624 unlock();
- 14625
- 14626 switch (opcode) {
- 14627 case HARD_INT: do_clocktick(); break;
- 14628 case GET_UPTIME: do_getuptime(); break;
- 14629 case GET_TIME: do_get_time(); break;
- 14630 case SET_TIME: do_set_time(&mc); break;
- 14631 case SET_ALARM: do_setalarm(&mc); break;
- 14632 case SET_SYNC_AL:do_setsyn_alrm(&mc); break;
- 14633 default: panic("clock task got bad message", mc.m_type);
- 14634 }
- 14635
- 14636 /* Send reply, except for clock tick. */
- 14637 mc.m_type = OK;
- 14638 if (opcode != HARD_INT) send(mc.m_source, &mc);
- 14639 }
- 14640 }
- 14643 /*===========================================================================*
- 14644 * do_clocktick *
- 14645 *===========================================================================*/
- 14646 PRIVATE void do_clocktick()
- 14647 {
- 14648 /* Despite its name, this routine is not called on every clock tick. It
- 14649 * is called on those clock ticks when a lot of work needs to be done.
- 14650 */
- 14651
- 14652 register struct proc *rp;
- 14653 register int proc_nr;
- 14654
- 14655 if (next_alarm <= realtime) {
- 14656 /* An alarm may have gone off, but proc may have exited, so check. */
- 14657 next_alarm = LONG_MAX; /* start computing next alarm */
- 14658 for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) {
- 14659 if (rp->p_alarm != 0) {
- 14660 /* See if this alarm time has been reached. */
- 14661 if (rp->p_alarm <= realtime) {
- 14662 /* A timer has gone off. If it is a user proc,
- 14663 * send it a signal. If it is a task, call the
- 14664 * function previously specified by the task.
- 14665 */
- 14666 proc_nr = proc_number(rp);
- 14667 if (watch_dog[proc_nr+NR_TASKS]) {
- 14668 watchdog_proc= proc_nr;
- 14669 (*watch_dog[proc_nr+NR_TASKS])();
- 14670 }
- 14671 else
- 14672 cause_sig(proc_nr, SIGALRM);
- 14673 rp->p_alarm = 0;
- 14674 }
- 14675
- 14676 /* Work on determining which alarm is next. */
- 14677 if (rp->p_alarm != 0 && rp->p_alarm < next_alarm)
- 14678 next_alarm = rp->p_alarm;
- 14679 }
- 14680 }
- 14681 }
- 14682
- 14683 /* If a user process has been running too long, pick another one. */
- 14684 if (--sched_ticks == 0) {
- 14685 if (bill_ptr == prev_ptr) lock_sched(); /* process has run too long */
- 14686 sched_ticks = SCHED_RATE; /* reset quantum */
- 14687 prev_ptr = bill_ptr; /* new previous process */
- 14688 }
- 14689 #if (SHADOWING == 1)
- 14690 if (rdy_head[SHADOW_Q]) unshadow(rdy_head[SHADOW_Q]);
- 14691 #endif
- 14692 }
- 14695 /*===========================================================================*
- 14696 * do_getuptime *
- 14697 *===========================================================================*/
- 14698 PRIVATE void do_getuptime()
- 14699 {
- 14700 /* Get and return the current clock uptime in ticks. */
- 14701
- 14702 mc.NEW_TIME = realtime; /* current uptime */
- 14703 }
- 14706 /*===========================================================================*
- 14707 * get_uptime *
- 14708 *===========================================================================*/
- 14709 PUBLIC clock_t get_uptime()
- 14710 {
- 14711 /* Get and return the current clock uptime in ticks. This function is
- 14712 * designed to be called from other tasks, so they can get uptime without
- 14713 * the overhead of messages. It has to be careful about pending_ticks.
- 14714 */
- 14715
- 14716 clock_t uptime;
- 14717
- 14718 lock();
- 14719 uptime = realtime + pending_ticks;
- 14720 unlock();
- 14721 return(uptime);
- 14722 }
- 14725 /*===========================================================================*
- 14726 * do_get_time *
- 14727 *===========================================================================*/
- 14728 PRIVATE void do_get_time()
- 14729 {
- 14730 /* Get and return the current clock time in seconds. */
- 14731
- 14732 mc.NEW_TIME = boot_time + realtime/HZ; /* current real time */
- 14733 }
- 14736 /*===========================================================================*
- 14737 * do_set_time *
- 14738 *===========================================================================*/
- 14739 PRIVATE void do_set_time(m_ptr)
- 14740 message *m_ptr; /* pointer to request message */
- 14741 {
- 14742 /* Set the real time clock. Only the superuser can use this call. */
- 14743
- 14744 boot_time = m_ptr->NEW_TIME - realtime/HZ;
- 14745 }
- 14748 /*===========================================================================*
- 14749 * do_setalarm *
- 14750 *===========================================================================*/
- 14751 PRIVATE void do_setalarm(m_ptr)
- 14752 message *m_ptr; /* pointer to request message */
- 14753 {
- 14754 /* A process wants an alarm signal or a task wants a given watch_dog function
- 14755 * called after a specified interval.
- 14756 */
- 14757
- 14758 register struct proc *rp;
- 14759 int proc_nr; /* which process wants the alarm */
- 14760 long delta_ticks; /* in how many clock ticks does he want it? */
- 14761 watchdog_t function; /* function to call (tasks only) */
- 14762
- 14763 /* Extract the parameters from the message. */
- 14764 proc_nr = m_ptr->CLOCK_PROC_NR; /* process to interrupt later */
- 14765 delta_ticks = m_ptr->DELTA_TICKS; /* how many ticks to wait */
- 14766 function = (watchdog_t) m_ptr->FUNC_TO_CALL;
- 14767 /* function to call (tasks only) */
- 14768 rp = proc_addr(proc_nr);
- 14769 mc.SECONDS_LEFT = (rp->p_alarm == 0 ? 0 : (rp->p_alarm - realtime)/HZ );
- 14770 if (!istaskp(rp)) function= 0; /* user processes get signaled */
- 14771 common_setalarm(proc_nr, delta_ticks, function);
- 14772 }
- 14775 /*===========================================================================*
- 14776 * do_setsyn_alrm *
- 14777 *===========================================================================*/
- 14778 PRIVATE void do_setsyn_alrm(m_ptr)
- 14779 message *m_ptr; /* pointer to request message */
- 14780 {
- 14781 /* A process wants a synchronous alarm.
- 14782 */
- 14783
- 14784 register struct proc *rp;
- 14785 int proc_nr; /* which process wants the alarm */
- 14786 long delta_ticks; /* in how many clock ticks does he want it? */
- 14787
- 14788 /* Extract the parameters from the message. */
- 14789 proc_nr = m_ptr->CLOCK_PROC_NR; /* process to interrupt later */
- 14790 delta_ticks = m_ptr->DELTA_TICKS; /* how many ticks to wait */
- 14791 rp = proc_addr(proc_nr);
- 14792 mc.SECONDS_LEFT = (rp->p_alarm == 0 ? 0 : (rp->p_alarm - realtime)/HZ );
- 14793 common_setalarm(proc_nr, delta_ticks, cause_alarm);
- 14794 }
- 14797 /*===========================================================================*
- 14798 * common_setalarm *
- 14799 *===========================================================================*/
- 14800 PRIVATE void common_setalarm(proc_nr, delta_ticks, function)
- 14801 int proc_nr; /* which process wants the alarm */
- 14802 long delta_ticks; /* in how many clock ticks does he want it? */
- 14803 watchdog_t function; /* function to call (0 if cause_sig is
- 14804 * to be called */
- 14805 {
- 14806 /* Finish up work of do_set_alarm and do_setsyn_alrm. Record an alarm
- 14807 * request and check to see if it is the next alarm needed.
- 14808 */
- 14809
- 14810 register struct proc *rp;
- 14811
- 14812 rp = proc_addr(proc_nr);
- 14813 rp->p_alarm = (delta_ticks == 0 ? 0 : realtime + delta_ticks);
- 14814 watch_dog[proc_nr+NR_TASKS] = function;
- 14815
- 14816 /* Which alarm is next? */
- 14817 next_alarm = LONG_MAX;
- 14818 for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++)
- 14819 if(rp->p_alarm != 0 && rp->p_alarm < next_alarm)next_alarm=rp->p_alarm;
- 14820
- 14821 }
- 14824 /*===========================================================================*
- 14825 * cause_alarm *
- 14826 *===========================================================================*/
- 14827 PRIVATE void cause_alarm()
- 14828 {
- 14829 /* Routine called if a timer goes off and the process requested a synchronous
- 14830 * alarm. The process number is in the global variable watchdog_proc (HACK).
- 14831 */
- 14832 message mess;
- 14833
- 14834 syn_table[watchdog_proc + NR_TASKS]= TRUE;
- 14835 if (!syn_al_alive) send (SYN_ALRM_TASK, &mess);
- 14836 }
- 14839 /*===========================================================================*
- 14840 * syn_alrm_task *
- 14841 *===========================================================================*/
- 14842 PUBLIC void syn_alrm_task()
- 14843 {
- 14844 /* Main program of the synchronous alarm task.
- 14845 * This task receives messages only from cause_alarm in the clock task.
- 14846 * It sends a CLOCK_INT message to a process that requested a syn_alrm.
- 14847 * Synchronous alarms are so called because, unlike a signals or the
- 14848 * activation of a watchdog, a synchronous alarm is received by a process
- 14849 * when it is in a known part of its code, that is, when it has issued
- 14850 * a call to receive a message.
- 14851 */
- 14852
- 14853 message mess;
- 14854 int work_done; /* ready to sleep ? */
- 14855 int *al_ptr; /* pointer in syn_table */
- 14856 int i;
- 14857
- 14858 syn_al_alive= TRUE;
- 14859 for (i= 0, al_ptr= syn_table; i<NR_TASKS+NR_PROCS; i++, al_ptr++)
- 14860 *al_ptr= FALSE;
- 14861
- 14862 while (TRUE) {
- 14863 work_done= TRUE;
- 14864 for (i= 0, al_ptr= syn_table; i<NR_TASKS+NR_PROCS; i++, al_ptr++)
- 14865 if (*al_ptr) {
- 14866 *al_ptr= FALSE;
- 14867 mess.m_type= CLOCK_INT;
- 14868 send (i-NR_TASKS, &mess);
- 14869 work_done= FALSE;
- 14870 }
- 14871 if (work_done) {
- 14872 syn_al_alive= FALSE;
- 14873 receive (CLOCK, &mess);
- 14874 syn_al_alive= TRUE;
- 14875 }
- 14876 }
- 14877 }
- 14880 /*===========================================================================*
- 14881 * clock_handler *
- 14882 *===========================================================================*/
- 14883 PRIVATE int clock_handler(irq)
- 14884 int irq;
- 14885 {
- 14886 /* This executes on every clock tick (i.e., every time the timer chip
- 14887 * generates an interrupt). It does a little bit of work so the clock
- 14888 * task does not have to be called on every tick.
- 14889 *
- 14890 * Switch context to do_clocktick if an alarm has gone off.
- 14891 * Also switch there to reschedule if the reschedule will do something.
- 14892 * This happens when
- 14893 * (1) quantum has expired
- 14894 * (2) current process received full quantum (as clock sampled it!)
- 14895 * (3) something else is ready to run.
- 14896 * Also call TTY and PRINTER and let them do whatever is necessary.
- 14897 *
- 14898 * Many global global and static variables are accessed here. The safety
- 14899 * of this must be justified. Most of them are not changed here:
- 14900 * k_reenter:
- 14901 * This safely tells if the clock interrupt is nested.
- 14902 * proc_ptr, bill_ptr:
- 14903 * These are used for accounting. It does not matter if proc.c
- 14904 * is changing them, provided they are always valid pointers,
- 14905 * since at worst the previous process would be billed.
- 14906 * next_alarm, realtime, sched_ticks, bill_ptr, prev_ptr,
- 14907 * rdy_head[USER_Q]:
- 14908 * These are tested to decide whether to call interrupt(). It
- 14909 * does not matter if the test is sometimes (rarely) backwards
- 14910 * due to a race, since this will only delay the high-level
- 14911 * processing by one tick, or call the high level unnecessarily.
- 14912 * The variables which are changed require more care:
- 14913 * rp->user_time, rp->sys_time:
- 14914 * These are protected by explicit locks in system.c. They are
- 14915 * not properly protected in dmp.c (the increment here is not
- 14916 * atomic) but that hardly matters.
- 14917 * pending_ticks:
- 14918 * This is protected by explicit locks in clock.c. Don't
- 14919 * update realtime directly, since there are too many
- 14920 * references to it to guard conveniently.
- 14921 * lost_ticks:
- 14922 * Clock ticks counted outside the clock task.
- 14923 * sched_ticks, prev_ptr:
- 14924 * Updating these competes with similar code in do_clocktick().
- 14925 * No lock is necessary, because if bad things happen here
- 14926 * (like sched_ticks going negative), the code in do_clocktick()
- 14927 * will restore the variables to reasonable values, and an
- 14928 * occasional missed or extra sched() is harmless.
- 14929 *
- 14930 * Are these complications worth the trouble? Well, they make the system 15%
- 14931 * faster on a 5MHz 8088, and make task debugging much easier since there are
- 14932 * no task switches on an inactive system.
- 14933 */
- 14934
- 14935 register struct proc *rp;
- 14936 register unsigned ticks;
- 14937 clock_t now;
- 14938
- 14939 if (ps_mca) {
- 14940 /* Acknowledge the PS/2 clock interrupt. */
- 14941 out_byte(PORT_B, in_byte(PORT_B) | CLOCK_ACK_BIT);
- 14942 }
- 14943
- 14944 /* Update user and system accounting times.
- 14945 * First charge the current process for user time.
- 14946 * If the current process is not the billable process (usually because it
- 14947 * is a task), charge the billable process for system time as well.
- 14948 * Thus the unbillable tasks' user time is the billable users' system time.
- 14949 */
- 14950 if (k_reenter != 0)
- 14951 rp = proc_addr(HARDWARE);
- 14952 else
- 14953 rp = proc_ptr;
- 14954 ticks = lost_ticks + 1;
- 14955 lost_ticks = 0;
- 14956 rp->user_time += ticks;
- 14957 if (rp != bill_ptr && rp != proc_addr(IDLE)) bill_ptr->sys_time += ticks;
- 14958
- 14959 pending_ticks += ticks;
- 14960 now = realtime + pending_ticks;
- 14961 if (tty_timeout <= now) tty_wakeup(now); /* possibly wake up TTY */
- 14962 #if (CHIP != M68000)
- 14963 pr_restart(); /* possibly restart printer */
- 14964 #endif
- 14965 #if (CHIP == M68000)
- 14966 kb_timer(); /* keyboard repeat */
- 14967 if (sched_ticks == 1) fd_timer(); /* floppy deselect */
- 14968 #endif
- 14969
- 14970 if (next_alarm <= now ||
- 14971 sched_ticks == 1 &&
- 14972 bill_ptr == prev_ptr &&
- 14973 #if (SHADOWING == 0)
- 14974 rdy_head[USER_Q] != NIL_PROC) {
- 14975 #else
- 14976 (rdy_head[USER_Q] != NIL_PROC || rdy_head[SHADOW_Q] != NIL_PROC)) {
- 14977 #endif
- 14978 interrupt(CLOCK);
- 14979 return 1; /* Reenable interrupts */
- 14980 }
- 14981
- 14982 if (--sched_ticks == 0) {
- 14983 /* If bill_ptr == prev_ptr, no ready users so don't need sched(). */
- 14984 sched_ticks = SCHED_RATE; /* reset quantum */
- 14985 prev_ptr = bill_ptr; /* new previous process */
- 14986 }
- 14987 return 1; /* Reenable clock interrupt */
- 14988 }
- 14990 #if (CHIP == INTEL)
- 14991
- 14992 /*===========================================================================*
- 14993 * init_clock *
- 14994 *===========================================================================*/
- 14995 PRIVATE void init_clock()
- 14996 {
- 14997 /* Initialize channel 0 of the 8253A timer to e.g. 60 Hz. */
- 14998
- 14999 out_byte(TIMER_MODE, SQUARE_WAVE); /* set timer to run continuously */
- 15000 out_byte(TIMER0, TIMER_COUNT); /* load timer low byte */
- 15001 out_byte(TIMER0, TIMER_COUNT >> 8); /* load timer high byte */
- 15002 put_irq_handler(CLOCK_IRQ, clock_handler); /* set the interrupt handler */
- 15003 enable_irq(CLOCK_IRQ); /* ready for clock interrupts */
- 15004 }
- 15007 /*===========================================================================*
- 15008 * clock_stop *
- 15009 *===========================================================================*/
- 15010 PUBLIC void clock_stop()
- 15011 {
- 15012 /* Reset the clock to the BIOS rate. (For rebooting) */
- 15013
- 15014 out_byte(TIMER_MODE, 0x36);
- 15015 out_byte(TIMER0, 0);
- 15016 out_byte(TIMER0, 0);
- 15017 }
- 15020 /*==========================================================================*
- 15021 * milli_delay *
- 15022 *==========================================================================*/
- 15023 PUBLIC void milli_delay(millisec)
- 15024 unsigned millisec;
- 15025 {
- 15026 /* Delay some milliseconds. */
- 15027
- 15028 struct milli_state ms;
- 15029
- 15030 milli_start(&ms);
- 15031 while (milli_elapsed(&ms) < millisec) {}
- 15032 }
- 15034 /*==========================================================================*
- 15035 * milli_start *
- 15036 *==========================================================================*/
- 15037 PUBLIC void milli_start(msp)
- 15038 struct milli_state *msp;
- 15039 {
- 15040 /* Prepare for calls to milli_elapsed(). */
- 15041
- 15042 msp->prev_count = 0;
- 15043 msp->accum_count = 0;
- 15044 }
- 15047 /*==========================================================================*
- 15048 * milli_elapsed *
- 15049 *==========================================================================*/
- 15050 PUBLIC unsigned milli_elapsed(msp)
- 15051 struct milli_state *msp;
- 15052 {
- 15053 /* Return the number of milliseconds since the call to milli_start(). Must be
- 15054 * polled rapidly.
- 15055 */
- 15056 unsigned count;
- 15057
- 15058 /* Read the counter for channel 0 of the 8253A timer. The counter
- 15059 * decrements at twice the timer frequency (one full cycle for each
- 15060 * half of square wave). The counter normally has a value between 0
- 15061 * and TIMER_COUNT, but before the clock task has been initialized,
- 15062 * its maximum value is 65535, as set by the BIOS.
- 15063 */
- 15064 out_byte(TIMER_MODE, LATCH_COUNT); /* make chip copy count to latch */
- 15065 count = in_byte(TIMER0); /* countdown continues during 2-step read */
- 15066 count |= in_byte(TIMER0) << 8;
- 15067
- 15068 /* Add difference between previous and new count unless the counter has
- 15069 * increased (restarted its cycle). We may lose a tick now and then, but
- 15070 * microsecond precision is not needed.
- 15071 */
- 15072 msp->accum_count += count <= msp->prev_count ? (msp->prev_count - count) : 1;
- 15073 msp->prev_count = count;
- 15074
- 15075 return msp->accum_count / (TIMER_FREQ / 1000);
- 15076 }
- 15077 #endif /* (CHIP == INTEL) */
- 15078
- 15079
- 15080 #if (CHIP == M68000)
- 15081 #include "staddr.h"
- 15082 #include "stmfp.h"
- 15083
- 15084 /*===========================================================================*
- 15085 * init_clock *
- 15086 *===========================================================================*/
- 15087 PRIVATE void init_clock()
- 15088 {
- 15089 /* Initialize the timer C in the MFP 68901.
- 15090 * Reducing to HZ is not possible by hardware. The resulting interrupt
- 15091 * rate is further reduced by software with a factor of 4.
- 15092 * Note that the expression below works for both HZ=50 and HZ=60.
- 15093 */
- 15094 do {
- 15095 MFP->mf_tcdr = TIMER_FREQ/(64*4*HZ);
- 15096 } while ((MFP->mf_tcdr & 0xFF) != TIMER_FREQ/(64*4*HZ));
- 15097 MFP->mf_tcdcr |= (T_Q064<<4);
- 15098 }
- 15099 #endif /* (CHIP == M68000) */
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/console.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 15100 /* Code and data for the IBM console driver.
- 15101 *
- 15102 * The 6845 video controller used by the IBM PC shares its video memory with
- 15103 * the CPU somewhere in the 0xB0000 memory bank. To the 6845 this memory
- 15104 * consists of 16-bit words. Each word has a character code in the low byte
- 15105 * and a so-called attribute byte in the high byte. The CPU directly modifies
- 15106 * video memory to display characters, and sets two registers on the 6845 that
- 15107 * specify the video origin and the cursor position. The video origin is the
- 15108 * place in video memory where the first character (upper left corner) can
- 15109 * be found. Moving the origin is a fast way to scroll the screen. Some
- 15110 * video adapters wrap around the top of video memory, so the origin can
- 15111 * move without bounds. For other adapters screen memory must sometimes be
- 15112 * moved to reset the origin. All computations on video memory use character
- 15113 * (word) addresses for simplicity and assume there is no wrapping. The
- 15114 * assembly support functions translate the word addresses to byte addresses
- 15115 * and the scrolling function worries about wrapping.
- 15116 */
- 15117
- 15118 #include "kernel.h"
- 15119 #include <termios.h>
- 15120 #include <minix/callnr.h>
- 15121 #include <minix/com.h>
- 15122 #include "protect.h"
- 15123 #include "tty.h"
- 15124 #include "proc.h"
- 15125
- 15126 /* Definitions used by the console driver. */
- 15127 #define MONO_BASE 0xB0000L /* base of mono video memory */
- 15128 #define COLOR_BASE 0xB8000L /* base of color video memory */
- 15129 #define MONO_SIZE 0x1000 /* 4K mono video memory */
- 15130 #define COLOR_SIZE 0x4000 /* 16K color video memory */
- 15131 #define EGA_SIZE 0x8000 /* EGA & VGA have at least 32K */
- 15132 #define BLANK_COLOR 0x0700 /* determines cursor color on blank screen */
- 15133 #define SCROLL_UP 0 /* scroll forward */
- 15134 #define SCROLL_DOWN 1 /* scroll backward */
- 15135 #define BLANK_MEM ((u16_t *) 0) /* tells mem_vid_copy() to blank the screen */
- 15136 #define CONS_RAM_WORDS 80 /* video ram buffer size */
- 15137 #define MAX_ESC_PARMS 2 /* number of escape sequence params allowed */
- 15138
- 15139 /* Constants relating to the controller chips. */
- 15140 #define M_6845 0x3B4 /* port for 6845 mono */
- 15141 #define C_6845 0x3D4 /* port for 6845 color */
- 15142 #define EGA 0x3C4 /* port for EGA card */
- 15143 #define INDEX 0 /* 6845's index register */
- 15144 #define DATA 1 /* 6845's data register */
- 15145 #define VID_ORG 12 /* 6845's origin register */
- 15146 #define CURSOR 14 /* 6845's cursor register */
- 15147
- 15148 /* Beeper. */
- 15149 #define BEEP_FREQ 0x0533 /* value to put into timer to set beep freq */
- 15150 #define B_TIME 3 /* length of CTRL-G beep is ticks */
- 15151
- 15152 /* definitions used for font management */
- 15153 #define GA_SEQUENCER_INDEX 0x3C4
- 15154 #define GA_SEQUENCER_DATA 0x3C5
- 15155 #define GA_GRAPHICS_INDEX 0x3CE
- 15156 #define GA_GRAPHICS_DATA 0x3CF
- 15157 #define GA_VIDEO_ADDRESS 0xA0000L
- 15158 #define GA_FONT_SIZE 8192
- 15159
- 15160 /* Global variables used by the console driver. */
- 15161 PUBLIC unsigned vid_seg; /* video ram selector (0xB0000 or 0xB8000) */
- 15162 PUBLIC unsigned vid_size; /* 0x2000 for color or 0x0800 for mono */
- 15163 PUBLIC unsigned vid_mask; /* 0x1FFF for color or 0x07FF for mono */
- 15164 PUBLIC unsigned blank_color = BLANK_COLOR; /* display code for blank */
- 15165
- 15166 /* Private variables used by the console driver. */
- 15167 PRIVATE int vid_port; /* I/O port for accessing 6845 */
- 15168 PRIVATE int wrap; /* hardware can wrap? */
- 15169 PRIVATE int softscroll; /* 1 = software scrolling, 0 = hardware */
- 15170 PRIVATE unsigned vid_base; /* base of video ram (0xB000 or 0xB800) */
- 15171 PRIVATE int beeping; /* speaker is beeping? */
- 15172 #define scr_width 80 /* # characters on a line */
- 15173 #define scr_lines 25 /* # lines on the screen */
- 15174 #define scr_size (80*25) /* # characters on the screen */
- 15175
- 15176 /* Per console data. */
- 15177 typedef struct console {
- 15178 tty_t *c_tty; /* associated TTY struct */
- 15179 int c_column; /* current column number (0-origin) */
- 15180 int c_row; /* current row (0 at top of screen) */
- 15181 int c_rwords; /* number of WORDS (not bytes) in outqueue */
- 15182 unsigned c_start; /* start of video memory of this console */
- 15183 unsigned c_limit; /* limit of this console's video memory */
- 15184 unsigned c_org; /* location in RAM where 6845 base points */
- 15185 unsigned c_cur; /* current position of cursor in video RAM */
- 15186 unsigned c_attr; /* character attribute */
- 15187 unsigned c_blank; /* blank attribute */
- 15188 char c_esc_state; /* 0=normal, 1=ESC, 2=ESC[ */
- 15189 char c_esc_intro; /* Distinguishing character following ESC */
- 15190 int *c_esc_parmp; /* pointer to current escape parameter */
- 15191 int c_esc_parmv[MAX_ESC_PARMS]; /* list of escape parameters */
- 15192 u16_t c_ramqueue[CONS_RAM_WORDS]; /* buffer for video RAM */
- 15193 } console_t;
- 15194
- 15195 PRIVATE int nr_cons= 1; /* actual number of consoles */
- 15196 PRIVATE console_t cons_table[NR_CONS];
- 15197 PRIVATE console_t *curcons; /* currently visible */
- 15198
- 15199 /* Color if using a color controller. */
- 15200 #define color (vid_port == C_6845)
- 15201
- 15202 /* Map from ANSI colors to the attributes used by the PC */
- 15203 PRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7};
- 15204
- 15205 /* Structure used for font management */
- 15206 struct sequence {
- 15207 unsigned short index;
- 15208 unsigned char port;
- 15209 unsigned char value;
- 15210 };
- 15211
- 15212 FORWARD _PROTOTYPE( void cons_write, (struct tty *tp) );
- 15213 FORWARD _PROTOTYPE( void cons_echo, (tty_t *tp, int c) );
- 15214 FORWARD _PROTOTYPE( void out_char, (console_t *cons, int c) );
- 15215 FORWARD _PROTOTYPE( void beep, (void) );
- 15216 FORWARD _PROTOTYPE( void do_escape, (console_t *cons, int c) );
- 15217 FORWARD _PROTOTYPE( void flush, (console_t *cons) );
- 15218 FORWARD _PROTOTYPE( void parse_escape, (console_t *cons, int c) );
- 15219 FORWARD _PROTOTYPE( void scroll_screen, (console_t *cons, int dir) );
- 15220 FORWARD _PROTOTYPE( void set_6845, (int reg, unsigned val) );
- 15221 FORWARD _PROTOTYPE( void stop_beep, (void) );
- 15222 FORWARD _PROTOTYPE( void cons_org0, (void) );
- 15223 FORWARD _PROTOTYPE( void ga_program, (struct sequence *seq) );
- 15224
- 15225
- 15226 /*===========================================================================*
- 15227 * cons_write *
- 15228 *===========================================================================*/
- 15229 PRIVATE void cons_write(tp)
- 15230 register struct tty *tp; /* tells which terminal is to be used */
- 15231 {
- 15232 /* Copy as much data as possible to the output queue, then start I/O. On
- 15233 * memory-mapped terminals, such as the IBM console, the I/O will also be
- 15234 * finished, and the counts updated. Keep repeating until all I/O done.
- 15235 */
- 15236
- 15237 int count;
- 15238 register char *tbuf;
- 15239 char buf[64];
- 15240 phys_bytes user_phys;
- 15241 console_t *cons = tp->tty_priv;
- 15242
- 15243 /* Check quickly for nothing to do, so this can be called often without
- 15244 * unmodular tests elsewhere.
- 15245 */
- 15246 if ((count = tp->tty_outleft) == 0 || tp->tty_inhibited) return;
- 15247
- 15248 /* Copy the user bytes to buf[] for decent addressing. Loop over the
- 15249 * copies, since the user buffer may be much larger than buf[].
- 15250 */
- 15251 do {
- 15252 if (count > sizeof(buf)) count = sizeof(buf);
- 15253 user_phys = proc_vir2phys(proc_addr(tp->tty_outproc), tp->tty_out_vir);
- 15254 phys_copy(user_phys, vir2phys(buf), (phys_bytes) count);
- 15255 tbuf = buf;
- 15256
- 15257 /* Update terminal data structure. */
- 15258 tp->tty_out_vir += count;
- 15259 tp->tty_outcum += count;
- 15260 tp->tty_outleft -= count;
- 15261
- 15262 /* Output each byte of the copy to the screen. Avoid calling
- 15263 * out_char() for the "easy" characters, put them into the buffer
- 15264 * directly.
- 15265 */
- 15266 do {
- 15267 if ((unsigned) *tbuf < ' ' || cons->c_esc_state > 0
- 15268 || cons->c_column >= scr_width
- 15269 || cons->c_rwords >= buflen(cons->c_ramqueue))
- 15270 {
- 15271 out_char(cons, *tbuf++);
- 15272 } else {
- 15273 cons->c_ramqueue[cons->c_rwords++] =
- 15274 cons->c_attr | (*tbuf++ & BYTE);
- 15275 cons->c_column++;
- 15276 }
- 15277 } while (--count != 0);
- 15278 } while ((count = tp->tty_outleft) != 0 && !tp->tty_inhibited);
- 15279
- 15280 flush(cons); /* transfer anything buffered to the screen */
- 15281
- 15282 /* Reply to the writer if all output is finished. */
- 15283 if (tp->tty_outleft == 0) {
- 15284 tty_reply(tp->tty_outrepcode, tp->tty_outcaller, tp->tty_outproc,
- 15285 tp->tty_outcum);
- 15286 tp->tty_outcum = 0;
- 15287 }
- 15288 }
- 15291 /*===========================================================================*
- 15292 * cons_echo *
- 15293 *===========================================================================*/
- 15294 PRIVATE void cons_echo(tp, c)
- 15295 register tty_t *tp; /* pointer to tty struct */
- 15296 int c; /* character to be echoed */
- 15297 {
- 15298 /* Echo keyboard input (print & flush). */
- 15299 console_t *cons = tp->tty_priv;
- 15300
- 15301 out_char(cons, c);
- 15302 flush(cons);
- 15303 }
- 15306 /*===========================================================================*
- 15307 * out_char *
- 15308 *===========================================================================*/
- 15309 PRIVATE void out_char(cons, c)
- 15310 register console_t *cons; /* pointer to console struct */
- 15311 int c; /* character to be output */
- 15312 {
- 15313 /* Output a character on the console. Check for escape sequences first. */
- 15314 if (cons->c_esc_state > 0) {
- 15315 parse_escape(cons, c);
- 15316 return;
- 15317 }
- 15318
- 15319 switch(c) {
- 15320 case 000: /* null is typically used for padding */
- 15321 return; /* better not do anything */
- 15322
- 15323 case 007: /* ring the bell */
- 15324 flush(cons); /* print any chars queued for output */
- 15325 beep();
- 15326 return;
- 15327
- 15328 case 'b': /* backspace */
- 15329 if (--cons->c_column < 0) {
- 15330 if (--cons->c_row >= 0) cons->c_column += scr_width;
- 15331 }
- 15332 flush(cons);
- 15333 return;
- 15334
- 15335 case 'n': /* line feed */
- 15336 if ((cons->c_tty->tty_termios.c_oflag & (OPOST|ONLCR))
- 15337 == (OPOST|ONLCR)) {
- 15338 cons->c_column = 0;
- 15339 }
- 15340 /*FALL THROUGH*/
- 15341 case 013: /* CTRL-K */
- 15342 case 014: /* CTRL-L */
- 15343 if (cons->c_row == scr_lines-1) {
- 15344 scroll_screen(cons, SCROLL_UP);
- 15345 } else {
- 15346 cons->c_row++;
- 15347 }
- 15348 flush(cons);
- 15349 return;
- 15350
- 15351 case 'r': /* carriage return */
- 15352 cons->c_column = 0;
- 15353 flush(cons);
- 15354 return;
- 15355
- 15356 case 't': /* tab */
- 15357 cons->c_column = (cons->c_column + TAB_SIZE) & ~TAB_MASK;
- 15358 if (cons->c_column > scr_width) {
- 15359 cons->c_column -= scr_width;
- 15360 if (cons->c_row == scr_lines-1) {
- 15361 scroll_screen(cons, SCROLL_UP);
- 15362 } else {
- 15363 cons->c_row++;
- 15364 }
- 15365 }
- 15366 flush(cons);
- 15367 return;
- 15368
- 15369 case 033: /* ESC - start of an escape sequence */
- 15370 flush(cons); /* print any chars queued for output */
- 15371 cons->c_esc_state = 1; /* mark ESC as seen */
- 15372 return;
- 15373
- 15374 default: /* printable chars are stored in ramqueue */
- 15375 if (cons->c_column >= scr_width) {
- 15376 if (!LINEWRAP) return;
- 15377 if (cons->c_row == scr_lines-1) {
- 15378 scroll_screen(cons, SCROLL_UP);
- 15379 } else {
- 15380 cons->c_row++;
- 15381 }
- 15382 cons->c_column = 0;
- 15383 flush(cons);
- 15384 }
- 15385 if (cons->c_rwords == buflen(cons->c_ramqueue)) flush(cons);
- 15386 cons->c_ramqueue[cons->c_rwords++] = cons->c_attr | (c & BYTE);
- 15387 cons->c_column++; /* next column */
- 15388 return;
- 15389 }
- 15390 }
- 15393 /*===========================================================================*
- 15394 * scroll_screen *
- 15395 *===========================================================================*/
- 15396 PRIVATE void scroll_screen(cons, dir)
- 15397 register console_t *cons; /* pointer to console struct */
- 15398 int dir; /* SCROLL_UP or SCROLL_DOWN */
- 15399 {
- 15400 unsigned new_line, new_org, chars;
- 15401
- 15402 flush(cons);
- 15403 chars = scr_size - scr_width; /* one screen minus one line */
- 15404
- 15405 /* Scrolling the screen is a real nuisance due to the various incompatible
- 15406 * video cards. This driver supports software scrolling (Hercules?),
- 15407 * hardware scrolling (mono and CGA cards) and hardware scrolling without
- 15408 * wrapping (EGA cards). In the latter case we must make sure that
- 15409 * c_start <= c_org && c_org + scr_size <= c_limit
- 15410 * holds, because EGA doesn't wrap around the end of video memory.
- 15411 */
- 15412 if (dir == SCROLL_UP) {
- 15413 /* Scroll one line up in 3 ways: soft, avoid wrap, use origin. */
- 15414 if (softscroll) {
- 15415 vid_vid_copy(cons->c_start + scr_width, cons->c_start, chars);
- 15416 } else
- 15417 if (!wrap && cons->c_org + scr_size + scr_width >= cons->c_limit) {
- 15418 vid_vid_copy(cons->c_org + scr_width, cons->c_start, chars);
- 15419 cons->c_org = cons->c_start;
- 15420 } else {
- 15421 cons->c_org = (cons->c_org + scr_width) & vid_mask;
- 15422 }
- 15423 new_line = (cons->c_org + chars) & vid_mask;
- 15424 } else {
- 15425 /* Scroll one line down in 3 ways: soft, avoid wrap, use origin. */
- 15426 if (softscroll) {
- 15427 vid_vid_copy(cons->c_start, cons->c_start + scr_width, chars);
- 15428 } else
- 15429 if (!wrap && cons->c_org < cons->c_start + scr_width) {
- 15430 new_org = cons->c_limit - scr_size;
- 15431 vid_vid_copy(cons->c_org, new_org + scr_width, chars);
- 15432 cons->c_org = new_org;
- 15433 } else {
- 15434 cons->c_org = (cons->c_org - scr_width) & vid_mask;
- 15435 }
- 15436 new_line = cons->c_org;
- 15437 }
- 15438 /* Blank the new line at top or bottom. */
- 15439 blank_color = cons->c_blank;
- 15440 mem_vid_copy(BLANK_MEM, new_line, scr_width);
- 15441
- 15442 /* Set the new video origin. */
- 15443 if (cons == curcons) set_6845(VID_ORG, cons->c_org);
- 15444 flush(cons);
- 15445 }
- 15448 /*===========================================================================*
- 15449 * flush *
- 15450 *===========================================================================*/
- 15451 PRIVATE void flush(cons)
- 15452 register console_t *cons; /* pointer to console struct */
- 15453 {
- 15454 /* Send characters buffered in 'ramqueue' to screen memory, check the new
- 15455 * cursor position, compute the new hardware cursor position and set it.
- 15456 */
- 15457 unsigned cur;
- 15458 tty_t *tp = cons->c_tty;
- 15459
- 15460 /* Have the characters in 'ramqueue' transferred to the screen. */
- 15461 if (cons->c_rwords > 0) {
- 15462 mem_vid_copy(cons->c_ramqueue, cons->c_cur, cons->c_rwords);
- 15463 cons->c_rwords = 0;
- 15464
- 15465 /* TTY likes to know the current column and if echoing messed up. */
- 15466 tp->tty_position = cons->c_column;
- 15467 tp->tty_reprint = TRUE;
- 15468 }
- 15469
- 15470 /* Check and update the cursor position. */
- 15471 if (cons->c_column < 0) cons->c_column = 0;
- 15472 if (cons->c_column > scr_width) cons->c_column = scr_width;
- 15473 if (cons->c_row < 0) cons->c_row = 0;
- 15474 if (cons->c_row >= scr_lines) cons->c_row = scr_lines - 1;
- 15475 cur = cons->c_org + cons->c_row * scr_width + cons->c_column;
- 15476 if (cur != cons->c_cur) {
- 15477 if (cons == curcons) set_6845(CURSOR, cur);
- 15478 cons->c_cur = cur;
- 15479 }
- 15480 }
- 15483 /*===========================================================================*
- 15484 * parse_escape *
- 15485 *===========================================================================*/
- 15486 PRIVATE void parse_escape(cons, c)
- 15487 register console_t *cons; /* pointer to console struct */
- 15488 char c; /* next character in escape sequence */
- 15489 {
- 15490 /* The following ANSI escape sequences are currently supported.
- 15491 * If n and/or m are omitted, they default to 1.
- 15492 * ESC [nA moves up n lines
- 15493 * ESC [nB moves down n lines
- 15494 * ESC [nC moves right n spaces
- 15495 * ESC [nD moves left n spaces
- 15496 * ESC [m;nH" moves cursor to (m,n)
- 15497 * ESC [J clears screen from cursor
- 15498 * ESC [K clears line from cursor
- 15499 * ESC [nL inserts n lines ar cursor
- 15500 * ESC [nM deletes n lines at cursor
- 15501 * ESC [nP deletes n chars at cursor
- 15502 * ESC [n@ inserts n chars at cursor
- 15503 * ESC [nm enables rendition n (0=normal, 4=bold, 5=blinking, 7=reverse)
- 15504 * ESC M scrolls the screen backwards if the cursor is on the top line
- 15505 */
- 15506
- 15507 switch (cons->c_esc_state) {
- 15508 case 1: /* ESC seen */
- 15509 cons->c_esc_intro = ' ';
- 15510 cons->c_esc_parmp = cons->c_esc_parmv;
- 15511 cons->c_esc_parmv[0] = cons->c_esc_parmv[1] = 0;
- 15512 switch (c) {
- 15513 case '[': /* Control Sequence Introducer */
- 15514 cons->c_esc_intro = c;
- 15515 cons->c_esc_state = 2;
- 15516 break;
- 15517 case 'M': /* Reverse Index */
- 15518 do_escape(cons, c);
- 15519 break;
- 15520 default:
- 15521 cons->c_esc_state = 0;
- 15522 }
- 15523 break;
- 15524
- 15525 case 2: /* ESC [ seen */
- 15526 if (c >= '0' && c <= '9') {
- 15527 if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
- 15528 *cons->c_esc_parmp = *cons->c_esc_parmp * 10 + (c-'0');
- 15529 } else
- 15530 if (c == ';') {
- 15531 if (++cons->c_esc_parmp < bufend(cons->c_esc_parmv))
- 15532 *cons->c_esc_parmp = 0;
- 15533 } else {
- 15534 do_escape(cons, c);
- 15535 }
- 15536 break;
- 15537 }
- 15538 }
- 15541 /*===========================================================================*
- 15542 * do_escape *
- 15543 *===========================================================================*/
- 15544 PRIVATE void do_escape(cons, c)
- 15545 register console_t *cons; /* pointer to console struct */
- 15546 char c; /* next character in escape sequence */
- 15547 {
- 15548 int value, n;
- 15549 unsigned src, dst, count;
- 15550
- 15551 /* Some of these things hack on screen RAM, so it had better be up to date */
- 15552 flush(cons);
- 15553
- 15554 if (cons->c_esc_intro == ' ') {
- 15555 /* Handle a sequence beginning with just ESC */
- 15556 switch (c) {
- 15557 case 'M': /* Reverse Index */
- 15558 if (cons->c_row == 0) {
- 15559 scroll_screen(cons, SCROLL_DOWN);
- 15560 } else {
- 15561 cons->c_row--;
- 15562 }
- 15563 flush(cons);
- 15564 break;
- 15565
- 15566 default: break;
- 15567 }
- 15568 } else
- 15569 if (cons->c_esc_intro == '[') {
- 15570 /* Handle a sequence beginning with ESC [ and parameters */
- 15571 value = cons->c_esc_parmv[0];
- 15572 switch (c) {
- 15573 case 'A': /* ESC [nA moves up n lines */
- 15574 n = (value == 0 ? 1 : value);
- 15575 cons->c_row -= n;
- 15576 flush(cons);
- 15577 break;
- 15578
- 15579 case 'B': /* ESC [nB moves down n lines */
- 15580 n = (value == 0 ? 1 : value);
- 15581 cons->c_row += n;
- 15582 flush(cons);
- 15583 break;
- 15584
- 15585 case 'C': /* ESC [nC moves right n spaces */
- 15586 n = (value == 0 ? 1 : value);
- 15587 cons->c_column += n;
- 15588 flush(cons);
- 15589 break;
- 15590
- 15591 case 'D': /* ESC [nD moves left n spaces */
- 15592 n = (value == 0 ? 1 : value);
- 15593 cons->c_column -= n;
- 15594 flush(cons);
- 15595 break;
- 15596
- 15597 case 'H': /* ESC [m;nH" moves cursor to (m,n) */
- 15598 cons->c_row = cons->c_esc_parmv[0] - 1;
- 15599 cons->c_column = cons->c_esc_parmv[1] - 1;
- 15600 flush(cons);
- 15601 break;
- 15602
- 15603 case 'J': /* ESC [sJ clears in display */
- 15604 switch (value) {
- 15605 case 0: /* Clear from cursor to end of screen */
- 15606 count = scr_size - (cons->c_cur - cons->c_org);
- 15607 dst = cons->c_cur;
- 15608 break;
- 15609 case 1: /* Clear from start of screen to cursor */
- 15610 count = cons->c_cur - cons->c_org;
- 15611 dst = cons->c_org;
- 15612 break;
- 15613 case 2: /* Clear entire screen */
- 15614 count = scr_size;
- 15615 dst = cons->c_org;
- 15616 break;
- 15617 default: /* Do nothing */
- 15618 count = 0;
- 15619 dst = cons->c_org;
- 15620 }
- 15621 blank_color = cons->c_blank;
- 15622 mem_vid_copy(BLANK_MEM, dst, count);
- 15623 break;
- 15624
- 15625 case 'K': /* ESC [sK clears line from cursor */
- 15626 switch (value) {
- 15627 case 0: /* Clear from cursor to end of line */
- 15628 count = scr_width - cons->c_column;
- 15629 dst = cons->c_cur;
- 15630 break;
- 15631 case 1: /* Clear from beginning of line to cursor */
- 15632 count = cons->c_column;
- 15633 dst = cons->c_cur - cons->c_column;
- 15634 break;
- 15635 case 2: /* Clear entire line */
- 15636 count = scr_width;
- 15637 dst = cons->c_cur - cons->c_column;
- 15638 break;
- 15639 default: /* Do nothing */
- 15640 count = 0;
- 15641 dst = cons->c_cur;
- 15642 }
- 15643 blank_color = cons->c_blank;
- 15644 mem_vid_copy(BLANK_MEM, dst, count);
- 15645 break;
- 15646
- 15647 case 'L': /* ESC [nL inserts n lines at cursor */
- 15648 n = value;
- 15649 if (n < 1) n = 1;
- 15650 if (n > (scr_lines - cons->c_row))
- 15651 n = scr_lines - cons->c_row;
- 15652
- 15653 src = cons->c_org + cons->c_row * scr_width;
- 15654 dst = src + n * scr_width;
- 15655 count = (scr_lines - cons->c_row - n) * scr_width;
- 15656 vid_vid_copy(src, dst, count);
- 15657 blank_color = cons->c_blank;
- 15658 mem_vid_copy(BLANK_MEM, src, n * scr_width);
- 15659 break;
- 15660
- 15661 case 'M': /* ESC [nM deletes n lines at cursor */
- 15662 n = value;
- 15663 if (n < 1) n = 1;
- 15664 if (n > (scr_lines - cons->c_row))
- 15665 n = scr_lines - cons->c_row;
- 15666
- 15667 dst = cons->c_org + cons->c_row * scr_width;
- 15668 src = dst + n * scr_width;
- 15669 count = (scr_lines - cons->c_row - n) * scr_width;
- 15670 vid_vid_copy(src, dst, count);
- 15671 blank_color = cons->c_blank;
- 15672 mem_vid_copy(BLANK_MEM, dst + count, n * scr_width);
- 15673 break;
- 15674
- 15675 case '@': /* ESC [n@ inserts n chars at cursor */
- 15676 n = value;
- 15677 if (n < 1) n = 1;
- 15678 if (n > (scr_width - cons->c_column))
- 15679 n = scr_width - cons->c_column;
- 15680
- 15681 src = cons->c_cur;
- 15682 dst = src + n;
- 15683 count = scr_width - cons->c_column - n;
- 15684 vid_vid_copy(src, dst, count);
- 15685 blank_color = cons->c_blank;
- 15686 mem_vid_copy(BLANK_MEM, src, n);
- 15687 break;
- 15688
- 15689 case 'P': /* ESC [nP deletes n chars at cursor */
- 15690 n = value;
- 15691 if (n < 1) n = 1;
- 15692 if (n > (scr_width - cons->c_column))
- 15693 n = scr_width - cons->c_column;
- 15694
- 15695 dst = cons->c_cur;
- 15696 src = dst + n;
- 15697 count = scr_width - cons->c_column - n;
- 15698 vid_vid_copy(src, dst, count);
- 15699 blank_color = cons->c_blank;
- 15700 mem_vid_copy(BLANK_MEM, dst + count, n);
- 15701 break;
- 15702
- 15703 case 'm': /* ESC [nm enables rendition n */
- 15704 switch (value) {
- 15705 case 1: /* BOLD */
- 15706 if (color) {
- 15707 /* Can't do bold, so use yellow */
- 15708 cons->c_attr = (cons->c_attr & 0xf0ff) | 0x0E00;
- 15709 } else {
- 15710 /* Set intensity bit */
- 15711 cons->c_attr |= 0x0800;
- 15712 }
- 15713 break;
- 15714
- 15715 case 4: /* UNDERLINE */
- 15716 if (color) {
- 15717 /* Use light green */
- 15718 cons->c_attr = (cons->c_attr & 0xf0ff) | 0x0A00;
- 15719 } else {
- 15720 cons->c_attr = (cons->c_attr & 0x8900);
- 15721 }
- 15722 break;
- 15723
- 15724 case 5: /* BLINKING */
- 15725 if (color) {
- 15726 /* Use magenta */
- 15727 cons->c_attr = (cons->c_attr & 0xf0ff) | 0x0500;
- 15728 } else {