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