| 1 | /* $Id: atalib.c 76 2015-12-28 01:37:00Z bird $ */
 | 
|---|
| 2 | /** @file
 | 
|---|
| 3 |  * Does a little write test.
 | 
|---|
| 4 |  */
 | 
|---|
| 5 | 
 | 
|---|
| 6 | /*
 | 
|---|
| 7 |  * Copyright (c) 2015 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
 | 
|---|
| 8 |  *
 | 
|---|
| 9 |  * This program is free software; you can redistribute it and/or modify
 | 
|---|
| 10 |  * it under the terms of the GNU General Public License as published by
 | 
|---|
| 11 |  * the Free Software Foundation; either version 3 of the License, or
 | 
|---|
| 12 |  * (at your option) any later version.
 | 
|---|
| 13 |  *
 | 
|---|
| 14 |  * This program is distributed in the hope that it will be useful,
 | 
|---|
| 15 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 16 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
| 17 |  * GNU General Public License for more details.
 | 
|---|
| 18 |  *
 | 
|---|
| 19 |  * You should have received a copy of the GNU General Public License
 | 
|---|
| 20 |  * along with This program.  If not, see <http://www.gnu.org/licenses/>
 | 
|---|
| 21 |  *
 | 
|---|
| 22 |  */
 | 
|---|
| 23 | 
 | 
|---|
| 24 | 
 | 
|---|
| 25 | /*********************************************************************************************************************************
 | 
|---|
| 26 | *   Header Files                                                                                                                 *
 | 
|---|
| 27 | *********************************************************************************************************************************/
 | 
|---|
| 28 | #include <stdarg.h>
 | 
|---|
| 29 | #include <stdio.h>
 | 
|---|
| 30 | #include <stdlib.h>
 | 
|---|
| 31 | #include <string.h>
 | 
|---|
| 32 | #include <stdint.h>
 | 
|---|
| 33 | #include <io.h>
 | 
|---|
| 34 | #include <conio.h>
 | 
|---|
| 35 | #include "atalib.h"
 | 
|---|
| 36 | 
 | 
|---|
| 37 | #define STR_TUPLE(a_szStr) a_szStr, sizeof(a_szStr) - 1
 | 
|---|
| 38 | 
 | 
|---|
| 39 | 
 | 
|---|
| 40 | /*********************************************************************************************************************************
 | 
|---|
| 41 | *   Global Variables                                                                                                             *
 | 
|---|
| 42 | *********************************************************************************************************************************/
 | 
|---|
| 43 | uint16_t g_uBasePort;
 | 
|---|
| 44 | uint16_t g_uCtrlPort;
 | 
|---|
| 45 | uint8_t  g_cPortShift;
 | 
|---|
| 46 | uint8_t  g_bDevice;
 | 
|---|
| 47 | uint8_t  g_fUseLbaMode = 1;
 | 
|---|
| 48 | uint8_t  g_f8BitData;
 | 
|---|
| 49 | uint8_t  g_fSupportsSetFeature8BitData;
 | 
|---|
| 50 | uint8_t  g_fSupportsSetFeatureWriteCache;
 | 
|---|
| 51 | uint8_t  g_fSupportsSetFeatureXferMode;
 | 
|---|
| 52 | int8_t   g_fSupportsReadBuffer = -1;
 | 
|---|
| 53 | int8_t   g_fSupportsWriteBuffer = -1;
 | 
|---|
| 54 | 
 | 
|---|
| 55 | uint16_t g_cHeads;
 | 
|---|
| 56 | uint8_t  g_cSectorsPerTrack;
 | 
|---|
| 57 | uint16_t g_cCylinders;
 | 
|---|
| 58 | uint16_t g_cSectorsPerCylinder;
 | 
|---|
| 59 | 
 | 
|---|
| 60 | /** The result of the identify command. */
 | 
|---|
| 61 | uint16_t g_awIdentify[256];
 | 
|---|
| 62 | 
 | 
|---|
| 63 | 
 | 
|---|
| 64 | uint16_t AtaReadPitCounter0(void);
 | 
|---|
| 65 | #pragma aux AtaReadPitCounter0 = \
 | 
|---|
| 66 |     "pushf" \
 | 
|---|
| 67 |     "cli" \
 | 
|---|
| 68 |     "mov al, 4" /* chan0, latch access[, mode 2, 16-bit] */ \
 | 
|---|
| 69 |     "out 43h, al" \
 | 
|---|
| 70 |     "in  al, 40h" \
 | 
|---|
| 71 |     "mov ah, al" \
 | 
|---|
| 72 |     "in  al, 40h" \
 | 
|---|
| 73 |     "xchg ah, al" \
 | 
|---|
| 74 |     "popf" \
 | 
|---|
| 75 |     value [ax] \
 | 
|---|
| 76 |     modify exact [ax];
 | 
|---|
| 77 | 
 | 
|---|
| 78 | uint8_t AtaReadPitCounter0Lsb(void);
 | 
|---|
| 79 | #pragma aux AtaReadPitCounter0Lsb = \
 | 
|---|
| 80 |     "in  al, 40h" \
 | 
|---|
| 81 |     value [al] \
 | 
|---|
| 82 |     modify exact [al];
 | 
|---|
| 83 | 
 | 
|---|
| 84 | 
 | 
|---|
| 85 | void AtaDelayMicroSecs(uint8_t cMicroSecs)
 | 
|---|
| 86 | {
 | 
|---|
| 87 |     /*
 | 
|---|
| 88 |      * ASSUME PIT chan 0 is not in mode 3 and running at 18Hz (reload 64K).
 | 
|---|
| 89 |      *
 | 
|---|
| 90 |      * ASSUME we won't be spending too many microsecs here, so we won't do
 | 
|---|
| 91 |      * an extremely accurate job converting PIT ticks to microseconds. Given
 | 
|---|
| 92 |      * the frequency of 1193182 HZ, that is a period of 838ns, we count each
 | 
|---|
| 93 |      * PIT tick as a microsecond but adding a leap period every 8 rounds
 | 
|---|
| 94 |      * (should've been 6, but 8 is cheaper to calculate).
 | 
|---|
| 95 |      */
 | 
|---|
| 96 |     uint16_t uPrev              = AtaReadPitCounter0();
 | 
|---|
| 97 |     uint16_t const cTicksNeeded = cMicroSecs + (cMicroSecs >> 3);
 | 
|---|
| 98 |     uint32_t cTicksElapsed      = 0;
 | 
|---|
| 99 |     while (cTicksElapsed < cTicksNeeded)
 | 
|---|
| 100 |     {
 | 
|---|
| 101 |         uint16_t uNow = AtaReadPitCounter0();
 | 
|---|
| 102 |         cTicksElapsed += uPrev - uNow;
 | 
|---|
| 103 |         uPrev = uNow;
 | 
|---|
| 104 |     }
 | 
|---|
| 105 | }
 | 
|---|
| 106 | 
 | 
|---|
| 107 | 
 | 
|---|
| 108 | #if 0 /* currently implemented as inline assembly */
 | 
|---|
| 109 | void AtaDelayPitTicks(uint8_t cTicks)
 | 
