📄 at_wini.c
字号:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/kernel/at_wini.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10100 /* This file contains the device dependent part of a driver for the IBM-AT
10101 * winchester controller.
10102 * It was written by Adri Koppes.
10103 *
10104 * The file contains one entry point:
10105 *
10106 * at_winchester_task: main entry when system is brought up
10107 *
10108 *
10109 * Changes:
10110 * 13 Apr 1992 by Kees J. Bot: device dependent/independent split.
10111 */
10112
10113 #include "kernel.h"
10114 #include "driver.h"
10115 #include "drvlib.h"
10116
10117 #if ENABLE_AT_WINI
10118
10119 /* I/O Ports used by winchester disk controllers. */
10120
10121 /* Read and write registers */
10122 #define REG_BASE0 0x1F0 /* base register of controller 0 */
10123 #define REG_BASE1 0x170 /* base register of controller 1 */
10124 #define REG_DATA 0 /* data register (offset from the base reg.) */
10125 #define REG_PRECOMP 1 /* start of write precompensation */
10126 #define REG_COUNT 2 /* sectors to transfer */
10127 #define REG_SECTOR 3 /* sector number */
10128 #define REG_CYL_LO 4 /* low byte of cylinder number */
10129 #define REG_CYL_HI 5 /* high byte of cylinder number */
10130 #define REG_LDH 6 /* lba, drive and head */
10131 #define LDH_DEFAULT 0xA0 /* ECC enable, 512 bytes per sector */
10132 #define LDH_LBA 0x40 /* Use LBA addressing */
10133 #define ldh_init(drive) (LDH_DEFAULT | ((drive) << 4))
10134
10135 /* Read only registers */
10136 #define REG_STATUS 7 /* status */
10137 #define STATUS_BSY 0x80 /* controller busy */
10138 #define STATUS_RDY 0x40 /* drive ready */
10139 #define STATUS_WF 0x20 /* write fault */
10140 #define STATUS_SC 0x10 /* seek complete (obsolete) */
10141 #define STATUS_DRQ 0x08 /* data transfer request */
10142 #define STATUS_CRD 0x04 /* corrected data */
10143 #define STATUS_IDX 0x02 /* index pulse */
10144 #define STATUS_ERR 0x01 /* error */
10145 #define REG_ERROR 1 /* error code */
10146 #define ERROR_BB 0x80 /* bad block */
10147 #define ERROR_ECC 0x40 /* bad ecc bytes */
10148 #define ERROR_ID 0x10 /* id not found */
10149 #define ERROR_AC 0x04 /* aborted command */
10150 #define ERROR_TK 0x02 /* track zero error */
10151 #define ERROR_DM 0x01 /* no data address mark */
10152
10153 /* Write only registers */
10154 #define REG_COMMAND 7 /* command */
10155 #define CMD_IDLE 0x00 /* for w_command: drive idle */
10156 #define CMD_RECALIBRATE 0x10 /* recalibrate drive */
10157 #define CMD_READ 0x20 /* read data */
10158 #define CMD_WRITE 0x30 /* write data */
10159 #define CMD_READVERIFY 0x40 /* read verify */
10160 #define CMD_FORMAT 0x50 /* format track */
10161 #define CMD_SEEK 0x70 /* seek cylinder */
10162 #define CMD_DIAG 0x90 /* execute device diagnostics */
10163 #define CMD_SPECIFY 0x91 /* specify parameters */
10164 #define ATA_IDENTIFY 0xEC /* identify drive */
10165 #define REG_CTL 0x206 /* control register */
10166 #define CTL_NORETRY 0x80 /* disable access retry */
10167 #define CTL_NOECC 0x40 /* disable ecc retry */
10168 #define CTL_EIGHTHEADS 0x08 /* more than eight heads */
10169 #define CTL_RESET 0x04 /* reset controller */
10170 #define CTL_INTDISABLE 0x02 /* disable interrupts */
10171
10172 /* Interrupt request lines. */
10173 #define AT_IRQ0 14 /* interrupt number for controller 0 */
10174 #define AT_IRQ1 15 /* interrupt number for controller 1 */
10175
10176 /* Common command block */
10177 struct command {
10178 u8_t precomp; /* REG_PRECOMP, etc. */
10179 u8_t count;
10180 u8_t sector;
10181 u8_t cyl_lo;
10182 u8_t cyl_hi;
10183 u8_t ldh;
10184 u8_t command;
10185 };
10186
10187
10188 /* Error codes */
10189 #define ERR (-1) /* general error */
10190 #define ERR_BAD_SECTOR (-2) /* block marked bad detected */
10191
10192 /* Some controllers don't interrupt, the clock will wake us up. */
10193 #define WAKEUP (32*HZ) /* drive may be out for 31 seconds max */
10194
10195 /* Miscellaneous. */
10196 #define MAX_DRIVES 4 /* this driver supports 4 drives (hd0 - hd19) */
10197 #if _WORD_SIZE > 2
10198 #define MAX_SECS 256 /* controller can transfer this many sectors */
10199 #else
10200 #define MAX_SECS 127 /* but not to a 16 bit process */
10201 #endif
10202 #define MAX_ERRORS 4 /* how often to try rd/wt before quitting */
10203 #define NR_DEVICES (MAX_DRIVES * DEV_PER_DRIVE)
10204 #define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS)
10205 #define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE)
10206 #define TIMEOUT 32000 /* controller timeout in ms */
10207 #define RECOVERYTIME 500 /* controller recovery time in ms */
10208 #define INITIALIZED 0x01 /* drive is initialized */
10209 #define DEAF 0x02 /* controller must be reset */
10210 #define SMART 0x04 /* drive supports ATA commands */
10211
10212
10213 /* Variables. */
10214 PRIVATE struct wini { /* main drive struct, one entry per drive */
10215 unsigned state; /* drive state: deaf, initialized, dead */
10216 unsigned base; /* base register of the register file */
10217 unsigned irq; /* interrupt request line */
10218 unsigned lcylinders; /* logical number of cylinders (BIOS) */
10219 unsigned lheads; /* logical number of heads */
10220 unsigned lsectors; /* logical number of sectors per track */
10221 unsigned pcylinders; /* physical number of cylinders (translated) */
10222 unsigned pheads; /* physical number of heads */
10223 unsigned psectors; /* physical number of sectors per track */
10224 unsigned ldhpref; /* top four bytes of the LDH (head) register */
10225 unsigned precomp; /* write precompensation cylinder / 4 */
10226 unsigned max_count; /* max request for this drive */
10227 unsigned open_ct; /* in-use count */
10228 struct device part[DEV_PER_DRIVE]; /* primary partitions: hd[0-4] */
10229 struct device subpart[SUB_PER_DRIVE]; /* subpartitions: hd[1-4][a-d] */
10230 } wini[MAX_DRIVES], *w_wn;
10231
10232 PRIVATE struct trans {
10233 struct iorequest_s *iop; /* belongs to this I/O request */
10234 unsigned long block; /* first sector to transfer */
10235 unsigned count; /* byte count */
10236 phys_bytes phys; /* user physical address */
10237 } wtrans[NR_IOREQS];
10238
10239 PRIVATE struct trans *w_tp; /* to add transfer requests */
10240 PRIVATE unsigned w_count; /* number of bytes to transfer */
10241 PRIVATE unsigned long w_nextblock; /* next block on disk to transfer */
10242 PRIVATE int w_opcode; /* DEV_READ or DEV_WRITE */
10243 PRIVATE int w_command; /* current command in execution */
10244 PRIVATE int w_status; /* status after interrupt */
10245 PRIVATE int w_drive; /* selected drive */
10246 PRIVATE struct device *w_dv; /* device's base and size */
10247
10248 FORWARD _PROTOTYPE( void init_params, (void) );
10249 FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr) );
10250 FORWARD _PROTOTYPE( struct device *w_prepare, (int device) );
10251 FORWARD _PROTOTYPE( int w_identify, (void) );
10252 FORWARD _PROTOTYPE( char *w_name, (void) );
10253 FORWARD _PROTOTYPE( int w_specify, (void) );
10254 FORWARD _PROTOTYPE( int w_schedule, (int proc_nr, struct iorequest_s *iop) );
10255 FORWARD _PROTOTYPE( int w_finish, (void) );
10256 FORWARD _PROTOTYPE( int com_out, (struct command *cmd) );
10257 FORWARD _PROTOTYPE( void w_need_reset, (void) );
10258 FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );
10259 FORWARD _PROTOTYPE( int com_simple, (struct command *cmd) );
10260 FORWARD _PROTOTYPE( void w_timeout, (void) );
10261 FORWARD _PROTOTYPE( int w_reset, (void) );
10262 FORWARD _PROTOTYPE( int w_intr_wait, (void) );
10263 FORWARD _PROTOTYPE( int w_waitfor, (int mask, int value) );
10264 FORWARD _PROTOTYPE( int w_handler, (int irq) );
10265 FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry) );
10266
10267 /* w_waitfor loop unrolled once for speed. */
10268 #define waitfor(mask, value) \
10269 ((in_byte(w_wn->base + REG_STATUS) & mask) == value \
10270 || w_waitfor(mask, value))
10271
10272
10273 /* Entry points to this driver. */
10274 PRIVATE struct driver w_dtab = {
10275 w_name, /* current device's name */
10276 w_do_open, /* open or mount request, initialize device */
10277 w_do_close, /* release device */
10278 do_diocntl, /* get or set a partition's geometry */
10279 w_prepare, /* prepare for I/O on a given minor device */
10280 w_schedule, /* precompute cylinder, head, sector, etc. */
10281 w_finish, /* do the I/O */
10282 nop_cleanup, /* nothing to clean up */
10283 w_geometry, /* tell the geometry of the disk */
10284 };
10285
10286 #if ENABLE_ATAPI
10287 #include "atapi.c" /* extra code for ATAPI CD-ROM */
10288 #endif
10289
10290
10291 /*===========================================================================*
10292 * at_winchester_task *
10293 *===========================================================================*/
10294 PUBLIC void at_winchester_task()
10295 {
10296 /* Set special disk parameters then call the generic main loop. */
10297
10298 init_params();
10299
10300 driver_task(&w_dtab);
10301 }
10304 /*============================================================================*
10305 * init_params *
10306 *============================================================================*/
10307 PRIVATE void init_params()
10308 {
10309 /* This routine is called at startup to initialize the drive parameters. */
10310
10311 u16_t parv[2];
10312 unsigned int vector;
10313 int drive, nr_drives, i;
10314 struct wini *wn;
10315 u8_t params[16];
10316 phys_bytes param_phys = vir2phys(params);
10317
10318 /* Get the number of drives from the BIOS data area */
10319 phys_copy(0x475L, param_phys, 1L);
10320 if ((nr_drives = params[0]) > 2) nr_drives = 2;
10321
10322 for (drive = 0, wn = wini; drive < MAX_DRIVES; drive++, wn++) {
10323 if (drive < nr_drives) {
10324 /* Copy the BIOS parameter vector */
10325 vector = drive == 0 ? WINI_0_PARM_VEC : WINI_1_PARM_VEC;
10326 phys_copy(vector * 4L, vir2phys(parv), 4L);
10327
10328 /* Calculate the address of the parameters and copy them */
10329 phys_copy(hclick_to_physb(parv[1]) + parv[0], param_phys, 16L);
10330
10331 /* Copy the parameters to the structures of the drive */
10332 wn->lcylinders = bp_cylinders(params);
10333 wn->lheads = bp_heads(params);
10334 wn->lsectors = bp_sectors(params);
10335 wn->precomp = bp_precomp(params) >> 2;
10336 }
10337 wn->ldhpref = ldh_init(drive);
10338 wn->max_count = MAX_SECS << SECTOR_SHIFT;
10339 if (drive < 2) {
10340 /* Controller 0. */
10341 wn->base = REG_BASE0;
10342 wn->irq = AT_IRQ0;
10343 } else {
10344 /* Controller 1. */
10345 wn->base = REG_BASE1;
10346 wn->irq = AT_IRQ1;
10347 }
10348 }
10349 }
10352 /*============================================================================*
10353 * w_do_open *
10354 *============================================================================*/
10355 PRIVATE int w_do_open(dp, m_ptr)
10356 struct driver *dp;
10357 message *m_ptr;
10358 {
10359 /* Device open: Initialize the controller and read the partition table. */
10360
10361 int r;
10362 struct wini *wn;
10363 struct command cmd;
10364
10365 if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
10366 wn = w_wn;
10367
10368 if (wn->state == 0) {
10369 /* Try to identify the device. */
10370 if (w_identify() != OK) {
10371 printf("%s: probe failed\n", w_name());
10372 if (wn->state & DEAF) w_reset();
10373 wn->state = 0;
10374 return(ENXIO);
10375 }
10376 }
10377 if (wn->open_ct++ == 0) {
10378 /* Partition the disk. */
10379 partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY);
10380 }
10381 return(OK);
10382 }
10385 /*===========================================================================*
10386 * w_prepare *
10387 *===========================================================================*/
10388 PRIVATE struct device *w_prepare(device)
10389 int device;
10390 {
10391 /* Prepare for I/O on a device. */
10392
10393 /* Nothing to transfer as yet. */
10394 w_count = 0;
10395
10396 if (device < NR_DEVICES) { /* hd0, hd1, ... */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -