OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [io/] [flash/] [current/] [src/] [flashiodev.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      flashiodev.c
4
//
5
//      Flash device interface to I/O subsystem
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2007, 2009 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    jlarmour
43
// Contributors: woehler, Andrew Lunn
44
// Date:         2004-12-03
45
// Purpose:      
46
// Description:  
47
//              
48
//####DESCRIPTIONEND####
49
//
50
//==========================================================================
51
 
52
// INCLUDES
53
 
54
#include <pkgconf/io_flash.h>
55
#include <errno.h>
56
#include <cyg/infra/cyg_type.h>
57
#include <cyg/infra/cyg_ass.h>
58
#include <cyg/io/devtab.h>
59
#include <cyg/io/config_keys.h>
60
#include <cyg/io/flash.h>
61
#include <string.h> // memcpy
62
#include <cyg/hal/hal_if.h>
63
#include <cyg/hal/drv_api.h> // mutexes
64
 
65
// MACROS
66
 
67
#define MIN(x,y) ((x)<(y) ? (x) : (y))
68
#define MAX(x,y) ((x)>(y) ? (x) : (y))
69
 
70
// TYPES
71
 
72
struct flashiodev_priv_t{
73
  cyg_devtab_entry_t handle;
74
  cyg_flashaddr_t start;
75
  cyg_flashaddr_t end;
76
  cyg_bool        valid;
77
};
78
// FUNCTION PROTOTYPES
79
 
80
static bool flashiodev_init( struct cyg_devtab_entry *tab );
81
static Cyg_ErrNo
82
flashiodev_lookup(struct cyg_devtab_entry **tab,
83
                  struct cyg_devtab_entry  *sub_tab,
84
                  const char *name) ;
85
static Cyg_ErrNo
86
flashiodev_bread( cyg_io_handle_t handle, void *buf, cyg_uint32 *len,
87
                  cyg_uint32 pos);
88
static Cyg_ErrNo
89
flashiodev_bwrite( cyg_io_handle_t handle, const void *buf, cyg_uint32 *len,
90
                   cyg_uint32 pos );
91
static Cyg_ErrNo
92
flashiodev_get_config( cyg_io_handle_t handle,
93
                       cyg_uint32 key,
94
                       void* buf,
95
                       cyg_uint32* len);
96
static Cyg_ErrNo
97
flashiodev_set_config( cyg_io_handle_t handle,
98
                       cyg_uint32 key,
99
                       const void* buf,
100
                       cyg_uint32* len);
101
 
102
// STATICS/GLOBALS
103
 
104
static struct flashiodev_priv_t flashiodev_table[CYGNUM_IO_FLASH_BLOCK_DEVICES];
105
static cyg_drv_mutex_t flashiodev_table_lock;
106
 
107
BLOCK_DEVIO_TABLE( cyg_io_flashdev_ops,
108
                   &flashiodev_bwrite,
109
                   &flashiodev_bread,
110
                   NULL, // no select
111
                   &flashiodev_get_config,
112
                   &flashiodev_set_config
113
                   );
114
 
115
 
116
BLOCK_DEVTAB_ENTRY( cyg_io_flashdev,
117
                    "/dev/flash/",
118
                    NULL,
119
                    &cyg_io_flashdev_ops,
120
                    &flashiodev_init,
121
                    &flashiodev_lookup,
122
                    NULL );
123
 
124
// FUNCTIONS
125
 
126
static bool
127
flashiodev_init( struct cyg_devtab_entry *tab )
128
{
129
  int stat = cyg_flash_init(NULL);
130
  cyg_ucount32 i;
131
 
132
  if (stat == CYG_FLASH_ERR_OK)
133
  {
134
      for (i=0; i<CYGNUM_IO_FLASH_BLOCK_DEVICES; i++)
135
      {
136
          CYG_ASSERT( tab->handlers == &cyg_io_flashdev_ops, "Unexpected handlers - not flashdev_ops" );
137
          flashiodev_table[i].handle.handlers = &cyg_io_flashdev_ops;
138
          flashiodev_table[i].handle.status = CYG_DEVTAB_STATUS_BLOCK;
139
          flashiodev_table[i].handle.priv = &flashiodev_table[i]; // link back
140
      } // for
141
      cyg_drv_mutex_init( &flashiodev_table_lock );
142
  } // if
143
 
144
  return (stat == CYG_FLASH_ERR_OK);
145
} // flashiodev_init()
146
 
147
#ifdef CYGFUN_IO_FLASH_BLOCK_FROM_DEVOFFSET
148
static cyg_uint32
149
parsenum( const char **str )
150
{
151
    cyg_uint32 num = 0;
152
    cyg_uint8 base = 10;
153
 
154
    // trim leading 0s
155
    while (**str == '0')
156
        (*str)++;
157
    // crudely detect hex by assuming that something with a leading 0x
158
    // can just match the 'x' with a leading 0 being trimmed.
159
    if ( (**str == 'x') || (**str == 'X') )
160
    {
161
        (*str)++;
162
        base = 16;
163
    }
164
 
165
    while (**str) {
166
        switch (**str)
167
        {
168
        case '0':
169
        case '1':
170
        case '2':
171
        case '3':
172
        case '4':
173
        case '5':
174
        case '6':
175
        case '7':
176
        case '8':
177
        case '9':
178
            num = (num * base) + (**str-'0');
179
            break;
180
        case 'a':
181
        case 'b':
182
        case 'c':
183
        case 'd':
184
        case 'e':
185
        case 'f':
186
            if ( base != 16 )
187
                return num;
188
            num = (num * base) + (**str-'a' + 10);
189
            break;
190
        case 'A':
191
        case 'B':
192
        case 'C':
193
        case 'D':
194
        case 'E':
195
        case 'F':
196
            if ( base != 16 )
197
                return num;
198
            num = (num << 4) + (**str-'A' + 10);
199
            break;
200
        default:
201
            return num;
202
        } // switch
203
        (*str)++;
204
    } // while
205
 
206
    return num;
207
} // parsenum()
208
#endif // ifdef CYGFUN_IO_FLASH_BLOCK_FROM_DEVOFFSET
209
 
210
static Cyg_ErrNo
211
flashiodev_lookup(struct cyg_devtab_entry **tab,
212
                  struct cyg_devtab_entry  *sub_tab,
213
                  const char *name)
214
{
215
    // We enter with **tab being the entry for /dev/flash only
216
    // We will leave with **tab instead pointing to a newly configured flash device instance
217
    // We could allocate the space for recording these dynamically, but that's overkill,
218
    // so we instead choose the eCos ethos of "let the user decide at configure time".
219
    // After all there's a good chance there'll be only one or two needed at one time.
220
 
221
    // There are two styles of path:
222
    //    /dev/flash/fis/<fispartitionname>
223
    // and
224
    //    /dev/flash/<deviceno>/<offset>[,<length>]
225
 
226
    cyg_flashaddr_t start=0;
227
    cyg_flashaddr_t end=0;
228
    cyg_bool valid = false;
229
 
230
#ifdef CYGFUN_IO_FLASH_BLOCK_FROM_FIS
231
    // First, support FIS
232
    if ((name[0] == 'f') && (name[1] == 'i') &&
233
        (name[2] == 's') && (name[3] == '/'))
234
    {
235
        CYG_ADDRESS     flash_base;
236
        unsigned long   size;
237
 
238
        if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_FLASH_BASE,
239
                                        (char *)&name[4],
240
                                        &flash_base))
241
            return -ENOENT;
242
 
243
        if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_SIZE,
244
                                        (char *)&name[4],
245
                                        &size))
246
            return -ENODEV; // If the previous call worked, then this failing would be very wrong.
247
        start = flash_base;
248
        end = flash_base + size - 1;
249
        valid = true;
250
    }
251
# ifdef CYGFUN_IO_FLASH_BLOCK_FROM_DEVOFFSET
252
    else
253
# endif
254
#endif // ifdef CYGFUN_IO_FLASH_BLOCK_FROM_FIS
255
#ifdef CYGFUN_IO_FLASH_BLOCK_FROM_DEVOFFSET
256
    // Next, support device numbers with offsets encoded in path name
257
    // Note that for now we assume < 10 flash devices. I think this is reasonable
258
    // to avoid unnecessary code. It can be changed later if needed.
259
    if ( (name[0] >= '0') && (name[0] <= '9') )
260
    {
261
        cyg_uint32 flashdevno = name[0] - '0';
262
        int res;
263
        cyg_flash_info_t info;
264
        cyg_uint32 offset;
265
        const char *tempstr;
266
 
267
        if (name[1] != '/')
268
            return -ENOTSUP;
269
        res = cyg_flash_get_info( flashdevno, &info );
270
        if (CYG_FLASH_ERR_OK != res)
271
            return -ENOENT;
272
 
273
        // Now modify with offset and optional length
274
        tempstr = &name[2];
275
        offset = parsenum( &tempstr );
276
 
277
        start = info.start + offset;
278
        end = info.end;
279
 
280
        if (*tempstr == ',') // optional length
281
        {
282
            cyg_uint32 length;
283
 
284
            tempstr++;
285
            length = parsenum( &tempstr );
286
 
287
            // Check we don't exceed end of device.
288
            // Note the flash end address is the last byte of addressible flash *not* the base+size
289
            if ( (start + length - 1) > end )
290
                return -EINVAL;
291
            end = start + length - 1;
292
        }
293
        valid = true;
294
    } // else if