|---|
| 110 | {
 | 
|---|
| 111 |     /*
 | 
|---|
| 112 |      * ASSUME PIT channel 0 is in mode 2.
 | 
|---|
| 113 |      * ASSUME PIT channel 0 is in LSB read mode.
 | 
|---|
| 114 |      * ASSUME PIT channel 0 is reloading a multiple of 256.
 | 
|---|
| 115 |      * ASSUME PIT channel 0 is not currently latched.
 | 
|---|
| 116 |      * ASSUME PIT channel 0 is in binary mode (not BCD).
 | 
|---|
| 117 |      */
 | 
|---|
| 118 |     uint8_t uPrev = AtaReadPitCounter0Lsb();
 | 
|---|
| 119 |     for (;;)
 | 
|---|
| 120 |     {
 | 
|---|
| 121 |         uint8_t uNow     = AtaReadPitCounter0Lsb();
 | 
|---|
| 122 |         uint8_t cElapsed = uPrev - uNow;
 | 
|---|
| 123 |         if (cElapsed >= cTicks)
 | 
|---|
| 124 |             break;
 | 
|---|
| 125 |         cElapsed -= cTicks;
 | 
|---|
| 126 |         uPrev = uNow;
 | 
|---|
| 127 |     }
 | 
|---|
| 128 | }
 | 
|---|
| 129 | #endif
 | 
|---|
| 130 | 
 | 
|---|
| 131 | 
 | 
|---|
| 132 | 
 | 
|---|
| 133 | size_t AtaPrintStatus(FILE *pOut, uint8_t bSts)
 | 
|---|
| 134 | {
 | 
|---|
| 135 |     size_t cch = fprintf(pOut, "%#x", bSts);
 | 
|---|
| 136 |     if (bSts & ATA_STS_BUSY) cch += fprintf(pOut, " busy");
 | 
|---|
| 137 |     if (bSts & ATA_STS_DRDY) cch += fprintf(pOut, " drdy");
 | 
|---|
| 138 |     if (bSts & ATA_STS_DF  ) cch += fprintf(pOut, " df");
 | 
|---|
| 139 |     if (bSts & ATA_STS_DSC ) cch += fprintf(pOut, " dsc");
 | 
|---|
| 140 |     if (bSts & ATA_STS_DRQ ) cch += fprintf(pOut, " drq");
 | 
|---|
| 141 |     if (bSts & ATA_STS_CORR) cch += fprintf(pOut, " corr");
 | 
|---|
| 142 |     if (bSts & ATA_STS_IDX ) cch += fprintf(pOut, " idx");
 | 
|---|
| 143 |     if (bSts & ATA_STS_ERR ) cch += fprintf(pOut, " err");
 | 
|---|
| 144 |     return cch;
 | 
|---|
| 145 | }
 | 
|---|
| 146 | 
 | 
|---|
| 147 | size_t AtaPrintError(FILE *pOut, uint8_t bErr)
 | 
|---|
| 148 | {
 | 
|---|
| 149 |     size_t cch = fprintf(pOut, "%#x", bErr);
 | 
|---|
| 150 |     if (bErr & ATA_ERR_RSVR  ) cch += fprintf(pOut, " rsrv");
 | 
|---|
| 151 |     if (bErr & ATA_ERR_UNC   ) cch += fprintf(pOut, " unc");
 | 
|---|
| 152 |     if (bErr & ATA_ERR_MC    ) cch += fprintf(pOut, " mc");
 | 
|---|
| 153 |     if (bErr & ATA_ERR_IDNF  ) cch += fprintf(pOut, " idnf");
 | 
|---|
| 154 |     if (bErr & ATA_ERR_MCR   ) cch += fprintf(pOut, " mcr");
 | 
|---|
| 155 |     if (bErr & ATA_ERR_ABRT  ) cch += fprintf(pOut, " abrt");
 | 
|---|
| 156 |     if (bErr & ATA_ERR_TKNONF) cch += fprintf(pOut, " tknonf");
 | 
|---|
| 157 |     if (bErr & ATA_ERR_AMNF  ) cch += fprintf(pOut, " amnf");
 | 
|---|
| 158 |     return cch;
 | 
|---|
| 159 | }
 | 
|---|
| 160 | 
 | 
|---|
| 161 | static int AtaError(uint8_t bSts, const char *pszFormat, ...)
 | 
|---|
| 162 | {
 | 
|---|
| 163 |     va_list va;
 | 
|---|
| 164 | 
 | 
|---|
| 165 |     fprintf(stderr, "error: ");
 | 
|---|
| 166 |     va_start(va, pszFormat);
 | 
|---|
| 167 |     vfprintf(stderr, pszFormat, va);
 | 
|---|
| 168 |     va_end(va);
 | 
|---|
| 169 | 
 | 
|---|
| 170 |     fprintf(stderr, "\n status=");
 | 
|---|
| 171 |     AtaPrintStatus(stderr, bSts);
 | 
|---|
| 172 |     fprintf(stderr, "\n  error= ");
 | 
|---|
| 173 |     AtaPrintError(stderr, inp(ATA_REG_ERROR(g_uBasePort)));
 | 
|---|
| 174 |     fprintf(stderr, "\n");
 | 
|---|
| 175 | 
 | 
|---|
| 176 |     return -1;
 | 
|---|
| 177 | }
 | 
|---|
| 178 | 
 | 
|---|
| 179 | uint8_t AtaWaitBusy(void)
 | 
|---|
| 180 | {
 | 
|---|
| 181 |     uint32_t cLoops = 0;
 | 
|---|
| 182 |     uint8_t  bStatus;
 | 
|---|
| 183 |     do
 | 
|---|
| 184 |     {
 | 
|---|
| 185 |         if ((++cLoops & 0xfffff) == 0)
 | 
|---|
| 186 |             fprintf(stderr, "AtaWaitBusyForData: cLoops=%#lx\n", cLoops);
 | 
|---|
| 187 |         bStatus = inp(ATA_REG_STATUS(g_uBasePort));
 | 
|---|
| 188 |     } while ((bStatus & (ATA_STS_BUSY | ATA_STS_ERR)) == ATA_STS_BUSY);
 | 
|---|
| 189 |     return bStatus;
 | 
|---|
| 190 | }
 | 
|---|
| 191 | 
 | 
|---|
| 192 | uint8_t AtaWaitBusyDeviceReady(void)
 | 
|---|
| 193 | {
 | 
|---|
| 194 |     uint32_t cLoops = 0;
 | 
|---|
| 195 |     uint8_t bStatus;
 | 
|---|
| 196 |     do
 | 
|---|
| 197 |     {
 | 
|---|
| 198 |         if ((++cLoops & 0xfffff) == 0)
 | 
|---|
| 199 |             fprintf(stderr, "AtaWaitBusyForData: cLoops=%#lx\n", cLoops);
 | 
|---|
| 200 |         bStatus = inp(ATA_REG_STATUS(g_uBasePort));
 | 
|---|
| 201 |     } while (    (bStatus & (ATA_STS_BUSY | ATA_STS_DRDY)) != ATA_STS_DRDY
 | 
|---|
| 202 |              && !(bStatus & ATA_STS_ERR) );
 | 
|---|
| 203 |     return bStatus;
 | 
|---|
| 204 | }
 | 
|---|
| 205 | 
 | 
|---|
| 206 | uint8_t AtaWaitBusyForData(void)
 | 
|---|
| 207 | {
 | 
|---|
| 208 |     uint32_t cLoops = 0;
 | 
|---|
| 209 |     uint8_t bStatus;
 | 
|---|
| 210 |     do
 | 
|---|
| 211 |     {
 | 
|---|
| 212 |         if ((++cLoops & 0xfffff) == 0)
 | 
|---|
| 213 |             fprintf(stderr, "AtaWaitBusyForData: cLoops=%#lx\n", cLoops);
 | 
|---|
| 214 |         bStatus = inp(ATA_REG_STATUS(g_uBasePort));
 | 
|---|
| 215 |     } while (    (bStatus & (ATA_STS_BUSY | ATA_STS_DRQ)) != ATA_STS_DRQ
 | 
|---|
| 216 |              && !(bStatus & ATA_STS_ERR) );
 | 
|---|
| 217 |     return bStatus;
 | 
|---|
| 218 | }
 | 
