📄 at_wini.c
字号:
int s; irq_hook = irq; if (skip > 0) { if (w_pci_debug) printf("atapci skipping controller (remain %d)\n", skip); skip--; continue; } if ((s=sys_irqsetpolicy(irq, 0, &irq_hook)) != OK) { printf("atapci: couldn't set IRQ policy %d\n", irq); continue; } if ((s=sys_irqenable(&irq_hook)) != OK) { printf("atapci: couldn't enable IRQ line %d\n", irq); continue; } } else { /* If not.. this is not the ata-pci controller we're * looking for. */ if (w_pci_debug) printf("atapci skipping compatability controller\n"); continue; } /* Primary channel not in compatability mode? */ if (interface & ATA_IF_NOTCOMPAT1) { u32_t base_cmd, base_ctl; base_cmd = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0; base_ctl = pci_attr_r32(devind, PCI_BAR_2) & 0xffffffe0; if (base_cmd != REG_CMD_BASE0 && base_cmd != REG_CMD_BASE1) { init_drive(&wini[w_next_drive], base_cmd, base_ctl, irq, 1, irq_hook, 0); init_drive(&wini[w_next_drive+1], base_cmd, base_ctl, irq, 1, irq_hook, 1); if (w_pci_debug) printf("atapci %d: 0x%x 0x%x irq %d\n", devind, base_cmd, base_ctl, irq); } else printf("atapci: ignored drives on primary channel, base %x\n", base_cmd); } /* Secondary channel not in compatability mode? */ if (interface & ATA_IF_NOTCOMPAT2) { u32_t base_cmd, base_ctl; base_cmd = pci_attr_r32(devind, PCI_BAR_3) & 0xffffffe0; base_ctl = pci_attr_r32(devind, PCI_BAR_4) & 0xffffffe0; if (base_cmd != REG_CMD_BASE0 && base_cmd != REG_CMD_BASE1) { init_drive(&wini[w_next_drive+2], base_cmd, base_ctl, irq, 1, irq_hook, 2); init_drive(&wini[w_next_drive+3], base_cmd, base_ctl, irq, 1, irq_hook, 3); if (w_pci_debug) printf("atapci %d: 0x%x 0x%x irq %d\n", devind, base_cmd, base_ctl, irq); } else printf("atapci: ignored drives on secondary channel, base %x\n", base_cmd); } w_next_drive += 4; }}/*===========================================================================* * w_do_open * *===========================================================================*/PRIVATE int w_do_open(dp, m_ptr)struct driver *dp;message *m_ptr;{/* Device open: Initialize the controller and read the partition table. */ struct wini *wn; if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO); wn = w_wn; /* If we've probed it before and it failed, don't probe it again. */ if (wn->state & IGNORING) return ENXIO; /* If we haven't identified it yet, or it's gone deaf, * (re-)identify it. */ if (!(wn->state & IDENTIFIED) || (wn->state & DEAF)) { /* Try to identify the device. */ if (w_identify() != OK) {#if VERBOSE printf("%s: probe failed\n", w_name());#endif if (wn->state & DEAF) w_reset(); wn->state = IGNORING; return(ENXIO); } /* Do a test transaction unless it's a CD drive (then * we can believe the controller, and a test may fail * due to no CD being in the drive). If it fails, ignore * the device forever. */ if (!(wn->state & ATAPI) && w_io_test() != OK) { wn->state |= IGNORING; return(ENXIO); }#if VERBOSE printf("%s: AT driver detected ", w_name()); if (wn->state & (SMART|ATAPI)) { printf("%.40s\n", w_id_string); } else { printf("%ux%ux%u\n", wn->pcylinders, wn->pheads, wn->psectors); }#endif }#if ENABLE_ATAPI if ((wn->state & ATAPI) && (m_ptr->COUNT & W_BIT)) return(EACCES);#endif /* If it's not an ATAPI device, then don't open with RO_BIT. */ if (!(wn->state & ATAPI) && (m_ptr->COUNT & RO_BIT)) return EACCES; /* Partition the drive if it's being opened for the first time, * or being opened after being closed. */ if (wn->open_ct == 0) {#if ENABLE_ATAPI if (wn->state & ATAPI) { int r; if ((r = atapi_open()) != OK) return(r); }#endif /* Partition the disk. */ partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY, wn->state & ATAPI); } wn->open_ct++; return(OK);}/*===========================================================================* * w_prepare * *===========================================================================*/PRIVATE struct device *w_prepare(int device){/* Prepare for I/O on a device. */struct wini *prev_wn;prev_wn = w_wn; w_device = device; if (device < NR_MINORS) { /* d0, d0p[0-3], d1, ... */ w_drive = device / DEV_PER_DRIVE; /* save drive number */ w_wn = &wini[w_drive]; w_dv = &w_wn->part[device % DEV_PER_DRIVE]; } else if ((unsigned) (device -= MINOR_d0p0s0) < NR_SUBDEVS) {/*d[0-7]p[0-3]s[0-3]*/ w_drive = device / SUB_PER_DRIVE; w_wn = &wini[w_drive]; w_dv = &w_wn->subpart[device % SUB_PER_DRIVE]; } else { w_device = -1; return(NIL_DEV); } return(w_dv);}/*===========================================================================* * w_identify * *===========================================================================*/PRIVATE int w_identify(){/* Find out if a device exists, if it is an old AT disk, or a newer ATA * drive, a removable media device, etc. */ struct wini *wn = w_wn; struct command cmd; int i, s; unsigned long size;#define id_byte(n) (&tmp_buf[2 * (n)])#define id_word(n) (((u16_t) id_byte(n)[0] << 0) \ |((u16_t) id_byte(n)[1] << 8))#define id_longword(n) (((u32_t) id_byte(n)[0] << 0) \ |((u32_t) id_byte(n)[1] << 8) \ |((u32_t) id_byte(n)[2] << 16) \ |((u32_t) id_byte(n)[3] << 24)) /* Try to identify the device. */ cmd.ldh = wn->ldhpref; cmd.command = ATA_IDENTIFY; if (com_simple(&cmd) == OK) { /* This is an ATA device. */ wn->state |= SMART; /* Device information. */ if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, SECTOR_SIZE)) != OK) panic(w_name(),"Call to sys_insw() failed", s); /* Why are the strings byte swapped??? */ for (i = 0; i < 40; i++) w_id_string[i] = id_byte(27)[i^1]; /* Preferred CHS translation mode. */ wn->pcylinders = id_word(1); wn->pheads = id_word(3); wn->psectors = id_word(6); size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors; if ((id_byte(49)[1] & 0x02) && size > 512L*1024*2) { /* Drive is LBA capable and is big enough to trust it to * not make a mess of it. */ wn->ldhpref |= LDH_LBA; size = id_longword(60); if (w_lba48 && ((id_word(83)) & (1L << 10))) { /* Drive is LBA48 capable (and LBA48 is turned on). */ if (id_word(102) || id_word(103)) { /* If no. of sectors doesn't fit in 32 bits, * trunacte to this. So it's LBA32 for now. * This can still address devices up to 2TB * though. */ size = ULONG_MAX; } else { /* Actual number of sectors fits in 32 bits. */ size = id_longword(100); } wn->lba48 = 1; } } if (wn->lcylinders == 0) { /* No BIOS parameters? Then make some up. */ wn->lcylinders = wn->pcylinders; wn->lheads = wn->pheads; wn->lsectors = wn->psectors; while (wn->lcylinders > 1024) { wn->lheads *= 2; wn->lcylinders /= 2; } }#if ENABLE_ATAPI } else if (cmd.command = ATAPI_IDENTIFY, com_simple(&cmd) == OK) { /* An ATAPI device. */ wn->state |= ATAPI; /* Device information. */ if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, 512)) != OK) panic(w_name(),"Call to sys_insw() failed", s); /* Why are the strings byte swapped??? */ for (i = 0; i < 40; i++) w_id_string[i] = id_byte(27)[i^1]; size = 0; /* Size set later. */#endif } else { /* Not an ATA device; no translations, no special features. Don't * touch it unless the BIOS knows about it. */ if (wn->lcylinders == 0) { return(ERR); } /* no BIOS parameters */ wn->pcylinders = wn->lcylinders; wn->pheads = wn->lheads; wn->psectors = wn->lsectors; size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors; } /* Size of the whole drive */ wn->part[0].dv_size = mul64u(size, SECTOR_SIZE); /* Reset/calibrate (where necessary) */ if (w_specify() != OK && w_specify() != OK) { return(ERR); } if (wn->irq == NO_IRQ) { /* Everything looks OK; register IRQ so we can stop polling. */ wn->irq = w_drive < 2 ? AT_WINI_0_IRQ : AT_WINI_1_IRQ; wn->irq_hook_id = wn->irq; /* id to be returned if interrupt occurs */ if ((s=sys_irqsetpolicy(wn->irq, IRQ_REENABLE, &wn->irq_hook_id)) != OK) panic(w_name(), "couldn't set IRQ policy", s); if ((s=sys_irqenable(&wn->irq_hook_id)) != OK) panic(w_name(), "couldn't enable IRQ line", s); } wn->state |= IDENTIFIED; return(OK);}/*===========================================================================* * w_name * *===========================================================================*/PRIVATE char *w_name(){/* Return a name for the current device. */ static char name[] = "AT-D0"; name[4] = '0' + w_drive; return name;}/*===========================================================================* * w_io_test * *===========================================================================*/PRIVATE int w_io_test(void){ int r, save_dev; int save_timeout, save_errors, save_wakeup; iovec_t iov;#ifdef CD_SECTOR_SIZE static char buf[CD_SECTOR_SIZE];#else static char buf[SECTOR_SIZE];#endif iov.iov_addr = (vir_bytes) buf; iov.iov_size = sizeof(buf); save_dev = w_device; /* Reduce timeout values for this test transaction. */ save_timeout = timeout_ticks; save_errors = max_errors; save_wakeup = wakeup_ticks; if (!w_standard_timeouts) { timeout_ticks = HZ * 4; wakeup_ticks = HZ * 6; max_errors = 3; } w_testing = 1; /* Try I/O on the actual drive (not any (sub)partition). */ if (w_prepare(w_drive * DEV_PER_DRIVE) == NIL_DEV) panic(w_name(), "Couldn't switch devices", NO_NUM); r = w_transfer(SELF, DEV_GATHER, 0, &iov, 1); /* Switch back. */ if (w_prepare(save_dev) == NIL_DEV) panic(w_name(), "Couldn't switch back devices", NO_NUM); /* Restore parameters. */ timeout_ticks = save_timeout; max_errors = save_errors; wakeup_ticks = save_wakeup; w_testing = 0; /* Test if everything worked. */ if (r != OK || iov.iov_size != 0) { return ERR; } /* Everything worked. */ return OK;}/*===========================================================================* * w_specify * *===========================================================================*/PRIVATE int w_specify(){/* Routine to initialize the drive after boot or when a reset is needed. */ struct wini *wn = w_wn; struct command cmd; if ((wn->state & DEAF) && w_reset() != OK) { return(ERR); } if (!(wn->state & ATAPI)) { /* Specify parameters: precompensation, number of heads and sectors. */ cmd.precomp = wn->precomp; cmd.count = wn->psectors; cmd.ldh = w_wn->ldhpref | (wn->pheads - 1); cmd.command = CMD_SPECIFY; /* Specify some parameters */ /* Output command block and see if controller accepts the parameters. */ if (com_simple(&cmd) != OK) return(ERR); if (!(wn->state & SMART)) { /* Calibrate an old disk. */ cmd.sector = 0; cmd.cyl_lo = 0; cmd.cyl_hi = 0; cmd.ldh = w_wn->ldhpref; cmd.command = CMD_RECALIBRATE; if (com_simple(&cmd) != OK) return(ERR); } } wn->state |= INITIALIZED; return(OK);}/*===========================================================================* * do_transfer * *===========================================================================*/PRIVATE int do_transfer(struct wini *wn, unsigned int precomp, unsigned int count, unsigned int sector, unsigned int opcode){ struct command cmd; unsigned secspcyl = wn->pheads * wn->psectors; cmd.precomp = precomp; cmd.count = count; cmd.command = opcode == DEV_SCATTER ? CMD_WRITE : CMD_READ; /* if (w_lba48 && wn->lba48) { } else */ if (wn->ldhpref & LDH_LBA) { cmd.sector = (sector >> 0) & 0xFF; cmd.cyl_lo = (sector >> 8) & 0xFF; cmd.cyl_hi = (sector >> 16) & 0xFF; cmd.ldh = wn->ldhpref | ((sector >> 24) & 0xF); } else { int cylinder, head, sec; cylinder = sector / secspcyl; head = (sector % secspcyl) / wn->psectors; sec = sector % wn->psectors; cmd.sector = sec + 1; cmd.cyl_lo = cylinder & BYTE; cmd.cyl_hi = (cylinder >> 8) & BYTE; cmd.ldh = wn->ldhpref | head; } return com_out(&cmd);}/*===========================================================================* * w_transfer *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -