// #include <device/ide.h>
// #include <ctype.h>
// #include <debug.h>
// #include <stdbool.h>
// #include <stdio.h>
// #include <device/block.h>
// #include <device/partition.h>
// #include <device/io.h>
// #include <interrupt.h>
// #include <synch.h>

// #include<device/console.h>

// /* The code in this file is an interface to an ATA (IDE)
//    controller.  It attempts to comply to [ATA-3]. */

// /* ATA command block port addresses. */
// #define reg_data(CHANNEL) ((CHANNEL)->reg_base + 0)     /* Data. */
// #define reg_error(CHANNEL) ((CHANNEL)->reg_base + 1)    /* Error. */
// #define reg_nsect(CHANNEL) ((CHANNEL)->reg_base + 2)    /* Sector Count. */
// #define reg_lbal(CHANNEL) ((CHANNEL)->reg_base + 3)     /* LBA 0:7. */
// #define reg_lbam(CHANNEL) ((CHANNEL)->reg_base + 4)     /* LBA 15:8. */
// #define reg_lbah(CHANNEL) ((CHANNEL)->reg_base + 5)     /* LBA 23:16. */
// #define reg_device(CHANNEL) ((CHANNEL)->reg_base + 6)   /* Device/LBA 27:24. */
// #define reg_status(CHANNEL) ((CHANNEL)->reg_base + 7)   /* Status (r/o). */
// #define reg_command(CHANNEL) reg_status (CHANNEL)       /* Command (w/o). */

// /* ATA control block port addresses.
//    (If we supported non-legacy ATA controllers this would not be
//    flexible enough, but it's fine for what we do.) */
// #define reg_ctl(CHANNEL) ((CHANNEL)->reg_base + 0x206)  /* Control (w/o). */
// #define reg_alt_status(CHANNEL) reg_ctl (CHANNEL)       /* Alt Status (r/o). */

// /* Alternate Status Register bits. */
// #define STA_BSY 0x80            /* Busy. */
// #define STA_DRDY 0x40           /* Device Ready. */
// #define STA_DRQ 0x08            /* Data Request. */

// /* Control Register bits. */
// #define CTL_SRST 0x04           /* Software Reset. */

// /* Device Register bits. */
// #define DEV_MBS 0xa0            /* Must be set. */
// #define DEV_LBA 0x40            /* Linear based addressing. */
// #define DEV_DEV 0x10            /* Select device: 0=master, 1=slave. */

// /* Commands.
//    Many more are defined but this is the small subset that we
//    use. */
// #define CMD_IDENTIFY_DEVICE 0xec        /* IDENTIFY DEVICE. */
// #define CMD_READ_SECTOR_RETRY 0x20      /* READ SECTOR with retries. */
// #define CMD_WRITE_SECTOR_RETRY 0x30     /* WRITE SECTOR with retries. */





// /* We support the two "legacy" ATA channels found in a standard PC. */
// #define CHANNEL_CNT 2
// static struct channel channels[CHANNEL_CNT];

// static struct block_operations ide_operations;

// static void reset_channel (struct channel *);
// static bool check_device_type (struct ata_disk *);
// static void identify_ata_device (struct ata_disk *);

// static void select_sector (struct ata_disk *, block_sector_t);
// static void issue_pio_command (struct channel *, uint8_t command);
// static void input_sector (struct channel *, void *);
// static void output_sector (struct channel *, const void *);

// static void wait_until_idle (const struct ata_disk *);
// static bool wait_while_busy (const struct ata_disk *);
// static void select_device (const struct ata_disk *);
// static void select_device_wait (const struct ata_disk *);