|---|
| 219 | 
 | 
|---|
| 220 | uint8_t AtaSubmitCommandAndWait(uint8_t bCommand)
 | 
|---|
| 221 | {
 | 
|---|
| 222 | 
 | 
|---|
| 223 |     outp(ATA_REG_COMMAND(g_uBasePort), bCommand);
 | 
|---|
| 224 |     ATA_DELAY_400NS();
 | 
|---|
| 225 |     return AtaWaitBusy();
 | 
|---|
| 226 | }
 | 
|---|
| 227 | 
 | 
|---|
| 228 | uint8_t AtaSubmitCommandAndWaitForData(uint8_t bCommand)
 | 
|---|
| 229 | {
 | 
|---|
| 230 | 
 | 
|---|
| 231 |     outp(ATA_REG_COMMAND(g_uBasePort), bCommand);
 | 
|---|
| 232 |     ATA_DELAY_400NS();
 | 
|---|
| 233 |     return AtaWaitBusyForData();
 | 
|---|
| 234 | }
 | 
|---|
| 235 | 
 | 
|---|
| 236 | uint8_t AtaSelectDevice(uint8_t bDevice)
 | 
|---|
| 237 | {
 | 
|---|
| 238 |     outp(ATA_REG_DEVICE_SELECT(g_uBasePort), g_bDevice);
 | 
|---|
| 239 |     ATA_DELAY_400NS();
 | 
|---|
| 240 |     return AtaWaitBusyDeviceReady();
 | 
|---|
| 241 | }
 | 
|---|
| 242 | 
 | 
|---|
| 243 | void AtaSetSectorAddress(uint32_t iSector, uint8_t bDevice)
 | 
|---|
| 244 | {
 | 
|---|
| 245 |     if (g_fUseLbaMode)
 | 
|---|
| 246 |     {
 | 
|---|
| 247 |         outp(ATA_REG_LBA_0_7(g_uBasePort), iSector & 0xff);
 | 
|---|
| 248 |         outp(ATA_REG_LBA_8_15(g_uBasePort), (iSector >> 8) & 0xff);
 | 
|---|
| 249 |         outp(ATA_REG_LBA_16_23(g_uBasePort), (iSector >> 16) & 0xff);
 | 
|---|
| 250 |         outp(ATA_REG_LBA_24_27_MODE(g_uBasePort), ((iSector >> 24) & 0x0f) | ATA_LBA_MODE | bDevice);
 | 
|---|
| 251 |     }
 | 
|---|
| 252 |     else
 | 
|---|
| 253 |     {
 | 
|---|
| 254 |         uint16_t iCyl = iSector / g_cSectorsPerCylinder;
 | 
|---|
| 255 |         uint16_t iRem = iSector % g_cSectorsPerCylinder;
 | 
|---|
| 256 |         uint8_t  iHd  = iRem / g_cSectorsPerTrack;
 | 
|---|
| 257 |         uint8_t  iSec = iRem % g_cSectorsPerTrack;
 | 
|---|
| 258 | 
 | 
|---|
| 259 |         outp(ATA_REG_SECTOR_NUMBER(g_uBasePort), iSec);
 | 
|---|
| 260 |         outp(ATA_REG_CYLINDER_LOW(g_uBasePort), iCyl & 0xff);
 | 
|---|
| 261 |         outp(ATA_REG_CYLINDER_HIGH(g_uBasePort), iCyl >> 8);
 | 
|---|
| 262 |         outp(ATA_REG_HEAD(g_uBasePort), iHd | bDevice);
 | 
|---|
| 263 |     }
 | 
|---|
| 264 | }
 | 
|---|
| 265 | 
 | 
|---|
| 266 | void AtaReadData(void *pvBuf, size_t cb, uint8_t f8BitData)
 | 
|---|
| 267 | {
 | 
|---|
| 268 |     uint16_t  uDataPort = ATA_REG_DATA(g_uBasePort);
 | 
|---|
| 269 |     uint16_t *pu16      = (uint16_t *)pvBuf;
 | 
|---|
| 270 |     cb >>= 1;
 | 
|---|
| 271 | 
 | 
|---|
| 272 |     if (f8BitData == 1)
 | 
|---|
| 273 |     {
 | 
|---|
| 274 |         while (cb-- > 0)
 | 
|---|
| 275 |         {
 | 
|---|
| 276 |             uint8_t b1 = inp(uDataPort);
 | 
|---|
| 277 |             uint8_t b2 = inp(uDataPort);
 | 
|---|
| 278 |             *pu16++ = b1 | ((uint16_t)b2 << 8);
 | 
|---|
| 279 |         }
 | 
|---|
| 280 |     }
 | 
|---|
| 281 |     else
 | 
|---|
| 282 |     {
 | 
|---|
| 283 |         while (cb-- > 0)
 | 
|---|
| 284 |             *pu16++ = inpw(uDataPort);
 | 
|---|
| 285 |     }
 | 
|---|
| 286 | }
 | 
|---|
| 287 | 
 | 
|---|
| 288 | void AtaWriteData(void const *pvBuf, size_t cb, uint8_t f8BitData)
 | 
|---|
| 289 | {
 | 
|---|
| 290 |     uint16_t register uDataPort = ATA_REG_DATA(g_uBasePort);
 | 
|---|
| 291 |     uint16_t const   *pu16      = (uint16_t const *)pvBuf;
 | 
|---|
| 292 | 
 | 
|---|
| 293 |     cb >>= 1;
 | 
|---|
| 294 |     if (f8BitData == 1)
 | 
|---|
| 295 |     {
 | 
|---|
| 296 |         while (cb-- > 0)
 | 
|---|
| 297 |         {
 | 
|---|
| 298 |             uint16_t register u16 = *pu16++;
 | 
|---|
| 299 |             outp(uDataPort, (uint8_t)u16);
 | 
|---|
| 300 |             outp(uDataPort, (uint8_t)(u16 >> 8));
 | 
|---|
| 301 |         }
 | 
|---|
| 302 |     }
 | 
|---|
| 303 |     else
 | 
|---|
| 304 |         while (cb-- > 0)
 | 
|---|
| 305 |             outpw(uDataPort, *pu16++);
 | 
|---|
| 306 | }
 | 
|---|
| 307 | 
 | 
|---|
| 308 | int AtaReadSector(uint32_t iSector, void *pvBuf)
 | 
|---|
| 309 | {
 | 
|---|
| 310 |     uint8_t bSts = AtaWaitBusy();
 | 
|---|
| 311 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 312 |         return AtaError(bSts, "Prepping for reading sector %lu", iSector);
 | 
|---|
| 313 | 
 | 
|---|
| 314 |     bSts = AtaSelectDevice(g_bDevice);
 | 
|---|
| 315 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 316 |         return AtaError(bSts, "Selecting device for reading sector %lu", iSector);
 | 
|---|
| 317 | 
 | 
|---|
| 318 |     outp(ATA_REG_FEATURES(g_uBasePort), 0x0);
 | 
|---|
| 319 |     outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1);
 | 
|---|
| 320 |     AtaSetSectorAddress(iSector, g_bDevice);
 | 
|---|
| 321 | 
 | 
|---|
| 322 |     bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_READ_SECTORS);
 | 
|---|
| 323 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 324 |         return AtaError(bSts, "Reading sector %lu", iSector);
 | 
|---|
| 325 | 
 | 
|---|
| 326 |     if (!(bSts & ATA_STS_DRQ))
 | 
|---|
| 327 |         return AtaError(bSts, "DRQ not set after reading sector %lu", iSector);
 | 
|---|
| 328 | 
 | 
