Cleanup in elf.c with .bss section clean; adm command mounts cdrom instead of floppy...
[ZeXOS.git] / kernel / drivers / block / drive.c
blob2d6531fc16699bbe7c88ddc3cfaac389d380e650
1 /*
2 * ZeX/OS
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/>.
22 #include <config.h>
23 #include <build.h>
25 #ifdef ARCH_i386
27 #include <system.h>
28 #include <mytypes.h>
29 #include <partition.h>
30 #include <dev.h>
31 #include <vfs.h>
32 #include <fs.h>
33 #include <arch/io.h>
34 #include <drive.h>
36 extern unsigned long timer_ticks;
38 static int drive_type (int port)
40 outb (0x70, port);
41 unsigned char c = inb (0x71);
43 if (c == 255)
44 return DRIVE_TYPE_CDROM;
46 return DRIVE_TYPE_HDD;
49 int lba28_drive_detect (int id)
51 int tmpword;
53 switch (id) {
54 case 0:
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
61 return 1;
63 return 0;
64 case 1:
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
71 return 1;
73 return 0;
74 case 2:
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
81 return 1;
83 return 0;
84 case 3:
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
91 return 1;
93 return 0;
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);
102 switch (flag) {
103 case LBA_FLAG_ERROR:
104 if(status & ATA_STATUS_ERR)
105 return 1;
106 break;
107 case LBA_FLAG_BUSY:
108 if(status & ATA_STATUS_BUSY)
109 return 1;
110 break;
111 case LBA_FLAG_DATA:
112 if(status & ATA_STATUS_DRQ)
113 return 1;
114 break;
115 default:
116 break;
119 return 0;
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))
129 return 0;
131 schedule ();
134 return 1;
137 int lba28_drive_read (partition_t *p, unsigned addr, unsigned char *buffer)
139 if (!p->base_io)
140 return 0;
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);
150 if (ata_wait (p)) {
151 DPRINT (DBG_DRIVER | DBG_BLOCK, "lba28_drive_read: device is busy");
152 return 0;
155 /*if (ata_status (p, LBA_FLAG_ERROR)) {
156 DPRINT (DBG_DRIVER | DBG_BLOCK, "lba28_drive_read: read error - device");
157 return 0;
160 if (!ata_status (p, LBA_FLAG_DATA)) {
161 DPRINT (DBG_DRIVER | DBG_BLOCK, "lba28_drive_read: no data are available");
162 return 0;
165 unsigned short tmpword;
166 // for read:
167 int idx;
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);
174 return 1;
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)
180 outb (0x1F1, 0x00);
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));
186 outb (0x1F7, 0x20);
188 //usleep (1000);
190 while (!(inb (0x1F7) & 0x08)) // 0x08
191 schedule ();
193 unsigned short tmpword;
194 // for read:
195 int idx;
196 int i;
197 for (idx = 0; idx < len; idx ++) {
198 tmpword = inw (0x1F0);
199 i = (idx * 2);
201 if (i < len)
202 buffer[i] = (unsigned char) tmpword;
203 if (i+1 < len)
204 buffer[i + 1] = (unsigned char) (tmpword >> 8);
207 return 1;
210 int lba28_drive_write (partition_t *p, unsigned addr, unsigned char *buffer)
212 if (!p->base_io)
213 return 0;
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;
226 if (ata_wait (p)) {
227 DPRINT (DBG_DRIVER | DBG_BLOCK, "lba28_drive_write: device is busy");
228 return 0;
231 /*if (ata_status (p, LBA_FLAG_ERROR)) {
232 DPRINT (DBG_DRIVER | DBG_BLOCK, "lba28_drive_write: write error - device");
233 return 0;
236 /*if (!ata_status (p, LBA_FLAG_DATA)) {
237 DPRINT (DBG_DRIVER | DBG_BLOCK, "lba28_drive_write: no data are available");
238 return 0;
241 unsigned short tmpword;
242 // for write:
243 int idx;
244 for (idx = 0; idx < 256; idx ++) {
245 tmpword = buffer[idx * 2] | (buffer[idx * 2 + 1] << 8);
246 outw (p->base_io, tmpword);
249 return 1;
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)
255 outb (0x1F1, 0x00);
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));
261 outb (0x1F7, 0x30);
263 while (!(inb (0x1F7) & 0x08))
264 schedule ();
266 unsigned short tmpword;
267 unsigned short l = 0;
268 unsigned short h = 0;
269 // for write:
271 int idx;
272 for (idx = 0; idx < 256; idx ++) {
273 l = 0;
274 h = 0;
276 if ((idx*2) < len)
277 l = buffer[idx * 2];
279 if ((idx*2+1) < len)
280 h = (buffer[idx * 2 + 1] << 8);
282 tmpword = l | h;
283 outw (0x1F0, tmpword);
286 return 1;
289 int lba28_drive_write_spec (partition_t *p, unsigned addr, unsigned char *buffer, unsigned len, unsigned offset)
291 outb (0x1F1, 0x00);
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));
297 outb (0x1F7, 0x30);
299 while (!(inb (0x1F7) & 0x08))
300 schedule ();
302 unsigned short tmpword;
303 unsigned short l = 0;
304 unsigned short h = 0;
305 // for write:
307 int idx;
308 int i = 0;
309 for (idx = 0; idx < 256; idx ++) {
310 l = 0;
311 h = 0 << 8;
312 i = (idx*2);
314 if (i >= offset)
315 if (i < len+offset)
316 l = buffer[i-offset];
318 if ((i+1) >= offset)
319 if ((i+1) < len+offset)
320 h = buffer[i-offset+1] << 8;
323 tmpword = l | h;
324 outw (0x1F0, tmpword);
327 return 1;
330 int lba48_drive_write (partition_t *p, unsigned long long addr, unsigned char *buffer)
332 outb (0x1F1, 0x00);
333 outb (0x1F1, 0x00);
335 outb (0x1F2, 0x00);
336 outb (0x1F2, 0x01);
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));
347 outb (0x1F7, 0x34);
349 while (!(inb (0x1F7) & 0x08)) // 0x08
350 schedule ();
352 unsigned short tmpword;
353 // for write:
354 int idx;
355 for (idx = 0; idx < 256; idx ++) {
356 tmpword = buffer[idx * 2] | (buffer[idx * 2 + 1] << 8);
357 outw (0x1F0, tmpword);
360 return 1;
363 bool ide_acthandler (unsigned act, partition_t *p, char *block, char *more, int n)
365 switch (act) {
366 case DEV_ACT_INIT:
368 return 1;
370 break;
371 case DEV_ACT_READ:
373 return (bool) lba28_drive_read (p, n, block);
375 break;
376 case DEV_ACT_WRITE:
378 return (bool) lba28_drive_write (p, n, block);
380 break;
381 case DEV_ACT_MOUNT:
383 //fs_t *fs = fs_detect (p);
384 int f = 0, t = 0;
386 curr_part = p;
388 unsigned l = strlen (more);
390 if (!l)
391 if (!p->fs->handler (FS_ACT_CHDIR, more, -1, 0))
392 return 0;
394 unsigned x = 0;
395 while (dir[x].name[0] != '\0') {
396 printf ("slozka: '%s'\n", dir[x].name);
397 x ++;
400 if (l) {
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))
411 return 0;
413 t = 1;
414 break;
417 f ++;
420 if (!t)
421 return 0;
424 f = 0;
425 unsigned fl = strlen (dir[f].name);
427 while (fl) {
428 unsigned attrib = VFS_FILEATTR_MOUNTED;
430 /*unsigned x = fl;
431 while (x) {
432 if (dir[f].name[x] != ' ')
434 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;
453 if (dir[f].read) {
454 attrib |= VFS_FILEATTR_READ;
455 attrib |= VFS_FILEATTR_WRITE;
457 if (dir[f].hidden)
458 attrib |= VFS_FILEATTR_HIDDEN;
459 if (dir[f].system)
460 attrib |= VFS_FILEATTR_SYSTEM;
461 if (dir[f].dir)
462 attrib |= VFS_FILEATTR_DIR;
463 else
464 attrib |= VFS_FILEATTR_FILE;
465 if (dir[f].bin)
466 attrib |= VFS_FILEATTR_BIN;
468 int i = 10;
469 while (i) {
470 if (dir[f].name[i] == ' ')
471 dir[f].name[i] = '\0';
472 else
473 break;
475 i --;
478 vfs_list_add (dir[f].name, attrib, block);
480 dir[y].read=0;
481 dir[y].hidden=0;
482 dir[y].system=0;
483 dir[y].volume=0;
484 dir[y].dir=0;
485 dir[y].bin=0;
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);
490 f ++;
491 fl = strlen (dir[f].name);
494 return 1;
496 break;
497 case DEV_ACT_UMOUNT:
499 if (!p->fs->handler (FS_ACT_EXIT, more, -1, 0))
500 return 0;
502 return 1;
506 return 0;
509 bool ata_acthandler (unsigned act, char drive, char *block)
511 switch (act) {
512 case DEV_ACT_INIT:
514 if (kernel_attr & KERNEL_NOATA)
515 return 0;
517 int res = 0;
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);
531 res ++;
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);
546 res ++;
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);
561 res ++;
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);
576 res ++;
579 return res;
581 break;
582 /*case DEV_ACT_READ:
584 lba28_drive_read (drive, 0x01, n, block);
585 return 1;
587 break;
588 case DEV_ACT_WRITE:
590 lba28_drive_write (drive, 0x01, n, block);
591 return 1;
595 return 0;
597 #endif