295
#endif
296
 
297
    if (valid)
298
    {
299
        // Find a slot and use it
300
        cyg_ucount32 i;
301
 
302
        cyg_drv_mutex_lock( &flashiodev_table_lock );
303
        for (i=0; i<CYGNUM_IO_FLASH_BLOCK_DEVICES; i++)
304
        {
305
            if ( !flashiodev_table[i].valid ) {
306
                flashiodev_table[i].start = start;
307
                flashiodev_table[i].end = end;
308
                flashiodev_table[i].valid = true;
309
                cyg_drv_mutex_unlock( &flashiodev_table_lock );
310
 
311
                *tab = &flashiodev_table[i].handle;
312
                // Theoretically we could set up the devtab entry more fully, e.g.
313
                // the name, but I don't see the need!
314
                return ENOERR;
315
            } // if
316
        } // for
317
        cyg_drv_mutex_unlock( &flashiodev_table_lock );
318
 
319
        // If we got here we must have reached the end of the table without finding a space
320
        return -ENOMEM;
321
    }
322
    // Wasn't valid, so....
323
    return -ENOENT;
324
} // flashiodev_lookup()
325
 
326
static Cyg_ErrNo
327
flashiodev_bread( cyg_io_handle_t handle, void *buf, cyg_uint32 *len,
328
                  cyg_uint32 pos)
329
{
330
  struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle;
331
  struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv;
332
 
333
  cyg_flashaddr_t startpos = dev->start + pos;
334
  Cyg_ErrNo err = ENOERR;
335
  int flasherr;
336
 
337
  CYG_ASSERT( dev->handle.handlers == &cyg_io_flashdev_ops, "bad flash operation link" );
338
  CYG_ASSERT( ((struct flashiodev_priv_t*)(dev->handle.priv))->valid, "operation on not valid flash device instance" );
339
 
340
#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
341
  cyg_flashaddr_t endpos = startpos + *len - 1;
342
  if ( startpos < dev->start )
343
    return -EINVAL;
344
  if ( endpos > dev->end )
345
    return -EINVAL;
346
#endif
347
 
348
  flasherr = cyg_flash_read( startpos,(void *)buf, *len, NULL );
349
 
350
  if ( flasherr != CYG_FLASH_ERR_OK )
351
    err = -EIO; // just something sane
352
  return err;
353
} // flashiodev_bread()
354
 