|---|
| 329 |     AtaReadData(pvBuf, 512, g_f8BitData);
 | 
|---|
| 330 |     bSts = inp(ATA_REG_STATUS(g_uBasePort));
 | 
|---|
| 331 |     if (bSts & ATA_STS_DRQ)
 | 
|---|
| 332 |         return AtaError(bSts, "DRQ is still set after reading sector %lu", iSector);
 | 
|---|
| 333 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 334 |         return AtaError(bSts, "ERR is set after reading sector %lu (#2)", iSector);
 | 
|---|
| 335 |     return 0;
 | 
|---|
| 336 | }
 | 
|---|
| 337 | 
 | 
|---|
| 338 | int AtaWriteSector(uint32_t iSector, void const *pvBuf)
 | 
|---|
| 339 | {
 | 
|---|
| 340 |     uint8_t bSts = AtaWaitBusy();
 | 
|---|
| 341 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 342 |         return AtaError(bSts, "Prepping for writing sector %lu", iSector);
 | 
|---|
| 343 | 
 | 
|---|
| 344 |     bSts = AtaSelectDevice(g_bDevice);
 | 
|---|
| 345 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 346 |         return AtaError(bSts, "Selecting device for writing sector %lu", iSector);
 | 
|---|
| 347 | 
 | 
|---|
| 348 |     outp(ATA_REG_FEATURES(g_uBasePort), 0x0);
 | 
|---|
| 349 |     outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1);
 | 
|---|
| 350 |     AtaSetSectorAddress(iSector, g_bDevice);
 | 
|---|
| 351 | 
 | 
|---|
| 352 |     bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_WRITE_SECTORS);
 | 
|---|
| 353 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 354 |         return AtaError(bSts, "writing sector (#1) %lu", iSector);
 | 
|---|
| 355 |     if (!(bSts & ATA_STS_DRQ))
 | 
|---|
| 356 |         return AtaError(bSts, "DRQ not set after writing sector (#1) %lu", iSector);
 | 
|---|
| 357 | 
 | 
|---|
| 358 |     AtaWriteData(pvBuf, 512, g_f8BitData);
 | 
|---|
| 359 |     ATA_DELAY_400NS();
 | 
|---|
| 360 |     bSts = AtaWaitBusy();
 | 
|---|
| 361 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 362 |         return AtaError(bSts, "writing sector (#2) %lu", iSector);
 | 
|---|
| 363 |     if (bSts & ATA_STS_DRQ)
 | 
|---|
| 364 |         return AtaError(bSts, "DRQ is set after writing sector (#2) %lu", iSector);
 | 
|---|
| 365 | 
 | 
|---|
| 366 |     return 0;
 | 
|---|
| 367 | }
 | 
|---|
| 368 | 
 | 
|---|
| 369 | 
 | 
|---|
| 370 | /**
 | 
|---|
| 371 |  * @param pvBuf     Pointer to a 512-byte buffer.
 | 
|---|
| 372 |  */
 | 
|---|
| 373 | int AtaReadBuffer(void *pvBuf, uint8_t fExtraChecks)
 | 
|---|
| 374 | {
 | 
|---|
| 375 |     uint8_t bSts;
 | 
|---|
| 376 | 
 | 
|---|
| 377 |     if (!g_fSupportsReadBuffer)
 | 
|---|
| 378 |         return -2;
 | 
|---|
| 379 | 
 | 
|---|
| 380 |     bSts = AtaWaitBusy();
 | 
|---|
| 381 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 382 |         return AtaError(bSts, "Prepping for reading buffer");
 | 
|---|
| 383 | 
 | 
|---|
| 384 |     bSts = AtaSelectDevice(g_bDevice);
 | 
|---|
| 385 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 386 |         return AtaError(bSts, "Selecting device for reading buffer");
 | 
|---|
| 387 | 
 | 
|---|
| 388 |     outp(ATA_REG_FEATURES(g_uBasePort),         0);
 | 
|---|
| 389 |     outp(ATA_REG_SECTOR_COUNT(g_uBasePort),     1); /* ignored */
 | 
|---|
| 390 |     outp(ATA_REG_SECTOR_NUMBER(g_uBasePort),    0);
 | 
|---|
| 391 |     outp(ATA_REG_CYLINDER_LOW(g_uBasePort),     0);
 | 
|---|
| 392 |     outp(ATA_REG_CYLINDER_HIGH(g_uBasePort),    0);
 | 
|---|
| 393 | 
 | 
|---|
| 394 |     bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_READ_BUFFER);
 | 
|---|
| 395 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 396 |         return AtaError(bSts, "Reading buffer");
 | 
|---|
| 397 | 
 | 
|---|
| 398 |     if (!(bSts & ATA_STS_DRQ))
 | 
|---|
| 399 |         return AtaError(bSts, "DRQ not set after reading buffer");
 | 
|---|
| 400 | 
 | 
|---|
| 401 |     if (!fExtraChecks)
 | 
|---|
| 402 |         AtaReadData(pvBuf, 512, g_f8BitData);
 | 
|---|
| 403 |     else
 | 
|---|
| 404 |         AtaReadData(pvBuf, 512, g_f8BitData);
 | 
|---|
| 405 |     bSts = inp(ATA_REG_STATUS(g_uBasePort));
 | 
|---|
| 406 |     if (bSts & ATA_STS_DRQ)
 | 
|---|
| 407 |         return AtaError(bSts, "DRQ is still set after reading buffer");
 | 
|---|
| 408 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 409 |         return AtaError(bSts, "ERR is set after reading buffer");
 | 
|---|
| 410 |     return 0;
 | 
|---|
| 411 | }
 | 
|---|
| 412 | 
 | 
|---|
| 413 | int AtaWriteBuffer(void const *pvBuf, uint8_t fExtraChecks)
 | 
|---|
| 414 | {
 | 
|---|
| 415 |     uint8_t bSts;
 | 
|---|
| 416 | 
 | 
|---|
| 417 |     if (!g_fSupportsWriteBuffer)
 | 
|---|
| 418 |         return -2;
 | 
|---|
| 419 | 
 | 
|---|
| 420 |     bSts = AtaWaitBusy();
 | 
|---|
| 421 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 422 |         return AtaError(bSts, "Prepping for writing buffer");
 | 
|---|
| 423 | 
 | 
|---|
| 424 |     bSts = AtaSelectDevice(g_bDevice);
 | 
|---|
| 425 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 426 |         return AtaError(bSts, "Selecting device for writing buffer");
 | 
|---|
| 427 | 
 | 
|---|
| 428 |     outp(ATA_REG_FEATURES(g_uBasePort),         0);
 | 
|---|
| 429 |     outp(ATA_REG_SECTOR_COUNT(g_uBasePort),     1); /* ignored */
 | 
|---|
| 430 |     outp(ATA_REG_SECTOR_NUMBER(g_uBasePort),    0);
 | 
|---|
| 431 |     outp(ATA_REG_CYLINDER_LOW(g_uBasePort),     0);
 | 
|---|
| 432 |     outp(ATA_REG_CYLINDER_HIGH(g_uBasePort),    0);
 | 
|---|
| 433 | 
 | 
|---|
| 434 |     bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_WRITE_BUFFER);
 | 
|---|
| 435 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 436 |         return AtaError(bSts, "writing buffer (#1)");
 | 
|---|
| 437 |     if (!(bSts & ATA_STS_DRQ))
 | 
|---|
| 438 |         return AtaError(bSts, "DRQ not set after writing buffer (#1)");
 | 
|---|
| 439 | 
 | 
|---|
| 440 |     if (!fExtraChecks)
 | 
