|
|
1.1 root 1: /*
2: * linux/kernel/hd.c
3: *
4: * (C) 1991 Linus Torvalds
5: */
6:
7: /*
8: * This is the low-level hd interrupt support. It traverses the
9: * request-list, using interrupts to jump between functions. As
10: * all the functions are called within interrupts, we may not
11: * sleep. Special care is recommended.
1.1.1.2 root 12: *
13: * modified by Drew Eckhardt to check nr of hd's from the CMOS.
1.1.1.5 root 14: *
15: * Thanks to Branko Lankester, [email protected], who found a bug
16: * in the early extended-partition checks and added DM partitions
1.1 root 17: */
18:
1.1.1.6 root 19: #include <errno.h>
20:
1.1 root 21: #include <linux/config.h>
22: #include <linux/sched.h>
1.1.1.4 root 23: #include <linux/timer.h>
1.1 root 24: #include <linux/fs.h>
25: #include <linux/kernel.h>
26: #include <linux/hdreg.h>
27: #include <asm/system.h>
28: #include <asm/io.h>
29: #include <asm/segment.h>
30:
31: #define MAJOR_NR 3
32: #include "blk.h"
33:
1.1.1.5 root 34: static inline unsigned char CMOS_READ(unsigned char addr)
35: {
36: outb_p(0x80|addr,0x70);
37: return inb_p(0x71);
38: }
1.1.1.2 root 39:
1.1.1.7 ! root 40: #define HD_DELAY 0
! 41:
1.1 root 42: /* Max read/write errors/sector */
1.1.1.2 root 43: #define MAX_ERRORS 7
1.1 root 44: #define MAX_HD 2
45:
1.1.1.2 root 46: static void recal_intr(void);
1.1.1.3 root 47: static void bad_rw_intr(void);
1.1.1.2 root 48:
1.1.1.3 root 49: static int recalibrate = 0;
1.1.1.6 root 50: static int reset = 0;
1.1.1.2 root 51:
1.1.1.7 ! root 52: #if (HD_DELAY > 0)
! 53: unsigned long last_req, read_timer();
! 54: #endif
! 55:
1.1 root 56: /*
57: * This struct defines the HD's and their types.
58: */
59: struct hd_i_struct {
1.1.1.4 root 60: unsigned int head,sect,cyl,wpcom,lzone,ctl;
1.1 root 61: };
62: #ifdef HD_TYPE
63: struct hd_i_struct hd_info[] = { HD_TYPE };
64: #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
65: #else
66: struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
67: static int NR_HD = 0;
68: #endif
69:
70: static struct hd_struct {
71: long start_sect;
72: long nr_sects;
1.1.1.4 root 73: } hd[MAX_HD<<6]={{0,0},};
1.1 root 74:
1.1.1.4 root 75: static int hd_sizes[MAX_HD<<6] = {0, };
1.1.1.3 root 76:
1.1 root 77: #define port_read(port,buf,nr) \
78: __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
79:
80: #define port_write(port,buf,nr) \
81: __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
82:
83: extern void hd_interrupt(void);
1.1.1.2 root 84: extern void rd_load(void);
1.1 root 85:
1.1.1.4 root 86: static unsigned int current_minor;
87:
1.1.1.6 root 88: /*
89: * Create devices for each logical partition in an extended partition.
90: * The logical partitions form a linked list, with each entry being
91: * a partition table with two entries. The first entry
92: * is the real data partition (with a start relative to the partition
93: * table start). The second is a pointer to the next logical partition
94: * (with a start relative to the entire extended partition).
95: * We do not create a Linux partition for the partition tables, but
96: * only for the actual data partitions.
97: */
98: static void extended_partition(unsigned int dev)
99: {
100: struct buffer_head *bh;
101: struct partition *p;
102: unsigned long first_sector, this_sector;
103:
104: first_sector = hd[MINOR(dev)].start_sect;
105: this_sector = first_sector;
106:
107: while (1) {
108: if ((current_minor & 0x3f) >= 60)
109: return;
110: if (!(bh = bread(dev,0))) {
111: printk("Unable to read partition table of device %04x\n",dev);
112: return;
113: }
114: /*
115: * This block is from a device that we're about to stomp on.
116: * So make sure nobody thinks this block is usable.
117: */
118: bh->b_dirt=0;
119: bh->b_uptodate=0;
120: if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
121: p = 0x1BE + (void *)bh->b_data;
122: /*
123: * Process the first entry, which should be the real
124: * data partition.
125: */
126: if (p->sys_ind == EXTENDED_PARTITION ||
127: !(hd[current_minor].nr_sects = p->nr_sects))
128: goto done; /* shouldn't happen */
129: hd[current_minor].start_sect = this_sector + p->start_sect;
130: printk(" Logical part %d start %d size %d end %d\n\r",
131: current_minor, hd[current_minor].start_sect,
132: hd[current_minor].nr_sects,
133: hd[current_minor].start_sect +
1.1.1.7 ! root 134: hd[current_minor].nr_sects - 1);
1.1.1.6 root 135: current_minor++;
136: p++;
137: /*
138: * Process the second entry, which should be a link
139: * to the next logical partition. Create a minor
140: * for this just long enough to get the next partition
141: * table. The minor will be reused for the real
142: * data partition.
143: */
144: if (p->sys_ind != EXTENDED_PARTITION ||
145: !(hd[current_minor].nr_sects = p->nr_sects))
146: goto done; /* no more logicals in this partition */
147: hd[current_minor].start_sect = first_sector + p->start_sect;
148: this_sector = first_sector + p->start_sect;
149: dev = 0x0300 | current_minor;
150: brelse(bh);
151: } else
152: goto done;
153: }
154: done:
155: brelse(bh);
156: }
157:
1.1.1.4 root 158: static void check_partition(unsigned int dev)
159: {
1.1.1.6 root 160: int i, minor = current_minor;
1.1.1.4 root 161: struct buffer_head *bh;
162: struct partition *p;
1.1.1.6 root 163: unsigned long first_sector;
1.1.1.4 root 164:
1.1.1.6 root 165: first_sector = hd[MINOR(dev)].start_sect;
1.1.1.4 root 166: if (!(bh = bread(dev,0))) {
167: printk("Unable to read partition table of device %04x\n",dev);
168: return;
169: }
1.1.1.6 root 170: printk("Drive %d:\n\r",minor >> 6);
171: current_minor += 4; /* first "extra" minor */
1.1.1.4 root 172: if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
173: p = 0x1BE + (void *)bh->b_data;
1.1.1.6 root 174: for (i=1 ; i<=4 ; minor++,i++,p++) {
175: if (!(hd[minor].nr_sects = p->nr_sects))
1.1.1.5 root 176: continue;
1.1.1.6 root 177: hd[minor].start_sect = first_sector + p->start_sect;
178: printk(" part %d start %d size %d end %d \n\r", i,
179: hd[minor].start_sect, hd[minor].nr_sects,
1.1.1.7 ! root 180: hd[minor].start_sect + hd[minor].nr_sects - 1);
1.1.1.5 root 181: if ((current_minor & 0x3f) >= 60)
182: continue;
183: if (p->sys_ind == EXTENDED_PARTITION) {
1.1.1.6 root 184: extended_partition(0x0300 | minor);
1.1.1.5 root 185: }
1.1.1.4 root 186: }
1.1.1.5 root 187: /*
188: * check for Disk Manager partition table
189: */
190: if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) {
191: p = 0x1BE + (void *)bh->b_data;
1.1.1.6 root 192: for (i = 4 ; i < 16 ; i++, current_minor++) {
1.1.1.5 root 193: p--;
194: if ((current_minor & 0x3f) >= 60)
195: break;
1.1.1.6 root 196: if (!(p->start_sect && p->nr_sects))
1.1.1.5 root 197: continue;
1.1.1.6 root 198: hd[current_minor].start_sect = p->start_sect;
199: hd[current_minor].nr_sects = p->nr_sects;
200: printk(" DM part %d start %d size %d end %d\n\r",
201: current_minor,
202: hd[current_minor].start_sect,
203: hd[current_minor].nr_sects,
204: hd[current_minor].start_sect +
1.1.1.7 ! root 205: hd[current_minor].nr_sects - 1);
1.1.1.5 root 206: }
1.1.1.4 root 207: }
208: } else
209: printk("Bad partition table on dev %04x\n",dev);
210: brelse(bh);
211: }
212:
1.1 root 213: /* This may be used only once, enforced by 'static int callable' */
214: int sys_setup(void * BIOS)
215: {
216: static int callable = 1;
217: int i,drive;
1.1.1.2 root 218: unsigned char cmos_disks;
1.1 root 219:
220: if (!callable)
221: return -1;
222: callable = 0;
223: #ifndef HD_TYPE
224: for (drive=0 ; drive<2 ; drive++) {
225: hd_info[drive].cyl = *(unsigned short *) BIOS;
226: hd_info[drive].head = *(unsigned char *) (2+BIOS);
227: hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
228: hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
229: hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
230: hd_info[drive].sect = *(unsigned char *) (14+BIOS);
231: BIOS += 16;
232: }
1.1.1.2 root 233:
234: /*
235: We querry CMOS about hard disks : it could be that
236: we have a SCSI/ESDI/etc controller that is BIOS
237: compatable with ST-506, and thus showing up in our
238: BIOS table, but not register compatable, and therefore
239: not present in CMOS.
240:
241: Furthurmore, we will assume that our ST-506 drives
242: <if any> are the primary drives in the system, and
243: the ones reflected as drive 1 or 2.
244:
245: The first drive is stored in the high nibble of CMOS
246: byte 0x12, the second in the low nibble. This will be
247: either a 4 bit drive type or 0xf indicating use byte 0x19
248: for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
249:
250: Needless to say, a non-zero value means we have
251: an AT controller hard disk for that drive.
252:
253:
254: */
255:
256: if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
257: if (cmos_disks & 0x0f)
258: NR_HD = 2;
259: else
260: NR_HD = 1;
261: else
262: NR_HD = 0;
1.1.1.6 root 263: #endif
264: for (i = 0 ; i < (MAX_HD<<6) ; i++) {
265: hd[i].start_sect = 0;
266: hd[i].nr_sects = 0;
1.1.1.2 root 267: }
1.1.1.6 root 268: for (i = 0 ; i < NR_HD ; i++)
269: hd[i<<6].nr_sects = hd_info[i].head*
270: hd_info[i].sect*hd_info[i].cyl;
1.1 root 271: for (drive=0 ; drive<NR_HD ; drive++) {
1.1.1.4 root 272: current_minor = 1+(drive<<6);
273: check_partition(0x0300+(drive<<6));
1.1 root 274: }
1.1.1.4 root 275: for (i=0 ; i<(MAX_HD<<6) ; i++)
1.1.1.3 root 276: hd_sizes[i] = hd[i].nr_sects>>1 ;
277: blk_size[MAJOR_NR] = hd_sizes;
1.1.1.2 root 278: if (NR_HD)
279: printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
280: rd_load();
1.1 root 281: mount_root();
282: return (0);
283: }
284:
1.1.1.7 ! root 285: #if (HD_DELAY > 0)
! 286: unsigned long read_timer(void)
! 287: {
! 288: unsigned long t;
! 289: int i;
! 290:
! 291: cli();
! 292: outb_p(0xc2, 0x43);
! 293: t = jiffies * 11931 + (inb_p(0x40) & 0x80 ? 5966 : 11932);
! 294: i = inb_p(0x40);
! 295: i |= inb(0x40) << 8;
! 296: sti();
! 297: return(t - i / 2);
! 298: }
! 299: #endif
! 300:
1.1 root 301: static int controller_ready(void)
302: {
1.1.1.3 root 303: int retries = 100000;
1.1 root 304:
1.1.1.4 root 305: while (--retries && (inb_p(HD_STATUS)&0x80))
306: /* nothing */;
307: if (!retries)
308: printk("controller_ready: status = %02x\n\r",
309: (unsigned char) inb_p(HD_STATUS));
1.1 root 310: return (retries);
311: }
312:
313: static int win_result(void)
314: {
1.1.1.2 root 315: int i=inb_p(HD_STATUS);
1.1 root 316:
317: if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
318: == (READY_STAT | SEEK_STAT))
319: return(0); /* ok */
1.1.1.5 root 320: if (i&1)
321: i=inb(HD_ERROR);
1.1 root 322: return (1);
323: }
324:
325: static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
326: unsigned int head,unsigned int cyl,unsigned int cmd,
327: void (*intr_addr)(void))
328: {
1.1.1.4 root 329: unsigned short port;
1.1 root 330:
331: if (drive>1 || head>15)
332: panic("Trying to write bad sector");
1.1.1.7 ! root 333: #if (HD_DELAY > 0)
! 334: while (read_timer() - last_req < HD_DELAY)
! 335: /* nothing */;
! 336: #endif
1.1.1.4 root 337: if (reset || !controller_ready()) {
338: reset = 1;
339: return;
340: }
1.1.1.3 root 341: SET_INTR(intr_addr);
1.1.1.2 root 342: outb_p(hd_info[drive].ctl,HD_CMD);
1.1 root 343: port=HD_DATA;
344: outb_p(hd_info[drive].wpcom>>2,++port);
345: outb_p(nsect,++port);
346: outb_p(sect,++port);
347: outb_p(cyl,++port);
348: outb_p(cyl>>8,++port);
349: outb_p(0xA0|(drive<<4)|head,++port);
1.1.1.7 ! root 350: outb_p(cmd,++port);
1.1 root 351: }
352:
353: static int drive_busy(void)
354: {
355: unsigned int i;
1.1.1.3 root 356: unsigned char c;
1.1 root 357:
1.1.1.6 root 358: for (i = 0; i < 500000 ; i++) {
1.1.1.3 root 359: c = inb_p(HD_STATUS);
360: c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
361: if (c == (READY_STAT | SEEK_STAT))
362: return 0;
363: }
1.1.1.4 root 364: printk("HD controller times out, c=%02x\n\r",c);
1.1 root 365: return(1);
366: }
367:
368: static void reset_controller(void)
369: {
370: int i;
371:
1.1.1.7 ! root 372: printk("HD-controller reset\r\n");
1.1 root 373: outb(4,HD_CMD);
1.1.1.3 root 374: for(i = 0; i < 1000; i++) nop();
1.1.1.2 root 375: outb(hd_info[0].ctl & 0x0f ,HD_CMD);
1.1 root 376: if (drive_busy())
377: printk("HD-controller still busy\n\r");
1.1.1.2 root 378: if ((i = inb(HD_ERROR)) != 1)
1.1 root 379: printk("HD-controller reset failed: %02x\n\r",i);
380: }
381:
1.1.1.3 root 382: static void reset_hd(void)
1.1 root 383: {
1.1.1.3 root 384: static int i;
385:
386: repeat:
387: if (reset) {
388: reset = 0;
389: i = -1;
390: reset_controller();
391: } else if (win_result()) {
392: bad_rw_intr();
393: if (reset)
394: goto repeat;
395: }
396: i++;
397: if (i < NR_HD) {
398: hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
399: hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
1.1.1.4 root 400: if (reset)
401: goto repeat;
1.1.1.3 root 402: } else
403: do_hd_request();
1.1 root 404: }
405:
1.1.1.6 root 406: /*
407: * Ok, don't know what to do with the unexpected interrupts: on some machines
408: * doing a reset and a retry seems to result in an eternal loop. Right now I
409: * ignore it, and just set the timeout.
410: */
1.1 root 411: void unexpected_hd_interrupt(void)
412: {
413: printk("Unexpected HD interrupt\n\r");
1.1.1.6 root 414: SET_TIMER;
415: #if 0
1.1.1.3 root 416: reset = 1;
417: do_hd_request();
1.1.1.6 root 418: #endif
1.1 root 419: }
420:
421: static void bad_rw_intr(void)
422: {
1.1.1.6 root 423: if (!CURRENT)
424: return;
1.1.1.2 root 425: if (++CURRENT->errors >= MAX_ERRORS)
1.1.1.7 ! root 426: if (CURRENT->bh && CURRENT->nr_sectors > 2) {
! 427: CURRENT->nr_sectors &= ~1;
! 428: next_buffer(0);
! 429: } else
! 430: end_request(0);
1.1.1.2 root 431: if (CURRENT->errors > MAX_ERRORS/2)
432: reset = 1;
1.1.1.5 root 433: else
434: recalibrate = 1;
1.1 root 435: }
436:
1.1.1.7 ! root 437: #define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)
! 438: #define STAT_OK (READY_STAT | SEEK_STAT)
! 439:
1.1 root 440: static void read_intr(void)
441: {
1.1.1.7 ! root 442: int i;
! 443:
! 444: i = (unsigned) inb_p(HD_STATUS);
! 445: if (!(i & DRQ_STAT))
! 446: goto bad_read;
! 447: if ((i & STAT_MASK) != STAT_OK)
! 448: goto bad_read;
1.1 root 449: port_read(HD_DATA,CURRENT->buffer,256);
1.1.1.7 ! root 450: i = (unsigned) inb_p(HD_STATUS);
! 451: if (!(i & BUSY_STAT))
! 452: if ((i & STAT_MASK) != STAT_OK)
! 453: goto bad_read;
1.1 root 454: CURRENT->errors = 0;
1.1.1.7 ! root 455: if (CURRENT->bh && (CURRENT->nr_sectors&1) && CURRENT->nr_sectors > 2)
! 456: next_buffer(1);
! 457: else
! 458: CURRENT->buffer += 512;
1.1 root 459: CURRENT->sector++;
1.1.1.7 ! root 460: if (--CURRENT->nr_sectors) {
! 461: SET_INTR(&read_intr);
1.1 root 462: return;
1.1.1.7 ! root 463: }
1.1 root 464: end_request(1);
1.1.1.7 ! root 465: #if (HD_DELAY > 0)
! 466: last_req = read_timer();
! 467: #endif
1.1 root 468: do_hd_request();
1.1.1.7 ! root 469: return;
! 470: bad_read:
! 471: if (i & ERR_STAT)
! 472: i = (unsigned) inb(HD_ERROR);
! 473: bad_rw_intr();
! 474: do_hd_request();
! 475: return;
1.1 root 476: }
477:
478: static void write_intr(void)
479: {
1.1.1.7 ! root 480: int i;
! 481:
! 482: i = (unsigned) inb_p(HD_STATUS);
! 483: if ((i & STAT_MASK) != STAT_OK)
! 484: goto bad_write;
! 485: if (CURRENT->nr_sectors < 2) {
! 486: end_request(1);
! 487: #if (HD_DELAY > 0)
! 488: last_req = read_timer();
! 489: #endif
1.1.1.2 root 490: do_hd_request();
1.1 root 491: return;
492: }
1.1.1.7 ! root 493: if (!(i & DRQ_STAT))
! 494: goto bad_write;
! 495: CURRENT->sector++;
! 496: CURRENT->nr_sectors--;
! 497: if (CURRENT->bh && !(CURRENT->nr_sectors & 1))
! 498: next_buffer(1);
! 499: else
1.1 root 500: CURRENT->buffer += 512;
1.1.1.7 ! root 501: SET_INTR(&write_intr);
! 502: port_write(HD_DATA,CURRENT->buffer,256);
! 503: return;
! 504: bad_write:
! 505: if (i & ERR_STAT)
! 506: i = (unsigned) inb(HD_ERROR);
! 507: bad_rw_intr();
1.1 root 508: do_hd_request();
1.1.1.7 ! root 509: return;
1.1 root 510: }
511:
1.1.1.2 root 512: static void recal_intr(void)
513: {
514: if (win_result())
515: bad_rw_intr();
516: do_hd_request();
517: }
518:
1.1.1.6 root 519: /*
520: * This is another of the error-routines I don't know what to do with. The
521: * best idea seems to just set reset, and start all over again.
522: */
1.1.1.4 root 523: static void hd_times_out(void)
1.1.1.5 root 524: {
525: do_hd = NULL;
526: reset = 1;
1.1.1.3 root 527: if (!CURRENT)
528: return;
1.1.1.6 root 529: printk("HD timeout\n\r");
530: cli();
1.1.1.3 root 531: if (++CURRENT->errors >= MAX_ERRORS)
1.1.1.7 ! root 532: if (CURRENT->bh && CURRENT->nr_sectors > 2) {
! 533: CURRENT->nr_sectors &= ~1;
! 534: next_buffer(0);
! 535: } else
! 536: end_request(0);
1.1.1.3 root 537: do_hd_request();
538: }
539:
1.1.1.6 root 540: static void do_hd_request(void)
1.1 root 541: {
542: int i,r;
543: unsigned int block,dev;
544: unsigned int sec,head,cyl;
545: unsigned int nsect;
546:
547: INIT_REQUEST;
548: dev = MINOR(CURRENT->dev);
549: block = CURRENT->sector;
1.1.1.5 root 550: nsect = CURRENT->nr_sectors;
551: if (dev >= (NR_HD<<6) || block+nsect > hd[dev].nr_sects) {
1.1 root 552: end_request(0);
553: goto repeat;
554: }
555: block += hd[dev].start_sect;
1.1.1.4 root 556: dev >>= 6;
557: sec = block % hd_info[dev].sect;
558: block /= hd_info[dev].sect;
559: head = block % hd_info[dev].head;
560: cyl = block / hd_info[dev].head;
1.1 root 561: sec++;
1.1.1.2 root 562: if (reset) {
563: recalibrate = 1;
1.1.1.3 root 564: reset_hd();
1.1.1.2 root 565: return;
566: }
567: if (recalibrate) {
568: recalibrate = 0;
1.1.1.7 ! root 569: hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
1.1.1.4 root 570: if (reset)
571: goto repeat;
1.1.1.2 root 572: return;
573: }
1.1 root 574: if (CURRENT->cmd == WRITE) {
575: hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
1.1.1.4 root 576: if (reset)
577: goto repeat;
1.1.1.3 root 578: for(i=0 ; i<10000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
1.1 root 579: /* nothing */ ;
580: if (!r) {
1.1.1.2 root 581: bad_rw_intr();
582: goto repeat;
1.1 root 583: }
584: port_write(HD_DATA,CURRENT->buffer,256);
585: } else if (CURRENT->cmd == READ) {
586: hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
1.1.1.4 root 587: if (reset)
588: goto repeat;
1.1 root 589: } else
590: panic("unknown hd-command");
591: }
592:
1.1.1.7 ! root 593: static int hd_ioctl(struct inode * inode, struct file * file,
! 594: unsigned int cmd, unsigned int arg)
1.1.1.6 root 595: {
596: struct hd_geometry *loc = (void *) arg;
1.1.1.7 ! root 597: int dev;
1.1.1.6 root 598:
1.1.1.7 ! root 599: if (!loc || !inode)
1.1.1.6 root 600: return -EINVAL;
1.1.1.7 ! root 601: dev = MINOR(inode->i_rdev) >> 6;
1.1.1.6 root 602: if (dev >= NR_HD)
603: return -EINVAL;
604: switch (cmd) {
605: case HDIO_REQ:
1.1.1.7 ! root 606: verify_area(loc, sizeof(*loc));
1.1.1.6 root 607: put_fs_byte(hd_info[dev].head,
608: (char *) &loc->heads);
609: put_fs_byte(hd_info[dev].sect,
610: (char *) &loc->sectors);
611: put_fs_word(hd_info[dev].cyl,
612: (short *) &loc->cylinders);
613: return 0;
614: default:
615: return -EINVAL;
616: }
617: }
1.1.1.7 ! root 618:
! 619: /*
! 620: * Releasing a block device means we sync() it, so that it can safely
! 621: * be forgotten about...
! 622: */
! 623: static void hd_release(struct inode * inode, struct file * file)
! 624: {
! 625: sync_dev(inode->i_rdev);
! 626: }
! 627:
! 628: static struct file_operations hd_fops = {
! 629: NULL, /* lseek - default */
! 630: block_read, /* read - general block-dev read */
! 631: block_write, /* write - general block-dev write */
! 632: NULL, /* readdir - bad */
! 633: NULL, /* select */
! 634: hd_ioctl, /* ioctl */
! 635: NULL, /* no special open code */
! 636: hd_release /* release */
! 637: };
! 638:
! 639: void hd_init(void)
! 640: {
! 641: blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
! 642: blkdev_fops[MAJOR_NR] = &hd_fops;
! 643: set_intr_gate(0x2E,&hd_interrupt);
! 644: outb_p(inb_p(0x21)&0xfb,0x21);
! 645: outb(inb_p(0xA1)&0xbf,0xA1);
! 646: timer_table[HD_TIMER].fn = hd_times_out;
! 647: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.