// static void interrupt_handler (int intr_num);
// struct ata_disk *swap_get (void)
// {
//   struct channel *c = &channels[1];
//   int dev_no;
//   snprintf (c->name, sizeof c->name, "hd%zu", 1);
//   c->reg_base=0x170;
//   c->irq=15+0x20;
//   lock_init (&c->lock);
//   c->expecting_interrupt = false;
//   sema_init (&c->completion_wait, 0);
//   struct ata_disk *d = &c->devices[1];
//   snprintf (d->name, sizeof d->name, "%s:%d", c->name, 1);
//   d->channel = c;
//   d->dev_no = dev_no;
//   d->is_ata = false;
//   d->capacity = 0;
//   d->read_cnt = d->write_cnt = 0;
//   reg_handler (c->irq, (void (*)(struct intr_frame *))interrupt_handler);
//   check_device_type (&c->devices[1]);
//       /* Reset hardware. */
//   reset_channel (c);
// }

// /* Initialize the disk subsystem and detect disks. */
// void
// ide_init (void) 
// {
//   size_t chan_no;

//   for (chan_no = 0; chan_no < CHANNEL_CNT; chan_no++)
//     {
//       struct channel *c = &channels[chan_no];
//       int dev_no;
//        snprintf (c->name, sizeof c->name, "hd%zu", chan_no);
//       /* Initialize channel. */
//       switch (chan_no) 
//         {
//         case 0:
//           // 496 
//           c->reg_base = 0x1f0;
//           c->irq = 14 + 0x20;
//           break;
//         case 1:
//           //368
//           c->reg_base = 0x170;
//           c->irq = 15 + 0x20;
//           break;
//         }
//       lock_init (&c->lock);
//       c->expecting_interrupt = false;
//       sema_init (&c->completion_wait, 0);
 
//       /* Initialize devices. */
//       for (dev_no = 0; dev_no < 2; dev_no++)
//         {
//           struct ata_disk *d = &c->devices[dev_no]; 
//           snprintf (d->name, sizeof d->name, "%s:%d", c->name, dev_no);
//           d->channel = c;
//           d->dev_no = dev_no;
//           d->is_ata = false;
//           d->capacity = 0;
//           d->read_cnt = d->write_cnt = 0;
//         }

//       /* Register interrupt handler. */
//         //c -> name 이 마지막 인자로 들어가야함 
//       reg_handler (c->irq, (void (*)(struct intr_frame *))interrupt_handler);

//       /* Reset hardware. */
//       reset_channel (c);

//       /* Distinguish ATA hard disks from other devices. */
//       if (check_device_type (&c->devices[0]))
//         check_device_type (&c->devices[1]);

//       /* Read hard disk identity information. */
//       for (dev_no = 0; dev_no < 2; dev_no++)
//         if (c->devices[dev_no].is_ata)
//           identify_ata_device (&c->devices[dev_no]);
//     }
// }
// /* Disk detection and identification. */

// static char *descramble_ata_string (char *, int size);

// /* Resets an ATA channel and waits for any devices present on it
//    to finish the reset. */


// static void
// reset_channel (struct channel *c) 
// {
//   bool present[2];
//   int dev_no;

//   /* The ATA reset sequence depends on which devices are present,
//      so we start by detecting device presence. */
//   for (dev_no = 0; dev_no < 2; dev_no++)
//     {
//       struct ata_disk *d = &c->devices[dev_no];

//       select_device (d);

//       outb (reg_nsect (c), 0x55);
//       outb (reg_lbal (c), 0xaa);

//       outb (reg_nsect (c), 0xaa);
//       outb (reg_lbal (c), 0x55);

//       outb (reg_nsect (c), 0x55);
//       outb (reg_lbal (c), 0xaa);

//       present[dev_no] = (inb (reg_nsect (c)) == 0x55
//                          && inb (reg_lbal (c)) == 0xaa);
//     }

//   /* Issue soft reset sequence, which selects device 0 as a side effect.
//      Also enable interrupts. */
//   outb (reg_ctl (c), 0);
//   outb (reg_ctl (c), CTL_SRST);
//   outb (reg_ctl (c), 0);

//   /* Wait for device 0 to clear BSY. */
//   if (present[0]) 
//     {
//       select_device (&c->devices[0]);
//       wait_while_busy (&c->devices[0]); 
//     }

//   /* Wait for device 1 to clear BSY. */
//   if (present[1])
//     {
//       int i;

