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

4.11
Last change on this file since 4977f07e was 4977f07e, checked in by Joel Sherrill <joel.sherrill@…>, on Oct 9, 2014 at 5:56:18 PM

i386/pc386: Eliminate multiple warnings

  • Property mode set to 100644
File size: 23.8 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.org/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 (RTEMS_MICROSECONDS_TO_TICKS (10000) ?
67                         RTEMS_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    (void) cur_multiple_sectors; /* avoid set but not used warning */
234
235    memset(model_number, 0, sizeof(model_number));
236
237    outport_byte(port+IDE_REGISTER_DEVICE_HEAD,
238                 (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS) | 0xE0);
239    /*
240      outport_byte(port+IDE_REGISTER_SECTOR_NUMBER,
241      (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS) | IDE_REGISTER_LBA3_L);
242    */
243
244    outport_byte(port+IDE_REGISTER_COMMAND, 0x00);
245
246    if (!pc386_ide_status_busy (port, PC386_IDE_PROBE_TIMEOUT,
247                                &status, pc386_ide_prestart_sleep))
248      continue;
249
250    inport_byte(port+IDE_REGISTER_STATUS,        status);
251    inport_byte(port+IDE_REGISTER_ERROR,         error);
252    inport_byte(port+IDE_REGISTER_CYLINDER_LOW,  cyllsb);
253    inport_byte(port+IDE_REGISTER_CYLINDER_HIGH, cylmsb);
254
255    if (pc386_ide_show)
256    {
257      printk("IDE%d:%s: status=%02x\n", minor, label, status);
258      printk("IDE%d:%s: error=%02x\n", minor, label, error);
259      printk("IDE%d:%s: cylinder-low=%02x\n", minor, label, cyllsb);
260      printk("IDE%d:%s: cylinder-high=%02x\n", minor, label, cylmsb);
261    }
262
263    outport_byte(port+IDE_REGISTER_COMMAND, 0xec);
264
265    if (!pc386_ide_status_busy (port, PC386_IDE_PRESTART_TIMEOUT,
266                                &status, pc386_ide_prestart_sleep))
267    {
268      if (pc386_ide_show)
269        printk("IDE%d:%s: device busy: %02x\n", minor, label, status);
270      continue;
271    }
272
273    data_ready = pc386_ide_status_data_ready (port,
274                                              250,
275                                              &status,
276                                              pc386_ide_prestart_sleep);
277
278    if (status & IDE_REGISTER_STATUS_ERR)
279    {
280      inport_byte(port+IDE_REGISTER_ERROR, error);
281      if (error != 4)
282      {
283        if (pc386_ide_show)
284          printk("IDE%d:%s: error=%04x\n", minor, label, error);
285        continue;
286      }
287      /*
288       * The device is an ATAPI device.
289       */
290      outport_byte(port+IDE_REGISTER_COMMAND, 0xa1);
291      data_ready = pc386_ide_status_data_ready (port,
292                                                250,
293                                                &status,
294                                                pc386_ide_prestart_sleep);
295    }
296
297    if (!data_ready)
298      continue;
299
300    byte = 0;
301    while (byte < 512)
302    {
303      uint16_t word;
304
305      if (pc386_ide_show && ((byte % 16) == 0))
306        printk("\n %04x : ", byte);
307
308      inport_word(port+IDE_REGISTER_DATA, word);
309
310      if (pc386_ide_show)
311        printk ("%04x ", word);
312
313      if (byte == 2)
314        cylinders = word;
315      if (byte == 6)
316        heads = word;
317      if (byte == 12)
318        sectors = word;
319
320      if (byte >= 54 && byte < (54 + 40))
321      {
322        *p = word >> 8;
323        p++;
324        *p = word;
325        p++;
326      }
327
328      if (byte == (47 * 2))
329        max_multiple_sectors = word & 0xff;
330
331      if (byte == (49 * 2))
332        capabilities = word;
333
334      if (byte == (59 * 2))
335      {
336        if (word & (1 << 8))
337          cur_multiple_sectors = word & 0xff;
338      }
339
340      if (byte == (60 * 2))
341        lba_sectors = word;
342      if (byte == (61 * 2))
343        lba_sectors |= word << 16;
344
345      byte += 2;
346    }
347
348    if (pc386_ide_show)
349      printk("\nbytes read = %d\n", byte);
350
351    if (p != &model_number[0])
352    {
353      uint32_t size;
354      uint32_t left;
355      uint32_t right;
356      char     units;
357
358      if (capabilities & (1 << 9))
359        size = lba_sectors;
360      else
361        size = cylinders * heads * sectors;
362
363      size /= 2;
364
365      if (size > (1024 * 1024))
366      {
367        size = (size * 10) / (1000 * 1000);
368        units = 'G';
369      }
370      else if (size > 1024)
371      {
372        size = (size * 10) / 1000;
373        units = 'M';
374      }
375      else
376      {
377        size = size * 10;
378        units = 'K';
379      }
380
381      left = size / 10;
382      right = size % 10;
383
384      p--;
385      while (*p == ' ')
386      {
387        *p = '\0';
388        p--;
389      }
390
391      printk("IDE%d:%s:%s, %u.%u%c (%u/%u/%u), max blk size:%d\n",
392             minor, label, model_number, left, right, units,
393             heads, cylinders, sectors, max_multiple_sectors * 512);
394    }
395
396#if IDE_CLEAR_MULTI_SECTOR_COUNT
397    if (max_multiple_sectors)
398    {
399      outport_byte(port+IDE_REGISTER_SECTOR_COUNT, 0);
400      outport_byte(port+IDE_REGISTER_COMMAND, 0xc6);
401
402      if (!pc386_ide_status_busy (port, PC386_IDE_PRESTART_TIMEOUT,
403                                  &status, pc386_ide_prestart_sleep))
404      {
405        if (pc386_ide_show)
406          printk("IDE%d:%s: device busy: %02x\n", minor, label, status);
407        continue;
408      }
409
410      inport_byte(port+IDE_REGISTER_STATUS, status);
411      if (status & IDE_REGISTER_STATUS_ERR)
412      {
413        inport_byte(port+IDE_REGISTER_ERROR, error);
414        if (error & IDE_REGISTER_ERROR_ABRT)
415          printk("IDE%d:%s: disable multiple failed\n", minor, label);
416        else
417          printk("IDE%d:%s: unknown error on disable multiple: %02x\n",
418                 minor, label, error);
419      }
420    }
421#endif
422
423    outport_byte(port+IDE_REGISTER_DEVICE_CONTROL,
424                 IDE_REGISTER_DEVICE_CONTROL_nIEN);
425    wait(10000);
426  }
427
428  pc386_ide_timeout = PC386_IDE_TASKING_TIMEOUT;
429
430  /*
431   * FIXME: enable interrupts, if needed
432   */
433}
434
435/*=========================================================================*\
436| Function:                                                                 |
437\*-------------------------------------------------------------------------*/
438static void pc386_ide_read_reg
439(
440/*-------------------------------------------------------------------------*\
441| Purpose:                                                                  |
442|  read a IDE controller register                                           |
443+---------------------------------------------------------------------------+
444| Input Parameters:                                                         |
445\*-------------------------------------------------------------------------*/
446 int                        minor,  /* controller minor number       */
447 int                        reg,    /* register index to access      */
448 uint16_t                  *value   /* ptr to return value location  */
449 )
450/*-------------------------------------------------------------------------*\
451| Return Value:                                                             |
452|    <none>                                                                 |
453\*=========================================================================*/
454{
455  uint32_t    port = IDE_Controller_Table[minor].port1;
456  uint8_t   bval1,bval2;
457
458  if (reg == IDE_REGISTER_DATA_WORD) {
459    inport_byte(port+reg, bval1);
460    inport_byte(port+reg+1, bval2);
461    *value = bval1 + (bval2 << 8);
462  }
463  else {
464    inport_byte(port+reg, bval1);
465    *value = bval1;
466  }
467#if PC386_IDE_DEBUG_OUT
468  pc386_ide_printk("pc386_ide_read_reg (0x%x)=0x%x\r\n",reg,*value & 0xff);
469#endif
470}
471
472/*=========================================================================*\
473| Function:                                                                 |
474\*-------------------------------------------------------------------------*/
475static void pc386_ide_write_reg
476(
477/*-------------------------------------------------------------------------*\
478| Purpose:                                                                  |
479|  write a IDE controller register                                          |
480+---------------------------------------------------------------------------+
481| Input Parameters:                                                         |
482\*-------------------------------------------------------------------------*/
483 int                        minor,  /* controller minor number       */
484 int                        reg,    /* register index to access      */
485 uint16_t                   value   /* value to write                */
486 )
487/*-------------------------------------------------------------------------*\
488| Return Value:                                                             |
489|    <none>                                                                 |
490\*=========================================================================*/
491{
492  uint32_t    port = IDE_Controller_Table[minor].port1;
493
494#if PC386_IDE_DEBUG_OUT
495  pc386_ide_printk("pc386_ide_write_reg(0x%x,0x%x)\r\n",reg,value & 0xff);
496#endif
497  if (reg == IDE_REGISTER_DATA_WORD) {
498    outport_word(port+reg,value);
499  }
500  else {
501    outport_byte(port+reg,value);
502  }
503}
504
505/*=========================================================================*\
506| Function:                                                                 |
507\*-------------------------------------------------------------------------*/
508static void pc386_ide_read_block
509(
510/*-------------------------------------------------------------------------*\
511| Purpose:                                                                  |
512|  read a IDE controller data block                                         |
513+---------------------------------------------------------------------------+
514| Input Parameters:                                                         |
515\*-------------------------------------------------------------------------*/
516 int                     minor,
517 uint32_t                block_size,
518 rtems_blkdev_sg_buffer *bufs,
519 uint32_t               *cbuf,
520 uint32_t               *pos
521 )
522/*-------------------------------------------------------------------------*\
523| Return Value:                                                             |
524|    <none>                                                                 |
525\*=========================================================================*/
526{
527  uint32_t port = IDE_Controller_Table[minor].port1;
528  uint32_t cnt = 0;
529#if PC386_IDE_DEBUG_OUT
530  int i32 = 0;
531  pc386_ide_printk("pc386_ide_read_block(bs=%u,bn=%u,bl=%u,cb=%d,p=%d)\n",
532                   block_size, bufs[(*cbuf)].block, llength, *cbuf, *pos);
533#endif
534
535  while (cnt < block_size)
536  {
537    uint16_t *lbuf;
538    uint8_t  status_val;
539    int      b;
540
541    if (!pc386_ide_status_data_ready (port, pc386_ide_timeout,
542                                      &status_val, pc386_ide_tasking_sleep))
543    {
544      printk ("pc386_ide_read_block: block=%u cbuf=%u status=%02x, cnt=%d bs=%d\n",
545              bufs[*cbuf].block, *cbuf, status_val, cnt, block_size);
546      /* FIXME: add an error here. */
547      return;
548    }
549
550    if (status_val & IDE_REGISTER_STATUS_ERR)
551    {
552      inport_byte(port+IDE_REGISTER_ERROR, status_val);
553      printk("pc386_ide_read_block: error: %02x\n", status_val);
554      return;
555    }
556
557    lbuf = (uint16_t*)((uint8_t*)(bufs[(*cbuf)].buffer) + (*pos));
558
559    for (b = 0; b < (ATA_SECTOR_SIZE / 2); b++)
560    {
561      inport_word(port+IDE_REGISTER_DATA,*lbuf);
562
563#if PC386_IDE_DEBUG_OUT
564      pc386_ide_printk("%04x ",*lbuf);
565      i32++;
566      if (i32 >= 16)
567      {
568        pc386_ide_printk("\n");
569        i32 = 0;
570      }
571#endif
572      lbuf++;
573    }
574    cnt    += ATA_SECTOR_SIZE;
575    (*pos) += ATA_SECTOR_SIZE;
576    if ((*pos) == bufs[(*cbuf)].length) {
577      (*pos) = 0;
578      (*cbuf)++;
579      lbuf = bufs[(*cbuf)].buffer;
580    }
581  }
582}
583
584/*=========================================================================*\
585| Function:                                                                 |
586\*-------------------------------------------------------------------------*/
587static void pc386_ide_write_block
588(
589/*-------------------------------------------------------------------------*\
590| Purpose:                                                                  |
591|  write a IDE controller data block                                        |
592+---------------------------------------------------------------------------+
593| Input Parameters:                                                         |
594\*-------------------------------------------------------------------------*/
595 int minor,
596 uint32_t                block_size,
597 rtems_blkdev_sg_buffer *bufs,
598 uint32_t               *cbuf,
599 uint32_t               *pos
600 )
601/*-------------------------------------------------------------------------*\
602| Return Value:                                                             |
603|    <none>                                                                 |
604\*=========================================================================*/
605{
606  uint32_t port = IDE_Controller_Table[minor].port1;
607  uint32_t cnt = 0;
608#if PC386_IDE_DEBUG_OUT
609  int i32 = 0;
610  pc386_ide_printk("pc386_ide_write_block(bs=%u,bn=%u,bl=%u,cb=%d,p=%d)\n",
611                   block_size, bufs[(*cbuf)].block, llength, *cbuf, *pos);
612#endif
613
614  while (cnt < block_size)
615  {
616    uint16_t *lbuf;
617    uint8_t  status_val;
618    int      b;
619
620    if (!pc386_ide_status_data_ready (port, pc386_ide_timeout,
621                                      &status_val, pc386_ide_tasking_sleep))
622    {
623      printk ("pc386_ide_write_block: block=%u status=%02x, cnt=%d bs=%d\n",
624              bufs[*cbuf].block, status_val, cnt, block_size);
625      /* FIXME: add an error here. */
626      return;
627    }
628
629    if (status_val & IDE_REGISTER_STATUS_ERR)
630    {
631      inport_byte(port+IDE_REGISTER_ERROR, status_val);
632      printk ("pc386_ide_write_block: error: %02x\n", status_val);
633      return;
634    }
635
636    lbuf = (uint16_t*)(((uint8_t*)bufs[*cbuf].buffer) + (*pos));
637
638    for (b = 0; b < (ATA_SECTOR_SIZE / 2); b++)
639    {
640#if PC386_IDE_DEBUG_OUT
641      pc386_ide_printk("%04x ",*lbuf);
642      i32++;
643      if (i32 >= 16)
644      {
645        pc386_ide_printk("\n");
646        i32 = 0;
647      }
648#endif
649      outport_word(port+IDE_REGISTER_DATA,*lbuf);
650      lbuf++;
651    }
652    cnt    += ATA_SECTOR_SIZE;
653    (*pos) += ATA_SECTOR_SIZE;
654    if ((*pos) == bufs[(*cbuf)].length) {
655      (*pos) = 0;
656      (*cbuf)++;
657      lbuf = bufs[(*cbuf)].buffer;
658    }
659  }
660}
661
662/*=========================================================================*\
663| Function:                                                                 |
664\*-------------------------------------------------------------------------*/
665static int pc386_ide_control
666(
667/*-------------------------------------------------------------------------*\
668| Purpose:                                                                  |
669|  control interface for controller                                         |
670+---------------------------------------------------------------------------+
671| Input Parameters:                                                         |
672\*-------------------------------------------------------------------------*/
673 int  minor,                        /* controller minor number       */
674 uint32_t   cmd,                    /* command to send               */
675 void * arg                         /* optional argument             */
676 )
677/*-------------------------------------------------------------------------*\
678| Return Value:                                                             |
679|    <none>                                                                 |
680\*=========================================================================*/
681{
682  return 0;
683}
684
685/*=========================================================================*\
686| Function:                                                                 |
687\*-------------------------------------------------------------------------*/
688static rtems_status_code pc386_ide_config_io_speed
689(
690/*-------------------------------------------------------------------------*\
691| Purpose:                                                                  |
692|  set up transfer speed, if possible                                       |
693+---------------------------------------------------------------------------+
694| Input Parameters:                                                         |
695\*-------------------------------------------------------------------------*/
696 int        minor,                   /* controller minor number       */
697 uint16_t   modes_avail              /* optional argument             */
698 )
699/*-------------------------------------------------------------------------*\
700| Return Value:                                                             |
701|    rtems_status_code                                                      |
702\*=========================================================================*/
703{
704  return RTEMS_SUCCESSFUL;
705}
706
707/*
708 * The following table configures the functions used for IDE drivers
709 * in this BSP.
710 */
711
712ide_ctrl_fns_t pc386_ide_ctrl_fns = {
713  pc386_ide_probe,
714  pc386_ide_initialize,
715  pc386_ide_control,
716  pc386_ide_read_reg,
717  pc386_ide_write_reg,
718  pc386_ide_read_block,
719  pc386_ide_write_block,
720  pc386_ide_config_io_speed
721};
Note: See TracBrowser for help on using the repository browser.