3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
5 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 #include <partition.h>
36 extern unsigned long timer_ticks
;
38 static int drive_type (int port
)
41 unsigned char c
= inb (0x71);
44 return DRIVE_TYPE_CDROM
;
46 return DRIVE_TYPE_HDD
;
49 int lba28_drive_detect (int id
)
55 outb (0x1F6, 0xA0); // use 0xB0 instead of 0xA0 to test the second drive on the controller
57 delay (200); // wait 1/250th of a second
59 tmpword
= inb (0x1F7); // read the status port
60 if (tmpword
& 0x40) // see if the busy bit is set
65 outb (0x1F6, 0xB0); // use 0xB0 instead of 0xA0 to test the second drive on the controller
67 delay (200); // wait 1/250th of a second
69 tmpword
= inb (0x1F7); // read the status port
70 if (tmpword
& 0x40) // see if the busy bit is set
75 outb (0x176, 0xA0); // use 0xB0 instead of 0xA0 to test the second drive on the controller
77 delay (200); // wait 1/250th of a second
79 tmpword
= inb (0x177); // read the status port
80 if (tmpword
& 0x40) // see if the busy bit is set
85 outb (0x176, 0xB0); // use 0xB0 instead of 0xA0 to test the second drive on the controller
87 delay (200); // wait 1/250th of a second
89 tmpword
= inb (0x177); // read the status port
90 if (tmpword
& 0x40) // see if the busy bit is set
97 /* check status of currently selected device */
98 int ata_status (partition_t
*p
, int flag
)
100 int status
= inb (p
->base_io
+ ATA_STATUS
);
104 if(status
& ATA_STATUS_ERR
)
108 if(status
& ATA_STATUS_BUSY
)
112 if(status
& ATA_STATUS_DRQ
)
122 int ata_wait (partition_t
*p
)
124 unsigned long stime
= timer_ticks
;
126 /* timeout for 5000ms */
127 while ((stime
+5000) > timer_ticks
) {
128 if (!ata_status (p
, LBA_FLAG_BUSY
))
137 int lba28_drive_read (partition_t
*p
, unsigned addr
, unsigned char *buffer
)
142 outb (p
->base_io
+ 1, 0x00);
143 outb (p
->base_io
+ 2, (unsigned char) 0x01);
144 outb (p
->base_io
+ 3, (unsigned) addr
);
145 outb (p
->base_io
+ 4, (unsigned) (addr
>> 8));
146 outb (p
->base_io
+ 5, (unsigned) (addr
>> 16));
147 outb (p
->base_io
+ 6, 0xE0 | (p
->id
<< 4) | ((addr
>> 24) & 0x0F));
148 outb (p
->base_io
+ 7, 0x20);
151 DPRINT (DBG_DRIVER
| DBG_BLOCK
, "lba28_drive_read: device is busy");
155 /*if (ata_status (p, LBA_FLAG_ERROR)) {
156 DPRINT (DBG_DRIVER | DBG_BLOCK, "lba28_drive_read: read error - device");
160 if (!ata_status (p
, LBA_FLAG_DATA
)) {
161 DPRINT (DBG_DRIVER
| DBG_BLOCK
, "lba28_drive_read: no data are available");
165 unsigned short tmpword
;
168 for (idx
= 0; idx
< 256; idx
++) {
169 tmpword
= inw (p
->base_io
);
170 buffer
[idx
* 2] = (unsigned char)tmpword
;
171 buffer
[idx
* 2 + 1] = (unsigned char) (tmpword
>> 8);
177 /* NOTE: this code is buggy, because you need everytime go from 0 to 256 indexes (512 bytes) */
178 int lba28_drive_read_len (partition_t
*p
, unsigned addr
, unsigned char *buffer
, unsigned len
)
181 outb (0x1F2, (unsigned char) 0x01);
182 outb (0x1F3, (unsigned) addr
);
183 outb (0x1F4, (unsigned) (addr
>> 8));
184 outb (0x1F5, (unsigned) (addr
>> 16));
185 outb (0x1F6, 0xE0 | (p
->id
<< 4) | ((addr
>> 24) & 0x0F));
190 while (!(inb (0x1F7) & 0x08)) // 0x08
193 unsigned short tmpword
;
197 for (idx
= 0; idx
< len
; idx
++) {
198 tmpword
= inw (0x1F0);
202 buffer
[i
] = (unsigned char) tmpword
;
204 buffer
[i
+ 1] = (unsigned char) (tmpword
>> 8);
210 int lba28_drive_write (partition_t
*p
, unsigned addr
, unsigned char *buffer
)
215 /* p->id = 0 for master device */
216 outb (p
->base_io
+ 1, 0x00);
217 outb (p
->base_io
+ 2, (unsigned char) 0x01);
218 outb (p
->base_io
+ 3, (unsigned) addr
);
219 outb (p
->base_io
+ 4, (unsigned) (addr
>> 8));
220 outb (p
->base_io
+ 5, (unsigned) (addr
>> 16));
221 outb (p
->base_io
+ 6, 0xE0 | (p
->id
<< 4) | ((addr
>> 24) & 0x0F));
222 outb (p
->base_io
+ 7, 0x30);
224 unsigned long stime
= timer_ticks
;
227 DPRINT (DBG_DRIVER
| DBG_BLOCK
, "lba28_drive_write: device is busy");
231 /*if (ata_status (p, LBA_FLAG_ERROR)) {
232 DPRINT (DBG_DRIVER | DBG_BLOCK, "lba28_drive_write: write error - device");
236 /*if (!ata_status (p, LBA_FLAG_DATA)) {
237 DPRINT (DBG_DRIVER | DBG_BLOCK, "lba28_drive_write: no data are available");
241 unsigned short tmpword
;
244 for (idx
= 0; idx
< 256; idx
++) {
245 tmpword
= buffer
[idx
* 2] | (buffer
[idx
* 2 + 1] << 8);
246 outw (p
->base_io
, tmpword
);
252 /* NOTE: this code is buggy, because you need everytime go from 0 to 256 indexes (512 bytes) */
253 int lba28_drive_write_len (partition_t
*p
, unsigned addr
, unsigned char *buffer
, unsigned len
)
256 outb (0x1F2, (unsigned char) 0x01);
257 outb (0x1F3, (unsigned) addr
);
258 outb (0x1F4, (unsigned char) (addr
>> 8));
259 outb (0x1F5, (unsigned char) (addr
>> 16));
260 outb (0x1F6, 0xE0 | (p
->id
<< 4) | ((addr
>> 24) & 0x0F));
263 while (!(inb (0x1F7) & 0x08))
266 unsigned short tmpword
;
267 unsigned short l
= 0;
268 unsigned short h
= 0;
272 for (idx
= 0; idx
< 256; idx
++) {
280 h
= (buffer
[idx
* 2 + 1] << 8);
283 outw (0x1F0, tmpword
);
289 int lba28_drive_write_spec (partition_t
*p
, unsigned addr
, unsigned char *buffer
, unsigned len
, unsigned offset
)
292 outb (0x1F2, (unsigned char) 0x01);
293 outb (0x1F3, (unsigned) addr
);
294 outb (0x1F4, (unsigned char) (addr
>> 8));
295 outb (0x1F5, (unsigned char) (addr
>> 16));
296 outb (0x1F6, 0xE0 | (p
->id
<< 4) | ((addr
>> 24) & 0x0F));
299 while (!(inb (0x1F7) & 0x08))
302 unsigned short tmpword
;
303 unsigned short l
= 0;
304 unsigned short h
= 0;
309 for (idx
= 0; idx
< 256; idx
++) {
316 l
= buffer
[i
-offset
];
319 if ((i
+1) < len
+offset
)
320 h
= buffer
[i
-offset
+1] << 8;
324 outw (0x1F0, tmpword
);
330 int lba48_drive_write (partition_t
*p
, unsigned long long addr
, unsigned char *buffer
)
338 outb (0x1F3, (unsigned char) (addr
>> 24));
339 outb (0x1F3, (unsigned char) addr
);
340 outb (0x1F4, (unsigned char) (addr
>> 32));
341 outb (0x1F4, (unsigned char) (addr
>> 8));
342 outb (0x1F5, (unsigned char) (addr
>> 40));
343 outb (0x1F5, (unsigned char) (addr
>> 16));
345 outb (0x1F6, 0x40 | (p
->id
<< 4));
349 while (!(inb (0x1F7) & 0x08)) // 0x08
352 unsigned short tmpword
;
355 for (idx
= 0; idx
< 256; idx
++) {
356 tmpword
= buffer
[idx
* 2] | (buffer
[idx
* 2 + 1] << 8);
357 outw (0x1F0, tmpword
);
363 bool ide_acthandler (unsigned act
, partition_t
*p
, char *block
, char *more
, int n
)
373 return (bool) lba28_drive_read (p
, n
, block
);
378 return (bool) lba28_drive_write (p
, n
, block
);
383 //fs_t *fs = fs_detect (p);
388 unsigned l
= strlen (more
);
391 if (!p
->fs
->handler (FS_ACT_CHDIR
, more
, -1, 0))
395 while (dir[x].name[0] != '\0') {
396 printf ("slozka: '%s'\n", dir[x].name);
401 if (!strcmp (more
, "."))
402 return p
->fs
->handler (FS_ACT_CHDIR
, more
, 0, l
);
404 if (!strcmp (more
, ".."))
405 return p
->fs
->handler (FS_ACT_CHDIR
, more
, 1, l
);
407 while (strlen (dir
[f
].name
)) {
408 //printf ("drive__: '%s' : %d | '%s'\n", dir[f].name, f, more);
409 if (!strncmp (dir
[f
].name
, more
, l
)) {
410 if (!p
->fs
->handler (FS_ACT_CHDIR
, more
, f
, l
))
425 unsigned fl
= strlen (dir
[f
].name
);
428 unsigned attrib
= VFS_FILEATTR_MOUNTED
;
432 if (dir[f].name[x] != ' ')
437 #define VFS_FILEATTR_FILE 0x1
438 #define VFS_FILEATTR_DIR 0x2
439 #define VFS_FILEATTR_HIDDEN 0x4
440 #define VFS_FILEATTR_SYSTEM 0x8
441 #define VFS_FILEATTR_BIN 0x10
442 #define VFS_FILEATTR_READ 0x20
443 #define VFS_FILEATTR_WRITE 0x40
445 case 0: dir[y].read=1; break;
446 case 1: dir[y].hidden=1; break;
447 case 2: dir[y].system=1; break;
448 case 3: dir[y].volume=1; break;
449 case 4: dir[y].dir=1; break;
450 case 5: dir[y].bin=1; break;
454 attrib
|= VFS_FILEATTR_READ
;
455 attrib
|= VFS_FILEATTR_WRITE
;
458 attrib
|= VFS_FILEATTR_HIDDEN
;
460 attrib
|= VFS_FILEATTR_SYSTEM
;
462 attrib
|= VFS_FILEATTR_DIR
;
464 attrib
|= VFS_FILEATTR_FILE
;
466 attrib
|= VFS_FILEATTR_BIN
;
470 if (dir
[f
].name
[i
] == ' ')
471 dir
[f
].name
[i
] = '\0';
478 vfs_list_add (dir
[f
].name
, attrib
, block
);
488 //printf ("add: %s to %s | %d%d%d%d%d\n", dir[f].name, block, dir[f].read, dir[f].hidden, dir[f].system, dir[f].volume, dir[f].dir, dir[f].bin);
491 fl
= strlen (dir
[f
].name
);
499 if (!p
->fs
->handler (FS_ACT_EXIT
, more
, -1, 0))
509 bool ata_acthandler (unsigned act
, char drive
, char *block
)
514 if (kernel_attr
& KERNEL_NOATA
)
519 if (lba28_drive_detect (0)) {
520 /* when it's hdd, check partition table, else pre-set isofs on cdrom drive */
521 int type
= drive_type (0x1b);
523 dev_t
*dev
= (dev_t
*) dev_register (type
== DRIVE_TYPE_CDROM
? "cda" : "hda",
524 "Drive controller", DEV_ATTR_BLOCK
, (dev_handler_t
*) &ide_acthandler
);
526 if (type
== DRIVE_TYPE_HDD
)
527 partition_table (dev
);
528 else if (type
== DRIVE_TYPE_CDROM
)
529 partition_add (dev
, fs_supported ("isofs"), 0);
534 if (lba28_drive_detect (1)) {
535 /* when it's hdd, check partition table, else pre-set isofs on cdrom drive */
536 int type
= drive_type (0x24+9);
538 dev_t
*dev
= (dev_t
*) dev_register (type
== DRIVE_TYPE_CDROM
? "cdb" : "hdb",
539 "Drive controller", DEV_ATTR_BLOCK
, (dev_handler_t
*) &ide_acthandler
);
541 if (type
== DRIVE_TYPE_HDD
)
542 partition_table (dev
);
543 else if (type
== DRIVE_TYPE_CDROM
)
544 partition_add (dev
, fs_supported ("isofs"), 0);
549 if (lba28_drive_detect (2)) {
550 /* when it's hdd, check partition table, else pre-set isofs on cdrom drive */
551 int type
= drive_type (0x24);
553 dev_t
*dev
= (dev_t
*) dev_register (type
== DRIVE_TYPE_CDROM
? "cdc" : "hdc",
554 "Drive controller", DEV_ATTR_BLOCK
, (dev_handler_t
*) &ide_acthandler
);
556 if (type
== DRIVE_TYPE_HDD
)
557 partition_table (dev
);
558 else if (type
== DRIVE_TYPE_CDROM
)
559 partition_add (dev
, fs_supported ("isofs"), 0);
564 if (lba28_drive_detect (3)) {
565 /* when it's hdd, check partition table, else pre-set isofs on cdrom drive */
566 int type
= drive_type (0x24+18);
568 dev_t
*dev
= (dev_t
*) dev_register (type
== DRIVE_TYPE_CDROM
? "cdd" : "hdd",
569 "Drive controller", DEV_ATTR_BLOCK
, (dev_handler_t
*) &ide_acthandler
);
571 if (type
== DRIVE_TYPE_HDD
)
572 partition_table (dev
);
573 else if (type
== DRIVE_TYPE_CDROM
)
574 partition_add (dev
, fs_supported ("isofs"), 0);
584 lba28_drive_read (drive, 0x01, n, block);
590 lba28_drive_write (drive, 0x01, n, block);