"seekable" device

Fernando RUIZ CASAS correo at fernando-ruiz.com
Wed Mar 27 14:11:27 UTC 2002


> -----Mensaje original-----
> De: Pattara Kiatisevi [mailto:pkiatisevi at student.ei.uni-stuttgart.de]
> Enviado el: miercoles, 27 de marzo de 2002 12:46
> Para: 'RTEMS Users'
> CC: oggonachip at yahoogroups.com
> Asunto: Re: "seekable" device
>
>
> Thank you for all answers but it is not yet clear. I mean, in my driver
> code I have an internal "fpos" variable to keep current position. And what
> I should do if there is a read (or write) call with offset:
>
> a) fpos = rw_args->offset
> b) fpos += rw_args->offset
>
> ?
>
> I see from man page of fseek, there is the "int whence" argument, I wonder
> how this argument will traverse to my driver.
>
> If this is mentioned in any document please let me know. Thank you very
> much..
>
> Pattara
>
In order to explain it more precise my own device:

In the rtems_device_read/write glue procedures you can see the offset
behaviour.

This offset is set when you fseek() the opened file or
after read/write 'C' procedures adding the bytes_moved args.

This is for a serial eeprom with I2C bus.

/*
 * ***************************************************************
 *
 *  Author: Fernando RUIZ CASAS (fernando.ruiz at ctv.es)
 *
 *  This module drives the XICOR X24C16,X24C08 Family of Serial E2PROM
 *
 *  Only two pins are necesasary to talk with the memory
 *
 *  SCL and SDA (serial clock and serial data)
 *  SCL is out pin, SDA is in/out pin
 *
 *  Only RANDOM BYTE READ and RANDOM BYTE WRITE are implemented
 *
 *  The X24C16 runs like two X24C08 into same bus with pin A2 select
 * ***************************************************************
 */
#include <rtems.h>
#include <rtems/libio.h>
#include <drivers.h>
#include <stdio.h>
#include <unistd.h>
#include <bsp_io.h>

#define SDA  PADR_PA7
#define SCL  PADR_PA8

#define SDA_IN()    SET_PA7_IN()
#define SDA_OUT()   SET_PA7_OUT()

#define DEVICE_ID    0xA0

/*------------------------------------------------------------*/
inline static void W(void) { asm("nop");}

static int e2p_size;

rtems_status_code e2p_end_host_write(unsigned short int adr) {
    int n,
        times,
        not_ack;
    unsigned int slave_adr;
    unsigned int mask;
    if (adr>=e2p_size) return RTEMS_INVALID_ADDRESS;
    slave_adr=DEVICE_ID|((adr/0x100)<<1); /* write slave adr */
    times=100;
    while (times--) {
      wdc_enable(FALSE);
      SDA=1;SDA_OUT();
      SDA=0;W();
      /* start: SDA H->L, SCL=H */
      SCL=1;W(); /* start condition */
      SDA=1;W();SDA=0;W(); /* transition */
      mask=0x80;
      SCL=0;W();/* Slave Adr */
      for(n=0;n<8;n++) {
	SDA=(mask&slave_adr)?1:0;
	SCL=1;W();SCL=0;W();
	mask>>=1;
      };
      SDA_IN();
      SCL=1;W();
      not_ack=SDA; /* ACK => SDA=0 */
      SDA=1;W();SDA_OUT();
      SCL=0;W();
      /* stop: SDA L->H, SCL=H */
      SDA=0;W();
      SCL=1;W(); /* stop condition */
      SDA=0;W();SDA=1;W(); /* transition */
      SCL=0;W();
      wdc_enable(TRUE);
      if (!not_ack) return RTEMS_SUCCESSFUL;
    };
    return RTEMS_TIMEOUT;
}

/*------------------------------------------------------------*/

rtems_status_code  e2p_byte_write(unsigned short int adr,
                                  unsigned char value) {
    int n,
        rst;
    unsigned int slave_adr;
    unsigned int mask;
    rst=0;
    if (adr>=e2p_size) return RTEMS_INVALID_ADDRESS;
    slave_adr=DEVICE_ID|((adr/0x100)<<1); /* write slave adr */
    slave_adr<<=8;
    slave_adr|=(adr&0x00FF);
    wdc_enable(FALSE);
    SDA=1;W();SDA_OUT();
    SDA=0;W();
    /* start: SDA H->L, SCL=H */
    SCL=1;W(); /* start condition */;
    SDA=1;W();SDA=0;W(); /* transition */
    mask=0x8000;
    SCL=0;W();/* Slave Adr */
    for(n=0;n<8;n++) {
     SDA=(mask&slave_adr)?1:0;
     SCL=1;W();SCL=0;W();
     mask>>=1;
    };
    SDA_IN();
    SCL=1;W();
    if (SDA) goto stop; /* !ACK => SDA=0 */
    SCL=0;W();
    SDA_OUT();
    mask=0x0080;
    SCL=0;W();/*  Word Adr */
    for(n=0;n<8;n++) {
     SDA=(mask&slave_adr)?1:0;
     SCL=1;W();SCL=0;W();
     mask>>=1;
    };
    SDA_IN();
    SCL=1;W();
    if (SDA) goto stop; /* !ACK => SDA=0 */
    SCL=0;W();
    SDA_OUT();
    mask=0x80;
    SCL=0;W();/*  Data byte */
    for(n=0;n<8;n++) {
     SDA=(mask&value)?1:0;
     SCL=1;W();SCL=0;W();
     mask>>=1;
    };
    SDA_IN();
    SCL=1;W();
    if (SDA) goto stop; /* !ACK => SDA=0 */
    SCL=0;W();
    rst=1;
stop:
    SDA_OUT();
    SCL=0;W();
    /* stop: SDA L->H, SCL=H */
    SDA=0;W();
    SCL=1;W(); /* stop condition */
    SDA=0;W();SDA=1;W(); /* transition */
    SCL=0;W();
    wdc_enable(TRUE);
    if (rst) return e2p_end_host_write(adr);
    return RTEMS_IO_ERROR;
}

