/[dynamips]/trunk/dev_pcmcia_disk.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/dev_pcmcia_disk.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

upstream/dynamips-0.2.6-RC1/dev_pcmcia_disk.c revision 2 by dpavlin, Sat Oct 6 16:03:58 2007 UTC upstream/dynamips-0.2.7-RC1/dev_pcmcia_disk.c revision 7 by dpavlin, Sat Oct 6 16:23:47 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   * Cisco C7200 (Predator) simulation platform.   * Cisco router simulation platform.
3   * Copyright (c) 2006 Christophe Fillot.  All rights reserved.   * Copyright (c) 2006 Christophe Fillot.  All rights reserved.
4   *   *
5   * PCMCIA ATA Flash emulation.   * PCMCIA ATA Flash emulation.
# Line 15  Line 15 
15  #include <sys/stat.h>  #include <sys/stat.h>
16  #include <fcntl.h>  #include <fcntl.h>
17    
18  #include "mips64.h"  #include "cpu.h"
19    #include "vm.h"
20  #include "dynamips.h"  #include "dynamips.h"
21  #include "memory.h"  #include "memory.h"
22  #include "device.h"  #include "device.h"
23    
24  #define DEBUG_ACCESS  0  #define DEBUG_ACCESS  0
25  #define DEBUG_ATA     0  #define DEBUG_ATA     0
26    #define DEBUG_READ    0
27    #define DEBUG_WRITE   0
28    
29  /* Default disk parameters: 4 heads, 32 sectors per track */  /* Default disk parameters: 4 heads, 32 sectors per track */
30  #define DISK_NR_HEADS         4  #define DISK_NR_HEADS         4
# Line 141  static int disk_read_sector(struct pcmci Line 144  static int disk_read_sector(struct pcmci
144  {  {
145     off_t disk_offset = (off_t)sect * SECTOR_SIZE;     off_t disk_offset = (off_t)sect * SECTOR_SIZE;
146    
147    #if DEBUG_READ
148       vm_log(d->vm,d->dev.name,"reading sector 0x%8.8x\n",sect);
149    #endif
150    
151     if (lseek(d->fd,disk_offset,SEEK_SET) == -1) {     if (lseek(d->fd,disk_offset,SEEK_SET) == -1) {
152        perror("read_sector: lseek");        perror("read_sector: lseek");
153        return(-1);        return(-1);
# Line 160  static int disk_write_sector(struct pcmc Line 167  static int disk_write_sector(struct pcmc
167  {    {  
168     off_t disk_offset = (off_t)sect * SECTOR_SIZE;     off_t disk_offset = (off_t)sect * SECTOR_SIZE;
169    
170    #if DEBUG_WRITE
171       vm_log(d->vm,d->dev.name,"writing sector 0x%8.8x\n",sect);
172    #endif
173    
174     if (lseek(d->fd,disk_offset,SEEK_SET) == -1) {     if (lseek(d->fd,disk_offset,SEEK_SET) == -1) {
175        perror("write_sector: lseek");        perror("write_sector: lseek");
176        return(-1);        return(-1);
# Line 182  static void ata_identify_device(struct p Line 193  static void ata_identify_device(struct p
193     sect_count = d->nr_heads * d->nr_cylinders * d->sects_per_track;     sect_count = d->nr_heads * d->nr_cylinders * d->sects_per_track;
194    
195     /* Clear all fields (for safety) */     /* Clear all fields (for safety) */
196     memset(p,0,SECTOR_SIZE);     memset(p,0x00,SECTOR_SIZE);
197    
198     /* Word 0: General Configuration */     /* Word 0: General Configuration */
199     p[0] = 0x8a;     p[0] = 0x8a;
# Line 222  static void ata_identify_device(struct p Line 233  static void ata_identify_device(struct p
233     /* Word 56: Current number of sectors per track */     /* Word 56: Current number of sectors per track */
234     p[112] = d->sects_per_track;     p[112] = d->sects_per_track;
235    
236     /* Word 57/58: Current of sectors per card (MSW/LSW) */     /* Word 57/58: Current of sectors per card (LSW/MSW) */
237     p[114] = (sect_count >> 16) & 0xFF;     p[114] = sect_count & 0xFF;
238     p[115] = (sect_count >> 24);     p[115] = (sect_count >> 8) & 0xFF;
239     p[116] = sect_count & 0xFF;  
240     p[117] = (sect_count >> 8) & 0xFF;     p[116] = (sect_count >> 16) & 0xFF;
241       p[117] = (sect_count >> 24);
242    
243    #if 0
244     /* Word 60/61: Total sectors addressable in LBA mode (MSW/LSW) */     /* Word 60/61: Total sectors addressable in LBA mode (MSW/LSW) */
245     p[120] = (sect_count >> 16) & 0xFF;     p[120] = (sect_count >> 16) & 0xFF;
246     p[121] = (sect_count >> 24);     p[121] = (sect_count >> 24);
247     p[122] = sect_count & 0xFF;     p[122] = sect_count & 0xFF;
248     p[123] = (sect_count >> 8) & 0xFF;     p[123] = (sect_count >> 8) & 0xFF;
249    #endif
250  }  }
251    
252  /* Set sector position */  /* Set sector position */
# Line 241  static void ata_set_sect_pos(struct pcmc Line 255  static void ata_set_sect_pos(struct pcmc
255     u_int cyl;     u_int cyl;
256    
257     if (d->head & ATA_DH_LBA) {     if (d->head & ATA_DH_LBA) {
258        /* TODO */        d->sect_pos  = (u_int)(d->head & 0x0F) << 24;
259     }        d->sect_pos |= (u_int)d->cyl_high << 16;
260          d->sect_pos |= (u_int)d->cyl_low  << 8;
261          d->sect_pos |= (u_int)d->sect_no;
262    
263     cyl = (((u_int)d->cyl_high) << 8) + d->cyl_low;  #if DEBUG_ATA
264     d->sect_pos = chs_to_lba(d,cyl,d->head & 0x0F,d->sect_no);        vm_log(d->vm,d->dev.name,"ata_set_sect_pos: LBA sect=0x%x\n",
265                 d->sect_pos);
266    #endif
267       } else {
268          cyl = (((u_int)d->cyl_high) << 8) + d->cyl_low;
269          d->sect_pos = chs_to_lba(d,cyl,d->head & 0x0F,d->sect_no);
270        
271    #if DEBUG_ATA
272          vm_log(d->vm,d->dev.name,
273                 "ata_set_sect_pos: cyl=0x%x,head=0x%x,sect=0x%x => "
274                 "sect_pos=0x%x\n",
275                 cyl,d->head & 0x0F,d->sect_no,d->sect_pos);
276    #endif
277       }
278  }  }
279    
280  /* ATA device identifier callback */  /* ATA device identifier callback */
# Line 292  static void ata_handle_cmd(struct pcmcia Line 321  static void ata_handle_cmd(struct pcmcia
321     vm_log(d->vm,d->dev.name,"ATA command 0x%2.2x\n",(u_int)d->ata_cmd);     vm_log(d->vm,d->dev.name,"ATA command 0x%2.2x\n",(u_int)d->ata_cmd);
322  #endif  #endif
323    
324       d->data_pos = 0;
325    
326     switch(d->ata_cmd) {     switch(d->ata_cmd) {
327        case ATA_CMD_IDENT_DEVICE:        case ATA_CMD_IDENT_DEVICE:
328           ata_identify_device(d);           ata_identify_device(d);
# Line 329  static void ata_handle_cmd(struct pcmcia Line 360  static void ata_handle_cmd(struct pcmcia
360  }  }
361    
362  /*  /*
363   * dev_pcmcia_disk_access()   * dev_pcmcia_disk_access_0()
364   */   */
365  void *dev_pcmcia_disk_access(cpu_mips_t *cpu,struct vdevice *dev,  void *dev_pcmcia_disk_access_0(cpu_gen_t *cpu,struct vdevice *dev,
366                               m_uint32_t offset,u_int op_size,u_int op_type,                                 m_uint32_t offset,u_int op_size,u_int op_type,
367                               m_uint64_t *data)                                 m_uint64_t *data)
368  {  {
369     struct pcmcia_disk_data *d = dev->priv_data;     struct pcmcia_disk_data *d = dev->priv_data;
    m_uint32_t d_offset;  
370    
371     /* Compute the good internal offset */     /* Compute the good internal offset */
372     offset = (offset >> 1) ^ 1;     offset = (offset >> 1) ^ 1;
# Line 345  void *dev_pcmcia_disk_access(cpu_mips_t Line 375  void *dev_pcmcia_disk_access(cpu_mips_t
375     if (op_type == MTS_READ) {     if (op_type == MTS_READ) {
376        cpu_log(cpu,d->dev.name,        cpu_log(cpu,d->dev.name,
377                "reading offset 0x%5.5x at pc=0x%llx (size=%u)\n",                "reading offset 0x%5.5x at pc=0x%llx (size=%u)\n",
378                offset,cpu->pc,op_size);                offset,cpu_get_pc(cpu),op_size);
379     } else {     } else {
380        cpu_log(cpu,d->dev.name,        cpu_log(cpu,d->dev.name,
381                "writing offset 0x%5.5x, data=0x%llx at pc=0x%llx (size=%u)\n",                "writing offset 0x%5.5x, data=0x%llx at pc=0x%llx (size=%u)\n",
382                offset,*data,cpu->pc,op_size);                offset,*data,cpu_get_pc(cpu),op_size);
383     }     }
384  #endif  #endif
385    
# Line 390  void *dev_pcmcia_disk_access(cpu_mips_t Line 420  void *dev_pcmcia_disk_access(cpu_mips_t
420              *data = (d->ata_status << 8) + d->head;              *data = (d->ata_status << 8) + d->head;
421           else {           else {
422              d->ata_cmd = *data >> 8;              d->ata_cmd = *data >> 8;
423              d->head = *data & 0xFF;              d->head = *data;
424              ata_handle_cmd(d);              ata_handle_cmd(d);
425           }                       }            
426           break;           break;
# Line 400  void *dev_pcmcia_disk_access(cpu_mips_t Line 430  void *dev_pcmcia_disk_access(cpu_mips_t
430           if ((offset >= d->data_offset) &&           if ((offset >= d->data_offset) &&
431               (offset < d->data_offset + (SECTOR_SIZE/2)))               (offset < d->data_offset + (SECTOR_SIZE/2)))
432           {           {
             d_offset = offset - d->data_offset;  
   
433              if (op_type == MTS_READ) {              if (op_type == MTS_READ) {
434                 *data =  d->data_buffer[(d_offset << 1)];                 *data =  d->data_buffer[(d->data_pos << 1)];
435                 *data += d->data_buffer[(d_offset << 1)+1] << 8;                 *data += d->data_buffer[(d->data_pos << 1)+1] << 8;
436              } else {              } else {
437                 d->data_buffer[(d_offset << 1)]   = *data & 0xFF;                 d->data_buffer[(d->data_pos << 1)]   = *data & 0xFF;
438                 d->data_buffer[(d_offset << 1)+1] = *data >> 8;                 d->data_buffer[(d->data_pos << 1)+1] = *data >> 8;
439              }              }
440                
441                d->data_pos++;
442    
443              /* Validate data transfer */              /* Buffer complete: call the callback function */
444              if (d_offset == d->data_pos) {              if (d->data_pos == (SECTOR_SIZE/2)) {
445                 d->data_pos++;                 d->data_pos = 0;
446                  
447                 /* Buffer validated: call the callback function */                 if (d->ata_cmd_callback)
448                 if (d->data_pos == (SECTOR_SIZE/2)) {                    d->ata_cmd_callback(d);
                   d->data_pos = 0;  
   
                   if (d->ata_cmd_callback)  
                      d->ata_cmd_callback(d);  
                }  
449              }              }
450           }           }
451     }     }
# Line 428  void *dev_pcmcia_disk_access(cpu_mips_t Line 453  void *dev_pcmcia_disk_access(cpu_mips_t
453     return NULL;     return NULL;
454  }  }
455    
456    /*
457     * dev_pcmcia_disk_access_1()
458     */
459    void *dev_pcmcia_disk_access_1(cpu_gen_t *cpu,struct vdevice *dev,
460                                   m_uint32_t offset,u_int op_size,u_int op_type,
461                                   m_uint64_t *data)
462    {
463       struct pcmcia_disk_data *d = dev->priv_data;
464    
465       /* Compute the good internal offset */
466       offset = (offset >> 1) ^ 1;
467      
468    #if DEBUG_ACCESS
469       if (op_type == MTS_READ) {
470          cpu_log(cpu,d->dev.name,
471                  "reading offset 0x%5.5x at pc=0x%llx (size=%u)\n",
472                  offset,cpu->pc,op_size);
473       } else {
474          cpu_log(cpu,d->dev.name,
475                  "writing offset 0x%5.5x, data=0x%llx at pc=0x%llx (size=%u)\n",
476                  offset,*data,cpu->pc,op_size);
477       }
478    #endif
479          
480       switch(offset) {
481          case 0x02:   /* Sector Count + Sector no */
482             if (op_type == MTS_READ) {
483                *data = (d->sect_no << 8) + d->sect_count;
484             } else {
485                d->sect_no    = *data >> 8;
486                d->sect_count = *data & 0xFF;
487             }
488             break;
489    
490          case 0x04:   /* Cylinder Low + Cylinder High */
491             if (op_type == MTS_READ) {
492                *data = (d->cyl_high << 8) + d->cyl_low;
493             } else {
494                d->cyl_high = *data >> 8;
495                d->cyl_low  = *data & 0xFF;
496             }
497             break;
498    
499          case 0x06:   /* Select Card/Head + Status/Command register */
500             if (op_type == MTS_READ)
501                *data = (d->ata_status << 8) + d->head;
502             else {
503                d->ata_cmd = *data >> 8;
504                d->head = *data & 0xFF;
505                ata_handle_cmd(d);
506             }            
507             break;
508    
509          case 0x08:
510             if (op_type == MTS_READ) {
511                *data =  d->data_buffer[(d->data_pos << 1)];
512                *data += d->data_buffer[(d->data_pos << 1)+1] << 8;
513             } else {
514                d->data_buffer[(d->data_pos << 1)]   = *data & 0xFF;
515                d->data_buffer[(d->data_pos << 1)+1] = *data >> 8;
516             }
517    
518             d->data_pos++;
519    
520             /* Buffer complete: call the callback function */
521             if (d->data_pos == (SECTOR_SIZE/2)) {
522                d->data_pos = 0;
523                  
524                if (d->ata_cmd_callback)
525                   d->ata_cmd_callback(d);
526             }
527             break;
528    
529          case 0x0E:
530             break;
531       }
532    
533       return NULL;
534    }
535    
536  /* Shutdown a PCMCIA disk device */  /* Shutdown a PCMCIA disk device */
537  void dev_pcmcia_disk_shutdown(vm_instance_t *vm,struct pcmcia_disk_data *d)  void dev_pcmcia_disk_shutdown(vm_instance_t *vm,struct pcmcia_disk_data *d)
538  {  {
# Line 449  void dev_pcmcia_disk_shutdown(vm_instanc Line 554  void dev_pcmcia_disk_shutdown(vm_instanc
554  /* Initialize a PCMCIA disk */  /* Initialize a PCMCIA disk */
555  vm_obj_t *dev_pcmcia_disk_init(vm_instance_t *vm,char *name,  vm_obj_t *dev_pcmcia_disk_init(vm_instance_t *vm,char *name,
556                                 m_uint64_t paddr,m_uint32_t len,                                 m_uint64_t paddr,m_uint32_t len,
557                                 u_int disk_size)                                 u_int disk_size,int mode)
558  {  {
559     struct pcmcia_disk_data *d;     struct pcmcia_disk_data *d;
560     m_uint32_t tot_sect;     m_uint32_t tot_sect;
# Line 497  vm_obj_t *dev_pcmcia_disk_init(vm_instan Line 602  vm_obj_t *dev_pcmcia_disk_init(vm_instan
602     d->dev.phys_addr = paddr;     d->dev.phys_addr = paddr;
603     d->dev.phys_len  = len;     d->dev.phys_len  = len;
604     d->dev.flags     = VDEVICE_FLAG_CACHING;     d->dev.flags     = VDEVICE_FLAG_CACHING;
605     d->dev.handler   = dev_pcmcia_disk_access;  
606       if (mode == 0)
607          d->dev.handler = dev_pcmcia_disk_access_0;
608       else
609          d->dev.handler = dev_pcmcia_disk_access_1;
610    
611     /* Map this device to the VM */     /* Map this device to the VM */
612     vm_bind_device(vm,&d->dev);     vm_bind_device(vm,&d->dev);
# Line 510  vm_obj_t *dev_pcmcia_disk_init(vm_instan Line 619  vm_obj_t *dev_pcmcia_disk_init(vm_instan
619     free(d);     free(d);
620     return NULL;     return NULL;
621  }  }
622    
623    /* Get the device associated with a PCMCIA disk object */
624    struct vdevice *dev_pcmcia_disk_get_device(vm_obj_t *obj)
625    {
626       struct pcmcia_disk_data *d;
627    
628       if (!obj || !(d = obj->data))
629          return NULL;
630    
631       return(&d->dev);
632    }

Legend:
Removed from v.2  
changed lines
  Added in v.7

  ViewVC Help
Powered by ViewVC 1.1.26