"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