summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/drivers/ata.c98
1 files changed, 53 insertions, 45 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 807d441351..d547692b56 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -81,6 +81,8 @@
81 81
82#define Q_SLEEP 0 82#define Q_SLEEP 0
83 83
84#define READ_TIMEOUT 5*HZ
85
84static struct mutex ata_mtx; 86static struct mutex ata_mtx;
85char ata_device; /* device 0 (master) or 1 (slave) */ 87char ata_device; /* device 0 (master) or 1 (slave) */
86int ata_io_address; /* 0x300 or 0x200, only valid on recorder */ 88int ata_io_address; /* 0x300 or 0x200, only valid on recorder */
@@ -166,6 +168,7 @@ int ata_read_sectors(unsigned long start,
166 void* buf) 168 void* buf)
167{ 169{
168 int ret = 0; 170 int ret = 0;
171 int timeout;
169 172
170 last_disk_activity = current_tick; 173 last_disk_activity = current_tick;
171 174
@@ -196,62 +199,67 @@ int ata_read_sectors(unsigned long start,
196 199
197 led(true); 200 led(true);
198 201
199 if ( count == 256 ) 202 timeout = current_tick + READ_TIMEOUT;
200 ATA_NSECTOR = 0; /* 0 means 256 sectors */ 203 while (TIME_BEFORE(current_tick, timeout)) {
201 else
202 ATA_NSECTOR = (unsigned char)count;
203
204 ATA_SECTOR = start & 0xff;
205 ATA_LCYL = (start >> 8) & 0xff;
206 ATA_HCYL = (start >> 16) & 0xff;
207 ATA_SELECT = ((start >> 24) & 0xf) | SELECT_LBA | ata_device;
208 ATA_COMMAND = CMD_READ_MULTIPLE;
209
210 while (count) {
211 int j;
212 int sectors;
213 int wordcount;
214 204
215 if (!wait_for_start_of_transfer()) 205 if ( count == 256 )
216 { 206 ATA_NSECTOR = 0; /* 0 means 256 sectors */
217 led(false); 207 else
218 mutex_unlock(&ata_mtx); 208 ATA_NSECTOR = (unsigned char)count;
219 return -1; 209
220 } 210 ATA_SECTOR = start & 0xff;
211 ATA_LCYL = (start >> 8) & 0xff;
212 ATA_HCYL = (start >> 16) & 0xff;
213 ATA_SELECT = ((start >> 24) & 0xf) | SELECT_LBA | ata_device;
214 ATA_COMMAND = CMD_READ_MULTIPLE;
215
216 while (count) {
217 int j;
218 int sectors;
219 int wordcount;
220
221 if (!wait_for_start_of_transfer()) {
222 ret = -4;
223 continue;
224 }
221 225
222 /* if destination address is odd, use byte copying, 226 /* if destination address is odd, use byte copying,
223 otherwise use word copying */ 227 otherwise use word copying */
224 228
225 if (count >= multisectors ) 229 if (count >= multisectors )
226 sectors = multisectors; 230 sectors = multisectors;
227 else 231 else
228 sectors = count; 232 sectors = count;
229 233
230 wordcount = sectors * SECTOR_SIZE / 2; 234 wordcount = sectors * SECTOR_SIZE / 2;
231 235
232 if ( (unsigned int)buf & 1 ) { 236 if ( (unsigned int)buf & 1 ) {
233 for (j=0; j < wordcount; j++) { 237 for (j=0; j < wordcount; j++) {
234 unsigned short tmp = SWAB16(ATA_DATA); 238 unsigned short tmp = SWAB16(ATA_DATA);
235 ((unsigned char*)buf)[j*2] = tmp >> 8; 239 ((unsigned char*)buf)[j*2] = tmp >> 8;
236 ((unsigned char*)buf)[j*2+1] = tmp & 0xff; 240 ((unsigned char*)buf)[j*2+1] = tmp & 0xff;
241 }
242 }
243 else {
244 for (j=0; j < wordcount; j++)
245 ((unsigned short*)buf)[j] = SWAB16(ATA_DATA);
237 } 246 }
238 }
239 else {
240 for (j=0; j < wordcount; j++)
241 ((unsigned short*)buf)[j] = SWAB16(ATA_DATA);
242 }
243 247
244#ifdef USE_INTERRUPT 248#ifdef USE_INTERRUPT
245 /* reading the status register clears the interrupt */ 249 /* reading the status register clears the interrupt */
246 j = ATA_STATUS; 250 j = ATA_STATUS;
247#endif 251#endif
248 buf += sectors * SECTOR_SIZE; /* Advance one chunk of sectors */ 252 buf += sectors * SECTOR_SIZE; /* Advance one chunk of sectors */
249 count -= sectors; 253 count -= sectors;
250 } 254 }
251 255
252 if(!wait_for_end_of_transfer()) 256 if(!wait_for_end_of_transfer()) {
253 ret = -3; 257 ret = -3;
258 continue;
259 }
254 260
261 break;
262 }
255 led(false); 263 led(false);
256 264
257 mutex_unlock(&ata_mtx); 265 mutex_unlock(&ata_mtx);