355
static Cyg_ErrNo
356
flashiodev_bwrite( cyg_io_handle_t handle, const void *buf, cyg_uint32 *len,
357
                   cyg_uint32 pos )
358
{
359
  struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle;
360
  struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv;
361
 
362
  Cyg_ErrNo err = ENOERR;
363
  int flasherr;
364
  cyg_flashaddr_t startpos = dev->start + pos;
365
 
366
  CYG_ASSERT( dev->handle.handlers == &cyg_io_flashdev_ops, "bad flash operation link" );
367
  CYG_ASSERT( ((struct flashiodev_priv_t*)(dev->handle.priv))->valid, "operation on not valid flash device instance" );
368
 
369
  // Unlike some other cases we _do_ do bounds checking on this all the time, because
370
  // the consequences of writing over the wrong bit of flash are so nasty.
371
  cyg_flashaddr_t endpos = startpos + *len - 1;
372
  if ( startpos < dev->start )
373
    return -EINVAL;
374
  if ( endpos > dev->end )
375
    return -EINVAL;
376
 
377
  flasherr = cyg_flash_program( startpos, (void *)buf, *len, NULL );
378
 
379
  if ( flasherr != CYG_FLASH_ERR_OK )
380
    err = -EIO; // just something sane
381
  return err;
382
} // flashiodev_bwrite()
383
 
384
static Cyg_ErrNo
385
flashiodev_get_config( cyg_io_handle_t handle,
386
                       cyg_uint32 key,
387
                       void* buf,
388
                       cyg_uint32* len)