|---|
| 441 |         AtaWriteData(pvBuf, 512, g_f8BitData);
 | 
|---|
| 442 |     else
 | 
|---|
| 443 |         AtaWriteData(pvBuf, 512, g_f8BitData);
 | 
|---|
| 444 |     ATA_DELAY_400NS();
 | 
|---|
| 445 |     bSts = AtaWaitBusy();
 | 
|---|
| 446 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 447 |         return AtaError(bSts, "writing buffer (#2)");
 | 
|---|
| 448 |     if (bSts & ATA_STS_DRQ)
 | 
|---|
| 449 |         return AtaError(bSts, "DRQ is set after writing buffer (#2)");
 | 
|---|
| 450 | 
 | 
|---|
| 451 |     return 0;
 | 
|---|
| 452 | }
 | 
|---|
| 453 | 
 | 
|---|
| 454 | int AtaIdentifyDevice(uint8_t bDevice, void *pvBuf)
 | 
|---|
| 455 | {
 | 
|---|
| 456 |     uint8_t bSts = AtaWaitBusy();
 | 
|---|
| 457 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 458 |         return AtaError(bSts, "Prepping for device %#x identification", bDevice);
 | 
|---|
| 459 | 
 | 
|---|
| 460 |     bSts = AtaSelectDevice(g_bDevice);
 | 
|---|
| 461 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 462 |         return AtaError(bSts, "Selecting device %#x for identification", bDevice);
 | 
|---|
| 463 | 
 | 
|---|
| 464 |     outp(ATA_REG_FEATURES(g_uBasePort),         0);
 | 
|---|
| 465 |     outp(ATA_REG_SECTOR_COUNT(g_uBasePort),     0);
 | 
|---|
| 466 |     outp(ATA_REG_SECTOR_NUMBER(g_uBasePort),    0);
 | 
|---|
| 467 |     outp(ATA_REG_CYLINDER_LOW(g_uBasePort),     0);
 | 
|---|
| 468 |     outp(ATA_REG_CYLINDER_HIGH(g_uBasePort),    0);
 | 
|---|
| 469 |     //outp(ATA_REG_HEAD(g_uBasePort), g_bDevice);
 | 
|---|
| 470 | 
 | 
|---|
| 471 |     bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_IDENTIFY_DEVICE);
 | 
|---|
| 472 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 473 |         return AtaError(bSts, "Device %#x identification", bDevice);
 | 
|---|
| 474 |     if (!(bSts & ATA_STS_DRQ))
 | 
|---|
| 475 |         return AtaError(bSts, "DRQ not set after device %#x identification", bDevice);
 | 
|---|
| 476 | 
 | 
|---|
| 477 |     AtaReadData(pvBuf, 512, g_f8BitData);
 | 
|---|
| 478 |     return 0;
 | 
|---|
| 479 | }
 | 
|---|
| 480 | 
 | 
|---|
| 481 | int AtaSetFeature(uint8_t bDevice, uint8_t bFeature, uint8_t bValue)
 | 
|---|
| 482 | {
 | 
|---|
| 483 |     uint8_t bSts = AtaWaitBusy();
 | 
|---|
| 484 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 485 |         return AtaError(bSts, "Prepping for setting device %#x feature %#x (%#x)", bDevice, bFeature, bValue);
 | 
|---|
| 486 | 
 | 
|---|
| 487 |     bSts = AtaSelectDevice(g_bDevice);
 | 
|---|
| 488 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 489 |         return AtaError(bSts, "Selecting device %#x for setting feature %#x (%#x)", bDevice, bFeature, bValue);
 | 
|---|
| 490 | 
 | 
|---|
| 491 |     outp(ATA_REG_FEATURES(g_uBasePort),         bFeature);
 | 
|---|
| 492 |     outp(ATA_REG_SECTOR_COUNT(g_uBasePort),     0);
 | 
|---|
| 493 |     outp(ATA_REG_SECTOR_NUMBER(g_uBasePort),    bValue);
 | 
|---|
| 494 |     outp(ATA_REG_CYLINDER_LOW(g_uBasePort),     0);
 | 
|---|
| 495 |     outp(ATA_REG_CYLINDER_HIGH(g_uBasePort),    0);
 | 
|---|
| 496 |     //outp(ATA_REG_HEAD(g_uBasePort), g_bDevice);
 | 
|---|
| 497 | 
 | 
|---|
| 498 |     bSts = AtaSubmitCommandAndWait(ATA_CMD_SET_FEATURES);
 | 
|---|
| 499 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 500 |         return AtaError(bSts, "Setting device %#x feature %#x (%#x)", bDevice, bFeature, bValue);
 | 
|---|
| 501 |     if (bSts & ATA_STS_DRQ)
 | 
|---|
| 502 |         return AtaError(bSts, "DRQ is set after setting device %#x feature %#x (%#x)", bDevice, bFeature, bValue);
 | 
|---|
| 503 |     return 0;
 | 
|---|
| 504 | }
 | 
|---|
| 505 | 
 | 
|---|
| 506 | int AtaInitDeviceParams(uint8_t bDevice, uint8_t cSectorsPerTrack, uint8_t cHeads)
 | 
|---|
| 507 | {
 | 
|---|
| 508 |     uint8_t bSts = AtaWaitBusy();
 | 
|---|
| 509 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 510 |         return AtaError(bSts, "Prepping for device %#x parameter initialization", bDevice);
 | 
|---|
| 511 | 
 | 
|---|
| 512 |     bSts = AtaSelectDevice(g_bDevice);
 | 
|---|
| 513 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 514 |         return AtaError(bSts, "Selecting device for device %#x parameter initialization", bDevice);
 | 
|---|
| 515 | 
 | 
|---|
| 516 |     outp(ATA_REG_FEATURES(g_uBasePort),         0);
 | 
|---|
| 517 |     outp(ATA_REG_SECTOR_COUNT(g_uBasePort),     cSectorsPerTrack);
 | 
|---|
| 518 |     outp(ATA_REG_SECTOR_NUMBER(g_uBasePort),    0);
 | 
|---|
| 519 |     outp(ATA_REG_CYLINDER_LOW(g_uBasePort),     0);
 | 
|---|
| 520 |     outp(ATA_REG_CYLINDER_HIGH(g_uBasePort),    0);
 | 
|---|
| 521 |     outp(ATA_REG_HEAD(g_uBasePort), g_bDevice | cHeads);
 | 
|---|
| 522 | 
 | 
|---|
| 523 |     bSts = AtaSubmitCommandAndWait(ATA_CMD_INIT_DEVICE_PARAMS);
 | 
|---|
| 524 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 525 |         return AtaError(bSts, "Device %#x parameter initialization", bDevice);
 | 
|---|
| 526 |     if (bSts & ATA_STS_DRQ)
 | 
|---|
| 527 |         return AtaError(bSts, "DRQ is set after device %#x parameter initialization", bDevice);
 | 
|---|
| 528 |     return 0;
 | 
|---|
| 529 | }
 | 
|---|
| 530 | 
 | 
|---|
| 531 | int AtaReset(void)
 | 
