source: rtems/c/src/lib/libbsp/i386/pc386/ide/ide.c @ bf5d715

4.115
Last change on this file since bf5d715 was bf5d715, checked in by Ralf Corsepius <ralf.corsepius@…>, on 12/09/11 at 13:12:40

2011-12-09 Ralf Corsépius <ralf.corsepius@…>

  • console/vt.c: Make _kd_mksound static.
  • ide/ide.c: Make pc386_ide_probe, pc386_ide_initialize, pc386_ide_read_reg, pc386_ide_write_reg, pc386_ide_write_block, pc386_ide_control, pc386_ide_config_io_speed static.
  • Property mode set to 100644
File size: 23.7 KB
Line 
1/*===============================================================*\
2| Project: RTEMS PC386 IDE harddisc driver                        |
3+-----------------------------------------------------------------+
4| File: ide.c                                                     |
5+-----------------------------------------------------------------+
6|                    Copyright (c) 2003 IMD                       |
7|      Ingenieurbuero fuer Microcomputertechnik Th. Doerfler      |
8|               <Thomas.Doerfler@imd-systems.de>                  |
9|                       all rights reserved                       |
10+-----------------------------------------------------------------+
11| this file contains the BSP layer for IDE access below the       |
12| libchip IDE harddisc driver                                     |
13| based on a board specific driver from                           |
14| Eugeny S. Mints, Oktet                                          |
15|                                                                 |
16|  The license and distribution terms for this file may be        |
17|  found in the file LICENSE in this distribution or at           |
18|  http://www.rtems.com/license/LICENSE.                     |
19|                                                                 |
20+-----------------------------------------------------------------+
21|   date                      history                        ID   |
22| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
23| 01.14.03  creation                                         doe  |
24\*===============================================================*/
25
26#include <rtems.h>
27#include <bsp.h>
28#include <libchip/ide_ctrl.h>
29#include <libchip/ide_ctrl_cfg.h>
30#include <libchip/ide_ctrl_io.h>
31
32#define ATA_SECTOR_SIZE (512)
33
34/*
35 * Use during initialisation.
36 */
37extern void Wait_X_ms(unsigned int msecs);
38
39bool pc386_ide_show;
40uint32_t pc386_ide_timeout;
41
42#define PC386_IDE_DEBUG_OUT 0
43
44#if PC386_IDE_DEBUG_OUT
45bool pc386_ide_trace;
46#define pc386_ide_printk if (pc386_ide_trace) printk
47#endif
48
49#define PC386_IDE_PROBE_TIMEOUT    (500)
50#define PC386_IDE_PRESTART_TIMEOUT (1000)
51#define PC386_IDE_TASKING_TIMEOUT  (2000)
52
53/*
54 * Prestart sleep using a calibrated timing loop.
55 */
56static void pc386_ide_prestart_sleep (void)
57{
58  Wait_X_ms (10);
59}
60
61/*
62 * Once tasking has started we use a task sleep.
63 */
64static void pc386_ide_tasking_sleep (void)
65{
66  rtems_task_wake_after (TOD_MICROSECONDS_TO_TICKS (10000) ?
67                         TOD_MICROSECONDS_TO_TICKS (10000) : 1);
68}
69
70typedef void (*pc386_ide_sleeper)(void);
71
72static void pc386_ide_sleep (pc386_ide_sleeper sleeper)
73{
74  sleeper ();
75}
76
77static void wait(volatile uint32_t loops)
78{
79  while (loops)
80    loops--;
81}
82
83static bool pc386_ide_status_busy (uint32_t          port,
84                                   volatile uint32_t timeout,
85                                   uint8_t*          status_val,
86                                   pc386_ide_sleeper sleeper)
87{
88  volatile uint8_t status;
89  int              polls;
90
91  do
92  {
93    polls = 500;
94    while (polls)
95    {
96      inport_byte (port + IDE_REGISTER_STATUS, status);
97      if ((status & IDE_REGISTER_STATUS_BSY) == 0)
98      {
99        *status_val = status;
100        return true;
101      }
102      polls--;
103    }
104
105    if (timeout)
106    {
107      timeout--;
108      pc386_ide_sleep (sleeper);
109    }
110  }
111  while (timeout);
112
113  *status_val = status;
114  return false;
115}
116
117static bool pc386_ide_status_data_ready (uint32_t          port,
118                                         volatile uint32_t timeout,
119                                         uint8_t*          status_val,
120                                         pc386_ide_sleeper sleeper)
121{
122  volatile uint8_t status;
123  int              polls;
124
125  do
126  {
127    polls = 1000;
128    while (polls)
129    {
130      inport_byte (port + IDE_REGISTER_STATUS, status);
131
132      if (((status & IDE_REGISTER_STATUS_BSY) == 0) &&
133          (status & IDE_REGISTER_STATUS_DRQ))
134      {
135        *status_val = status;
136        return true;
137      }
138
139      polls--;
140    }
141
142    if (timeout)
143    {
144      timeout--;
145      pc386_ide_sleep (sleeper);
146    }
147  }
148  while (timeout);
149
150  *status_val = status;
151  return false;
152}
153
154/*
155 * support functions for IDE harddisk IF
156 */
157/*=========================================================================*\
158| Function:                                                                 |
159\*-------------------------------------------------------------------------*/
160static bool pc386_ide_probe
161(
162/*-------------------------------------------------------------------------*\
163| Purpose:                                                                  |
164|  This function should probe, whether a IDE disk is available              |
165+---------------------------------------------------------------------------+
166| Input Parameters:                                                         |
167\*-------------------------------------------------------------------------*/
168 int minor
169 )
170/*-------------------------------------------------------------------------*\
171| Return Value:                                                             |
172|    true, when flash disk available                                        |
173\*=========================================================================*/
174{
175  bool ide_card_plugged = true; /* assume: we have a disk here */
176
177  return ide_card_plugged;
178}
179
180/*=========================================================================*\
181| Function:                                                                 |
182\*-------------------------------------------------------------------------*/
183static void pc386_ide_initialize
184(
185/*-------------------------------------------------------------------------*\
186  | Purpose:                                                                  |
187  |  initialize IDE access                                                    |
188  +---------------------------------------------------------------------------+
189  | Input Parameters:                                                         |
190  \*-------------------------------------------------------------------------*/
191  int  minor                              /* controller minor number       */
192 )
193/*-------------------------------------------------------------------------*\
194  | Return Value:                                                             |
195  |    <none>                                                                 |
196  \*=========================================================================*/
197{
198  uint32_t port = IDE_Controller_Table[minor].port1;
199  uint8_t  dev = 0;
200
201  if (pc386_ide_show)
202    printk("IDE%d: port base: %04x\n", minor, port);
203
204  outport_byte(port+IDE_REGISTER_DEVICE_HEAD,
205               (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS) | 0xE0);
206  wait(10000);
207  outport_byte(port+IDE_REGISTER_DEVICE_CONTROL,
208               IDE_REGISTER_DEVICE_CONTROL_SRST | IDE_REGISTER_DEVICE_CONTROL_nIEN);
209  wait(10000);
210  outport_byte(port+IDE_REGISTER_DEVICE_CONTROL,
211               IDE_REGISTER_DEVICE_CONTROL_nIEN);
212  wait(10000);
213
214  for (dev = 0; dev < 2; dev++)
215  {
216    uint16_t    capabilities = 0;
217    uint32_t    byte;
218    uint8_t     status;
219    uint8_t     error;
220    uint8_t     cyllsb;
221    uint8_t     cylmsb;
222    const char* label = dev ? " slave" : "master";
223    int         max_multiple_sectors = 0;
224    int         cur_multiple_sectors = 0;
225    uint32_t    cylinders = 0;
226    uint32_t    heads = 0;
227    uint32_t    sectors = 0;
228    uint32_t    lba_sectors = 0;
229    char        model_number[41];
230    char*       p = &model_number[0];
231    bool        data_ready;
232
233    memset(model_number, 0, sizeof(model_number));
234
235    outport_byte(port+IDE_REGISTER_DEVICE_HEAD,
236                 (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS) | 0xE0);
237    /*
238      outport_byte(port+IDE_REGISTER_SECTOR_NUMBER,
239      (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS) | IDE_REGISTER_LBA3_L);
240    */
241
242    outport_byte(port+IDE_REGISTER_COMMAND, 0x00);
243
244    if (!pc386_ide_status_busy (port, PC386_IDE_PROBE_TIMEOUT,
245                                &status, pc386_ide_prestart_sleep))
246      continue;
247
248    inport_byte(port+IDE_REGISTER_STATUS,        status);
249    inport_byte(port+IDE_REGISTER_ERROR,         error);
250    inport_byte(port+IDE_REGISTER_CYLINDER_LOW,  cyllsb);
251    inport_byte(port+IDE_REGISTER_CYLINDER_HIGH, cylmsb);
252
253    if (pc386_ide_show)
254    {
255      printk("IDE%d:%s: status=%02x\n", minor, label, status);
256      printk("IDE%d:%s: error=%02x\n", minor, label, error);
257      printk("IDE%d:%s: cylinder-low=%02x\n", minor, label, cyllsb);
258      printk("IDE%d:%s: cylinder-high=%02x\n", minor, label, cylmsb);
259    }
260
261    outport_byte(port+IDE_REGISTER_COMMAND, 0xec);
262
263    if (!pc386_ide_status_busy (port, PC386_IDE_PRESTART_TIMEOUT,
264                                &status, pc386_ide_prestart_sleep))
265    {
266      if (pc386_ide_show)
267        printk("IDE%d:%s: device busy: %02x\n", minor, label, status);
268      continue;
269    }
270
271    data_ready = pc386_ide_status_data_ready (port,
272                                              250,
273                                              &status,
274                                              pc386_ide_prestart_sleep);
275
276    if (status & IDE_REGISTER_STATUS_ERR)
277    {
278      inport_byte(port+IDE_REGISTER_ERROR, error);
279      if (error != 4)
280      {
281        if (pc386_ide_show)
282          printk("IDE%d:%s: error=%04x\n", minor, label, error);
283        continue;
284      }
285      /*
286       * The device is an ATAPI device.
287       */
288      outport_byte(port+IDE_REGISTER_COMMAND, 0xa1);
289      data_ready = pc386_ide_status_data_ready (port,
290                                                250,
291                                                &status,
292                                                pc386_ide_prestart_sleep);
293    }
294
295    if (!data_ready)
296      continue;
297
298    byte = 0;
299    while (byte < 512)
300    {
301      uint16_t word;
302
303      if (pc386_ide_show && ((byte % 16) == 0))
304        printk("\n %04x : ", byte);
305
306      inport_word(port+IDE_REGISTER_DATA, word);
307
308      if (pc386_ide_show)
309        printk ("%04x ", word);
310
311      if (byte == 2)
312        cylinders = word;
313      if (byte == 6)
314        heads = word;
315      if (byte == 12)
316        sectors = word;
317
318      if (byte >= 54 && byte < (54 + 40))
319      {
320        *p = word >> 8;
321        p++;
322        *p = word;
323        p++;
324      }
325
326      if (byte == (47 * 2))
327        max_multiple_sectors = word & 0xff;
328
329      if (byte == (49 * 2))
330        capabilities = word;
331
332      if (byte == (59 * 2))
333      {
334        if (word & (1 << 8))
335          cur_multiple_sectors = word & 0xff;
336      }
337
338      if (byte == (60 * 2))
339        lba_sectors = word;
340      if (byte == (61 * 2))
341        lba_sectors |= word << 16;
342
343      byte += 2;
344    }
345
346    if (pc386_ide_show)
347      printk("\nbytes read = %d\n", byte);
348
349    if (p != &model_number[0])
350    {
351      uint32_t size;
352      uint32_t left;
353      uint32_t right;
354      char     units;
355
356      if (capabilities & (1 << 9))
357        size = lba_sectors;
358      else
359        size = cylinders * heads * sectors;
360
361      size /= 2;
362
363      if (size > (1024 * 1024))
364      {
365        size = (size * 10) / (1000 * 1000);
366        units = 'G';
367      }
368      else if (size > 1024)
369      {
370        size = (size * 10) / 1000;
371        units = 'M';
372      }
373      else
374      {
375        size = size * 10;
376        units = 'K';
377      }
378
379      left = size / 10;
380      right = size % 10;
381
382      p--;
383      while (*p == ' ')
384      {
385        *p = '\0';
386        p--;
387      }
388
389      printk("IDE%d:%s:%s, %u.%u%c (%u/%u/%u), max blk size:%d\n",
390             minor, label, model_number, left, right, units,
391             heads, cylinders, sectors, max_multiple_sectors * 512);
392    }
393
394#if IDE_CLEAR_MULTI_SECTOR_COUNT
395    if (max_multiple_sectors)
396    {
397      outport_byte(port+IDE_REGISTER_SECTOR_COUNT, 0);
398      outport_byte(port+IDE_REGISTER_COMMAND, 0xc6);
399
400      if (!pc386_ide_status_busy (port, PC386_IDE_PRESTART_TIMEOUT,
401                                  &status, pc386_ide_prestart_sleep))
402      {
403        if (pc386_ide_show)
404          printk("IDE%d:%s: device busy: %02x\n", minor, label, status);
405        continue;
406      }
407
408      inport_byte(port+IDE_REGISTER_STATUS, status);
409      if (status & IDE_REGISTER_STATUS_ERR)
410      {
411        inport_byte(port+IDE_REGISTER_ERROR, error);
412        if (error & IDE_REGISTER_ERROR_ABRT)
413          printk("IDE%d:%s: disable multiple failed\n", minor, label);
414        else
415          printk("IDE%d:%s: unknown error on disable multiple: %02x\n",
416                 minor, label, error);
417      }
418    }
419#endif
420
421    outport_byte(port+IDE_REGISTER_DEVICE_CONTROL,
422                 IDE_REGISTER_DEVICE_CONTROL_nIEN);
423    wait(10000);
424  }
425
426  pc386_ide_timeout = PC386_IDE_TASKING_TIMEOUT;
427
428  /*
429   * FIXME: enable interrupts, if needed
430   */
431}
432
433/*=========================================================================*\
434| Function:                                                                 |
435\*-------------------------------------------------------------------------*/
436static void pc386_ide_read_reg
437(
438/*-------------------------------------------------------------------------*\
439| Purpose:                                                                  |
440|  read a IDE controller register                                           |
441+---------------------------------------------------------------------------+
442| Input Parameters:                                                         |
443\*-------------------------------------------------------------------------*/
444 int                        minor,  /* controller minor number       */
445 int                        reg,    /* register index to access      */
446 uint16_t                  *value   /* ptr to return value location  */
447 )
448/*-------------------------------------------------------------------------*\
449| Return Value:                                                             |
450|    <none>                                                                 |
451\*=========================================================================*/
452{
453  uint32_t    port = IDE_Controller_Table[minor].port1;
454  uint8_t   bval1,bval2;
455
456  if (reg == IDE_REGISTER_DATA_WORD) {
457    inport_byte(port+reg, bval1);
458    inport_byte(port+reg+1, bval2);
459    *value = bval1 + (bval2 << 8);
460  }
461  else {
462    inport_byte(port+reg, bval1);
463    *value = bval1;
464  }
465#if PC386_IDE_DEBUG_OUT
466  pc386_ide_printk("pc386_ide_read_reg (0x%x)=0x%x\r\n",reg,*value & 0xff);
467#endif
468}
469
470/*=========================================================================*\
471| Function:                                                                 |
472\*-------------------------------------------------------------------------*/
473static void pc386_ide_write_reg
474(
475/*-------------------------------------------------------------------------*\
476| Purpose:                                                                  |
477|  write a IDE controller register                                          |
478+---------------------------------------------------------------------------+
479| Input Parameters:                                                         |
480\*-------------------------------------------------------------------------*/
481 int                        minor,  /* controller minor number       */
482 int                        reg,    /* register index to access      */
483 uint16_t                   value   /* value to write                */
484 )
485/*-------------------------------------------------------------------------*\
486| Return Value:                                                             |
487|    <none>                                                                 |
488\*=========================================================================*/
489{
490  uint32_t    port = IDE_Controller_Table[minor].port1;
491
492#if PC386_IDE_DEBUG_OUT
493  pc386_ide_printk("pc386_ide_write_reg(0x%x,0x%x)\r\n",reg,value & 0xff);
494#endif
495  if (reg == IDE_REGISTER_DATA_WORD) {
496    outport_word(port+reg,value);
497  }
498  else {
499    outport_byte(port+reg,value);
500  }
501}
502
503/*=========================================================================*\
504| Function:                                                                 |
505\*-------------------------------------------------------------------------*/
506static void pc386_ide_read_block
507(
508/*-------------------------------------------------------------------------*\
509| Purpose:                                                                  |
510|  read a IDE controller data block                                         |
511+---------------------------------------------------------------------------+
512| Input Parameters:                                                         |
513\*-------------------------------------------------------------------------*/
514 int                     minor,
515 uint32_t                block_size,
516 rtems_blkdev_sg_buffer *bufs,
517 uint32_t               *cbuf,
518 uint32_t               *pos
519 )
520/*-------------------------------------------------------------------------*\
521| Return Value:                                                             |
522|    <none>                                                                 |
523\*=========================================================================*/
524{
525  uint32_t port = IDE_Controller_Table[minor].port1;
526  uint32_t cnt = 0;
527#if PC386_IDE_DEBUG_OUT
528  int i32 = 0;
529  pc386_ide_printk("pc386_ide_read_block(bs=%u,bn=%u,bl=%u,cb=%d,p=%d)\n",
530                   block_size, bufs[(*cbuf)].block, llength, *cbuf, *pos);
531#endif
532
533  while (cnt < block_size)
534  {
535    uint16_t *lbuf;
536    uint8_t  status_val;
537    int      b;
538
539    if (!pc386_ide_status_data_ready (port, pc386_ide_timeout,
540                                      &status_val, pc386_ide_tasking_sleep))
541    {
542      printk ("pc386_ide_read_block: block=%u cbuf=%u status=%02x, cnt=%d bs=%d\n",
543              bufs[*cbuf].block, *cbuf, status_val, cnt, block_size);
544      /* FIXME: add an error here. */
545      return;
546    }
547
548    if (status_val & IDE_REGISTER_STATUS_ERR)
549    {
550      inport_byte(port+IDE_REGISTER_ERROR, status_val);
551      printk("pc386_ide_read_block: error: %02x\n", status_val);
552      return;
553    }
554
555    lbuf = (uint16_t*)((uint8_t*)(bufs[(*cbuf)].buffer) + (*pos));
556
557    for (b = 0; b < (ATA_SECTOR_SIZE / 2); b++)
558    {
559      inport_word(port+IDE_REGISTER_DATA,*lbuf);
560
561#if PC386_IDE_DEBUG_OUT
562      pc386_ide_printk("%04x ",*lbuf);
563      i32++;
564      if (i32 >= 16)
565      {
566        pc386_ide_printk("\n");
567        i32 = 0;
568      }
569#endif
570      lbuf++;
571    }
572    cnt    += ATA_SECTOR_SIZE;
573    (*pos) += ATA_SECTOR_SIZE;
574    if ((*pos) == bufs[(*cbuf)].length) {
575      (*pos) = 0;
576      (*cbuf)++;
577      lbuf = bufs[(*cbuf)].buffer;
578    }
579  }
580}
581
582/*=========================================================================*\
583| Function:                                                                 |
584\*-------------------------------------------------------------------------*/
585static void pc386_ide_write_block
586(
587/*-------------------------------------------------------------------------*\
588| Purpose:                                                                  |
589|  write a IDE controller data block                                        |
590+---------------------------------------------------------------------------+
591| Input Parameters:                                                         |
592\*-------------------------------------------------------------------------*/
593 int minor,
594 uint32_t                block_size,
595 rtems_blkdev_sg_buffer *bufs,
596 uint32_t               *cbuf,
597 uint32_t               *pos
598 )
599/*-------------------------------------------------------------------------*\
600| Return Value:                                                             |
601|    <none>                                                                 |
602\*=========================================================================*/
603{
604  uint32_t port = IDE_Controller_Table[minor].port1;
605  uint32_t cnt = 0;
606#if PC386_IDE_DEBUG_OUT
607  int i32 = 0;
608  pc386_ide_printk("pc386_ide_write_block(bs=%u,bn=%u,bl=%u,cb=%d,p=%d)\n",
609                   block_size, bufs[(*cbuf)].block, llength, *cbuf, *pos);
610#endif
611
612  while (cnt < block_size)
613  {
614    uint16_t *lbuf;
615    uint8_t  status_val;
616    int      b;
617
618    if (!pc386_ide_status_data_ready (port, pc386_ide_timeout,
619                                      &status_val, pc386_ide_tasking_sleep))
620    {
621      printk ("pc386_ide_write_block: block=%u status=%02x, cnt=%d bs=%d\n",
622              bufs[*cbuf].block, status_val, cnt, block_size);
623      /* FIXME: add an error here. */
624      return;
625    }
626
627    if (status_val & IDE_REGISTER_STATUS_ERR)
628    {
629      inport_byte(port+IDE_REGISTER_ERROR, status_val);
630      printk ("pc386_ide_write_block: error: %02x\n", status_val);
631      return;
632    }
633
634    lbuf = (uint16_t*)(((uint8_t*)bufs[*cbuf].buffer) + (*pos));
635
636    for (b = 0; b < (ATA_SECTOR_SIZE / 2); b++)
637    {
638#if PC386_IDE_DEBUG_OUT
639      pc386_ide_printk("%04x ",*lbuf);
640      i32++;
641      if (i32 >= 16)
642      {
643        pc386_ide_printk("\n");
644        i32 = 0;
645      }
646#endif
647      outport_word(port+IDE_REGISTER_DATA,*lbuf);
648      lbuf++;
649    }
650    cnt    += ATA_SECTOR_SIZE;
651    (*pos) += ATA_SECTOR_SIZE;
652    if ((*pos) == bufs[(*cbuf)].length) {
653      (*pos) = 0;
654      (*cbuf)++;
655      lbuf = bufs[(*cbuf)].buffer;
656    }
657  }
658}
659
660/*=========================================================================*\
661| Function:                                                                 |
662\*-------------------------------------------------------------------------*/
663static int pc386_ide_control
664(
665/*-------------------------------------------------------------------------*\
666| Purpose:                                                                  |
667|  control interface for controller                                         |
668+---------------------------------------------------------------------------+
669| Input Parameters:                                                         |
670\*-------------------------------------------------------------------------*/
671 int  minor,                        /* controller minor number       */
672 uint32_t   cmd,                    /* command to send               */
673 void * arg                         /* optional argument             */
674 )
675/*-------------------------------------------------------------------------*\
676| Return Value:                                                             |
677|    <none>                                                                 |
678\*=========================================================================*/
679{
680  return 0;
681}
682
683/*=========================================================================*\
684| Function:                                                                 |
685\*-------------------------------------------------------------------------*/
686static rtems_status_code pc386_ide_config_io_speed
687(
688/*-------------------------------------------------------------------------*\
689| Purpose:                                                                  |
690|  set up transfer speed, if possible                                       |
691+---------------------------------------------------------------------------+
692| Input Parameters:                                                         |
693\*-------------------------------------------------------------------------*/
694 int        minor,                   /* controller minor number       */
695 uint16_t   modes_avail              /* optional argument             */
696 )
697/*-------------------------------------------------------------------------*\
698| Return Value:                                                             |
699|    rtems_status_code                                                      |
700\*=========================================================================*/
701{
702  return RTEMS_SUCCESSFUL;
703}
704
705/*
706 * The following table configures the functions used for IDE drivers
707 * in this BSP.
708 */
709
710ide_ctrl_fns_t pc386_ide_ctrl_fns = {
711  pc386_ide_probe,
712  pc386_ide_initialize,
713  pc386_ide_control,
714  pc386_ide_read_reg,
715  pc386_ide_write_reg,
716  pc386_ide_read_block,
717  pc386_ide_write_block,
718  pc386_ide_config_io_speed
719};
Note: See TracBrowser for help on using the repository browser.