/*------------------------------------------------------------*
 *
 * Previous to issue the slave address with R/W bit set to one,
 * the master must first perform a dummy write operation.
 *
 *------------------------------------------------------------*/

rtems_status_code  e2p_byte_read(unsigned short int adr,
                                 unsigned char *value) {
    int n,
        rst;
    unsigned int slave_adr;
    unsigned int mask;
    rst=0;
    if (adr>=e2p_size) return RTEMS_INVALID_ADDRESS;
    slave_adr=DEVICE_ID|((adr/0x100)<<1); /* write slave adr */
    slave_adr<<=8;
    slave_adr|=(adr&0x00FF);
    wdc_enable(FALSE);
    SDA=1;W();SDA_OUT();
    SDA=0;W();
    /* start: SDA H->L, SCL=H */
    SCL=1;W(); /* start condition */
    SDA=1;W();SDA=0;W(); /* transition */
    mask=0x8000;
    SCL=0;W();/* Slave Adr */
    for(n=0;n<8;n++) {
     SDA=(mask&slave_adr)?1:0;
     SCL=1;W();SCL=0;W();
     mask>>=1;
    };
    SDA_IN();
    SCL=1;W();
    if (SDA) goto stop; /* !ACK => SDA=0 */
    SCL=0;W();
    SDA_OUT();
    mask=0x0080;
    SCL=0;W();/*  Word Adr */
    for(n=0;n<8;n++) {
     SDA=(mask&slave_adr)?1:0;
     SCL=1;W();SCL=0;W();
     mask>>=1;
    };
    SDA_IN();
    SCL=1;W();
    if (SDA) goto stop; /* !ACK => SDA=0 */
    SCL=0;W();
    SDA_OUT();
    /* start: SDA H->L, SCL=H */
    SCL=1;W(); /* start condition */
    SDA=1;W();SDA=0;W(); /* transition */
    slave_adr|=0x0100; /* read data R/W bit set to one */
    mask=0x8000;
    SCL=0;W();/* Slave Adr */
    for(n=0;n<8;n++) {
     SDA=(mask&slave_adr)?1:0;
     SCL=1;W();SCL=0;W();
     mask>>=1;
    };
    SDA_IN();
    SCL=1;W();
    if (SDA) goto stop; /* !ACK => SDA=0 */
    SCL=0;W();
    mask=0x0080;
    SCL=0;W();
    *value=0;
    for(n=0;n<8;n++) {
     SCL=1;W();
     if (SDA) *value|=mask;
     SCL=0;W();
     mask>>=1;
    };
    SDA=1;W();
    SDA_OUT();
    SCL=1;W();SCL=0;W();
    rst=1;
stop:
    SDA_OUT();
    SCL=0;W();
    /* stop: SDA L->H, SCL=H */
    SDA=0;W();
    SCL=1;W(); /* stop condition */
    SDA=0;W();SDA=1;W(); /* transition */
    SCL=0;W();
    wdc_enable(TRUE);
    if (rst) return RTEMS_SUCCESSFUL;
    return RTEMS_IO_ERROR;
}

/*------------------------------------------------------------*/
int e2p_init(void) {
     unsigned char c;
     e2p_size=2048;
     if (e2p_byte_read(e2p_size-1,&c)==RTEMS_SUCCESSFUL) return TRUE;
     e2p_size=1024;
     if (e2p_byte_read(e2p_size-1,&c)==RTEMS_SUCCESSFUL) return TRUE;
     return FALSE;
}
/*------------------------------------------------------------*/
/*  e2pdrv
 *
 *  This module is the e2p device driver routines.
 *
 *  Derived from rtems' stub driver.
 *
 *  Author: Fernando RUIZ CASAS (fernando.ruiz at ctv.es)
 *
 *  Input parameters:
 *    major - device major number
 *    minor - device minor number
 *    pargb - pointer to parameter block
 *
 *  Output parameters:
 *    rval       - E2P_SUCCESSFUL
 *
 */


/*-------------------------------------------*/
static rtems_id e2p_sem;
/*-------------------------------------------*/
rtems_device_driver e2p_close(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void *pargp
)
{
  return E2P_SUCCESSFUL;
}