|---|
| 532 | {
 | 
|---|
| 533 |     uint8_t bSts;
 | 
|---|
| 534 | 
 | 
|---|
| 535 |     /* Set the reset flat. */
 | 
|---|
| 536 |     outp(ATA_REG_CONTROL(g_uBasePort), ATA_CTL_SRST | ATA_CTL_IEN);
 | 
|---|
| 537 | /** @todo This still needs work - it doesn't work when ERR is set. */
 | 
|---|
| 538 | 
 | 
|---|
| 539 |     /* Wait for the busy flag response. */
 | 
|---|
| 540 |     ATA_DELAY_5US();
 | 
|---|
| 541 |     while (!(bSts = inp(ATA_REG_STATUS(g_uBasePort))) & ATA_STS_BUSY)
 | 
|---|
| 542 |         ATA_DELAY_400NS();
 | 
|---|
| 543 | 
 | 
|---|
| 544 |     /* Clear the reset flag, keeping ints disabled. */
 | 
|---|
| 545 |     outp(ATA_REG_CONTROL(g_uBasePort), ATA_CTL_IEN);
 | 
|---|
| 546 |     ATA_DELAY_400NS();
 | 
|---|
| 547 | 
 | 
|---|
| 548 |     /* Wait for the controller to become non-busy. */
 | 
|---|
| 549 |     bSts = AtaWaitBusy();
 | 
|---|
| 550 |     if (bSts & ATA_STS_ERR)
 | 
|---|
| 551 |         return AtaError(bSts, "Software reset failed");
 | 
|---|
| 552 |     return 0;
 | 
|---|
| 553 | }
 | 
|---|
| 554 | 
 | 
|---|
| 555 | int AtaReInit(void)
 | 
|---|
| 556 | {
 | 
|---|
| 557 |     int rc;
 | 
|---|
| 558 | 
 | 
|---|
| 559 |     /* Reset the controller + devices. */
 | 
|---|
| 560 |     if (AtaReset() != 0)
 | 
|---|
| 561 |         return -1;
 | 
|---|
| 562 | 
 | 
|---|
| 563 |     if (g_fSupportsSetFeature8BitData)
 | 
|---|
| 564 |     {
 | 
|---|
| 565 |         if (g_f8BitData == 1 || g_f8BitData == 3)
 | 
|---|
| 566 |             rc = AtaSetFeature(g_bDevice, ATA_FEATURE_EN_8BIT_DATA, 0);
 | 
|---|
| 567 |         else if (g_f8BitData == 0)
 | 
|---|
| 568 |             rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_8BIT_DATA, 0);
 | 
|---|
| 569 |         else
 | 
|---|
| 570 |             rc = 0;
 | 
|---|
| 571 |         if (rc != 0)
 | 
|---|
| 572 |             return rc;
 | 
|---|
| 573 |     }
 | 
|---|
| 574 | 
 | 
|---|
| 575 |     /* Try disable write cache. */
 | 
|---|
| 576 |     if (g_fSupportsSetFeatureWriteCache)
 | 
|---|
| 577 |     {
 | 
|---|
| 578 |         rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_WRITE_CACHE, 0);
 | 
|---|
| 579 |         if (rc != 0)
 | 
|---|
| 580 |             return rc;
 | 
|---|
| 581 |     }
 | 
|---|
| 582 | 
 | 
|---|
| 583 |     /* Select PIO mode without IORDY. */
 | 
|---|
| 584 |     if (g_fSupportsSetFeatureXferMode)
 | 
|---|
| 585 |     {
 | 
|---|
| 586 |         rc = AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY);
 | 
|---|
| 587 |         if (rc != 0)
 | 
|---|
| 588 |             return rc;
 | 
|---|
| 589 |     }
 | 
|---|
| 590 | 
 | 
|---|
| 591 |     return 0;
 | 
|---|
| 592 | }
 | 
|---|
| 593 | 
 | 
|---|
| 594 | int AtaInit(uint16_t uBasePort, uint16_t uCtrlPort, uint8_t cPortShift, uint8_t bDevice, uint8_t f8BitData, uint8_t fReset)
 | 
|---|
| 595 | {
 | 
|---|
| 596 |     int rc;
 | 
|---|
| 597 |     uint8_t bSts, bStsAlt;
 | 
|---|
| 598 | 
 | 
|---|
| 599 |     g_uBasePort  = uBasePort;
 | 
|---|
| 600 |     g_uCtrlPort  = uCtrlPort;
 | 
|---|
| 601 |     g_cPortShift = cPortShift;
 | 
|---|
| 602 |     g_bDevice    = bDevice;
 | 
|---|
| 603 |     g_f8BitData  = f8BitData;
 | 
|---|
| 604 |     g_fSupportsSetFeature8BitData = 1;
 | 
|---|
| 605 |     g_fSupportsSetFeatureWriteCache = 1;
 | 
|---|
| 606 |     g_fSupportsSetFeatureXferMode = 1;
 | 
|---|
| 607 | 
 | 
|---|
| 608 |     /* Check whether the two status registers match up. If they don't we
 | 
|---|
| 609 |        probably don't have a controller at this address. */
 | 
|---|
| 610 |     inp(ATA_REG_STATUS(g_uBasePort));
 | 
|---|
| 611 |     bSts    = inp(ATA_REG_STATUS(g_uBasePort));
 | 
|---|
| 612 |     bStsAlt = inp(ATA_REG_ALT_STATUS(g_uCtrlPort));
 | 
|---|
| 613 |     if (bSts != bStsAlt || bSts == 0xff)
 | 
|---|
| 614 |     {
 | 
|---|
| 615 |         fprintf(stderr, "Status register differs or is 0xff\n");
 | 
|---|
| 616 |         fprintf(stderr, " port %#05x    status=", ATA_REG_STATUS(g_uBasePort));
 | 
|---|
| 617 |         AtaPrintStatus(stderr, bSts);
 | 
|---|
| 618 |         fprintf(stderr, "\n");
 | 
|---|
| 619 |         fprintf(stderr, " port %#05x alt status=", ATA_REG_ALT_STATUS(g_uCtrlPort));
 | 
|---|
| 620 |         AtaPrintStatus(stderr, bStsAlt);
 | 
|---|
| 621 |         fprintf(stderr, "\n");
 | 
|---|
| 622 |         return -1;
 | 
|---|
| 623 |     }
 | 
|---|
| 624 |     printf("Pre init status=");
 | 
|---|
| 625 |     AtaPrintStatus(stdout, bSts);
 | 
|---|
| 626 |     printf("\n");
 | 
|---|
| 627 | 
 | 
|---|
| 628 |     for (;;)
 | 
|---|
| 629 |     {
 | 
|---|
| 630 |         /* Reset the controller + devices. */
 | 
|---|
| 631 |         if (fReset)
 | 
|---|
| 632 |             if (AtaReset() != 0)
 | 
|---|
| 633 |                 return -1;
 | 
|---|
| 634 |         fReset = 1;
 | 
|---|
| 635 | 
 | 
|---|
| 636 |         /* Enable 8-bit data transfers (just to be on the safe side). */
 | 
|---|
| 637 |         if (g_fSupportsSetFeature8BitData)
 | 
|---|
| 638 |         {
 | 
|---|
| 639 |             if (g_f8BitData == 1 || g_f8BitData == 3)
 | 
|---|
| 640 |                 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_EN_8BIT_DATA, 0);
 | 
|---|
| 641 |             else if (g_f8BitData == 0)
 | 
|---|
| 642 |                 rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_8BIT_DATA, 0);
 | 
|---|
| 643 |             else
 | 
|---|
| 644 |                 rc = 0;
 | 
|---|
| 645 |             if (rc != 0)
 | 
|---|
| 646 |             {
 | 
|---|
| 647 |                 fprintf(stderr,
 | 
|---|
| 648 |                         f8BitData
 | 
|---|
| 649 |                         ? "warning: ATA_FEATURE_EN_8BIT_DATA failed, assuming not supported. Retrying in 16-bit mode."
 | 
|---|
| 650 |                         : "warning: ATA_FEATURE_DI_8BIT_DATA failed, assuming not supported. Retrying.");
 | 
|---|
| 651 |                 g_fSupportsSetFeature8BitData = 0;
 | 
|---|
| 652 |                 g_f8BitData = 0;
 | 
|---|
| 653 |                 continue;
 | 
|---|
| 654 |             }
 | 
|---|
| 655 |         }
 | 