389
{
390
  struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle;
391
  struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv;
392
 
393
  CYG_ASSERT( dev->handle.handlers == &cyg_io_flashdev_ops, "bad flash operation link" );
394
  CYG_ASSERT( ((struct flashiodev_priv_t*)(dev->handle.priv))->valid, "operation on not valid flash device instance" );
395
 
396
  switch (key) {
397
  case CYG_IO_GET_CONFIG_FLASH_ERASE:
398
    {
399
#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
400
      if (*len != sizeof( cyg_io_flash_getconfig_erase_t ) )
401
        return -EINVAL;
402
#endif
403
      {
404
        cyg_io_flash_getconfig_erase_t *e = (cyg_io_flash_getconfig_erase_t *)buf;
405
        cyg_flashaddr_t startpos = dev->start + e->offset;
406
 
407
        // Unlike some other cases we _do_ do bounds checking on this all the time, because
408
        // the consequences of erasing the wrong bit of flash are so nasty.
409
        cyg_flashaddr_t endpos = startpos + e->len - 1;
410
        if ( startpos < dev->start )
411
          return -EINVAL;
412
        if ( endpos > dev->end )
413
          return -EINVAL;
414
 
415
        e->flasherr = cyg_flash_erase( startpos, e->len, &e->err_address );
416
      }
417
      return ENOERR;
418
    }
419
 
420
#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING    
421
  case CYG_IO_GET_CONFIG_FLASH_LOCK:
422
    {
423
#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
424
      if (*len != sizeof( cyg_io_flash_getconfig_lock_t ) )
425
        return -EINVAL;
426
#endif
427
      {
428
        cyg_io_flash_getconfig_lock_t *d = (cyg_io_flash_getconfig_lock_t *)buf;
429
        cyg_flashaddr_t startpos = dev->start + d->offset;
430
 
431
#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time        
432
        cyg_flashaddr_t endpos = startpos + d->len - 1;
433
        if ( startpos < dev->start )
434
          return -EINVAL;
435
        if ( endpos > dev->end )
436
          return -EINVAL;
437
#endif
438
 
439
        d->flasherr = cyg_flash_lock( startpos, d->len, &d->err_address );
440
      }
441
      return ENOERR;
442
    }
443
 
444
  case CYG_IO_GET_CONFIG_FLASH_UNLOCK:
445
    {
446
#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
447
      if (*len != sizeof( cyg_io_flash_getconfig_unlock_t ) )
448
        return -EINVAL;
449
#endif
450
      {
451
        cyg_io_flash_getconfig_unlock_t *d = (cyg_io_flash_getconfig_unlock_t *)buf;
452
        cyg_flashaddr_t startpos = dev->start + d->offset;
453
 
454
#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time        
455
        cyg_flashaddr_t endpos = startpos + d->len - 1;
456
        if ( startpos < dev->start )
457
          return -EINVAL;
458
        if ( endpos > dev->end )
459
          return -EINVAL;
460
#endif        
461
        d->flasherr = cyg_flash_unlock( startpos, d->len, &d->err_address );
462
      }
463
      return ENOERR;
464
    }
465
#endif
466
 
467
  case CYG_IO_GET_CONFIG_FLASH_DEVSIZE:
468
    {
469
#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
470
      if ( *len != sizeof( cyg_io_flash_getconfig_devsize_t ) )
471
        return -EINVAL;
472
#endif
473
      {
474
        cyg_io_flash_getconfig_devsize_t *d =
475
          (cyg_io_flash_getconfig_devsize_t *)buf;
476
 
477
        d->dev_size = dev->end - dev->start + 1;
478
      }
479
      return ENOERR;
480
    }
481
 
482
  case CYG_IO_GET_CONFIG_FLASH_DEVADDR:
483
    {
484
#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
485
      if ( *len != sizeof( cyg_io_flash_getconfig_devaddr_t ) )
486
        return -EINVAL;
487
#endif
488
      {
489
        cyg_io_flash_getconfig_devaddr_t *d =
490
          (cyg_io_flash_getconfig_devaddr_t *)buf;
491
 
492
        d->dev_addr = dev->start;
493
      }
494
      return ENOERR;
495
    }
496
 
497
  case CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE:
498
    {
499
      cyg_io_flash_getconfig_blocksize_t *b =
500
        (cyg_io_flash_getconfig_blocksize_t *)buf;
501
      cyg_flashaddr_t pos = dev->start + b->offset;
502
 
503
#ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time
504
      if ( pos < dev->start )
505
        return -EINVAL;
506
      if ( pos > dev->end )
507
        return -EINVAL;
508
      if ( *len != sizeof( cyg_io_flash_getconfig_blocksize_t ) )
509
        return -EINVAL;
510
#endif  
511
 
512
      b->block_size = cyg_flash_block_size( pos );
513
      return ENOERR;
514
    }
515
 
516
  default:
517
    return -EINVAL;
518
  }
519
} // flashiodev_get_config()
520
 
521
static Cyg_ErrNo
522
flashiodev_set_config( cyg_io_handle_t handle,
523
                       cyg_uint32 key,
524
                       const void* buf,
525
                       cyg_uint32* len)
526
{
527
  struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle;
528
  struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv;
529
 
530
  CYG_ASSERT( dev->handle.handlers == &cyg_io_flashdev_ops, "bad flash operation link" );
531
  CYG_ASSERT( ((struct flashiodev_priv_t*)(dev->handle.priv))->valid, "operation on not valid flash device instance" );
532
 
533
  switch (key) {
534
  case CYG_IO_SET_CONFIG_CLOSE:
535
    {
536
        Cyg_ErrNo err = ENOERR;
537
        cyg_drv_mutex_lock( &flashiodev_table_lock );
538
        if (!dev->valid)
539
        {
540
            err = -EBADF;
541
        } else {
542
            dev->valid = false;
543
        }
544
        cyg_drv_mutex_unlock( &flashiodev_table_lock );
545
        return err;
546
    }
547
  default:
548
    return -EINVAL;
549
  }
550
} // flashiodev_set_config()
551
 
552
// EOF flashiodev.c

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.