COMPLETE.T
上传用户:jnzhq888
上传日期:2007-01-18
资源大小:51694k
文件大小:2535k
- 18751 message mess;
- 18752
- 18753 mess.DEVICE = device;
- 18754 mess.POSITION = offset << SECTOR_SHIFT;
- 18755 mess.COUNT = SECTOR_SIZE;
- 18756 mess.ADDRESS = (char *) tmp_buf;
- 18757 mess.PROC_NR = proc_number(proc_ptr);
- 18758 mess.m_type = DEV_READ;
- 18759
- 18760 if (do_rdwt(dp, &mess) != SECTOR_SIZE) {
- 18761 printf("%s: can't read partition tablen", (*dp->dr_name)());
- 18762 return 0;
- 18763 }
- 18764 if (tmp_buf[510] != 0x55 || tmp_buf[511] != 0xAA) {
- 18765 /* Invalid partition table. */
- 18766 return 0;
- 18767 }
- 18768 memcpy(table, (tmp_buf + PART_TABLE_OFF), NR_PARTITIONS * sizeof(table[0]));
- 18769 return 1;
- 18770 }
-
-
- 18773 /*===========================================================================*
- 18774 * sort *
- 18775 *===========================================================================*/
- 18776 PRIVATE void sort(table)
- 18777 struct part_entry *table;
- 18778 {
- 18779 /* Sort a partition table. */
- 18780 struct part_entry *pe, tmp;
- 18781 int n = NR_PARTITIONS;
- 18782
- 18783 do {
- 18784 for (pe = table; pe < table + NR_PARTITIONS-1; pe++) {
- 18785 if (pe[0].sysind == NO_PART
- 18786 || (pe[0].lowsec > pe[1].lowsec
- 18787 && pe[1].sysind != NO_PART)) {
- 18788 tmp = pe[0]; pe[0] = pe[1]; pe[1] = tmp;
- 18789 }
- 18790 }
- 18791 } while (--n > 0);
- 18792 }
- .Op 247 src/kernel/esdi_wini.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/esdi_wini.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 18800 /* device dependent part of a hard disk driver for ibm ps/2 esdi adapter
- 18801 *
- 18802 * written by doug burks, based on other minix wini drivers.
- 18803 * some additions by art roberts
- 18804 *
- 18805 * references:
- 18806 * ibm personal system/2 hardware technical reference (1988)
- 18807 * ibm 60/120mb fixed disk drive technical reference (1988)
- 18808 *
- 18809 * caveats:
- 18810 * * this driver has been reported to work on ibm ps/2 models 50 and
- 18811 * 70 with ibm's 60/120mb hard disks.
- 18812 * * for a true esdi adapter, changes will have to be made, but this
- 18813 * certainly serves as a good start.
- 18814 * * no timeouts are implemented, so this driver could hang under
- 18815 * adverse conditions.
- 18816 * * the error processing has not been tested. my disk works too well.
- 18817 *
- 18818 * The file contains one entry point:
- 18819 *
- 18820 * esdi_winchester_task: main entry when system is brought up
- 18821 *
- 18822 *
- 18823 * Changes:
- 18824 * 3 May 1992 by Kees J. Bot: device dependent/independent split.
- 18825 */
- 18826 #include "kernel.h"
- 18827 #include "driver.h"
- 18828 #include "drvlib.h"
- 18829
- 18830 #if ENABLE_ESDI_WINI
- 18831
- 18832 /* If the DMA buffer is large enough then use it always. */
- 18833 #define USE_BUF (DMA_BUF_SIZE > BLOCK_SIZE)
- 18834
- 18835
- 18836 /***** esdi i/o adapter ports */
- 18837
- 18838 #define CMD_REG 0x3510 /* command interface register */
- 18839 #define STAT_REG 0x3510 /* status interface register */
- 18840 #define BCTL_REG 0x3512 /* basic control register */
- 18841 #define BST_REG 0x3512 /* basic status register */
- 18842 #define ATT_REG 0x3513 /* attention register */
- 18843 #define INT_REG 0x3513 /* interrupt status register */
- 18844
- 18845
- 18846 /***** basic status register bits */
- 18847
- 18848 #define DMA_ENA 0x80 /* DMA enabled? */
- 18849 #define INT_PND 0x40 /* interrupt pending? */
- 18850 #define CMD_PRG 0x20 /* command in progress? */
- 18851 #define BUSY 0x10 /* is adapter busy? */
- 18852 #define STR_FUL 0x08 /* status interface register set? */
- 18853 #define CMD_FUL 0x04 /* command interface register full? */
- 18854 #define XFR_REQ 0x02 /* data transfer operation ready? */
- .Ep 248 src/kernel/esdi_wini.c
- 18855 #define INT_SET 0x01 /* adapter sending interrupt? */
- 18856
- 18857
- 18858 /***** attention register commands */
- 18859
- 18860 #define ATT_CMD 0x01 /* command request */
- 18861 #define ATT_EOI 0x02 /* end of interrupt processing */
- 18862 #define ATT_ABT 0x03 /* abort the current command */
- 18863 #define ATT_RST 0xE4 /* reset the esdi adapter */
- 18864
- 18865
- 18866 /***** dma register addresses */
- 18867
- 18868 #define DMA_EXTCMD 0x18 /* extended function register */
- 18869 #define DMA_EXEC 0x1A /* extended function execute */
- 18870
- 18871
- 18872 /***** miscellaneous */
- 18873
- 18874 #define ERR (-1) /* general error code */
- 18875 #define ERR_BAD_SECTOR (-2) /* block marked bad detected */
- 18876 #define MAX_ERRORS 4 /* maximum number of read/write retries */
- 18877 #define MAX_DRIVES 2 /* maximum number of physical drives */
- 18878 #define NR_DEVICES (MAX_DRIVES*DEV_PER_DRIVE)
- 18879 /* Maximum number of logical devices */
- 18880 #define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS)
- 18881 #define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE)
- 18882
- 18883 #define SYS_PORTA 0x92 /* system control port a */
- 18884 #define LIGHT_ON 0xC0 /* fixed-disk activity light reg. mask */
- 18885
- 18886
- 18887 /***** variables */
- 18888
- 18889 PRIVATE struct wini { /* disk/partition information */
- 18890 unsigned open_ct; /* in-use count */
- 18891 struct device part[DEV_PER_DRIVE]; /* primary partitions: hd[0-4] */
- 18892 struct device subpart[SUB_PER_DRIVE]; /* subpartitions: hd[1-4][a-d] */
- 18893 } wini[MAX_DRIVES], *w_wn;
- 18894
- 18895 PRIVATE struct trans {
- 18896 struct iorequest_s *iop; /* belongs to this I/O request */
- 18897 unsigned long block; /* first sector to transfer */
- 18898 unsigned count; /* byte count */
- 18899 phys_bytes phys; /* user physical address */
- 18900 phys_bytes dma; /* DMA physical address */
- 18901 } wtrans[NR_IOREQS];
- 18902
- 18903 PRIVATE int nr_drives; /* actual number of physical disk drive */
- 18904 PRIVATE int command[4]; /* controller command buffer */
- 18905 PRIVATE unsigned int status_block[9]; /* status block output from a command */
- 18906 PRIVATE int dma_channel; /* fixed disk dma channel number */
- 18907 PRIVATE struct trans *w_tp; /* to add transfer requests */
- 18908 PRIVATE unsigned w_count; /* number of bytes to transfer */
- 18909 PRIVATE unsigned long w_nextblock; /* next block on disk to transfer */
- 18910 PRIVATE int w_opcode; /* DEV_READ or DEV_WRITE */
- 18911 PRIVATE int w_drive; /* selected drive */
- 18912 PRIVATE int w_istat; /* interrupt status of last command */
- 18913 PRIVATE struct device *w_dv; /* device's base and size */
- 18914
- .Op 249 src/kernel/esdi_wini.c
- 18915
- 18916 /***** functions */
- 18917
- 18918 FORWARD _PROTOTYPE( struct device *w_prepare, (int device) );
- 18919 FORWARD _PROTOTYPE( char *w_name, (void) );
- 18920 FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr) );
- 18921 FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );
- 18922 FORWARD _PROTOTYPE( void w_init, (void) );
- 18923 FORWARD _PROTOTYPE( int w_command, (int device, int cmd, int num_words) );
- 18924 FORWARD _PROTOTYPE( int w_schedule, (int proc_nr, struct iorequest_s *iop) );
- 18925 FORWARD _PROTOTYPE( int w_finish, (void) );
- 18926 FORWARD _PROTOTYPE( int w_transfer, (struct trans *tp, unsigned count) );
- 18927 FORWARD _PROTOTYPE( int w_att_write, (int value) );
- 18928 FORWARD _PROTOTYPE( void w_interrupt, (int dma) );
- 18929 FORWARD _PROTOTYPE( int w_handler, (int irq) );
- 18930 FORWARD _PROTOTYPE( void w_dma_setup, (struct trans *tp, unsigned count) );
- 18931 FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry));
- 18932
- 18933
- 18934 /* Entry points to this driver. */
- 18935 PRIVATE struct driver w_dtab = {
- 18936 w_name, /* current device's name */
- 18937 w_do_open, /* open or mount request, initialize device */
- 18938 w_do_close, /* release device */
- 18939 do_diocntl, /* get or set a partition's geometry */
- 18940 w_prepare, /* prepare for I/O on a given minor device */
- 18941 w_schedule, /* precompute cylinder, head, sector, etc. */
- 18942 w_finish, /* do the I/O */
- 18943 nop_cleanup, /* no cleanup needed */
- 18944 w_geometry /* tell the geometry of the disk */
- 18945 };
- 18946
- 18947
- 18948 /*===========================================================================*
- 18949 * esdi_winchester_task *
- 18950 *===========================================================================*/
- 18951 PUBLIC void esdi_winchester_task()
- 18952 {
- 18953 driver_task(&w_dtab);
- 18954 }
-
-
- 18957 /*===========================================================================*
- 18958 * w_prepare *
- 18959 *===========================================================================*/
- 18960 PRIVATE struct device *w_prepare(device)
- 18961 int device;
- 18962 {
- 18963 /* Prepare for I/O on a device. */
- 18964
- 18965 /* Nothing to transfer as yet. */
- 18966 w_count = 0;
- 18967
- 18968 if (device < NR_DEVICES) { /* hd0, hd1, ... */
- 18969 w_drive = device / DEV_PER_DRIVE; /* save drive number */
- 18970 w_wn = &wini[w_drive];
- 18971 w_dv = &w_wn->part[device % DEV_PER_DRIVE];
- 18972 } else
- 18973 if ((unsigned) (device -= MINOR_hd1a) < NR_SUBDEVS) { /* hd1a, hd1b, ... */
- 18974 w_drive = device / SUB_PER_DRIVE;
- .Ep 250 src/kernel/esdi_wini.c
- 18975 w_wn = &wini[w_drive];
- 18976 w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
- 18977 } else {
- 18978 return(NIL_DEV);
- 18979 }
- 18980 return(w_drive < nr_drives ? w_dv : NIL_DEV);
- 18981 }
-
-
- 18984 /*===========================================================================*
- 18985 * w_name *
- 18986 *===========================================================================*/
- 18987 PRIVATE char *w_name()
- 18988 {
- 18989 /* Return a name for the current device. */
- 18990 static char name[] = "esdi-hd5";
- 18991
- 18992 name[7] = '0' + w_drive * DEV_PER_DRIVE;
- 18993 return name;
- 18994 }
-
-
- 18997 /*============================================================================*
- 18998 * w_do_open *
- 18999 *============================================================================*/
- 19000 PRIVATE int w_do_open(dp, m_ptr)
- 19001 struct driver *dp;
- 19002 message *m_ptr;
- 19003 {
- 19004 /* Device open: Initialize the controller and read the partition table. */
- 19005
- 19006 static int init_done = FALSE;
- 19007
- 19008 if (!init_done) { w_init(); init_done = TRUE; }
- 19009
- 19010 if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
- 19011
- 19012 if (w_wn->open_ct++ == 0) {
- 19013 /* partition the disk */
- 19014 partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY);
- 19015 }
- 19016 return(OK);
- 19017 }
-
-
- 19020 /*============================================================================*
- 19021 * w_do_close *
- 19022 *============================================================================*/
- 19023 PRIVATE int w_do_close(dp, m_ptr)
- 19024 struct driver *dp;
- 19025 message *m_ptr;
- 19026 {
- 19027 /* Device close: Release a device. */
- 19028
- 19029 if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
- 19030 w_wn->open_ct--;
- 19031 return(OK);
- 19032 }
-
-
- .Op 251 src/kernel/esdi_wini.c
- 19035 /*============================================================================*
- 19036 * w_init *
- 19037 *============================================================================*/
- 19038 PRIVATE void w_init()
- 19039 {
- 19040 /* initializes everything needed to run the hard disk
- 19041 *
- 19042 * the following items are initialized:
- 19043 * -- hard disk attributes stored in bios
- 19044 * -- dma transfer channel, read from system register
- 19045 * -- dma transfer and interrupts [disabled]
- 19046 *
- 19047 * the hard disk adapter is initialized when the ibm ps/2 is turned on,
- 19048 * using the programmable option select registers. thus the only
- 19049 * additional initialization is making sure the dma transfer and interrupts
- 19050 * are disabled. other initialization problems could be checked for, such
- 19051 * as an operation underway. the paranoid could add a check for adapter
- 19052 * activity and abort the operations. the truly paranoid can reset the
- 19053 * adapter. until such worries are proven, why bother?
- 19054 */
- 19055 unsigned int drive; /* hard disk drive number */
- 19056 unsigned long size; /* hard disk size */
- 19057
- 19058 /* get the number of drives from the bios */
- 19059 phys_copy(0x475L, tmp_phys, 1L);
- 19060 nr_drives = tmp_buf[0];
- 19061 if (nr_drives > MAX_DRIVES) nr_drives = MAX_DRIVES;
- 19062
- 19063 put_irq_handler(AT_WINI_IRQ, w_handler);
- 19064 enable_irq(AT_WINI_IRQ); /* ready for winchester interrupts */
- 19065
- 19066 for (drive = 0; drive < nr_drives; ++drive) {
- 19067 (void) w_prepare(drive * DEV_PER_DRIVE);
- 19068 if (w_command(drive, 0x0609, 6) != OK) {
- 19069 printf("%s: unable to get parametersn", w_name());
- 19070 nr_drives = drive;
- 19071 break;
- 19072 }
- 19073 /* size of the drive */
- 19074 size = ((unsigned long) status_block[2] << 0) |
- 19075 ((unsigned long) status_block[3] << 16);
- 19076 if (drive == 0) {
- 19077 if (w_command(7, 0x060A, 5) != OK) {
- 19078 printf("%s: unable to get dma channeln", w_name());
- 19079 nr_drives = 0;
- 19080 return;
- 19081 }
- 19082 dma_channel = (status_block[2] & 0x3C00) >> 10;
- 19083 }
- 19084 printf("%s: %lu sectorsn", w_name(), size);
- 19085 w_wn->part[0].dv_size = size << SECTOR_SHIFT;
- 19086 }
- 19087 }
-
-
- 19090 /*===========================================================================*
- 19091 * w_command *
- 19092 *===========================================================================*/
- 19093 PRIVATE int w_command(device, cmd, num_words)
- 19094 int device; /* i device to operate on */
- .Ep 252 src/kernel/esdi_wini.c
- 19095 /* 1-2 physical disk drive number */
- 19096 /* 7 hard disk controller */
- 19097 int cmd; /* i command to execute */
- 19098 int num_words; /* i expected size of status block */
- 19099 {
- 19100 /* executes a command for a particular device
- 19101 *
- 19102 * the operation is conducted as follows:
- 19103 * -- create the command block
- 19104 * -- initialize for command reading by the controller
- 19105 * -- write the command block to the controller, making sure the
- 19106 * controller has digested the previous command word, before shoving
- 19107 * the next down its throat
- 19108 * -- wait for an interrupt
- 19109 * -- read expected number of words of command status information
- 19110 * -- return the command status block
- 19111 *
- 19112 * reading and writing registers is accompanied by enabling and disabling
- 19113 * interrupts to ensure that the status register contents still apply when
- 19114 * the desired register is read/written.
- 19115 */
- 19116 register int ki; /* -- scratch -- */
- 19117 int status; /* disk adapter status register value */
- 19118
- 19119 device <<= 5; /* adjust device for our use */
- 19120 command[0] = cmd | device; /* build command block */
- 19121 command[1] = 0;
- 19122
- 19123 w_att_write(device | ATT_CMD);
- 19124
- 19125 for (ki = 0; ki < 2; ++ki) {
- 19126 out_word(CMD_REG, command[ki]);
- 19127 unlock();
- 19128 while (TRUE) {
- 19129 lock();
- 19130 status = in_byte(BST_REG);
- 19131 if (!(status & CMD_FUL)) break;
- 19132 unlock();
- 19133 }
- 19134 }
- 19135 unlock();
- 19136
- 19137 w_interrupt(0);
- 19138 if (w_istat != (device | 0x01)) {
- 19139 w_att_write(device | ATT_ABT);
- 19140 w_interrupt(0);
- 19141 return(ERR);
- 19142 }
- 19143 for (ki = 0; ki < num_words; ++ki) {
- 19144 while (TRUE) {
- 19145 lock();
- 19146 status = in_byte(BST_REG);
- 19147 if (status & STR_FUL) break;
- 19148 unlock();
- 19149 }
- 19150 status_block[ki] = in_word(STAT_REG);
- 19151 unlock();
- 19152 }
- 19153 w_att_write(device | ATT_EOI);
- 19154
- .Op 253 src/kernel/esdi_wini.c
- 19155 return(OK);
- 19156 }
-
-
- 19159 /*===========================================================================*
- 19160 * w_schedule *
- 19161 *===========================================================================*/
- 19162 PRIVATE int w_schedule(proc_nr, iop)
- 19163 int proc_nr; /* process doing the request */
- 19164 struct iorequest_s *iop; /* pointer to read or write request */
- 19165 {
- 19166 /* Gather I/O requests on consecutive blocks so they may be read/written
- 19167 * in one command if using a buffer. Check and gather all the requests
- 19168 * and try to finish them as fast as possible if unbuffered.
- 19169 */
- 19170 int r, opcode;
- 19171 unsigned long pos;
- 19172 unsigned nbytes, count;
- 19173 unsigned long block;
- 19174 phys_bytes user_phys, dma_phys;
- 19175
- 19176 /* This many bytes to read/write */
- 19177 nbytes = iop->io_nbytes;
- 19178 if ((nbytes & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
- 19179
- 19180 /* From/to this position on the device */
- 19181 pos = iop->io_position;
- 19182 if ((pos & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
- 19183
- 19184 /* To/from this user address */
- 19185 user_phys = numap(proc_nr, (vir_bytes) iop->io_buf, nbytes);
- 19186 if (user_phys == 0) return(iop->io_nbytes = EINVAL);
- 19187
- 19188 /* Read or write? */
- 19189 opcode = iop->io_request & ~OPTIONAL_IO;
- 19190
- 19191 /* Which block on disk and how close to EOF? */
- 19192 if (pos >= w_dv->dv_size) return(OK); /* At EOF */
- 19193 if (pos + nbytes > w_dv->dv_size) nbytes = w_dv->dv_size - pos;
- 19194 block = (w_dv->dv_base + pos) >> SECTOR_SHIFT;
- 19195
- 19196 if (USE_BUF && w_count > 0 && block != w_nextblock) {
- 19197 /* This new request can't be chained to the job being built */
- 19198 if ((r = w_finish()) != OK) return(r);
- 19199 }
- 19200
- 19201 /* The next consecutive block */
- 19202 if (USE_BUF) w_nextblock = block + (nbytes >> SECTOR_SHIFT);
- 19203
- 19204 /* While there are "unscheduled" bytes in the request: */
- 19205 do {
- 19206 count = nbytes;
- 19207
- 19208 if (USE_BUF) {
- 19209 if (w_count == DMA_BUF_SIZE) {
- 19210 /* Can't transfer more than the buffer allows. */
- 19211 if ((r = w_finish()) != OK) return(r);
- 19212 }
- 19213
- 19214 if (w_count + count > DMA_BUF_SIZE)
- .Ep 254 src/kernel/esdi_wini.c
- 19215 count = DMA_BUF_SIZE - w_count;
- 19216 } else {
- 19217 if (w_tp == wtrans + NR_IOREQS) {
- 19218 /* All transfer slots in use. */
- 19219 if ((r = w_finish()) != OK) return(r);
- 19220 }
- 19221 }
- 19222
- 19223 if (w_count == 0) {
- 19224 /* The first request in a row, initialize. */
- 19225 w_opcode = opcode;
- 19226 w_tp = wtrans;
- 19227 }
- 19228
- 19229 if (USE_BUF) {
- 19230 dma_phys = tmp_phys + w_count;
- 19231 } else {
- 19232 /* Note: No 64K boundary problem, the better PS/2's have a
- 19233 * working DMA chip.
- 19234 */
- 19235 dma_phys = user_phys;
- 19236 }
- 19237
- 19238 /* Store I/O parameters */
- 19239 w_tp->iop = iop;
- 19240 w_tp->block = block;
- 19241 w_tp->count = count;
- 19242 w_tp->phys = user_phys;
- 19243 w_tp->dma = dma_phys;
- 19244
- 19245 /* Update counters */
- 19246 w_tp++;
- 19247 w_count += count;
- 19248 block += count >> SECTOR_SHIFT;
- 19249 user_phys += count;
- 19250 nbytes -= count;
- 19251 } while (nbytes > 0);
- 19252
- 19253 return(OK);
- 19254 }
-
-
- 19257 /*===========================================================================*
- 19258 * w_finish *
- 19259 *===========================================================================*/
- 19260 PRIVATE int w_finish()
- 19261 {
- 19262 /* carries out the I/O requests gathered in wtrans[]
- 19263 *
- 19264 * fills the disk information structure for one block at a time or many
- 19265 * in a row before calling 'w_transfer' to do the dirty work. while
- 19266 * unsuccessful operations are re-tried, this may be superfluous, since
- 19267 * the controller does the same on its own. turns on the fixed disk
- 19268 * activity light, while busy. computers need blinking lights, right?
- 19269 */
- 19270
- 19271 struct trans *tp = wtrans, *tp2;
- 19272 unsigned count;
- 19273 int r, errors = 0, many = USE_BUF;
- 19274
- .Op 255 src/kernel/esdi_wini.c
- 19275 if (w_count == 0) return(OK); /* Spurious finish. */
- 19276
- 19277 do {
- 19278 if (w_opcode == DEV_WRITE) {
- 19279 tp2 = tp;
- 19280 count = 0;
- 19281 do {
- 19282 if (USE_BUF || tp2->dma == tmp_phys) {
- 19283 phys_copy(tp2->phys, tp2->dma,
- 19284 (phys_bytes) tp2->count);
- 19285 }
- 19286 count += tp2->count;
- 19287 tp2++;
- 19288 } while (many && count < w_count);
- 19289 } else {
- 19290 count = many ? w_count : tp->count;
- 19291 }
- 19292
- 19293 /* Turn on the disk activity light. */
- 19294 out_byte(SYS_PORTA, in_byte(SYS_PORTA) | LIGHT_ON);
- 19295
- 19296 /* Perform the transfer. */
- 19297 r = w_transfer(tp, count);
- 19298
- 19299 /* Turn off the disk activity light. */
- 19300 out_byte(SYS_PORTA, in_byte(SYS_PORTA) & ~LIGHT_ON);
- 19301
- 19302 if (r != OK) {
- 19303 /* An error occurred, try again block by block unless */
- 19304 if (r == ERR_BAD_SECTOR || ++errors == MAX_ERRORS)
- 19305 return(tp->iop->io_nbytes = EIO);
- 19306
- 19307 many = 0;
- 19308 continue;
- 19309 }
- 19310 errors = 0;
- 19311
- 19312 w_count -= count;
- 19313
- 19314 do {
- 19315 if (w_opcode == DEV_READ) {
- 19316 if (USE_BUF || tp->dma == tmp_phys) {
- 19317 phys_copy(tp->dma, tp->phys,
- 19318 (phys_bytes) tp->count);
- 19319 }
- 19320 }
- 19321 tp->iop->io_nbytes -= tp->count;
- 19322 count -= tp->count;
- 19323 tp++;
- 19324 } while (count > 0);
- 19325 } while (w_count > 0);
- 19326
- 19327 return(OK);
- 19328 }
-
-
- 19331 /*===========================================================================*
- 19332 * w_transfer *
- 19333 *===========================================================================*/
- 19334 PRIVATE int w_transfer(tp, count)
- .Ep 256 src/kernel/esdi_wini.c
- 19335 struct trans *tp; /* pointer to the transfer struct */
- 19336 unsigned int count; /* bytes to transfer */
- 19337 {
- 19338 /* reads/writes a single block of data from/to the hard disk
- 19339 *
- 19340 * the read/write operation performs the following steps:
- 19341 * -- create the command block
- 19342 * -- initialize the command reading by the controller
- 19343 * -- write the command block to the controller, making sure the
- 19344 * controller has digested the previous command word, before
- 19345 * shoving the next down its throat.
- 19346 * -- wait for an interrupt, which must return a 'data transfer ready'
- 19347 * status. abort the command if it doesn't.
- 19348 * -- set up and start up the direct memory transfer
- 19349 * -- wait for an interrupt, signalling the end of the transfer
- 19350 */
- 19351 int device; /* device mask for the command register */
- 19352 int ki; /* -- scratch -- */
- 19353 int status; /* basic status register value */
- 19354
- 19355 device = w_drive << 5;
- 19356 command[0] = (w_opcode == DEV_WRITE ? 0x4602 : 0x4601) | device;
- 19357 command[1] = count >> SECTOR_SHIFT;
- 19358 command[2] = (int) (tp->block & 0xFFFF);
- 19359 command[3] = (int) (tp->block >> 16);
- 19360
- 19361 w_att_write(device | ATT_CMD);
- 19362
- 19363 for (ki = 0; ki < 4; ++ki) {
- 19364 out_word(CMD_REG, command[ki]);
- 19365 unlock();
- 19366 while (TRUE) {
- 19367 lock();
- 19368 status = in_byte(BST_REG);
- 19369 if (!(status & CMD_FUL)) break;
- 19370 unlock();
- 19371 }
- 19372 }
- 19373 unlock();
- 19374
- 19375 w_interrupt(0);
- 19376 if (w_istat != (device | 0x0B)) {
- 19377 w_att_write(device | ATT_ABT);
- 19378 w_interrupt(0);
- 19379 return(ERR);
- 19380 }
- 19381 w_dma_setup(tp, count);
- 19382
- 19383 w_interrupt(1);
- 19384
- 19385 w_att_write(device | ATT_EOI);
- 19386
- 19387 if ((w_istat & 0x0F) > 8) return(ERR);
- 19388 return(OK);
- 19389 }
-
-
-
- 19393 /*==========================================================================*
- 19394 * w_att_write *
- .Op 257 src/kernel/esdi_wini.c
- 19395 *==========================================================================*/
- 19396 PRIVATE int w_att_write(value)
- 19397 register int value;
- 19398 {
- 19399 /* writes a command to the esdi attention register
- 19400 *
- 19401 * waits for the controller to finish its business before sending the
- 19402 * command to the controller. note that the interrupts must be off to read
- 19403 * the basic status register and, if the controller is ready, must not be
- 19404 * turned back on until the attention register command is sent.
- 19405 */
- 19406 int status; /* basic status register value */
- 19407
- 19408 while (TRUE) {
- 19409 lock();
- 19410 status = in_byte(BST_REG);
- 19411 if (!(status & (INT_PND | BUSY))) break;
- 19412 unlock();
- 19413 }
- 19414 out_byte(ATT_REG, value);
- 19415 unlock();
- 19416
- 19417 return(OK);
- 19418 }
-
-
-
- 19422 /*===========================================================================*
- 19423 * w_interrupt *
- 19424 *===========================================================================*/
- 19425 PRIVATE void w_interrupt(dma)
- 19426 int dma; /* i dma transfer is underway */
- 19427 {
- 19428 /* waits for an interrupt from the hard disk controller
- 19429 *
- 19430 * enable interrupts on the hard disk and interrupt controllers (and dma if
- 19431 * necessary). wait for an interrupt. when received, return the interrupt
- 19432 * status register value.
- 19433 *
- 19434 * an interrupt can be detected either from the basic status register or
- 19435 * through a system interrupt handler. the handler is used for all
- 19436 * interrupts, due to the expected long times to process reads and writes
- 19437 * and to avoid busy waits.
- 19438 */
- 19439 message dummy; /* -- scratch -- */
- 19440
- 19441 out_byte(BCTL_REG, dma ? 0x03 : 0x01);
- 19442
- 19443 receive(HARDWARE, &dummy);
- 19444
- 19445 out_byte(BCTL_REG, 0);
- 19446 if (dma) out_byte(DMA_EXTCMD, 0x90 + dma_channel);
- 19447 }
-
-
-
- 19451 /*==========================================================================*
- 19452 * w_handler *
- 19453 *==========================================================================*/
- 19454 PRIVATE int w_handler(irq)
- .Ep 258 src/kernel/esdi_wini.c
- 19455 int irq;
- 19456 {
- 19457 /* Disk interrupt, send message to winchester task and reenable interrupts. */
- 19458
- 19459 w_istat = in_byte(INT_REG);
- 19460 interrupt(WINCHESTER);
- 19461 return 1;
- 19462 }
-
-
-
- 19466 /*==========================================================================*
- 19467 * w_dma_setup *
- 19468 *==========================================================================*/
- 19469 PRIVATE void w_dma_setup(tp, count)
- 19470 struct trans *tp;
- 19471 unsigned int count;
- 19472 {
- 19473 /* programs the dma controller to move data to and from the hard disk.
- 19474 *
- 19475 * uses the extended mode operation of the ibm ps/2 interrupt controller
- 19476 * chip, rather than the intel 8237 (pc/at) compatible mode.
- 19477 */
- 19478
- 19479 lock();
- 19480 out_byte(DMA_EXTCMD, 0x90 + dma_channel);
- 19481 /* Disable access to dma channel 5 */
- 19482 out_byte(DMA_EXTCMD, 0x20 + dma_channel);
- 19483 /* Clear the address byte pointer */
- 19484 out_byte(DMA_EXEC, (int) tp->dma >> 0); /* address bits 0..7 */
- 19485 out_byte(DMA_EXEC, (int) tp->dma >> 8); /* address bits 8..15 */
- 19486 out_byte(DMA_EXEC, (int) (tp->dma >> 16)); /* address bits 16..19 */
- 19487 out_byte(DMA_EXTCMD, 0x40 + dma_channel);
- 19488 /* Clear the count byte pointer */
- 19489 out_byte(DMA_EXEC, (count - 1) >> 0); /* count bits 0..7 */
- 19490 out_byte(DMA_EXEC, (count - 1) >> 8); /* count bits 8..15 */
- 19491 out_byte(DMA_EXTCMD, 0x70 + dma_channel);
- 19492 /* Set the transfer mode */
- 19493 out_byte(DMA_EXEC, w_opcode == DEV_WRITE ? 0x44 : 0x4C);
- 19494 out_byte(DMA_EXTCMD, 0xA0 + dma_channel);
- 19495 /* Enable access to dma channel 5 */
- 19496 unlock();
- 19497 }
-
-
- 19500 /*============================================================================*
- 19501 * w_geometry *
- 19502 *============================================================================*/
- 19503 PRIVATE void w_geometry(entry)
- 19504 struct partition *entry;
- 19505 {
- 19506 entry->cylinders = (w_wn->part[0].dv_size >> SECTOR_SHIFT) / (64 * 32);
- 19507 entry->heads = 64;
- 19508 entry->sectors = 32;
- 19509 }
- 19510 #endif /* ENABLE_ESDI_WINI */
- .Op 259 src/kernel/exception.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/exception.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 19600 /* This file contains a simple exception handler. Exceptions in user
- 19601 * processes are converted to signals. Exceptions in the kernel, MM and
- 19602 * FS cause a panic.
- 19603 */
- 19604
- 19605 #include "kernel.h"
- 19606 #include <signal.h>
- 19607 #include "proc.h"
- 19608
- 19609 /*==========================================================================*
- 19610 * exception *
- 19611 *==========================================================================*/
- 19612 PUBLIC void exception(vec_nr)
- 19613 unsigned vec_nr;
- 19614 {
- 19615 /* An exception or unexpected interrupt has occurred. */
- 19616
- 19617 struct ex_s {
- 19618 char *msg;
- 19619 int signum;
- 19620 int minprocessor;
- 19621 };
- 19622 static struct ex_s ex_data[] = {
- 19623 "Divide error", SIGFPE, 86,
- 19624 "Debug exception", SIGTRAP, 86,
- 19625 "Nonmaskable interrupt", SIGBUS, 86,
- 19626 "Breakpoint", SIGEMT, 86,
- 19627 "Overflow", SIGFPE, 86,
- 19628 "Bounds check", SIGFPE, 186,
- 19629 "Invalid opcode", SIGILL, 186,
- 19630 "Coprocessor not available", SIGFPE, 186,
- 19631 "Double fault", SIGBUS, 286,
- 19632 "Copressor segment overrun", SIGSEGV, 286,
- 19633 "Invalid TSS", SIGSEGV, 286,
- 19634 "Segment not present", SIGSEGV, 286,
- 19635 "Stack exception", SIGSEGV, 286, /* STACK_FAULT already used */
- 19636 "General protection", SIGSEGV, 286,
- 19637 "Page fault", SIGSEGV, 386, /* not close */
- 19638 NIL_PTR, SIGILL, 0, /* probably software trap */
- 19639 "Coprocessor error", SIGFPE, 386,
- 19640 };
- 19641 register struct ex_s *ep;
- 19642 struct proc *saved_proc;
- 19643
- 19644 saved_proc= proc_ptr; /* Save proc_ptr, because it may be changed by debug
- 19645 * statements.
- 19646 */
- 19647
- 19648 ep = &ex_data[vec_nr];
- 19649
- 19650 if (vec_nr == 2) { /* spurious NMI on some machines */
- 19651 printf("got spurious NMIn");
- 19652 return;
- 19653 }
- 19654
- .Ep 260 src/kernel/exception.c
- 19655 if (k_reenter == 0 && isuserp(saved_proc)) {
- 19656 unlock(); /* this is protected like sys_call() */
- 19657 cause_sig(proc_number(saved_proc), ep->signum);
- 19658 return;
- 19659 }
- 19660
- 19661 /* This is not supposed to happen. */
- 19662 if (ep->msg == NIL_PTR || processor < ep->minprocessor)
- 19663 printf("nIntel-reserved exception %dn", vec_nr);
- 19664 else
- 19665 printf("n%sn", ep->msg);
- 19666 printf("process number %d, pc = 0x%04x:0x%08xn",
- 19667 proc_number(saved_proc),
- 19668 (unsigned) saved_proc->p_reg.cs,
- 19669 (unsigned) saved_proc->p_reg.pc);
- 19670 panic("exception in system code", NO_NUM);
- 19671 }
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/floppy.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 19700 /* This file contains the device dependent part of the driver for the Floppy
- 19701 * Disk Controller (FDC) using the NEC PD765 chip.
- 19702 *
- 19703 * The file contains one entry point:
- 19704 *
- 19705 * floppy_task: main entry when system is brought up
- 19706 * floppy_stop: stop all activity
- 19707 *
- 19708 * Changes:
- 19709 * 27 Oct. 1986 by Jakob Schripsema: fdc_results fixed for 8 MHz
- 19710 * 28 Nov. 1986 by Peter Kay: better resetting for 386
- 19711 * 06 Jan. 1988 by Al Crew: allow 1.44 MB diskettes
- 19712 * 1989 by Bruce Evans: I/O vector to keep up with 1-1 interleave
- 19713 * 13 May 1991 by Don Chapman: renovated the errors loop.
- 19714 * 1991 by Bruce Evans: len[] / motors / reset / step rate / ...
- 19715 * 14 Feb 1992 by Andy Tanenbaum: check drive density on opens only
- 19716 * 27 Mar 1992 by Kees J. Bot: last details on density checking
- 19717 * 04 Apr 1992 by Kees J. Bot: device dependent/independent split
- 19718 */
- 19719
- 19720 #include "kernel.h"
- 19721 #include "driver.h"
- 19722 #include "drvlib.h"
- 19723 #include <ibm/diskparm.h>
- 19724
- 19725 /* I/O Ports used by floppy disk task. */
- 19726 #define DOR 0x3F2 /* motor drive control bits */
- 19727 #define FDC_STATUS 0x3F4 /* floppy disk controller status register */
- 19728 #define FDC_DATA 0x3F5 /* floppy disk controller data register */
- 19729 #define FDC_RATE 0x3F7 /* transfer rate register */
- 19730 #define DMA_ADDR 0x004 /* port for low 16 bits of DMA address */
- 19731 #define DMA_TOP 0x081 /* port for top 4 bits of 20-bit DMA addr */
- 19732 #define DMA_COUNT 0x005 /* port for DMA count (count = bytes - 1) */
- 19733 #define DMA_FLIPFLOP 0x00C /* DMA byte pointer flip-flop */
- 19734 #define DMA_MODE 0x00B /* DMA mode port */
- .Op 261 src/kernel/floppy.c
- 19735 #define DMA_INIT 0x00A /* DMA init port */
- 19736 #define DMA_RESET_VAL 0x06
- 19737
- 19738 /* Status registers returned as result of operation. */
- 19739 #define ST0 0x00 /* status register 0 */
- 19740 #define ST1 0x01 /* status register 1 */
- 19741 #define ST2 0x02 /* status register 2 */
- 19742 #define ST3 0x00 /* status register 3 (return by DRIVE_SENSE) */
- 19743 #define ST_CYL 0x03 /* slot where controller reports cylinder */
- 19744 #define ST_HEAD 0x04 /* slot where controller reports head */
- 19745 #define ST_SEC 0x05 /* slot where controller reports sector */
- 19746 #define ST_PCN 0x01 /* slot where controller reports present cyl */
- 19747
- 19748 /* Fields within the I/O ports. */
- 19749 /* Main status register. */
- 19750 #define CTL_BUSY 0x10 /* bit is set when read or write in progress */
- 19751 #define DIRECTION 0x40 /* bit is set when reading data reg is valid */
- 19752 #define MASTER 0x80 /* bit is set when data reg can be accessed */
- 19753
- 19754 /* Digital output port (DOR). */
- 19755 #define MOTOR_SHIFT 4 /* high 4 bits control the motors in DOR */
- 19756 #define ENABLE_INT 0x0C /* used for setting DOR port */
- 19757
- 19758 /* ST0. */
- 19759 #define ST0_BITS 0xF8 /* check top 5 bits of seek status */
- 19760 #define TRANS_ST0 0x00 /* top 5 bits of ST0 for READ/WRITE */
- 19761 #define SEEK_ST0 0x20 /* top 5 bits of ST0 for SEEK */
- 19762
- 19763 /* ST1. */
- 19764 #define BAD_SECTOR 0x05 /* if these bits are set in ST1, recalibrate */
- 19765 #define WRITE_PROTECT 0x02 /* bit is set if diskette is write protected */
- 19766
- 19767 /* ST2. */
- 19768 #define BAD_CYL 0x1F /* if any of these bits are set, recalibrate */
- 19769
- 19770 /* ST3 (not used). */
- 19771 #define ST3_FAULT 0x80 /* if this bit is set, drive is sick */
- 19772 #define ST3_WR_PROTECT 0x40 /* set when diskette is write protected */
- 19773 #define ST3_READY 0x20 /* set when drive is ready */
- 19774
- 19775 /* Floppy disk controller command bytes. */
- 19776 #define FDC_SEEK 0x0F /* command the drive to seek */
- 19777 #define FDC_READ 0xE6 /* command the drive to read */
- 19778 #define FDC_WRITE 0xC5 /* command the drive to write */
- 19779 #define FDC_SENSE 0x08 /* command the controller to tell its status */
- 19780 #define FDC_RECALIBRATE 0x07 /* command the drive to go to cyl 0 */
- 19781 #define FDC_SPECIFY 0x03 /* command the drive to accept params */
- 19782 #define FDC_READ_ID 0x4A /* command the drive to read sector identity */
- 19783 #define FDC_FORMAT 0x4D /* command the drive to format a track */
- 19784
- 19785 /* DMA channel commands. */
- 19786 #define DMA_READ 0x46 /* DMA read opcode */
- 19787 #define DMA_WRITE 0x4A /* DMA write opcode */
- 19788
- 19789 /* Parameters for the disk drive. */
- 19790 #define HC_SIZE 2880 /* # sectors on largest legal disk (1.44MB) */
- 19791 #define NR_HEADS 0x02 /* two heads (i.e., two tracks/cylinder) */
- 19792 #define MAX_SECTORS 18 /* largest # sectors per track */
- 19793 #define DTL 0xFF /* determines data length (sector size) */
- 19794 #define SPEC2 0x02 /* second parameter to SPECIFY */
- .Ep 262 src/kernel/floppy.c
- 19795 #define MOTOR_OFF 3*HZ /* how long to wait before stopping motor */
- 19796 #define WAKEUP 2*HZ /* timeout on I/O, FDC won't quit. */
- 19797
- 19798 /* Error codes */
- 19799 #define ERR_SEEK (-1) /* bad seek */
- 19800 #define ERR_TRANSFER (-2) /* bad transfer */
- 19801 #define ERR_STATUS (-3) /* something wrong when getting status */
- 19802 #define ERR_READ_ID (-4) /* bad read id */
- 19803 #define ERR_RECALIBRATE (-5) /* recalibrate didn't work properly */
- 19804 #define ERR_DRIVE (-6) /* something wrong with a drive */
- 19805 #define ERR_WR_PROTECT (-7) /* diskette is write protected */
- 19806 #define ERR_TIMEOUT (-8) /* interrupt timeout */
- 19807
- 19808 /* No retries on some errors. */
- 19809 #define err_no_retry(err) ((err) <= ERR_WR_PROTECT)
- 19810
- 19811 /* Encoding of drive type in minor device number. */
- 19812 #define DEV_TYPE_BITS 0x7C /* drive type + 1, if nonzero */
- 19813 #define DEV_TYPE_SHIFT 2 /* right shift to normalize type bits */
- 19814 #define FORMAT_DEV_BIT 0x80 /* bit in minor to turn write into format */
- 19815
- 19816 /* Miscellaneous. */
- 19817 #define MAX_ERRORS 6 /* how often to try rd/wt before quitting */
- 19818 #define MAX_RESULTS 7 /* max number of bytes controller returns */
- 19819 #define NR_DRIVES 2 /* maximum number of drives */
- 19820 #define DIVISOR 128 /* used for sector size encoding */
- 19821 #define SECTOR_SIZE_CODE 2 /* code to say "512" to the controller */
- 19822 #define TIMEOUT 500 /* milliseconds waiting for FDC */
- 19823 #define NT 7 /* number of diskette/drive combinations */
- 19824 #define UNCALIBRATED 0 /* drive needs to be calibrated at next use */
- 19825 #define CALIBRATED 1 /* no calibration needed */
- 19826 #define BASE_SECTOR 1 /* sectors are numbered starting at 1 */
- 19827 #define NO_SECTOR 0 /* current sector unknown */
- 19828 #define NO_CYL (-1) /* current cylinder unknown, must seek */
- 19829 #define NO_DENS 100 /* current media unknown */
- 19830 #define BSY_IDLE 0 /* busy doing nothing */
- 19831 #define BSY_IO 1 /* doing I/O */
- 19832 #define BSY_WAKEN 2 /* got a wakeup call */
- 19833
- 19834 /* Variables. */
- 19835 PRIVATE struct floppy { /* main drive struct, one entry per drive */
- 19836 int fl_curcyl; /* current cylinder */
- 19837 int fl_hardcyl; /* hardware cylinder, as opposed to: */
- 19838 int fl_cylinder; /* cylinder number addressed */
- 19839 int fl_sector; /* sector addressed */
- 19840 int fl_head; /* head number addressed */
- 19841 char fl_calibration; /* CALIBRATED or UNCALIBRATED */
- 19842 char fl_density; /* NO_DENS = ?, 0 = 360K; 1 = 360K/1.2M; etc.*/
- 19843 char fl_class; /* bitmap for possible densities */
- 19844 struct device fl_geom; /* Geometry of the drive */
- 19845 struct device fl_part[NR_PARTITIONS]; /* partition's base & size */
- 19846 } floppy[NR_DRIVES], *f_fp;
- 19847
- 19848 /* Gather transfer data for each sector. */
- 19849 PRIVATE struct trans { /* precomputed transfer params */
- 19850 unsigned tr_count; /* byte count */
- 19851 struct iorequest_s *tr_iop; /* belongs to this I/O request */
- 19852 phys_bytes tr_phys; /* user physical address */
- 19853 phys_bytes tr_dma; /* DMA physical address */
- 19854 } ftrans[MAX_SECTORS];
- .Op 263 src/kernel/floppy.c
- 19855
- 19856 PRIVATE unsigned f_count; /* this many bytes to transfer */
- 19857 PRIVATE unsigned f_nexttrack; /* don't do blocks above this */
- 19858 PRIVATE int motor_status; /* bitmap of current motor status */
- 19859 PRIVATE int motor_goal; /* bitmap of desired motor status */
- 19860 PRIVATE int need_reset; /* set to 1 when controller must be reset */
- 19861 PRIVATE int d; /* diskette/drive combination */
- 19862 PRIVATE int f_drive; /* selected drive */
- 19863 PRIVATE int f_device; /* selected minor device */
- 19864 PRIVATE int f_opcode; /* DEV_READ or DEV_WRITE */
- 19865 PRIVATE int f_sectors; /* sectors per track of the floppy */
- 19866 PRIVATE int f_must; /* must do part of the next track? */
- 19867 PRIVATE int f_busy; /* BSY_IDLE, BSY_IO, BSY_WAKEN */
- 19868 PRIVATE int current_spec1; /* latest spec1 sent to the controller */
- 19869 PRIVATE struct device *f_dv; /* device's base and size */
- 19870 PRIVATE struct disk_parameter_s fmt_param; /* parameters for format */
- 19871 PRIVATE char f_results[MAX_RESULTS];/* the controller can give lots of output */
- 19872
- 19873
- 19874 /* Seven combinations of diskette/drive are supported.
- 19875 *
- 19876 * # Drive diskette Sectors Tracks Rotation Data-rate Comment
- 19877 * 0 360K 360K 9 40 300 RPM 250 kbps Standard PC DSDD
- 19878 * 1 1.2M 1.2M 15 80 360 RPM 500 kbps AT disk in AT drive
- 19879 * 2 720K 360K 9 40 300 RPM 250 kbps Quad density PC
- 19880 * 3 720K 720K 9 80 300 RPM 250 kbps Toshiba, et al.
- 19881 * 4 1.2M 360K 9 40 360 RPM 300 kbps PC disk in AT drive
- 19882 * 5 1.2M 720K 9 80 360 RPM 300 kbps Toshiba in AT drive
- 19883 * 6 1.44M 1.44M 18 80 300 RPM 500 kbps PS/2, et al.
- 19884 *
- 19885 * In addition, 720K diskettes can be read in 1.44MB drives, but that does
- 19886 * not need a different set of parameters. This combination uses
- 19887 *
- 19888 * X 1.44M 720K 9 80 300 RPM 250 kbps PS/2, et al.
- 19889 */
- 19890 PRIVATE char gap[NT] =
- 19891 {0x2A, 0x1B, 0x2A, 0x2A, 0x23, 0x23, 0x1B}; /* gap size */
- 19892 PRIVATE char rate[NT] =
- 19893 {0x02, 0x00, 0x02, 0x02, 0x01, 0x01, 0x00}; /* 2=250,1=300,0=500 kbps*/
- 19894 PRIVATE char nr_sectors[NT] =
- 19895 {9, 15, 9, 9, 9, 9, 18}; /* sectors/track */
- 19896 PRIVATE int nr_blocks[NT] =
- 19897 {720, 2400, 720, 1440, 720, 1440, 2880}; /* sectors/diskette*/
- 19898 PRIVATE char steps_per_cyl[NT] =
- 19899 {1, 1, 2, 1, 2, 1, 1}; /* 2 = dbl step */
- 19900 PRIVATE char mtr_setup[NT] =
- 19901 {1*HZ/4,3*HZ/4,1*HZ/4,4*HZ/4,3*HZ/4,3*HZ/4,4*HZ/4}; /* in ticks */
- 19902 PRIVATE char spec1[NT] =
- 19903 {0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF}; /* step rate, etc. */
- 19904 PRIVATE char test_sector[NT] =
- 19905 {4*9, 14, 2*9, 4*9, 2*9, 4*9, 17}; /* to recognize it */
- 19906
- 19907 #define b(d) (1 << (d)) /* bit for density d. */
- 19908
- 19909 /* The following table is used with the test_sector array to recognize a
- 19910 * drive/floppy combination. The sector to test has been determined by
- 19911 * looking at the differences in gap size, sectors/track, and double stepping.
- 19912 * This means that types 0 and 3 can't be told apart, only the motor start
- 19913 * time differs. If a read test succeeds then the drive is limited to the
- 19914 * set of densities it can support to avoid unnecessary tests in the future.
- .Ep 264 src/kernel/floppy.c
- 19915 */
- 19916
- 19917 PRIVATE struct test_order {
- 19918 char t_density; /* floppy/drive type */
- 19919 char t_class; /* limit drive to this class of densities */
- 19920 } test_order[NT-1] = {
- 19921 { 6, b(3) | b(6) }, /* 1.44M {720K, 1.44M} */
- 19922 { 1, b(1) | b(4) | b(5) }, /* 1.2M {1.2M, 360K, 720K} */
- 19923 { 3, b(2) | b(3) | b(6) }, /* 720K {360K, 720K, 1.44M} */
- 19924 { 4, b(1) | b(4) | b(5) }, /* 360K {1.2M, 360K, 720K} */
- 19925 { 5, b(1) | b(4) | b(5) }, /* 720K {1.2M, 360K, 720K} */
- 19926 { 2, b(2) | b(3) }, /* 360K {360K, 720K} */
- 19927 /* Note that type 0 is missing, type 3 can read/write it too (alas). */
- 19928 };
- 19929
- 19930 FORWARD _PROTOTYPE( struct device *f_prepare, (int device) );
- 19931 FORWARD _PROTOTYPE( char *f_name, (void) );
- 19932 FORWARD _PROTOTYPE( void f_cleanup, (void) );
- 19933 FORWARD _PROTOTYPE( int f_schedule, (int proc_nr, struct iorequest_s *iop) );
- 19934 FORWARD _PROTOTYPE( int f_finish, (void) );
- 19935 FORWARD _PROTOTYPE( void defuse, (void) );
- 19936 FORWARD _PROTOTYPE( void dma_setup, (struct trans *tp) );
- 19937 FORWARD _PROTOTYPE( void start_motor, (void) );
- 19938 FORWARD _PROTOTYPE( void stop_motor, (void) );
- 19939 FORWARD _PROTOTYPE( int seek, (struct floppy *fp) );
- 19940 FORWARD _PROTOTYPE( int f_transfer, (struct floppy *fp, struct trans *tp) );
- 19941 FORWARD _PROTOTYPE( int fdc_results, (void) );
- 19942 FORWARD _PROTOTYPE( int f_handler, (int irq) );
- 19943 FORWARD _PROTOTYPE( void fdc_out, (int val) );
- 19944 FORWARD _PROTOTYPE( int recalibrate, (struct floppy *fp) );
- 19945 FORWARD _PROTOTYPE( void f_reset, (void) );
- 19946 FORWARD _PROTOTYPE( void send_mess, (void) );
- 19947 FORWARD _PROTOTYPE( int f_intr_wait, (void) );
- 19948 FORWARD _PROTOTYPE( void f_timeout, (void) );
- 19949 FORWARD _PROTOTYPE( int read_id, (struct floppy *fp) );
- 19950 FORWARD _PROTOTYPE( int f_do_open, (struct driver *dp, message *m_ptr) );
- 19951 FORWARD _PROTOTYPE( int test_read, (int density) );
- 19952 FORWARD _PROTOTYPE( void f_geometry, (struct partition *entry));
- 19953
- 19954
- 19955 /* Entry points to this driver. */
- 19956 PRIVATE struct driver f_dtab = {
- 19957 f_name, /* current device's name */
- 19958 f_do_open, /* open or mount request, sense type of diskette */
- 19959 do_nop, /* nothing on a close */
- 19960 do_diocntl, /* get or set a partitions geometry */
- 19961 f_prepare, /* prepare for I/O on a given minor device */
- 19962 f_schedule, /* precompute cylinder, head, sector, etc. */
- 19963 f_finish, /* do the I/O */
- 19964 f_cleanup, /* cleanup before sending reply to user process */
- 19965 f_geometry /* tell the geometry of the diskette */
- 19966 };
- 19967
- 19968
- 19969 /*===========================================================================*
- 19970 * floppy_task *
- 19971 *===========================================================================*/
- 19972 PUBLIC void floppy_task()
- 19973 {
- 19974 /* Initialize the floppy structure. */
- .Op 265 src/kernel/floppy.c
- 19975
- 19976 struct floppy *fp;
- 19977
- 19978 for (fp = &floppy[0]; fp < &floppy[NR_DRIVES]; fp++) {
- 19979 fp->fl_curcyl = NO_CYL;
- 19980 fp->fl_density = NO_DENS;
- 19981 fp->fl_class = ~0;
- 19982 }
- 19983
- 19984 put_irq_handler(FLOPPY_IRQ, f_handler);
- 19985 enable_irq(FLOPPY_IRQ); /* ready for floppy interrupts */
- 19986
- 19987 driver_task(&f_dtab);
- 19988 }
-
-
- 19991 /*===========================================================================*
- 19992 * f_prepare *
- 19993 *===========================================================================*/
- 19994 PRIVATE struct device *f_prepare(device)
- 19995 int device;
- 19996 {
- 19997 /* Prepare for I/O on a device. */
- 19998
- 19999 /* Leftover jobs after an I/O error must be removed */
- 20000 if (f_count > 0) defuse();
- 20001
- 20002 f_device = device;
- 20003 f_drive = device & ~(DEV_TYPE_BITS | FORMAT_DEV_BIT);
- 20004 if (f_drive < 0 || f_drive >= NR_DRIVES) return(NIL_DEV);
- 20005
- 20006 f_fp = &floppy[f_drive];
- 20007 f_dv = &f_fp->fl_geom;
- 20008 d = f_fp->fl_density;
- 20009 f_sectors = nr_sectors[d];
- 20010
- 20011 f_must = TRUE; /* the first transfers must be done */
- 20012
- 20013 /* A partition? */
- 20014 if ((device &= DEV_TYPE_BITS) >= MINOR_fd0a)
- 20015 f_dv = &f_fp->fl_part[(device - MINOR_fd0a) >> DEV_TYPE_SHIFT];
- 20016
- 20017 return f_dv;
- 20018 }
-
-
- 20021 /*===========================================================================*
- 20022 * f_name *
- 20023 *===========================================================================*/
- 20024 PRIVATE char *f_name()
- 20025 {
- 20026 /* Return a name for the current device. */
- 20027 static char name[] = "fd3";
- 20028
- 20029 name[2] = '0' + f_drive;
- 20030 return name;
- 20031 }
-
-
- 20034 /*===========================================================================*
- .Ep 266 src/kernel/floppy.c
- 20035 * f_cleanup *
- 20036 *===========================================================================*/
- 20037 PRIVATE void f_cleanup()
- 20038 {
- 20039 /* Start watchdog timer to turn all motors off in a few seconds.
- 20040 * There is a race here. An old watchdog might bite before the
- 20041 * new delay is installed, and turn of the motors prematurely.
- 20042 * This cannot be solved simply by resetting motor_goal after
- 20043 * sending the message, because the new watchdog might bite
- 20044 * before motor_goal is reset. Then the motors would stay on
- 20045 * until after the next floppy access. This could be fixed with
- 20046 * extra code (call the clock task twice in some cases). Or
- 20047 * stop_motor() could be replaced by send_mess(), and send a
- 20048 * STOP_MOTOR message to be accepted by the clock task. This
- 20049 * would be slower but have the advantage that this comment could
- 20050 * be deleted!
- 20051 *
- 20052 * Since it is not likely and not serious for an old watchdog to
- 20053 * bite, accept that possibility for now. A full solution to the
- 20054 * motor madness requires a lots of extra work anyway, such as
- 20055 * a separate timer for each motor, and smaller delays for motors
- 20056 * that have just been turned off or start faster than the spec.
- 20057 * (is there a motor-ready bit?).
- 20058 */
- 20059 motor_goal = 0;
- 20060 clock_mess(MOTOR_OFF, stop_motor);
- 20061 }
-
-
- 20064 /*===========================================================================*
- 20065 * f_schedule *
- 20066 *===========================================================================*/
- 20067 PRIVATE int f_schedule(proc_nr, iop)
- 20068 int proc_nr; /* process doing the request */
- 20069 struct iorequest_s *iop; /* pointer to read or write request */
- 20070 {
- 20071 int r, opcode, spanning;
- 20072 unsigned long pos;
- 20073 unsigned block; /* Seen any 32M floppies lately? */
- 20074 unsigned nbytes, count, dma_count;
- 20075 phys_bytes user_phys, dma_phys;
- 20076 struct trans *tp, *tp0;
- 20077
- 20078 /* Ignore any alarm to turn motor off, now there is work to do. */
- 20079 motor_goal = motor_status;
- 20080
- 20081 /* This many bytes to read/write */
- 20082 nbytes = iop->io_nbytes;
- 20083 if ((nbytes & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
- 20084
- 20085 /* From/to this position on disk */
- 20086 pos = iop->io_position;
- 20087 if ((pos & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
- 20088
- 20089 /* To/from this user address */
- 20090 user_phys = numap(proc_nr, (vir_bytes) iop->io_buf, nbytes);
- 20091 if (user_phys == 0) return(iop->io_nbytes = EINVAL);
- 20092
- 20093 /* Read, write or format? */
- 20094 opcode = iop->io_request & ~OPTIONAL_IO;
- .Op 267 src/kernel/floppy.c
- 20095 if (f_device & FORMAT_DEV_BIT) {
- 20096 if (opcode != DEV_WRITE) return(iop->io_nbytes = EIO);
- 20097 if (nbytes != BLOCK_SIZE) return(iop->io_nbytes = EINVAL);
- 20098
- 20099 phys_copy(user_phys + SECTOR_SIZE, vir2phys(&fmt_param),
- 20100 (phys_bytes) sizeof fmt_param);
- 20101
- 20102 /* Check that the number of sectors in the data is reasonable, to
- 20103 * avoid division by 0. Leave checking of other data to the FDC.
- 20104 */
- 20105 if (fmt_param.sectors_per_cylinder == 0)
- 20106 return(iop->io_nbytes = EIO);
- 20107
- 20108 /* Only the first sector of the parameters now needed. */
- 20109 iop->io_nbytes = nbytes = SECTOR_SIZE;
- 20110 }
- 20111
- 20112 /* Which block on disk and how close to EOF? */
- 20113 if (pos >= f_dv->dv_size) return(OK); /* At EOF */
- 20114 if (pos + nbytes > f_dv->dv_size) nbytes = f_dv->dv_size - pos;
- 20115 block = (f_dv->dv_base + pos) >> SECTOR_SHIFT;
- 20116
- 20117 spanning = FALSE; /* set if the block spans a track */
- 20118
- 20119 /* While there are "unscheduled" bytes in the request: */
- 20120 do {
- 20121 count = nbytes;
- 20122
- 20123 if (f_count > 0 && block >= f_nexttrack) {
- 20124 /* The new job leaves the track, finish all gathered jobs */
- 20125 if ((r = f_finish()) != OK) return(r);
- 20126 f_must = spanning;
- 20127 }
- 20128
- 20129 if (f_count == 0) {
- 20130 /* This is the first job, compute cylinder and head */
- 20131 f_opcode = opcode;
- 20132 f_fp->fl_cylinder = block / (NR_HEADS * f_sectors);
- 20133 f_fp->fl_hardcyl = f_fp->fl_cylinder * steps_per_cyl[d];
- 20134 f_fp->fl_head = (block % (NR_HEADS * f_sectors)) / f_sectors;
- 20135
- 20136 /* See where the next track starts, one is trouble enough */
- 20137 f_nexttrack = (f_fp->fl_cylinder * NR_HEADS
- 20138 + f_fp->fl_head + 1) * f_sectors;
- 20139 }
- 20140
- 20141 /* Don't do track spanning I/O. */
- 20142 if (block + (count >> SECTOR_SHIFT) > f_nexttrack)
- 20143 count = (f_nexttrack - block) << SECTOR_SHIFT;
- 20144
- 20145 /* Memory chunk to DMA. */
- 20146 dma_phys = user_phys;
- 20147 dma_count = dma_bytes_left(dma_phys);
- 20148
- 20149 #if _WORD_SIZE > 2
- 20150 /* The DMA chip uses a 24 bit address, so don't DMA above 16MB. */
- 20151 if (dma_phys >= 0x1000000) dma_count = 0;
- 20152 #endif
- 20153 if (dma_count < count) {
- 20154 /* Nearing a 64K boundary. */
- .Ep 268 src/kernel/floppy.c
- 20155 if (dma_count >= SECTOR_SIZE) {
- 20156 /* Can read a few sectors before hitting the
- 20157 * boundary.
- 20158 */
- 20159 count = dma_count & ~SECTOR_MASK;
- 20160 } else {
- 20161 /* Must use the special buffer for this. */
- 20162 count = SECTOR_SIZE;
- 20163 dma_phys = tmp_phys;
- 20164 }
- 20165 }
- 20166
- 20167 /* Store the I/O parameters in the ftrans slots for the sectors to
- 20168 * read. The first slot specifies all sectors, the ones following
- 20169 * it each specify one sector less. This allows I/O to be started
- 20170 * in the middle of a block.
- 20171 */
- 20172 tp = tp0 = &ftrans[block % f_sectors];
- 20173
- 20174 block += count >> SECTOR_SHIFT;
- 20175 nbytes -= count;
- 20176 f_count += count;
- 20177 if (!(iop->io_request & OPTIONAL_IO)) f_must = TRUE;
- 20178
- 20179 do {
- 20180 tp->tr_count = count;
- 20181 tp->tr_iop = iop;
- 20182 tp->tr_phys = user_phys;
- 20183 tp->tr_dma = dma_phys;
- 20184 tp++;
- 20185
- 20186 user_phys += SECTOR_SIZE;
- 20187 dma_phys += SECTOR_SIZE;
- 20188 count -= SECTOR_SIZE;
- 20189 } while (count > 0);
- 20190
- 20191 spanning = TRUE; /* the rest of the block may span a track */
- 20192 } while (nbytes > 0);
- 20193
- 20194 return(OK);
- 20195 }
-
-
- 20198 /*===========================================================================*
- 20199 * f_finish *
- 20200 *===========================================================================*/
- 20201 PRIVATE int f_finish()
- 20202 {
- 20203 /* Carry out the I/O requests gathered in ftrans[]. */
- 20204
- 20205 struct floppy *fp = f_fp;
- 20206 struct trans *tp;
- 20207 int r, errors;
- 20208
- 20209 if (f_count == 0) return(OK); /* Spurious finish. */
- 20210
- 20211 /* If all the requests are optional then don't read from the next track.
- 20212 * (There may be enough buffers to read the next track, but doing so is
- 20213 * unwise. It's no good to be greedy on a slow device.)
- 20214 */
- .Op 269 src/kernel/floppy.c
- 20215 if (!f_must) {
- 20216 defuse();
- 20217 return(EAGAIN);
- 20218 }
- 20219
- 20220 /* See if motor is running; if not, turn it on and wait */
- 20221 start_motor();
- 20222
- 20223 /* Let read_id find out the next sector to read/write if it pays to do so.
- 20224 * Note that no read_id is done while formatting if there is one format
- 20225 * request per track as there should be.
- 20226 */
- 20227 fp->fl_sector = f_count >= (6 * SECTOR_SIZE) ? 0 : BASE_SECTOR;
- 20228
- 20229 do {
- 20230 /* This loop allows a failed operation to be repeated. */
- 20231 errors = 0;
- 20232 for (;;) {
- 20233 /* First check to see if a reset is needed. */
- 20234 if (need_reset) f_reset();
- 20235
- 20236 /* Set the stepping rate */
- 20237 if (current_spec1 != spec1[d]) {
- 20238 fdc_out(FDC_SPECIFY);
- 20239 current_spec1 = spec1[d];
- 20240 fdc_out(current_spec1);
- 20241 fdc_out(SPEC2);
- 20242 }
- 20243
- 20244 /* Set the data rate */
- 20245 if (pc_at) out_byte(FDC_RATE, rate[d]);
- 20246
- 20247 /* If we are going to a new cylinder, perform a seek. */
- 20248 r = seek(fp);
- 20249
- 20250 if (fp->fl_sector == NO_SECTOR) {
- 20251 /* Don't retry read_id too often, we need tp soon */
- 20252 if (errors > 0) fp->fl_sector = BASE_SECTOR;
- 20253
- 20254 /* Find out what the current sector is */
- 20255 if (r == OK) r = read_id(fp);
- 20256 }
- 20257
- 20258 /* Look for the next job in ftrans[] */
- 20259 if (fp->fl_sector != NO_SECTOR) {
- 20260 for (;;) {
- 20261 if (fp->fl_sector >= BASE_SECTOR + f_sectors)
- 20262 fp->fl_sector = BASE_SECTOR;
- 20263
- 20264 tp = &ftrans[fp->fl_sector - BASE_SECTOR];
- 20265 if (tp->tr_count > 0) break;
- 20266 fp->fl_sector++;
- 20267 }
- 20268 /* Do not transfer more than f_count bytes. */
- 20269 if (tp->tr_count > f_count) tp->tr_count = f_count;
- 20270 }
- 20271
- 20272 if (r == OK && tp->tr_dma == tmp_phys
- 20273 && f_opcode == DEV_WRITE) {
- 20274 /* Copy the bad user buffer to the DMA buffer. */
- .Ep 270 src/kernel/floppy.c
- 20275 phys_copy(tp->tr_phys, tp->tr_dma,
- 20276 (phys_bytes) tp->tr_count);
- 20277 }
- 20278
- 20279 /* Set up the DMA chip and perform the transfer. */
- 20280 if (r == OK) {
- 20281 dma_setup(tp);
- 20282 r = f_transfer(fp, tp);
- 20283 }
- 20284
- 20285 if (r == OK && tp->tr_dma == tmp_phys
- 20286 && f_opcode == DEV_READ) {
- 20287 /* Copy the DMA buffer to the bad user buffer. */
- 20288 phys_copy(tp->tr_dma, tp->tr_phys,
- 20289 (phys_bytes) tp->tr_count);
- 20290 }
- 20291
- 20292 if (r == OK) break; /* if successful, exit loop */
- 20293
- 20294 /* Don't retry if write protected or too many errors. */
- 20295 if (err_no_retry(r) || ++errors == MAX_ERRORS) {
- 20296 if (fp->fl_sector != 0) tp->tr_iop->io_nbytes = EIO;
- 20297 return(EIO);
- 20298 }
- 20299
- 20300 /* Recalibrate if halfway, but bail out if optional I/O. */
- 20301 if (errors == MAX_ERRORS / 2) {
- 20302 fp->fl_calibration = UNCALIBRATED;
- 20303 if (tp->tr_iop->io_request & OPTIONAL_IO)
- 20304 return(tp->tr_iop->io_nbytes = EIO);
- 20305 }
- 20306 }
- 20307 f_count -= tp->tr_count;
- 20308 tp->tr_iop->io_nbytes -= tp->tr_count;
- 20309 } while (f_count > 0);
- 20310
- 20311 /* Defuse the leftover partial jobs. */
- 20312 defuse();
- 20313
- 20314 return(OK);
- 20315 }
-
-
- 20318 /*===========================================================================*
- 20319 * defuse *
- 20320 *===========================================================================*/
- 20321 PRIVATE void defuse()
- 20322 {
- 20323 /* Invalidate leftover requests in the transfer array. */
- 20324
- 20325 struct trans *tp;
- 20326
- 20327 for (tp = ftrans; tp < ftrans + MAX_SECTORS; tp++) tp->tr_count = 0;
- 20328 f_count = 0;
- 20329 }
-
-
- 20332 /*===========================================================================*
- 20333 * dma_setup *
- 20334 *===========================================================================*/
- .Op 271 src/kernel/floppy.c
- 20335 PRIVATE void dma_setup(tp)
- 20336 struct trans *tp; /* pointer to the transfer struct */
- 20337 {
- 20338 /* The IBM PC can perform DMA operations by using the DMA chip. To use it,
- 20339 * the DMA (Direct Memory Access) chip is loaded with the 20-bit memory address
- 20340 * to be read from or written to, the byte count minus 1, and a read or write
- 20341 * opcode. This routine sets up the DMA chip. Note that the chip is not
- 20342 * capable of doing a DMA across a 64K boundary (e.g., you can't read a
- 20343 * 512-byte block starting at physical address 65520).
- 20344 */
- 20345
- 20346 /* Set up the DMA registers. (The comment on the reset is a bit strong,
- 20347 * it probably only resets the floppy channel.)
- 20348 */
- 20349 out_byte(DMA_INIT, DMA_RESET_VAL); /* reset the dma controller */
- 20350 out_byte(DMA_FLIPFLOP, 0); /* write anything to reset it */
- 20351 out_byte(DMA_MODE, f_opcode == DEV_WRITE ? DMA_WRITE : DMA_READ);
- 20352 out_byte(DMA_ADDR, (int) tp->tr_dma >> 0);
- 20353 out_byte(DMA_ADDR, (int) tp->tr_dma >> 8);
- 20354 out_byte(DMA_TOP, (int) (tp->tr_dma >> 16));
- 20355 out_byte(DMA_COUNT, (tp->tr_count - 1) >> 0);
- 20356 out_byte(DMA_COUNT, (tp->tr_count - 1) >> 8);
- 20357 out_byte(DMA_INIT, 2); /* some sort of enable */
- 20358 }
-
-
- 20361 /*===========================================================================*
- 20362 * start_motor *
- 20363 *===========================================================================*/
- 20364 PRIVATE void start_motor()
- 20365 {
- 20366 /* Control of the floppy disk motors is a big pain. If a motor is off, you
- 20367 * have to turn it on first, which takes 1/2 second. You can't leave it on
- 20368 * all the time, since that would wear out the diskette. However, if you turn
- 20369 * the motor off after each operation, the system performance will be awful.
- 20370 * The compromise used here is to leave it on for a few seconds after each
- 20371 * operation. If a new operation is started in that interval, it need not be
- 20372 * turned on again. If no new operation is started, a timer goes off and the
- 20373 * motor is turned off. I/O port DOR has bits to control each of 4 drives.
- 20374 * The timer cannot go off while we are changing with the bits, since the
- 20375 * clock task cannot run while another (this) task is active, so there is no
- 20376 * need to lock().
- 20377 */
- 20378
- 20379 int motor_bit, running;
- 20380 message mess;
- 20381
- 20382 motor_bit = 1 << f_drive; /* bit mask for this drive */
- 20383 running = motor_status & motor_bit; /* nonzero if this motor is running */
- 20384 motor_goal = motor_status | motor_bit;/* want this drive running too */
- 20385
- 20386 out_byte(DOR, (motor_goal << MOTOR_SHIFT) | ENABLE_INT | f_drive);
- 20387 motor_status = motor_goal;
- 20388
- 20389 /* If the motor was already running, we don't have to wait for it. */
- 20390 if (running) return; /* motor was already running */
- 20391 clock_mess(mtr_setup[d], send_mess); /* motor was not running */
- 20392 receive(CLOCK, &mess); /* wait for clock interrupt */
- 20393 }
-
- .Ep 272 src/kernel/floppy.c
-
- 20396 /*===========================================================================*
- 20397 * stop_motor *
- 20398 *===========================================================================*/
- 20399 PRIVATE void stop_motor()
- 20400 {
- 20401 /* This routine is called by the clock interrupt after several seconds have
- 20402 * elapsed with no floppy disk activity. It checks to see if any drives are
- 20403 * supposed to be turned off, and if so, turns them off.
- 20404 */
- 20405
- 20406 if (motor_goal != motor_status) {
- 20407 out_byte(DOR, (motor_goal << MOTOR_SHIFT) | ENABLE_INT);
- 20408 motor_status = motor_goal;
- 20409 }
- 20410 }
-
-
- 20413 /*===========================================================================*
- 20414 * floppy_stop *
- 20415 *===========================================================================*/
- 20416 PUBLIC void floppy_stop()
- 20417 {
- 20418 /* Stop all activity. */
- 20419
- 20420 motor_goal = 0;
- 20421 stop_motor();
- 20422 }
-
-
- 20425 /*===========================================================================*
- 20426 * seek *
- 20427 *===========================================================================*/
- 20428 PRIVATE int seek(fp)
- 20429 struct floppy *fp; /* pointer to the drive struct */
- 20430 {
- 20431 /* Issue a SEEK command on the indicated drive unless the arm is already
- 20432 * positioned on the correct cylinder.
- 20433 */
- 20434
- 20435 int r;
- 20436 message mess;
- 20437
- 20438 /* Are we already on the correct cylinder? */
- 20439 if (fp->fl_calibration == UNCALIBRATED)
- 20440 if (recalibrate(fp) != OK) return(ERR_SEEK);
- 20441 if (fp->fl_curcyl == fp->fl_hardcyl) return(OK);
- 20442
- 20443 /* No. Wrong cylinder. Issue a SEEK and wait for interrupt. */
- 20444 fdc_out(FDC_SEEK);
- 20445 fdc_out((fp->fl_head << 2) | f_drive);
- 20446 fdc_out(fp->fl_hardcyl);
- 20447 if (need_reset) return(ERR_SEEK); /* if controller is sick, abort seek */
- 20448 if (f_intr_wait() != OK) return(ERR_TIMEOUT);
- 20449
- 20450 /* Interrupt has been received. Check drive status. */
- 20451 fdc_out(FDC_SENSE); /* probe FDC to make it return status */
- 20452 r = fdc_results(); /* get controller status bytes */
- 20453 if (r != OK || (f_results[ST0] & ST0_BITS) != SEEK_ST0
- 20454 || f_results[ST1] != fp->fl_hardcyl) {
- .Op 273 src/kernel/floppy.c
- 20455 /* seek failed, may need a recalibrate */
- 20456 return(ERR_SEEK);
- 20457 }
- 20458 /* give head time to settle on a format, no retrying here! */
- 20459 if (f_device & FORMAT_DEV_BIT) {
- 20460 clock_mess(2, send_mess);
- 20461 receive(CLOCK, &mess);
- 20462 }
- 20463 fp->fl_curcyl = fp->fl_hardcyl;
- 20464 return(OK);
- 20465 }
-
-
- 20468 /*===========================================================================*
- 20469 * f_transfer *
- 20470 *===========================================================================*/
- 20471 PRIVATE int f_transfer(fp, tp)
- 20472 struct floppy *fp; /* pointer to the drive struct */
- 20473 struct trans *tp; /* pointer to the transfer struct */
- 20474 {
- 20475 /* The drive is now on the proper cylinder. Read, write or format 1 block. */
- 20476
- 20477 int r, s;
- 20478
- 20479 /* Never attempt a transfer if the drive is uncalibrated or motor is off. */
- 20480 if (fp->fl_calibration == UNCALIBRATED) return(ERR_TRANSFER);
- 20481 if ((motor_status & (1 << f_drive)) == 0) return(ERR_TRANSFER);
- 20482
- 20483 /* The command is issued by outputting several bytes to the controller chip.
- 20484 */
- 20485 if (f_device & FORMAT_DEV_BIT) {
- 20486 fdc_out(FDC_FORMAT);
- 20487 fdc_out((fp->fl_head << 2) | f_drive);
- 20488 fdc_out(fmt_param.sector_size_code);
- 20489 fdc_out(fmt_param.sectors_per_cylinder);
- 20490 fdc_out(fmt_param.gap_length_for_format);
- 20491 fdc_out(fmt_param.fill_byte_for_format);
- 20492 } else {
- 20493 fdc_out(f_opcode == DEV_WRITE ? FDC_WRITE : FDC_READ);
- 20494 fdc_out((fp->fl_head << 2) | f_drive);
- 20495 fdc_out(fp->fl_cylinder);
- 20496 fdc_out(fp->fl_head);
- 20497 fdc_out(fp->fl_sector);
- 20498 fdc_out(SECTOR_SIZE_CODE);
- 20499 fdc_out(f_sectors);
- 20500 fdc_out(gap[d]); /* sector gap */
- 20501 fdc_out(DTL); /* data length */
- 20502 }
- 20503
- 20504 /* Block, waiting for disk interrupt. */
- 20505 if (need_reset) return(ERR_TRANSFER); /* if controller is sick, abort op */
- 20506
- 20507 if (f_intr_wait() != OK) return(ERR_TIMEOUT);
- 20508
- 20509 /* Get controller status and check for errors. */
- 20510 r = fdc_results();
- 20511 if (r != OK) return(r);
- 20512
- 20513 if (f_results[ST1] & WRITE_PROTECT) {
- 20514 printf("%s: diskette is write protected.n", f_name());
- .Ep 274 src/kernel/floppy.c
- 20515 return(ERR_WR_PROTECT);
- 20516 }
- 20517
- 20518 if ((f_results[ST0] & ST0_BITS) != TRANS_ST0) return(ERR_TRANSFER);
- 20519 if (f_results[ST1] | f_results[ST2]) return(ERR_TRANSFER);
- 20520
- 20521 if (f_device & FORMAT_DEV_BIT) return(OK);
- 20522
- 20523 /* Compare actual numbers of sectors transferred with expected number. */
- 20524 s = (f_results[ST_CYL] - fp->fl_cylinder) * NR_HEADS * f_sectors;
- 20525 s += (f_results[ST_HEAD] - fp->fl_head) * f_sectors;
- 20526 s += (f_results[ST_SEC] - fp->fl_sector);
- 20527 if ((s << SECTOR_SHIFT) != tp->tr_count) return(ERR_TRANSFER);
- 20528
- 20529 /* This sector is next for I/O: */
- 20530 fp->fl_sector = f_results[ST_SEC];
- 20531 return(OK);
- 20532 }
-
-
- 20535 /*==========================================================================*
- 20536 * fdc_results *
- 20537 *==========================================================================*/
- 20538 PRIVATE int fdc_results()
- 20539 {
- 20540 /* Extract results from the controller after an operation, then allow floppy
- 20541 * interrupts again.
- 20542 */
- 20543
- 20544 int result_nr, status;
- 20545 struct milli_state ms;
- 20546
- 20547 /* Extract bytes from FDC until it says it has no more. The loop is
- 20548 * really an outer loop on result_nr and an inner loop on status.
- 20549 */
- 20550 result_nr = 0;
- 20551 milli_start(&ms);
- 20552 do {
- 20553 /* Reading one byte is almost a mirror of fdc_out() - the DIRECTION
- 20554 * bit must be set instead of clear, but the CTL_BUSY bit destroys
- 20555 * the perfection of the mirror.
- 20556 */
- 20557 status = in_byte(FDC_STATUS) & (MASTER | DIRECTION | CTL_BUSY);
- 20558 if (status == (MASTER | DIRECTION | CTL_BUSY)) {
- 20559 if (result_nr >= MAX_RESULTS) break; /* too many results */
- 20560 f_results[result_nr++] = in_byte(FDC_DATA);
- 20561 continue;
- 20562 }
- 20563 if (status == MASTER) { /* all read */
- 20564 enable_irq(FLOPPY_IRQ);
- 20565 return(OK); /* only good exit */
- 20566 }
- 20567 } while (milli_elapsed(&ms) < TIMEOUT);
- 20568 need_reset = TRUE; /* controller chip must be reset */
- 20569 enable_irq(FLOPPY_IRQ);
- 20570 return(ERR_STATUS);
- 20571 }
-
-
- 20574 /*==========================================================================*
- .Op 275 src/kernel/floppy.c
- 20575 * f_handler *
- 20576 *==========================================================================*/
- 20577 PRIVATE int f_handler(irq)
- 20578 int irq;
- 20579 {
- 20580 /* FDC interrupt, send message to floppy task. */
- 20581
- 20582 interrupt(FLOPPY);
- 20583 return 0;
- 20584 }
-
-
- 20587 /*===========================================================================*
- 20588 * fdc_out *
- 20589 *===========================================================================*/
- 20590 PRIVATE void fdc_out(val)
- 20591 int val; /* write this byte to floppy disk controller */
- 20592 {
- 20593 /* Output a byte to the controller. This is not entirely trivial, since you
- 20594 * can only write to it when it is listening, and it decides when to listen.
- 20595 * If the controller refuses to listen, the FDC chip is given a hard reset.
- 20596 */
- 20597
- 20598 struct milli_state ms;
- 20599
- 20600 if (need_reset) return; /* if controller is not listening, return */
- 20601
- 20602 /* It may take several tries to get the FDC to accept a command. */
- 20603 milli_start(&ms);
- 20604 while ((in_byte(FDC_STATUS) & (MASTER | DIRECTION)) != (MASTER | 0)) {
- 20605 if (milli_elapsed(&ms) >= TIMEOUT) {
- 20606 /* Controller is not listening. Hit it over the head. */
- 20607 need_reset = TRUE;
- 20608 return;
- 20609 }
- 20610 }
- 20611 out_byte(FDC_DATA, val);
- 20612 }
-
-
- 20615 /*===========================================================================*
- 20616 * recalibrate *
- 20617 *===========================================================================*/
- 20618 PRIVATE int recalibrate(fp)
- 20619 struct floppy *fp; /* pointer tot he drive struct */
- 20620 {
- 20621 /* The floppy disk controller has no way of determining its absolute arm
- 20622 * position (cylinder). Instead, it steps the arm a cylinder at a time and
- 20623 * keeps track of where it thinks it is (in software). However, after a
- 20624 * SEEK, the hardware reads information from the diskette telling where the
- 20625 * arm actually is. If the arm is in the wrong place, a recalibration is done,
- 20626 * which forces the arm to cylinder 0. This way the controller can get back
- 20627 * into sync with reality.
- 20628 */
- 20629
- 20630 int r;
- 20631
- 20632 /* Issue the RECALIBRATE command and wait for the interrupt. */
- 20633 start_motor(); /* can't recalibrate with motor off */
- 20634 fdc_out(FDC_RECALIBRATE); /* tell drive to recalibrate itself */
- .Ep 276 src/kernel/floppy.c
- 20635 fdc_out(f_drive); /* specify drive */
- 20636 if (need_reset) return(ERR_SEEK); /* don't wait if controller is sick */
- 20637 if (f_intr_wait() != OK) return(ERR_TIMEOUT);
- 20638
- 20639 /* Determine if the recalibration succeeded. */
- 20640 fdc_out(FDC_SENSE); /* issue SENSE command to request results */
- 20641 r = fdc_results(); /* get results of the FDC_RECALIBRATE command*/
- 20642 fp->fl_curcyl = NO_CYL; /* force a SEEK next time */
- 20643 if (r != OK || /* controller would not respond */
- 20644 (f_results[ST0] & ST0_BITS) != SEEK_ST0 || f_results[ST_PCN] != 0) {
- 20645 /* Recalibration failed. FDC must be reset. */
- 20646 need_reset = TRUE;
- 20647 return(ERR_RECALIBRATE);
- 20648 } else {
- 20649 /* Recalibration succeeded. */
- 20650 fp->fl_calibration = CALIBRATED;
- 20651 return(OK);
- 20652 }
- 20653 }
-
-
- 20656 /*===========================================================================*
- 20657 * f_reset *
- 20658 *===========================================================================*/
- 20659 PRIVATE void f_reset()
- 20660 {
- 20661 /* Issue a reset to the controller. This is done after any catastrophe,
- 20662 * like the controller refusing to respond.
- 20663 */
- 20664
- 20665 int i;
- 20666 message mess;
- 20667
- 20668 /* Disable interrupts and strobe reset bit low. */
- 20669 need_reset = FALSE;
- 20670
- 20671 /* It is not clear why the next lock is needed. Writing 0 to DOR causes
- 20672 * interrupt, while the PC documentation says turning bit 8 off disables
- 20673 * interrupts. Without the lock:
- 20674 * 1) the interrupt handler sets the floppy mask bit in the 8259.
- 20675 * 2) writing ENABLE_INT to DOR causes the FDC to assert the interrupt
- 20676 * line again, but the mask stops the cpu being interrupted.
- 20677 * 3) the sense interrupt clears the interrupt (not clear which one).
- 20678 * and for some reason the reset does not work.
- 20679 */
- 20680 lock();
- 20681 motor_status = 0;
- 20682 motor_goal = 0;
- 20683 out_byte(DOR, 0); /* strobe reset bit low */
- 20684 out_byte(DOR, ENABLE_INT); /* strobe it high again */
- 20685 unlock();
- 20686 receive(HARDWARE, &mess); /* collect the RESET interrupt */
- 20687
- 20688 /* The controller supports 4 drives and returns a result for each of them.
- 20689 * Collect all the results now. The old version only collected the first
- 20690 * result. This happens to work for 2 drives, but it doesn't work for 3
- 20691 * or more drives, at least with only drives 0 and 2 actually connected
- 20692 * (the controller generates an extra interrupt for the middle drive when
- 20693 * drive 2 is accessed and the driver panics).
- 20694 *
- .Op 277 src/kernel/floppy.c
- 20695 * It would be better to keep collecting results until there are no more.
- 20696 * For this, fdc_results needs to return the number of results (instead
- 20697 * of OK) when it succeeds.
- 20698 */
- 20699 for (i = 0; i < 4; i++) {
- 20700 fdc_out(FDC_SENSE); /* probe FDC to make it return status */
- 20701 (void) fdc_results(); /* flush controller */
- 20702 }
- 20703 for (i = 0; i < NR_DRIVES; i++) /* clear each drive */
- 20704 floppy[i].fl_calibration = UNCALIBRATED;
- 20705
- 20706 /* The current timing parameters must be specified again. */
- 20707 current_spec1 = 0;
- 20708 }
-
-
- 20711 /*===========================================================================*
- 20712 * send_mess *
- 20713 *===========================================================================*/
- 20714 PRIVATE void send_mess()
- 20715 {
- 20716 /* This routine is called when the clock task has timed out on motor startup.*/
- 20717
- 20718 message mess;
- 20719
- 20720 send(FLOPPY, &mess);
- 20721 }
-
-
- 20724 /*===========================================================================*
- 20725 * f_intr_wait *
- 20726 *===========================================================================*/
- 20727 PRIVATE int f_intr_wait()
- 20728 {
- 20729 /* Wait for an interrupt, but not forever. The FDC may have all the time of
- 20730 * the world, but we humans do not.
- 20731 */
- 20732 message mess;
- 20733
- 20734 f_busy = BSY_IO;
- 20735 clock_mess(WAKEUP, f_timeout);
- 20736 receive(HARDWARE, &mess);
- 20737
- 20738 if (f_busy == BSY_WAKEN) {
- 20739 /* No interrupt from the FDC, this means that there is probably no
- 20740 * floppy in the drive. Get the FDC down to earth and return error.
- 20741 */
- 20742 f_reset();
- 20743 return(ERR_TIMEOUT);
- 20744 }
- 20745 f_busy = BSY_IDLE;
- 20746 return(OK);
- 20747 }
-
-
- 20750 /*===========================================================================*
- 20751 * f_timeout *
- 20752 *===========================================================================*/
- 20753 PRIVATE void f_timeout()
- 20754 {
- .Ep 278 src/kernel/floppy.c
- 20755 /* When it takes too long for the FDC to get an interrupt (no floppy in the
- 20756 * drive), this routine is called. It sets a flag and fakes a hardware
- 20757 * interrupt.
- 20758 */
- 20759 if (f_busy == BSY_IO) {
- 20760 f_busy = BSY_WAKEN;
- 20761 interrupt(FLOPPY);
- 20762 }
- 20763 }
-
-
- 20766 /*==========================================================================*
- 20767 * read_id *
- 20768 *==========================================================================*/
- 20769 PRIVATE int read_id(fp)
- 20770 struct floppy *fp; /* pointer to the drive struct */
- 20771 {
- 20772 /* Determine current cylinder and sector. */
- 20773
- 20774 int result;
- 20775
- 20776 /* Never attempt a read id if the drive is uncalibrated or motor is off. */
- 20777 if (fp->fl_calibration == UNCALIBRATED) return(ERR_READ_ID);
- 20778 if ((motor_status & (1 << f_drive)) == 0) return(ERR_READ_ID);
- 20779
- 20780 /* The command is issued by outputting 2 bytes to the controller chip. */
- 20781 fdc_out(FDC_READ_ID); /* issue the read id command */
- 20782 fdc_out( (f_fp->fl_head << 2) | f_drive);
- 20783
- 20784 /* Block, waiting for disk interrupt. */
- 20785 if (need_reset) return(ERR_READ_ID); /* if controller is sick, abort op */
- 20786
- 20787 if (f_intr_wait() != OK) return(ERR_TIMEOUT);
- 20788
- 20789 /* Get controller status and check for errors. */
- 20790 result = fdc_results();
- 20791 if (result != OK) return(result);
- 20792
- 20793 if ((f_results[ST0] & ST0_BITS) != TRANS_ST0) return(ERR_READ_ID);
- 20794 if (f_results[ST1] | f_results[ST2]) return(ERR_READ_ID);
- 20795
- 20796 /* The next sector is next for I/O: */
- 20797 f_fp->fl_sector = f_results[ST_SEC] + 1;
- 20798 return(OK);
- 20799 }
-
-
- 20802 /*==========================================================================*
- 20803 * f_do_open *
- 20804 *==========================================================================*/
- 20805 PRIVATE int f_do_open(dp, m_ptr)
- 20806 struct driver *dp;
- 20807 message *m_ptr; /* pointer to open message */
- 20808 {
- 20809 /* Handle an open on a floppy. Determine diskette type if need be. */
- 20810
- 20811 int dtype;
- 20812 struct test_order *top;
- 20813
- 20814 /* Decode the message parameters. */
- .Op 279 src/kernel/floppy.c
- 20815 if (f_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
- 20816
- 20817 dtype = f_device & DEV_TYPE_BITS; /* get density from minor dev */
- 20818 if (dtype >= MINOR_fd0a) dtype = 0;
- 20819 if (dtype != 0) {
- 20820 /* All types except 0 indicate a specific drive/medium combination.*/
- 20821 dtype = (dtype >> DEV_TYPE_SHIFT) - 1;
- 20822 if (dtype >= NT) return(ENXIO);
- 20823 f_fp->fl_density = dtype;
- 20824 f_fp->fl_geom.dv_size = (long) nr_blocks[dtype] << SECTOR_SHIFT;
- 20825 return(OK);
- 20826 }
- 20827 if (f_device & FORMAT_DEV_BIT) return(EIO); /* Can't format /dev/fdx */
- 20828
- 20829 /* No need to test if the motor is still running. */
- 20830 if (motor_status & (1 << f_drive)) return(OK);
- 20831
- 20832 /* The device opened is /dev/fdx. Experimentally determine drive/medium.
- 20833 * First check fl_density. If it is not NO_DENS, the drive has been used
- 20834 * before and the value of fl_density tells what was found last time. Try
- 20835 * that first.
- 20836 */
- 20837 if (f_fp->fl_density != NO_DENS && test_read(f_fp->fl_density) == OK)
- 20838 return(OK);
- 20839
- 20840 /* Either drive type is unknown or a different diskette is now present.
- 20841 * Use test_order to try them one by one.
- 20842 */
- 20843 for (top = &test_order[0]; top < &test_order[NT-1]; top++) {
- 20844 dtype = top->t_density;
- 20845
- 20846 /* Skip densities that have been proven to be impossible */
- 20847 if (!(f_fp->fl_class & (1 << dtype))) continue;
- 20848
- 20849 if (test_read(dtype) == OK) {
- 20850 /* The test succeeded, use this knowledge to limit the
- 20851 * drive class to match the density just read.
- 20852 */
- 20853 f_fp->fl_class &= top->t_class;
- 20854 return(OK);
- 20855 }
- 20856 /* Test failed, wrong density or did it time out? */
- 20857 if (f_busy == BSY_WAKEN) break;
- 20858 }
- 20859 f_fp->fl_density = NO_DENS;
- 20860 return(EIO); /* nothing worked */
- 20861 }
-
-
- 20864 /*==========================================================================*
- 20865 * test_read *
- 20866 *==========================================================================*/
- 20867 PRIVATE int test_read(density)
- 20868 int density;
- 20869 {
- 20870 /* Try to read the highest numbered sector on cylinder 2. Not all floppy
- 20871 * types have as many sectors per track, and trying cylinder 2 finds the
- 20872 * ones that need double stepping.
- 20873 */
- 20874
- .Ep 280 src/kernel/floppy.c
- 20875 message m;
- 20876 int r, device;
- 20877
- 20878 f_fp->fl_density = density;
- 20879 device = ((density + 1) << DEV_TYPE_SHIFT) + f_drive;
- 20880 f_fp->fl_geom.dv_size = (long) nr_blocks[density] << SECTOR_SHIFT;
- 20881 m.m_type = DEV_READ;
- 20882 m.DEVICE = device;
- 20883 m.PROC_NR = FLOPPY;
- 20884 m.COUNT = SECTOR_SIZE;
- 20885 m.POSITION = (long) test_sector[density] * SECTOR_SIZE;
- 20886 m.ADDRESS = (char *) tmp_buf;
- 20887 r = do_rdwt(&f_dtab, &m);
- 20888 if (r != SECTOR_SIZE) return(EIO);
- 20889
- 20890 partition(&f_dtab, f_drive, P_FLOPPY);
- 20891 return(OK);
- 20892 }
-
-
- 20895 /*============================================================================*
- 20896 * f_geometry *
- 20897 *============================================================================*/
- 20898 PRIVATE void f_geometry(entry)
- 20899 struct partition *entry;
- 20900 {
- 20901 entry->cylinders = nr_blocks[d] / (NR_HEADS * f_sectors);
- 20902 entry->heads = NR_HEADS;
- 20903 entry->sectors = f_sectors;
- 20904 }
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/i8259.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 21000 /* This file contains routines for initializing the 8259 interrupt controller:
- 21001 * get_irq_handler: address of handler for a given interrupt
- 21002 * put_irq_handler: register an interrupt handler
- 21003 * intr_init: initialize the interrupt controller(s)
- 21004 */
- 21005
- 21006 #include "kernel.h"
- 21007
- 21008 #define ICW1_AT 0x11 /* edge triggered, cascade, need ICW4 */
- 21009 #define ICW1_PC 0x13 /* edge triggered, no cascade, need ICW4 */
- 21010 #define ICW1_PS 0x19 /* level triggered, cascade, need ICW4 */
- 21011 #define ICW4_AT 0x01 /* not SFNM, not buffered, normal EOI, 8086 */
- 21012 #define ICW4_PC 0x09 /* not SFNM, buffered, normal EOI, 8086 */
- 21013
- 21014 FORWARD _PROTOTYPE( int spurious_irq, (int irq) );
- 21015
- 21016 #if _WORD_SIZE == 2
- 21017 typedef _PROTOTYPE( void (*vecaddr_t), (void) );
- 21018
- 21019 FORWARD _PROTOTYPE( void set_vec, (int vec_nr, vecaddr_t addr) );
- .Op 281 src/kernel/i8259.c
- 21020
- 21021 PRIVATE vecaddr_t int_vec[] = {
- 21022 int00, int01, int02, int03, int04, int05, int06, int07,
- 21023 };
- 21024
- 21025 PRIVATE vecaddr_t irq_vec[] = {
- 21026 hwint00, hwint01, hwint02, hwint03, hwint04, hwint05, hwint06, hwint07,
- 21027 hwint08, hwint09, hwint10, hwint11, hwint12, hwint13, hwint14, hwint15,
- 21028 };
- 21029 #else
- 21030 #define set_vec(nr, addr) ((void)0)
- 21031 #endif
- 21032
- 21033
- 21034 /*==========================================================================*
- 21035 * intr_init *
- 21036 *==========================================================================*/
- 21037 PUBLIC void intr_init(mine)
- 21038 int mine;
- 21039 {
- 21040 /* Initialize the 8259s, finishing with all interrupts disabled. This is
- 21041 * only done in protected mode, in real mode we don't touch the 8259s, but
- 21042 * use the BIOS locations instead. The flag "mine" is set if the 8259s are
- 21043 * to be programmed for Minix, or to be reset to what the BIOS expects.
- 21044 */
- 21045
- 21046 int i;
- 21047
- 21048 lock();
- 21049 if (protected_mode) {
- 21050 /* The AT and newer PS/2 have two interrupt controllers, one master,
- 21051 * one slaved at IRQ 2. (We don't have to deal with the PC that
- 21052 * has just one controller, because it must run in real mode.)
- 21053 */
- 21054 out_byte(INT_CTL, ps_mca ? ICW1_PS : ICW1_AT);
- 21055 out_byte(INT_CTLMASK, mine ? IRQ0_VECTOR : BIOS_IRQ0_VEC);
- 21056 /* ICW2 for master */
- 21057 out_byte(INT_CTLMASK, (1 << CASCADE_IRQ)); /* ICW3 tells slaves */
- 21058 out_byte(INT_CTLMASK, ICW4_AT);
- 21059 out_byte(INT_CTLMASK, ~(1 << CASCADE_IRQ)); /* IRQ 0-7 mask */
- 21060 out_byte(INT2_CTL, ps_mca ? ICW1_PS : ICW1_AT);
- 21061 out_byte(INT2_CTLMASK, mine ? IRQ8_VECTOR : BIOS_IRQ8_VEC);
- 21062 /* ICW2 for slave */
- 21063 out_byte(INT2_CTLMASK, CASCADE_IRQ); /* ICW3 is slave nr */
- 21064 out_byte(INT2_CTLMASK, ICW4_AT);
- 21065 out_byte(INT2_CTLMASK, ~0); /* IRQ 8-15 mask */
- 21066 } else {
- 21067 /* Use the BIOS interrupt vectors in real mode. We only reprogram the
- 21068 * exceptions here, the interrupt vectors are reprogrammed on demand.
- 21069 * SYS_VECTOR is the Minix system call for message passing.
- 21070 */
- 21071 for (i = 0; i < 8; i++) set_vec(i, int_vec[i]);
- 21072 set_vec(SYS_VECTOR, s_call);
- 21073 }
- 21074
- 21075 /* Initialize the table of interrupt handlers. */
- 21076 for (i = 0; i < NR_IRQ_VECTORS; i++) irq_table[i] = spurious_irq;
- 21077 }
-
- 21079 /*=========================================================================*
- .Ep 282 src/kernel/i8259.c
- 21080 * spurious_irq *
- 21081 *=========================================================================*/
- 21082 PRIVATE int spurious_irq(irq)
- 21083 int irq;
- 21084 {
- 21085 /* Default interrupt handler. It complains a lot. */
- 21086
- 21087 if (irq < 0 || irq >= NR_IRQ_VECTORS)
- 21088 panic("invalid call to spurious_irq", irq);
- 21089
- 21090 printf("spurious irq %dn", irq);
- 21091
- 21092 return 1; /* Reenable interrupt */
- 21093 }
-
- 21095 /*=========================================================================*
- 21096 * put_irq_handler *
- 21097 *=========================================================================*/
- 21098 PUBLIC void put_irq_handler(irq, handler)
- 21099 int irq;
- 21100 irq_handler_t handler;
- 21101 {
- 21102 /* Register an interrupt handler. */
- 21103
- 21104 if (irq < 0 || irq >= NR_IRQ_VECTORS)
- 21105 panic("invalid call to put_irq_handler", irq);
- 21106
- 21107 if (irq_table[irq] == handler)
- 21108 return; /* extra initialization */
- 21109
- 21110 if (irq_table[irq] != spurious_irq)
- 21111 panic("attempt to register second irq handler for irq", irq);
- 21112
- 21113 disable_irq(irq);
- 21114 if (!protected_mode) set_vec(BIOS_VECTOR(irq), irq_vec[irq]);
- 21115 irq_table[irq]= handler;
- 21116 irq_use |= 1 << irq;
- 21117 }
-
-
- 21120 #if _WORD_SIZE == 2
- 21121 /*===========================================================================*
- 21122 * set_vec *
- 21123 *===========================================================================*/
- 21124 PRIVATE void set_vec(vec_nr, addr)
- 21125 int vec_nr; /* which vector */
- 21126 vecaddr_t addr; /* where to start */
- 21127 {
- 21128 /* Set up a real mode interrupt vector. */
- 21129
- 21130 u16_t vec[2];
- 21131
- 21132 /* Build the vector in the array 'vec'. */
- 21133 vec[0] = (u16_t) addr;
- 21134 vec[1] = (u16_t) physb_to_hclick(code_base);
- 21135
- 21136 /* Copy the vector into place. */
- 21137 phys_copy(vir2phys(vec), vec_nr * 4L, 4L);
- 21138 }
- 21139 #endif /* _WORD_SIZE == 2 */
- .Op 283 src/kernel/keyboard.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/keyboard.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 21200 /* Keyboard driver for PC's and AT's.
- 21201 *
- 21202 * Changed by Marcus Hampel (04/02/1994)
- 21203 * - Loadable keymaps
- 21204 */
- 21205
- 21206 #include "kernel.h"
- 21207 #include <termios.h>
- 21208 #include <signal.h>
- 21209 #include <unistd.h>
- 21210 #include <minix/callnr.h>
- 21211 #include <minix/com.h>
- 21212 #include <minix/keymap.h>
- 21213 #include "tty.h"
- 21214 #include "keymaps/us-std.src"
- 21215
- 21216 /* Standard and AT keyboard. (PS/2 MCA implies AT throughout.) */
- 21217 #define KEYBD 0x60 /* I/O port for keyboard data */
- 21218
- 21219 /* AT keyboard. */
- 21220 #define KB_COMMAND 0x64 /* I/O port for commands on AT */
- 21221 #define KB_GATE_A20 0x02 /* bit in output port to enable A20 line */
- 21222 #define KB_PULSE_OUTPUT 0xF0 /* base for commands to pulse output port */
- 21223 #define KB_RESET 0x01 /* bit in output port to reset CPU */
- 21224 #define KB_STATUS 0x64 /* I/O port for status on AT */
- 21225 #define KB_ACK 0xFA /* keyboard ack response */
- 21226 #define KB_BUSY 0x02 /* status bit set when KEYBD port ready */
- 21227 #define LED_CODE 0xED /* command to keyboard to set LEDs */
- 21228 #define MAX_KB_ACK_RETRIES 0x1000 /* max #times to wait for kb ack */
- 21229 #define MAX_KB_BUSY_RETRIES 0x1000 /* max #times to loop while kb busy */
- 21230 #define KBIT 0x80 /* bit used to ack characters to keyboard */
- 21231
- 21232 /* Miscellaneous. */
- 21233 #define ESC_SCAN 1 /* Reboot key when panicking */
- 21234 #define SLASH_SCAN 53 /* to recognize numeric slash */
- 21235 #define HOME_SCAN 71 /* first key on the numeric keypad */
- 21236 #define DEL_SCAN 83 /* DEL for use in CTRL-ALT-DEL reboot */
- 21237 #define CONSOLE 0 /* line number for console */
- 21238 #define MEMCHECK_ADR 0x472 /* address to stop memory check after reboot */
- 21239 #define MEMCHECK_MAG 0x1234 /* magic number to stop memory check */
- 21240
- 21241 #define kb_addr() (&kb_lines[0]) /* there is only one keyboard */
- 21242 #define KB_IN_BYTES 32 /* size of keyboard input buffer */
- 21243
- 21244 PRIVATE int alt1; /* left alt key state */
- 21245 PRIVATE int alt2; /* right alt key state */
- 21246 PRIVATE int capslock; /* caps lock key state */
- 21247 PRIVATE int esc; /* escape scan code detected? */
- 21248 PRIVATE int control; /* control key state */
- 21249 PRIVATE int caps_off; /* 1 = normal position, 0 = depressed */
- 21250 PRIVATE int numlock; /* number lock key state */
- 21251 PRIVATE int num_off; /* 1 = normal position, 0 = depressed */
- 21252 PRIVATE int slock; /* scroll lock key state */
- 21253 PRIVATE int slock_off; /* 1 = normal position, 0 = depressed */
- 21254 PRIVATE int shift; /* shift key state */
- .Ep 284 src/kernel/keyboard.c
- 21255
- 21256 PRIVATE char numpad_map[] =
- 21257 {'H', 'Y', 'A', 'B', 'D', 'C', 'V', 'U', 'G', 'S', 'T', '@'};
- 21258
- 21259 /* Keyboard structure, 1 per console. */
- 21260 struct kb_s {
- 21261 char *ihead; /* next free spot in input buffer */
- 21262 char *itail; /* scan code to return to TTY */
- 21263 int icount; /* # codes in buffer */
- 21264 char ibuf[KB_IN_BYTES]; /* input buffer */
- 21265 };
- 21266
- 21267 PRIVATE struct kb_s kb_lines[NR_CONS];
- 21268
- 21269 FORWARD _PROTOTYPE( int kb_ack, (void) );
- 21270 FORWARD _PROTOTYPE( int kb_wait, (void) );
- 21271 FORWARD _PROTOTYPE( int func_key, (int scode) );
- 21272 FORWARD _PROTOTYPE( int scan_keyboard, (void) );
- 21273 FORWARD _PROTOTYPE( unsigned make_break, (int scode) );
- 21274 FORWARD _PROTOTYPE( void set_leds, (void) );
- 21275 FORWARD _PROTOTYPE( int kbd_hw_int, (int irq) );
- 21276 FORWARD _PROTOTYPE( void kb_read, (struct tty *tp) );
- 21277 FORWARD _PROTOTYPE( unsigned map_key, (int scode) );
- 21278
- 21279
- 21280 /*===========================================================================*
- 21281 * map_key0 *
- 21282 *===========================================================================*/
- 21283 /* Map a scan code to an ASCII code ignoring modifiers. */
- 21284 #define map_key0(scode)
- 21285 ((unsigned) keymap[(scode) * MAP_COLS])
- 21286
- 21287
- 21288 /*===========================================================================*
- 21289 * map_key *
- 21290 *===========================================================================*/
- 21291 PRIVATE unsigned map_key(scode)
- 21292 int scode;
- 21293 {
- 21294 /* Map a scan code to an ASCII code. */
- 21295
- 21296 int caps, column;
- 21297 u16_t *keyrow;
- 21298
- 21299 if (scode == SLASH_SCAN && esc) return '/'; /* don't map numeric slash */
- 21300
- 21301 keyrow = &keymap[scode * MAP_COLS];
- 21302
- 21303 caps = shift;
- 21304 if (numlock && HOME_SCAN <= scode && scode <= DEL_SCAN) caps = !caps;
- 21305 if (capslock && (keyrow[0] & HASCAPS)) caps = !caps;
- 21306
- 21307 if (alt1 || alt2) {
- 21308 column = 2;
- 21309 if (control || alt2) column = 3; /* Ctrl + Alt1 == Alt2 */
- 21310 if (caps) column = 4;
- 21311 } else {
- 21312 column = 0;
- 21313 if (caps) column = 1;
- 21314 if (control) column = 5;
- .Op 285 src/kernel/keyboard.c
- 21315 }
- 21316 return keyrow[column] & ~HASCAPS;
- 21317 }
-
-
- 21320 /*===========================================================================*
- 21321 * kbd_hw_int *
- 21322 *===========================================================================*/
- 21323 PRIVATE int kbd_hw_int(irq)
- 21324 int irq;
- 21325 {
- 21326 /* A keyboard interrupt has occurred. Process it. */
- 21327
- 21328 int code;
- 21329 unsigned km;
- 21330 register struct kb_s *kb;
- 21331
- 21332 /* Fetch the character from the keyboard hardware and acknowledge it. */
- 21333 code = scan_keyboard();
- 21334
- 21335 /* The IBM keyboard interrupts twice per key, once when depressed, once when
- 21336 * released. Filter out the latter, ignoring all but the shift-type keys.
- 21337 * The shift-type keys 29, 42, 54, 56, 58, and 69 must be processed normally.
- 21338 */
- 21339
- 21340 if (code & 0200) {
- 21341 /* A key has been released (high bit is set). */
- 21342 km = map_key0(code & 0177);
- 21343 if (km != CTRL && km != SHIFT && km != ALT && km != CALOCK
- 21344 && km != NLOCK && km != SLOCK && km != EXTKEY)
- 21345 return 1;
- 21346 }
- 21347
- 21348 /* Store the character in memory so the task can get at it later. */
- 21349 kb = kb_addr();
- 21350 if (kb->icount < KB_IN_BYTES) {
- 21351 *kb->ihead++ = code;
- 21352 if (kb->ihead == kb->ibuf + KB_IN_BYTES) kb->ihead = kb->ibuf;
- 21353 kb->icount++;
- 21354 tty_table[current].tty_events = 1;
- 21355 force_timeout();
- 21356 }
- 21357 /* Else it doesn't fit - discard it. */
- 21358 return 1; /* Reenable keyboard interrupt */
- 21359 }
-
-
- 21362 /*==========================================================================*
- 21363 * kb_read *
- 21364 *==========================================================================*/
- 21365 PRIVATE void kb_read(tp)
- 21366 tty_t *tp;
- 21367 {
- 21368 /* Process characters from the circular keyboard buffer. */
- 21369
- 21370 struct kb_s *kb;
- 21371 char buf[3];
- 21372 int scode;
- 21373 unsigned ch;
- 21374
- .Ep 286 src/kernel/keyboard.c
- 21375 kb = kb_addr();
- 21376 tp = &tty_table[current]; /* always use the current console */
- 21377
- 21378 while (kb->icount > 0) {
- 21379 scode = *kb->itail++; /* take one key scan code */
- 21380 if (kb->itail == kb->ibuf + KB_IN_BYTES) kb->itail = kb->ibuf;
- 21381 lock();
- 21382 kb->icount--;
- 21383 unlock();
- 21384
- 21385 /* Function keys are being used for debug dumps. */
- 21386 if (func_key(scode)) continue;
- 21387
- 21388 /* Perform make/break processing. */
- 21389 ch = make_break(scode);
- 21390
- 21391 if (ch <= 0xFF) {
- 21392 /* A normal character. */
- 21393 buf[0] = ch;
- 21394 (void) in_process(tp, buf, 1);
- 21395 } else
- 21396 if (HOME <= ch && ch <= INSRT) {
- 21397 /* An ASCII escape sequence generated by the numeric pad. */
- 21398 buf[0] = ESC;
- 21399 buf[1] = '[';
- 21400 buf[2] = numpad_map[ch - HOME];
- 21401 (void) in_process(tp, buf, 3);
- 21402 } else
- 21403 if (ch == ALEFT) {
- 21404 /* Choose lower numbered console as current console. */
- 21405 select_console(current - 1);
- 21406 } else
- 21407 if (ch == ARIGHT) {
- 21408 /* Choose higher numbered console as current console. */
- 21409 select_console(current + 1);
- 21410 } else
- 21411 if (AF1 <= ch && ch <= AF12) {
- 21412 /* Alt-F1 is console, Alt-F2 is ttyc1, etc. */
- 21413 select_console(ch - AF1);
- 21414 }
- 21415 }
- 21416 }
-
-
- 21419 /*===========================================================================*
- 21420 * make_break *
- 21421 *===========================================================================*/
- 21422 PRIVATE unsigned make_break(scode)
- 21423 int scode; /* scan code of key just struck or released */
- 21424 {
- 21425 /* This routine can handle keyboards that interrupt only on key depression,
- 21426 * as well as keyboards that interrupt on key depression and key release.
- 21427 * For efficiency, the interrupt routine filters out most key releases.
- 21428 */
- 21429 int ch, make;
- 21430 static int CAD_count = 0;
- 21431
- 21432 /* Check for CTRL-ALT-DEL, and if found, halt the computer. This would
- 21433 * be better done in keyboard() in case TTY is hung, except control and
- 21434 * alt are set in the high level code.
- .Op 287 src/kernel/keyboard.c
- 21435 */
- 21436 if (control && (alt1 || alt2) && scode == DEL_SCAN)
- 21437 {
- 21438 if (++CAD_count == 3) wreboot(RBT_HALT);
- 21439 cause_sig(INIT_PROC_NR, SIGABRT);
- 21440 return -1;
- 21441 }
- 21442
- 21443 /* High-order bit set on key release. */
- 21444 make = (scode & 0200 ? 0 : 1); /* 0 = release, 1 = press */
- 21445
- 21446 ch = map_key(scode & 0177); /* map to ASCII */
- 21447
- 21448 switch (ch) {
- 21449 case CTRL:
- 21450 control = make;
- 21451 ch = -1;
- 21452 break;
- 21453 case SHIFT:
- 21454 shift = make;
- 21455 ch = -1;
- 21456 break;
- 21457 case ALT:
- 21458 if (make) {
- 21459 if (esc) alt2 = 1; else alt1 = 1;
- 21460 } else {
- 21461 alt1 = alt2 = 0;
- 21462 }
- 21463 ch = -1;
- 21464 break;
- 21465 case CALOCK:
- 21466 if (make && caps_off) {
- 21467 capslock = 1 - capslock;
- 21468 set_leds();
- 21469 }
- 21470 caps_off = 1 - make;
- 21471 ch = -1;
- 21472 break;
- 21473 case NLOCK:
- 21474 if (make && num_off) {
- 21475 numlock = 1 - numlock;
- 21476 set_leds();
- 21477 }
- 21478 num_off = 1 - make;
- 21479 ch = -1;
- 21480 break;
- 21481 case SLOCK:
- 21482 if (make & slock_off) {
- 21483 slock = 1 - slock;
- 21484 set_leds();
- 21485 }
- 21486 slock_off = 1 - make;
- 21487 ch = -1;
- 21488 break;
- 21489 case EXTKEY:
- 21490 esc = 1;
- 21491 return(-1);
- 21492 default:
- 21493 if (!make) ch = -1;
- 21494 }
- .Ep 288 src/kernel/keyboard.c
- 21495 esc = 0;
- 21496 return(ch);
- 21497 }
-
-
- 21500 /*===========================================================================*
- 21501 * set_leds *
- 21502 *===========================================================================*/
- 21503 PRIVATE void set_leds()
- 21504 {
- 21505 /* Set the LEDs on the caps lock and num lock keys */
- 21506
- 21507 unsigned leds;
- 21508
- 21509 if (!pc_at) return; /* PC/XT doesn't have LEDs */
- 21510
- 21511 /* encode LED bits */
- 21512 leds = (slock << 0) | (numlock << 1) | (capslock << 2);
- 21513
- 21514 kb_wait(); /* wait for buffer empty */
- 21515 out_byte(KEYBD, LED_CODE); /* prepare keyboard to accept LED values */
- 21516 kb_ack(); /* wait for ack response */
- 21517
- 21518 kb_wait(); /* wait for buffer empty */
- 21519 out_byte(KEYBD, leds); /* give keyboard LED values */
- 21520 kb_ack(); /* wait for ack response */
- 21521 }
-
-
- 21524 /*==========================================================================*
- 21525 * kb_wait *
- 21526 *==========================================================================*/
- 21527 PRIVATE int kb_wait()
- 21528 {
- 21529 /* Wait until the controller is ready; return zero if this times out. */
- 21530
- 21531 int retries;
- 21532
- 21533 retries = MAX_KB_BUSY_RETRIES + 1;
- 21534 while (--retries != 0 && in_byte(KB_STATUS) & KB_BUSY)
- 21535 ; /* wait until not busy */
- 21536 return(retries); /* nonzero if ready */
- 21537 }
-
-
- 21540 /*==========================================================================*
- 21541 * kb_ack *
- 21542 *==========================================================================*/
- 21543 PRIVATE int kb_ack()
- 21544 {
- 21545 /* Wait until kbd acknowledges last command; return zero if this times out. */
- 21546
- 21547 int retries;
- 21548
- 21549 retries = MAX_KB_ACK_RETRIES + 1;
- 21550 while (--retries != 0 && in_byte(KEYBD) != KB_ACK)
- 21551 ; /* wait for ack */
- 21552 return(retries); /* nonzero if ack received */
- 21553 }
-
- .Op 289 src/kernel/keyboard.c
- 21555 /*===========================================================================*
- 21556 * kb_init *
- 21557 *===========================================================================*/
- 21558 PUBLIC void kb_init(tp)
- 21559 tty_t *tp;
- 21560 {
- 21561 /* Initialize the keyboard driver. */
- 21562
- 21563 register struct kb_s *kb;
- 21564
- 21565 /* Input function. */
- 21566 tp->tty_devread = kb_read;
- 21567
- 21568 kb = kb_addr();
- 21569
- 21570 /* Set up input queue. */
- 21571 kb->ihead = kb->itail = kb->ibuf;
- 21572
- 21573 /* Set initial values. */
- 21574 caps_off = 1;
- 21575 num_off = 1;
- 21576 slock_off = 1;
- 21577 esc = 0;
- 21578
- 21579 set_leds(); /* turn off numlock led */
- 21580
- 21581 scan_keyboard(); /* stop lockup from leftover keystroke */
- 21582
- 21583 put_irq_handler(KEYBOARD_IRQ, kbd_hw_int); /* set the interrupt handler */
- 21584 enable_irq(KEYBOARD_IRQ); /* safe now everything initialised! */
- 21585 }
-
-
- 21588 /*===========================================================================*
- 21589 * kbd_loadmap *
- 21590 *===========================================================================*/
- 21591 PUBLIC int kbd_loadmap(user_phys)
- 21592 phys_bytes user_phys;
- 21593 {
- 21594 /* Load a new keymap. */
- 21595
- 21596 phys_copy(user_phys, vir2phys(keymap), (phys_bytes) sizeof(keymap));
- 21597 return(OK);
- 21598 }
-
-
- 21601 /*===========================================================================*
- 21602 * func_key *
- 21603 *===========================================================================*/
- 21604 PRIVATE int func_key(scode)
- 21605 int scode; /* scan code for a function key */
- 21606 {
- 21607 /* This procedure traps function keys for debugging and control purposes. */
- 21608
- 21609 unsigned code;
- 21610
- 21611 code = map_key0(scode); /* first ignore modifiers */
- 21612 if (code < F1 || code > F12) return(FALSE); /* not our job */
- 21613
- 21614 switch (map_key(scode)) { /* include modifiers */
- .Ep 290 src/kernel/keyboard.c
- 21615
- 21616 case F1: p_dmp(); break; /* print process table */
- 21617 case F2: map_dmp(); break; /* print memory map */
- 21618 case F3: toggle_scroll(); break; /* hardware vs. software scrolling */
- 21619
- 21620 #if ENABLE_NETWORKING
- 21621 case F5: dp_dump(); break; /* network statistics */
- 21622 #endif
- 21623 case CF7: sigchar(&tty_table[CONSOLE], SIGQUIT); break;
- 21624 case CF8: sigchar(&tty_table[CONSOLE], SIGINT); break;
- 21625 case CF9: sigchar(&tty_table[CONSOLE], SIGKILL); break;
- 21626 default: return(FALSE);
- 21627 }
- 21628 return(TRUE);
- 21629 }
-
-
- 21632 /*==========================================================================*
- 21633 * scan_keyboard *
- 21634 *==========================================================================*/
- 21635 PRIVATE int scan_keyboard()
- 21636 {
- 21637 /* Fetch the character from the keyboard hardware and acknowledge it. */
- 21638
- 21639 int code;
- 21640 int val;
- 21641
- 21642 code = in_byte(KEYBD); /* get the scan code for the key struck */
- 21643 val = in_byte(PORT_B); /* strobe the keyboard to ack the char */
- 21644 out_byte(PORT_B, val | KBIT); /* strobe the bit high */
- 21645 out_byte(PORT_B, val); /* now strobe it low */
- 21646 return code;
- 21647 }
-
-
- 21650 /*==========================================================================*
- 21651 * wreboot *
- 21652 *==========================================================================*/
- 21653 PUBLIC void wreboot(how)
- 21654 int how; /* 0 = halt, 1 = reboot, 2 = panic!, ... */
- 21655 {
- 21656 /* Wait for keystrokes for printing debugging info and reboot. */
- 21657
- 21658 int quiet, code;
- 21659 static u16_t magic = MEMCHECK_MAG;
- 21660 struct tasktab *ttp;
- 21661
- 21662 /* Mask all interrupts. */
- 21663 out_byte(INT_CTLMASK, ~0);
- 21664
- 21665 /* Tell several tasks to stop. */
- 21666 cons_stop();
- 21667 #if ENABLE_NETWORKING
- 21668 dp8390_stop();
- 21669 #endif
- 21670 floppy_stop();
- 21671 clock_stop();
- 21672
- 21673 if (how == RBT_HALT) {
- 21674 printf("System Haltedn");
- .Op 291 src/kernel/keyboard.c
- 21675 if (!mon_return) how = RBT_PANIC;
- 21676 }
- 21677
- 21678 if (how == RBT_PANIC) {
- 21679 /* A panic! */
- 21680 printf("Hit ESC to reboot, F-keys for debug dumpsn");
- 21681
- 21682 (void) scan_keyboard(); /* ack any old input */
- 21683 quiet = scan_keyboard();/* quiescent value (0 on PC, last code on AT)*/
- 21684 for (;;) {
- 21685 milli_delay(100); /* pause for a decisecond */
- 21686 code = scan_keyboard();
- 21687 if (code != quiet) {
- 21688 /* A key has been pressed. */
- 21689 if (code == ESC_SCAN) break; /* reboot if ESC typed */
- 21690 (void) func_key(code); /* process function key */
- 21691 quiet = scan_keyboard();
- 21692 }
- 21693 }
- 21694 how = RBT_REBOOT;
- 21695 }
- 21696
- 21697 if (how == RBT_REBOOT) printf("Rebootingn");
- 21698
- 21699 if (mon_return && how != RBT_RESET) {
- 21700 /* Reinitialize the interrupt controllers to the BIOS defaults. */
- 21701 intr_init(0);
- 21702 out_byte(INT_CTLMASK, 0);
- 21703 out_byte(INT2_CTLMASK, 0);
- 21704
- 21705 /* Return to the boot monitor. */
- 21706 if (how == RBT_HALT) {
- 21707 reboot_code = vir2phys("");
- 21708 } else
- 21709 if (how == RBT_REBOOT) {
- 21710 reboot_code = vir2phys("delay;boot");
- 21711 }
- 21712 level0(monitor);
- 21713 }
- 21714
- 21715 /* Stop BIOS memory test. */
- 21716 phys_copy(vir2phys(&magic), (phys_bytes) MEMCHECK_ADR,
- 21717 (phys_bytes) sizeof(magic));
- 21718
- 21719 if (protected_mode) {
- 21720 /* Use the AT keyboard controller to reset the processor.
- 21721 * The A20 line is kept enabled in case this code is ever
- 21722 * run from extended memory, and because some machines
- 21723 * appear to drive the fake A20 high instead of low just
- 21724 * after reset, leading to an illegal opode trap. This bug
- 21725 * is more of a problem if the fake A20 is in use, as it
- 21726 * would be if the keyboard reset were used for real mode.
- 21727 */
- 21728 kb_wait();
- 21729 out_byte(KB_COMMAND,
- 21730 KB_PULSE_OUTPUT | (0x0F & ~(KB_GATE_A20 | KB_RESET)));
- 21731 milli_delay(10);
- 21732
- 21733 /* If the nice method fails then do a reset. In protected
- 21734 * mode this means a processor shutdown.
- .Ep 292 src/kernel/keyboard.c
- 21735 */
- 21736 printf("Hard reset...n");
- 21737 milli_delay(250);
- 21738 }
- 21739 /* In real mode, jumping to the reset address is good enough. */
- 21740 level0(reset);
- 21741 }
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/main.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 21800 /* This file contains the main program of MINIX. The routine main()
- 21801 * initializes the system and starts the ball rolling by setting up the proc
- 21802 * table, interrupt vectors, and scheduling each task to run to initialize
- 21803 * itself.
- 21804 *
- 21805 * The entries into this file are:
- 21806 * main: MINIX main program
- 21807 * panic: abort MINIX due to a fatal error
- 21808 */
- 21809
- 21810 #include "kernel.h"
- 21811 #include <signal.h>
- 21812 #include <unistd.h>
- 21813 #include <minix/callnr.h>
- 21814 #include <minix/com.h>
- 21815 #include "proc.h"
- 21816
- 21817
- 21818 /*===========================================================================*
- 21819 * main *
- 21820 *===========================================================================*/
- 21821 PUBLIC void main()
- 21822 {
- 21823 /* Start the ball rolling. */
- 21824
- 21825 register struct proc *rp;
- 21826 register int t;
- 21827 int sizeindex;
- 21828 phys_clicks text_base;
- 21829 vir_clicks text_clicks;
- 21830 vir_clicks data_clicks;
- 21831 phys_bytes phys_b;
- 21832 reg_t ktsb; /* kernel task stack base */
- 21833 struct memory *memp;
- 21834 struct tasktab *ttp;
- 21835
- 21836 /* Initialize the interrupt controller. */
- 21837 intr_init(1);
- 21838
- 21839 /* Interpret memory sizes. */
- 21840 mem_init();
- 21841
- 21842 /* Clear the process table.
- 21843 * Set up mappings for proc_addr() and proc_number() macros.
- 21844 */
- .Op 293 src/kernel/main.c
- 21845 for (rp = BEG_PROC_ADDR, t = -NR_TASKS; rp < END_PROC_ADDR; ++rp, ++t) {
- 21846 rp->p_flags = P_SLOT_FREE;
- 21847 rp->p_nr = t; /* proc number from ptr */
- 21848 (pproc_addr + NR_TASKS)[t] = rp; /* proc ptr from number */
- 21849 }
- 21850
- 21851 /* Set up proc table entries for tasks and servers. The stacks of the
- 21852 * kernel tasks are initialized to an array in data space. The stacks
- 21853 * of the servers have been added to the data segment by the monitor, so
- 21854 * the stack pointer is set to the end of the data segment. All the
- 21855 * processes are in low memory on the 8086. On the 386 only the kernel
- 21856 * is in low memory, the rest if loaded in extended memory.
- 21857 */
- 21858
- 21859 /* Task stacks. */
- 21860 ktsb = (reg_t) t_stack;
- 21861
- 21862 for (t = -NR_TASKS; t <= LOW_USER; ++t) {
- 21863 rp = proc_addr(t); /* t's process slot */
- 21864 ttp = &tasktab[t + NR_TASKS]; /* t's task attributes */
- 21865 strcpy(rp->p_name, ttp->name);
- 21866 if (t < 0) {
- 21867 if (ttp->stksize > 0) {
- 21868 rp->p_stguard = (reg_t *) ktsb;
- 21869 *rp->p_stguard = STACK_GUARD;
- 21870 }
- 21871 ktsb += ttp->stksize;
- 21872 rp->p_reg.sp = ktsb;
- 21873 text_base = code_base >> CLICK_SHIFT;
- 21874 /* tasks are all in the kernel */
- 21875 sizeindex = 0; /* and use the full kernel sizes */
- 21876 memp = &mem[0]; /* remove from this memory chunk */
- 21877 } else {
- 21878 sizeindex = 2 * t + 2; /* MM, FS, INIT have their own sizes */
- 21879 }
- 21880 rp->p_reg.pc = (reg_t) ttp->initial_pc;
- 21881 rp->p_reg.psw = istaskp(rp) ? INIT_TASK_PSW : INIT_PSW;
- 21882
- 21883 text_clicks = sizes[sizeindex];
- 21884 data_clicks = sizes[sizeindex + 1];
- 21885 rp->p_map[T].mem_phys = text_base;
- 21886 rp->p_map[T].mem_len = text_clicks;
- 21887 rp->p_map[D].mem_phys = text_base + text_clicks;
- 21888 rp->p_map[D].mem_len = data_clicks;
- 21889 rp->p_map[S].mem_phys = text_base + text_clicks + data_clicks;
- 21890 rp->p_map[S].mem_vir = data_clicks; /* empty - stack is in data */
- 21891 text_base += text_clicks + data_clicks; /* ready for next, if server */
- 21892 memp->size -= (text_base - memp->base);
- 21893 memp->base = text_base; /* memory no longer free */
- 21894
- 21895 if (t >= 0) {
- 21896 /* Initialize the server stack pointer. Take it down one word
- 21897 * to give crtso.s something to use as "argc".
- 21898 */
- 21899 rp->p_reg.sp = (rp->p_map[S].mem_vir +
- 21900 rp->p_map[S].mem_len) << CLICK_SHIFT;
- 21901 rp->p_reg.sp -= sizeof(reg_t);
- 21902 }
- 21903
- 21904 #if _WORD_SIZE == 4
- .Ep 294 src/kernel/main.c
- 21905 /* Servers are loaded in extended memory if in 386 mode. */
- 21906 if (t < 0) {
- 21907 memp = &mem[1];
- 21908 text_base = 0x100000 >> CLICK_SHIFT;
- 21909 }
- 21910 #endif
- 21911 if (!isidlehardware(t)) lock_ready(rp); /* IDLE, HARDWARE neveready */
- 21912 rp->p_flags = 0;
- 21913
- 21914 alloc_segments(rp);
- 21915 }
- 21916
- 21917 proc[NR_TASKS+INIT_PROC_NR].p_pid = 1;/* INIT of course has pid 1 */
- 21918 bill_ptr = proc_addr(IDLE); /* it has to point somewhere */
- 21919 lock_pick_proc();
- 21920
- 21921 /* Now go to the assembly code to start running the current process. */
- 21922 restart();
- 21923 }
-
-
- 21926 /*===========================================================================*
- 21927 * panic *
- 21928 *===========================================================================*/
- 21929 PUBLIC void panic(s,n)
- 21930 _CONST char *s;
- 21931 int n;
- 21932 {
- 21933 /* The system has run aground of a fatal error. Terminate execution.
- 21934 * If the panic originated in MM or FS, the string will be empty and the
- 21935 * file system already syncked. If the panic originates in the kernel, we are
- 21936 * kind of stuck.
- 21937 */
- 21938
- 21939 if (*s != 0) {
- 21940 printf("nKernel panic: %s",s);
- 21941 if (n != NO_NUM) printf(" %d", n);
- 21942 printf("n");
- 21943 }
- 21944 wreboot(RBT_PANIC);
- 21945 }
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/mcd.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 22000 /* This file contains the driver for a Mitsumi cdrom controller.
- 22001 *
- 22002 * The file contains one entry point:
- 22003 *
- 22004 * mcd_task: main entry when system is brought up
- 22005 *
- 22006 * Mar 30 1995 Author: Michel R. Prevenier
- 22007 */
- 22008
- 22009
- .Op 295 src/kernel/mcd.c