|---|
| 656 | 
 | 
|---|
| 657 |         /* Try disable write cache. */
 | 
|---|
| 658 |         if (g_fSupportsSetFeatureWriteCache)
 | 
|---|
| 659 |         {
 | 
|---|
| 660 |             rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_WRITE_CACHE, 0);
 | 
|---|
| 661 |             if (rc != 0)
 | 
|---|
| 662 |             {
 | 
|---|
| 663 |                 fprintf(stderr, "warning: ATA_FEATURE_DI_WRITE_CACHE failed, assuming not supported. Retrying.");
 | 
|---|
| 664 |                 g_fSupportsSetFeatureWriteCache = 0;
 | 
|---|
| 665 |                 continue;
 | 
|---|
| 666 |             }
 | 
|---|
| 667 |         }
 | 
|---|
| 668 | 
 | 
|---|
| 669 |         /* Select PIO mode without IORDY. */
 | 
|---|
| 670 |         if (g_fSupportsSetFeatureXferMode)
 | 
|---|
| 671 |         {
 | 
|---|
| 672 |             rc = AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY);
 | 
|---|
| 673 |             if (rc != 0)
 | 
|---|
| 674 |             {
 | 
|---|
| 675 |                 fprintf(stderr, "warning: ATA_FEATURE_SET_XFERMODE = DEFAULT_NO_IORDY failed, assuming not supported. Retrying.");
 | 
|---|
| 676 |                 g_fSupportsSetFeatureXferMode = 0;
 | 
|---|
| 677 |                 continue;
 | 
|---|
| 678 |             }
 | 
|---|
| 679 |         }
 | 
|---|
| 680 | 
 | 
|---|
| 681 |         /* Identify the device. */
 | 
|---|
| 682 |         memset(g_awIdentify, 0, sizeof(g_awIdentify));
 | 
|---|
| 683 |         if (AtaIdentifyDevice(g_bDevice, g_awIdentify) != 0)
 | 
|---|
| 684 |             return -1;
 | 
|---|
| 685 | 
 | 
|---|
| 686 |         /** @todo this is rather simple... */
 | 
|---|
| 687 |         g_cCylinders = g_awIdentify[1];
 | 
|---|
| 688 |         g_cHeads     = g_awIdentify[3];
 | 
|---|
| 689 |         g_cSectorsPerTrack = g_awIdentify[6];
 | 
|---|
| 690 |         g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack;
 | 
|---|
| 691 |         printf("Device %#x at %#x/%#x: %u cylinders, %u heads, %u sectors, %s data\n",
 | 
|---|
| 692 |                g_bDevice, g_uBasePort, g_uCtrlPort, g_cCylinders, g_cHeads, g_cSectorsPerTrack,
 | 
|---|
| 693 |                g_f8BitData == 1 ? "8-bit" : g_f8BitData == 3 ? "8/16-bit" : g_f8BitData == 0 ? "16-bit(!)" : "16-bit");
 | 
|---|
| 694 | 
 | 
|---|
| 695 |         /* Figure 5-9 in SanDisk Manual Rev 12.0: */
 | 
|---|
| 696 |         if (   g_awIdentify[82] != 0 && g_awIdentify[82] != UINT16_C(0xffff)
 | 
|---|
| 697 |             && g_awIdentify[83] != 0 && g_awIdentify[83] != UINT16_C(0xffff)
 | 
|---|
| 698 |             && g_awIdentify[84] != 0 && g_awIdentify[84] != UINT16_C(0xffff)
 | 
|---|
| 699 |             && (g_awIdentify[83] & UINT16_C(0xc000)) == UINT16_C(0x4000)
 | 
|---|
| 700 |             && (g_awIdentify[84] & UINT16_C(0xc000)) == UINT16_C(0x4000) )
 | 
|---|
| 701 |         {
 | 
|---|
| 702 |             g_fSupportsWriteBuffer = (g_awIdentify[82] & UINT16_C(0x1000)) != 0;
 | 
|---|
| 703 |             g_fSupportsReadBuffer  = (g_awIdentify[82] & UINT16_C(0x2000)) != 0;
 | 
|---|
| 704 |         }
 | 
|---|
| 705 |         printf("  %s WRITE_BUFFER, %s READ_BUFFER\n",
 | 
|---|
| 706 |                g_fSupportsWriteBuffer == 1 ? "have" : g_fSupportsWriteBuffer == 0 ? "no" : "uncertain",
 | 
|---|
| 707 |                g_fSupportsReadBuffer  == 1 ? "have" : g_fSupportsReadBuffer  == 0 ? "no" : "uncertain");
 | 
|---|
| 708 |         break;
 | 
|---|
| 709 |     }
 | 
|---|
| 710 | 
 | 
|---|
| 711 |     return 0;
 | 
|---|
| 712 | }
 | 
|---|
| 713 | 
 | 
|---|
| 714 | int AtaArgMatchWithValue(const char *pszArg, const char *pszMatch, size_t cchMatch,
 | 
|---|
| 715 |                          int cArgs, char **papszArgs, int *piArg, const char **ppszValue)
 | 
|---|
| 716 | {
 | 
|---|
| 717 |     if (strncmp(pszArg, pszMatch, cchMatch) == 0)
 | 
|---|
| 718 |     {
 | 
|---|
| 719 |         pszArg += cchMatch;
 | 
|---|
| 720 |         if (!*pszArg)
 | 
|---|
| 721 |         {
 | 
|---|
| 722 |             if (*piArg < cArgs)
 | 
|---|
| 723 |             {
 | 
|---|
| 724 |                 *ppszValue = papszArgs[*piArg];
 | 
|---|
| 725 |                 *piArg += 1;
 | 
|---|
| 726 |             }
 | 
|---|
| 727 |             else
 | 
|---|
| 728 |             {
 | 
|---|
| 729 |                 fprintf(stderr, "syntax error: Option '%s' is missing argument value\n", pszMatch);
 | 
|---|
| 730 |                 *ppszValue = NULL;
 | 
|---|
| 731 |             }
 | 
|---|
| 732 |             return 1;
 | 
|---|
| 733 |         }
 | 
|---|
| 734 | 
 | 
|---|
| 735 |         if (*pszArg == ':' || *pszArg == '=')
 | 
|---|
| 736 |         {
 | 
|---|
| 737 |             if (!*pszArg)
 | 
|---|
| 738 |                 fprintf(stderr, "syntax error: Option '%s' is missing argument value\n", pszMatch);
 | 
|---|
| 739 |             *ppszValue = pszArg;
 | 
|---|
| 740 |             return 1;
 | 
|---|
| 741 |         }
 | 
|---|
| 742 |     }
 | 
|---|
| 743 | 
 | 
|---|
| 744 |     return 0;
 | 
|---|
| 745 | }
 | 
|---|
| 746 | 
 | 
|---|
| 747 | int AtaInitFromArgv(int iArg, int cArgs, char **papszArgs)
 | 