//       select_device (&c->devices[1]);
//       for (i = 0; i < 3000; i++) 
//         {
//           if (inb (reg_nsect (c)) == 1 && inb (reg_lbal (c)) == 1)
//             break;
//         }
//       wait_while_busy (&c->devices[1]);
//     }
// }

// /* Checks whether device D is an ATA disk and sets D's is_ata
//    member appropriately.  If D is device 0 (master), returns true
//    if it's possible that a slave (device 1) exists on this
//    channel.  If D is device 1 (slave), the return value is not
//    meaningful. */
// static bool
// check_device_type (struct ata_disk *d) 
// {
//   struct channel *c = d->channel;
//   uint8_t error, lbam, lbah, status;

//   select_device (d);

//   error = inb (reg_error (c));
//   lbam = inb (reg_lbam (c));
//   lbah = inb (reg_lbah (c));
//   status = inb (reg_status (c));

//   if ((error != 1 && (error != 0x81 || d->dev_no == 1))
//       || (status & STA_DRDY) == 0
//       || (status & STA_BSY) != 0)
//     {
//       d->is_ata = false;
//       return error != 0x81;      
//     }
//   else 
//     {
//       d->is_ata = (lbam == 0 && lbah == 0) || (lbam == 0x3c && lbah == 0xc3);
//       return true; 
//     }
// }

// /* Sends an IDENTIFY DEVICE command to disk D and reads the
//    response.  Registers the disk with the block device
//    layer. */

// // modifed
// static void
// identify_ata_device (struct ata_disk *d) 
// {
//   struct channel *c = d->channel;
//   uint16_t id[BLOCK_SECTOR_SIZE/2];
//   block_sector_t capacity;
//   char *model, *serial;
//   char extra_info[128];
//   struct block *block;

//   /* Send the IDENTIFY DEVICE command, wait for an interrupt
//      indicating the device's response is ready, and read the data
//      into our buffer. */
//   select_device_wait (d);
//   issue_pio_command (c, CMD_IDENTIFY_DEVICE);
//   if (!wait_while_busy (d))
//     {
//       d->is_ata = false;
//       return;
//     }

//   input_sector (c, id);
//   /* Calculate capacity. */
//   d->capacity = id[60] | ((uint32_t) id[61] << 16);
//       printk("idec \n\n capacity %d \n\n\n\n", d->capacity );
//   /* Calculate capacity.
//      Read model name and serial number. */
//   capacity = *(uint32_t *) &id[60 * 2];
//   model = descramble_ata_string (&id[10 * 2], 20);
//   serial = descramble_ata_string (&id[27 * 2], 40);
//   snprintf (extra_info, sizeof extra_info,
//             "model \"%s\", serial \"%s\"", model, serial);

//   /* Disable access to IDE disks over 1 GB, which are likely
//      physical IDE disks rather than virtual ones.  If we don't
//      allow access to those, we're less likely to scribble on
//      someone's important data.  You can disable this check by
//      hand if you really want to do so. */
//   if (capacity >= 1024 * 1024 * 1024 / BLOCK_SECTOR_SIZE)
//     {
//       print_human_readable_size (capacity * 512);
//       d->is_ata = false;
//       return;
//     }
// }

// /* Translates STRING, which consists of SIZE bytes in a funky
//    format, into a null-terminated string in-place.  Drops
//    trailing whitespace and null bytes.  Returns STRING.  */
// static char *
// descramble_ata_string (char *string, int size) 
// {
//   int i;

//   /* Swap all pairs of bytes. */
//   for (i = 0; i + 1 < size; i += 2)
//     {
//       char tmp = string[i];
//       string[i] = string[i + 1];
//       string[i + 1] = tmp;
//     }

//   /* Find the last non-white, non-null character. */
//   for (size--; size > 0; size--)
//     {
//       int c = string[size - 1];
//       if (c != '\0' && !isspace (c))
//         break; 
//     }
//   string[size] = '\0';