/*-------------------------------------------*/
rtems_device_driver e2p_control(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void *pargp
)
{
  return E2P_SUCCESSFUL;
}

/*-------------------------------------------*/
rtems_device_driver e2p_initialize(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void *pargp
)
{
  char * name_dev;
  rtems_device_driver status ;

  if (e2p_init()) {
   name_dev=(e2p_size==2048)?"/dev/x24c16":"/dev/x24c08";

   status = rtems_io_register_name(name_dev,
		                   major,
    				  (rtems_device_minor_number) 0
    				   );
   if (status != E2P_SUCCESSFUL) rtems_fatal_error_occurred(status);
   status=rtems_semaphore_create(rtems_build_name('E','2','P',' '),
 		  		 1,
				 RTEMS_BINARY_SEMAPHORE|
				 RTEMS_INHERIT_PRIORITY|
				 RTEMS_PRIORITY,
				 RTEMS_NO_PRIORITY,
				 &e2p_sem);

   if (status != E2P_SUCCESSFUL) rtems_fatal_error_occurred(status);
   if (link(name_dev,"/dev/e2p")<0)
	    rtems_fatal_error_occurred(RTEMS_IO_ERROR);
  };

  return E2P_SUCCESSFUL;
}

/*-------------------------------------------*/
rtems_device_driver e2p_open(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void *pargp
)
{
  return E2P_SUCCESSFUL;
}

/*-------------------------------------------*/
rtems_device_driver e2p_read(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void *pargp
)
{
  int n,adr;
  rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) pargp ;
  rtems_status_code sc;

  sc=rtems_semaphore_obtain(e2p_sem,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
  if (sc!=RTEMS_SUCCESSFUL) return sc;

  rw_args->bytes_moved=0;
  adr=rw_args->offset;  /* HELLO!! I'm here, THE OFFSET */

  for (n=0;n<rw_args->count;n++) {
   if (adr>=e2p_size) break;
   sc=e2p_byte_read(adr,&rw_args->buffer[n]);
   if (sc!=RTEMS_SUCCESSFUL) break;
   rw_args->bytes_moved++;
   adr++;
  };

  rtems_semaphore_release(e2p_sem);

  return E2P_SUCCESSFUL;
}

/*-------------------------------------------*/
rtems_device_driver e2p_write(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void *pargp
)
{
  int n,adr;
  rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) pargp ;
  rtems_status_code sc;

  sc=rtems_semaphore_obtain(e2p_sem,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
  if (sc!=RTEMS_SUCCESSFUL) return sc;


  rw_args->bytes_moved=0;
  adr=rw_args->offset;  /* HELLO!! I'm here, THE OFFSET */

  for (n=0;n<rw_args->count;n++) {
   if (adr>=e2p_size) break;
   sc=e2p_byte_write(adr,rw_args->buffer[n]);
   if (sc!=RTEMS_SUCCESSFUL) break;
   rw_args->bytes_moved++;
   adr++;
  };

  rtems_semaphore_release(e2p_sem);

  return E2P_SUCCESSFUL;
}
/*-------------------------------------------*/

> -----Mensaje original-----
> De: Pattara Kiatisevi [mailto:pkiatisevi at student.ei.uni-stuttgart.de]
> Enviado el: miercoles, 27 de marzo de 2002 12:46
> Para: 'RTEMS Users'
> CC: oggonachip at yahoogroups.com
> Asunto: Re: "seekable" device
>
>
> Thank you for all answers but it is not yet clear. I mean, in my driver
> code I have an internal "fpos" variable to keep current position. And what
> I should do if there is a read (or write) call with offset:
>
> a) fpos = rw_args->offset
> b) fpos += rw_args->offset
>
> ?
>
> I see from man page of fseek, there is the "int whence" argument, I wonder
> how this argument will traverse to my driver.
>
> If this is mentioned in any document please let me know. Thank you very
> much..
>
> Pattara
>
> On Thu, 21 Mar 2002, Aaron J. Grier wrote:
>
> > On Thu, Mar 21, 2002 at 05:17:48PM +0100, Pattara Kiatisevi wrote:
> >
> > > I have a hopefully simple question about this "fseek" function. What
> > > will happen if an application calls "fseek" to a device? I mean, how
> > > can I adjust my device driver (I wrote a /dev/soundinput to simulate a
> > > song file) to support this seek function? Now I have only
> > > soundinput_initialize(), open(), close(), read(), write() and ioctl().
> >
> > in the io struct (rtems_libio_rw_args_t *) passed to read and write,
> > there's a member "offset" which is manipulated by fseek.  it looks
> > something like this:
> >
> > rw_args = (rtems_libio_rw_args_t *) arg;
> > buffer = rw_args->buffer;
> > count = rw_args->count;
> > offset = rw_args->offset;
> >
> > --
> >   Aaron J. Grier  |   Frye Electronics, Tigard, OR   |  aaron at frye.com
> >      "In a few thousand years people will be scratching their heads
> >        wondering how on earth the first computer was invented and
> >           bootstrapped without a prior computer to do it with."
> >                     --  Chris Malcolm, on comp.arch
> >
> >
>
>




More information about the users mailing list