|---|
| 748 | {
 | 
|---|
| 749 |     uint8_t  bDevice    = ATA_DEV_MASTER;
 | 
|---|
| 750 |     uint8_t  fReset     = 0;
 | 
|---|
| 751 | #if 0
 | 
|---|
| 752 |     uint16_t uBasePort  = 0x1f0;    /* Primary ATA host controller. */
 | 
|---|
| 753 |     uint16_t uCtrlPort  = 0x3f0;    /* The control block of the primary ATA host controller. */
 | 
|---|
| 754 |     uint8_t  cShiftPort = 0;
 | 
|---|
| 755 |     uint8_t  f8BitData  = 0;
 | 
|---|
| 756 | #else
 | 
|---|
| 757 |     uint16_t uBasePort  = 0x300;    /* Lo-tech CF-lite. */
 | 
|---|
| 758 |     uint16_t uCtrlPort  = 0x310;    /* Lo-tech CF-lite. */
 | 
|---|
| 759 |     uint8_t  cShiftPort = 1;        /* Special Lo-tech CF-lite hack. */
 | 
|---|
| 760 |     uint8_t  f8BitData  = 1;
 | 
|---|
| 761 | #endif
 | 
|---|
| 762 | 
 | 
|---|
| 763 |     while (iArg < cArgs)
 | 
|---|
| 764 |     {
 | 
|---|
| 765 |         const char *pszArg = papszArgs[iArg++];
 | 
|---|
| 766 |         const char *pszValue;
 | 
|---|
| 767 |         int         iWhich = 0;
 | 
|---|
| 768 |         if (   (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("--base-port"), cArgs, papszArgs, &iArg, &pszValue))
 | 
|---|
| 769 |             || (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("-b"), cArgs, papszArgs, &iArg, &pszValue))
 | 
|---|
| 770 |             || (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("--ctrl-port"), cArgs, papszArgs, &iArg, &pszValue) * 2)
 | 
|---|
| 771 |             || (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("-c"), cArgs, papszArgs, &iArg, &pszValue)          * 2) )
 | 
|---|
| 772 |          {
 | 
|---|
| 773 |             unsigned long uTmp = strtoul(pszValue, NULL, 16);
 | 
|---|
| 774 |             if (uTmp < 16 || uTmp >= 1024)
 | 
|---|
| 775 |             {
 | 
|---|
| 776 |                 fprintf(stderr, "error: Invalid port number %#lx for %s (valid range 0x010..0x3ff)\n", uTmp, pszArg);
 | 
|---|
| 777 |                 return -1;
 | 
|---|
| 778 |             }
 | 
|---|
| 779 |             if (iWhich == 1)
 | 
|---|
| 780 |                 uBasePort = (uint16_t)uTmp;
 | 
|---|
| 781 |             else
 | 
|---|
| 782 |                 uCtrlPort = (uint16_t)uTmp;
 | 
|---|
| 783 |         }
 | 
|---|
| 784 |         else if (   AtaArgMatchWithValue(pszArg, STR_TUPLE("--port-shift"), cArgs, papszArgs, &iArg, &pszValue)
 | 
|---|
| 785 |                  || AtaArgMatchWithValue(pszArg, STR_TUPLE("-s"), cArgs, papszArgs, &iArg, &pszValue) )
 | 
|---|
| 786 |         {
 | 
|---|
| 787 |             unsigned long uTmp = strtoul(pszValue, NULL, 0);
 | 
|---|
| 788 |             if (uTmp >= 4)
 | 
|---|
| 789 |             {
 | 
|---|
| 790 |                 fprintf(stderr, "error: Invalid port shift number %#lx (valid range 0..3)\n", uTmp);
 | 
|---|
| 791 |                 return -1;
 | 
|---|
| 792 |             }
 | 
|---|
| 793 |             cShiftPort = (uint8_t)uTmp;
 | 
|---|
| 794 |         }
 | 
|---|
| 795 |         else if (   AtaArgMatchWithValue(pszArg, STR_TUPLE("--device"), cArgs, papszArgs, &iArg, &pszValue)
 | 
|---|
| 796 |                  || AtaArgMatchWithValue(pszArg, STR_TUPLE("-d"), cArgs, papszArgs, &iArg, &pszValue) )
 | 
|---|
| 797 |         {
 | 
|---|
| 798 |             unsigned long uTmp = strtoul(pszValue, NULL, 16);
 | 
|---|
| 799 |             if (   uTmp != ATA_DEV_MASTER
 | 
|---|
| 800 |                 && uTmp != ATA_DEV_SLAVE)
 | 
|---|
| 801 |             {
 | 
|---|
| 802 |                 fprintf(stderr, "error: Invalid device number %#lx; only %#x (master) or %#x (slave) are allowed.\n",
 | 
|---|
| 803 |                         uTmp, ATA_DEV_MASTER, ATA_DEV_SLAVE);
 | 
|---|
| 804 |                 return -1;
 | 
|---|
| 805 |             }
 | 
|---|
| 806 |             bDevice = (uint8_t)uTmp;
 | 
|---|
| 807 |         }
 | 
|---|
| 808 |         else if (   strcmp(pszArg, "--8-bit-data") == 0
 | 
|---|
| 809 |                  || strcmp(pszArg, "-8") == 0)
 | 
|---|
| 810 |             f8BitData = 1;
 | 
|---|
| 811 |         else if (   strcmp(pszArg, "--8-bit-data-plus") == 0
 | 
|---|
| 812 |                  || strcmp(pszArg, "-8+") == 0)
 | 
|---|
| 813 |             f8BitData = 3;
 | 
|---|
| 814 |         else if (   strcmp(pszArg, "--16-bit-data") == 0
 | 
|---|
| 815 |                  || strcmp(pszArg, "-16") == 0)
 | 
|---|
| 816 |             f8BitData = 0;
 | 
|---|
| 817 |         else if (strcmp(pszArg, "--16-bit-data-no-change") == 0)
 | 
|---|
| 818 |             f8BitData = UINT8_MAX;
 | 
|---|
| 819 |         else if (strcmp(pszArg, "--reset") == 0)
 | 
|---|
| 820 |             fReset = 1;
 | 
|---|
| 821 |         else if (strcmp(pszArg, "--no-reset") == 0)
 | 
|---|
| 822 |             fReset = 0;
 | 
|---|
| 823 |         else if (   strcmp(pszArg, "--ide") == 0
 | 
|---|
| 824 |                  || strcmp(pszArg, "--ide-primary") == 0)
 | 
|---|
| 825 |         {
 | 
|---|
| 826 |             /* Normal IDE, primary. */
 | 
|---|
| 827 |             uBasePort  = 0x1f0;
 | 
|---|
| 828 |             uCtrlPort  = 0x3f0;
 | 
|---|
| 829 |             cShiftPort = 0;
 | 
|---|
| 830 |             f8BitData  = UINT8_MAX;
 | 
|---|
| 831 |         }
 | 
|---|
| 832 |         else if (strcmp(pszArg, "--ide-secondary") == 0)
 | 
|---|
| 833 |         {
 | 
|---|
| 834 |             /* Normal IDE, secondary. */
 | 
|---|
| 835 |             uBasePort  = 0x170;
 | 
|---|
| 836 |             uCtrlPort  = 0x370;
 | 
|---|
| 837 |             cShiftPort = 0;
 | 
|---|
| 838 |             f8BitData  = UINT8_MAX;
 | 
|---|
| 839 |         }
 | 
|---|
| 840 |         else if (strcmp(pszArg, "--xt-cf") == 0)
 | 
|---|
| 841 |         {
 | 
|---|
| 842 |             /* Lo-tech CF-lite. */
 | 
|---|
| 843 |             uBasePort  = 0x300;
 | 
|---|
| 844 |             uCtrlPort  = 0x310;
 | 
|---|
| 845 |             cShiftPort = 1;
 | 
|---|
| 846 |             f8BitData  = 1;
 | 
|---|
| 847 |         }
 | 
|---|
| 848 |     }
 | 
|---|
| 849 | 
 | 
|---|
| 850 |     return AtaInit(uBasePort, uCtrlPort, cShiftPort, bDevice, f8BitData, fReset);
 | 
|---|
| 851 | }
 | 
|---|
| 852 | 
 | 
|---|