//   return string;
// }
// 
// /* Reads sector SEC_NO from disk D into BUFFER, which must have
//    room for BLOCK_SECTOR_SIZE bytes.
//    Internally synchronizes accesses to disks, so external
//    per-disk locking is unneeded. */
// static void
// ide_read (void *d_, block_sector_t sec_no, void *buffer)
// {
//   struct ata_disk *d = d_;
//   struct channel *c = d->channel;
//   lock_acquire (&c->lock);
//   select_sector (d, sec_no);
//   issue_pio_command (c, CMD_READ_SECTOR_RETRY);
//   sema_down (&c->completion_wait);
//   if (!wait_while_busy (d))
//     ;
//   input_sector (c, buffer);
//   lock_release (&c->lock);
// }

// /* Write sector SEC_NO to disk D from BUFFER, which must contain
//    BLOCK_SECTOR_SIZE bytes.  Returns after the disk has
//    acknowledged receiving the data.
//    Internally synchronizes accesses to disks, so external
//    per-disk locking is unneeded. */
// static void
// ide_write (void *d_, block_sector_t sec_no, const void *buffer)
// {
//   struct ata_disk *d = d_;
//   struct channel *c = d->channel;
//   lock_acquire (&c->lock);
//   select_sector (d, sec_no);
//   issue_pio_command (c, CMD_WRITE_SECTOR_RETRY);
//   if (!wait_while_busy (d))
//     ;
//   output_sector (c, buffer);
//   sema_down (&c->completion_wait);
//   lock_release (&c->lock);
// }

// static struct block_operations ide_operations =
//   {
//     ide_read,
//     ide_write
//   };
// 
// /* Selects device D, waiting for it to become ready, and then
//    writes SEC_NO to the disk's sector selection registers.  (We
//    use LBA mode.) */
// static void
// select_sector (struct ata_disk *d, block_sector_t sec_no)
// {
//   struct channel *c = d->channel;
  
//   select_device_wait (d);
//   outb (reg_nsect (c), 1);
//   outb (reg_lbal (c), sec_no);
//   outb (reg_lbam (c), sec_no >> 8);
//   outb (reg_lbah (c), (sec_no >> 16));
//   outb (reg_device (c),
//         DEV_MBS | DEV_LBA | (d->dev_no == 1 ? DEV_DEV : 0) | (sec_no >> 24));
// }

// /* Writes COMMAND to channel C and prepares for receiving a
//    completion interrupt. */
// static void
// issue_pio_command (struct channel *c, uint8_t command) 
// {
//   /* Interrupts must be enabled or our semaphore will never be
//      up'd by the completion handler. */
//   c->expecting_interrupt = true;
//   outb (reg_command (c), command);
// }

// /* Reads a sector from channel C's data register in PIO mode into
//    SECTOR, which must have room for BLOCK_SECTOR_SIZE bytes. */
// static void
// input_sector (struct channel *c, void *sector) 
// {
//   insw (reg_data (c), sector, BLOCK_SECTOR_SIZE / 2);
// }

// /* Writes SECTOR to channel C's data register in PIO mode.
//    SECTOR must contain BLOCK_SECTOR_SIZE bytes. */
// static void
// output_sector (struct channel *c, const void *sector) 
// {
//   outsw (reg_data (c), sector, BLOCK_SECTOR_SIZE / 2);
// }
// 
// /* Low-level ATA primitives. */

// /* Wait up to 10 seconds for the controller to become idle, that
//    is, for the BSY and DRQ bits to clear in the status register.

//    As a side effect, reading the status register clears any
//    pending interrupt. */
// static void
// wait_until_idle (const struct ata_disk *d) 
// {
//   int i;

//   for (i = 0; i < 1000; i++) 
//     {
//       if ((inb (reg_status (d->channel)) & (STA_BSY | STA_DRQ)) == 0)
//         return;
//     }
// }

// /* Wait up to 30 seconds for disk D to clear BSY,
//    and then return the status of the DRQ bit.
//    The ATA standards say that a disk may take as long as that to
//    complete its reset. */
// static bool
// wait_while_busy (const struct ata_disk *d) 
// {
//   struct channel *c = d->channel;
//   int i;
  
//   for (i = 0; i < 3000; i++)
//     {
//       if (i == 700);
//       if (!(inb (reg_alt_status (c)) & STA_BSY)) 
//         {
//           if (i >= 700);
//           return (inb (reg_alt_status (c)) & STA_DRQ) != 0;
//         }
//     }
//   return false;
// }

// /* Program D's channel so that D is now the selected disk. */
// static void
// select_device (const struct ata_disk *d) 
// {
//   struct channel *c = d->channel;
//   uint8_t dev = DEV_MBS;
//   if (d->dev_no == 1)
//     dev |= DEV_DEV;
//   outb (reg_device (c), dev);
//   inb (reg_alt_status (c));
// }

// /* Select disk D in its channel, as select_device(), but wait for
//    the channel to become idle before and after. */
// static void
// select_device_wait (const struct ata_disk *d) 
// {
//   wait_until_idle (d);
//   select_device (d);
//   wait_until_idle (d);
// }
// 
// /* ATA interrupt handler. */
// static void
// interrupt_handler (int intr_num) 
// {

//   struct channel *c;

//   for (c = channels; c < channels + CHANNEL_CNT; c++)
//     if (intr_num == c->irq)
//       {
//         if (c->expecting_interrupt) 
//           {
//             inb (reg_status (c));                /*Acknowledge interrupt.*/ 
//             sema_up (&c->completion_wait);      /* Wake up waiter. */
//           }
//         else
//           ;
//         return;
//       }
// }
// /////modifiy

// struct ata_disk *
// disk_get (int chan_no, int dev_no) 
// {
//   if (chan_no < (int) CHANNEL_CNT) 
//     {
//       struct ata_disk *d = &channels[chan_no].devices[dev_no];
//       //if (d->is_ata)
//         return d; 
//     }
//   return NULL;
// }
// disk_sector_t
// disk_size (struct ata_disk *d) 
// {
//   if (d == NULL)
//   {
//     //printk("disk_size return error  d is NULL \n");
//     return -1;
//   }
  
//   return d->capacity;
// }

// /* Reads sector SEC_NO from disk D into BUFFER, which must have
//    room for DISK_SECTOR_SIZE bytes.
//    Internally synchronizes accesses to disks, so external
//    per-disk locking is unneeded. */
// void
// disk_read (struct ata_disk *d, disk_sector_t sec_no, void *buffer) 
// {
//   struct channel *c;
  
//   //ASSERT (d != NULL);
//   //ASSERT (buffer != NULL);

//   c = d->channel;
//   lock_acquire (&c->lock);
//   select_sector (d, sec_no);
//   issue_pio_command (c, CMD_READ_SECTOR_RETRY);
//   sema_down (&c->completion_wait);
//   if (!wait_while_busy (d))
//   {
//     //PANIC ("%s: disk read failed, sector=%"PRDSNu, d->name, sec_no);
//   }
    
//   input_sector (c, buffer);
//   d->read_cnt++;
//   lock_release (&c->lock);
// }


// /* Write sector SEC_NO to disk D from BUFFER, which must contain
//    DISK_SECTOR_SIZE bytes.  Returns after the disk has
//    acknowledged receiving the data.
//    Internally synchronizes accesses to disks, so external
//    per-disk locking is unneeded. */
// void
// disk_write (struct ata_disk *d, disk_sector_t sec_no, const void *buffer)
// {
//   printk("disk_write step 1\n");
//   struct channel *c;
  
// //ASSERT (d != NULL);
//  // ASSERT (buffer != NULL);
//   //printk("disk_write step 1\n");
//   // c = d->channel;
//   // lock_acquire (&c->lock);
//   // select_sector (d, sec_no);
//   // issue_pio_command (c, CMD_WRITE_SECTOR_RETRY);
//   // if (!wait_while_busy (d))
//   // {
//   //   printk("%s: disk write failed, sector=%PRDSNu\n",PRDSNu,d->name,sec_no);
//   // }
//   // printk("disk_write step 2\n");
//   // output_sector (c, buffer);
//   // sema_down (&c->completion_wait);
//   // d->write_cnt++;
//   // lock_release (&c->lock);
// }