Skip to content

Commit

Permalink
driver/mem:add Mem Driver.
Browse files Browse the repository at this point in the history
Signed-off-by: yangguangcai <[email protected]>
  • Loading branch information
yangguangcai1 committed Aug 26, 2024
1 parent ee6fdb2 commit b054771
Show file tree
Hide file tree
Showing 6 changed files with 315 additions and 0 deletions.
26 changes: 26 additions & 0 deletions Documentation/components/drivers/special/devmem.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
==============
DEVMEM Drivers
==============

The `devmem` driver provides an interface for accessing memory-mapped
I/O in an embedded system. This driver allows for reading, writing, and
memory mapping of specific memory regions or device registers.

``read()``: This function reads data from the memory-mapped I/O address
space into the buffer provided by the caller. The first byte read
corresponds to the address specified by the device's "current memory
address". The addresses for subsequent bytes depend on the auto-increment
behavior of the specific device.

``write()``: This function transfers data from the provided data buffer by
the caller to the memory-mapped I/O address space. The first byte written
corresponds to the address specified by the device's "current memory address".

``mmap()``: The `mmap()` function provides a mechanism to map a device's
memory region into the user space, allowing direct access to device
registers or memory regions. The mapped region can be accessed using
normal memory operations.

The function requires a base address and size for the memory region
to be mapped. If successful, it returns a pointer to the mapped region.
If mapping fails, it returns `EINVAL` and `errno` is set appropriately.
4 changes: 4 additions & 0 deletions drivers/drivers_initialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ void drivers_initialize(void)
devzero_register(); /* Standard /dev/zero */
#endif

#ifdef CONFIG_DEV_MEM
devmem_register();
#endif

#if defined(CONFIG_DEV_LOOP)
loop_register(); /* Standard /dev/loop */
#endif
Expand Down
7 changes: 7 additions & 0 deletions drivers/misc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ config DEV_ZERO
bool "Enable /dev/zero"
default n

config DEV_MEM
bool "Enable /dev/mem"
default n
---help---
It is a full image of physical memory and can be used to
access physical memory.

config DEV_ASCII
bool "Enable /dev/ascii"
default n
Expand Down
4 changes: 4 additions & 0 deletions drivers/misc/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ ifeq ($(CONFIG_DEV_ZERO),y)
CSRCS += dev_zero.c
endif

ifeq ($(CONFIG_DEV_MEM),y)
CSRCS += dev_mem.c
endif

ifeq ($(CONFIG_DEV_ASCII),y)
CSRCS += dev_ascii.c
endif
Expand Down
262 changes: 262 additions & 0 deletions drivers/misc/dev_mem.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
/****************************************************************************
* drivers/misc/dev_mem.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/

/****************************************************************************
* Included Files
****************************************************************************/

#include <nuttx/drivers/drivers.h>
#include <nuttx/kmalloc.h>
#include <nuttx/memoryregion.h>
#include <sys/param.h>
#include <sys/mman.h>

/****************************************************************************
* Pre-processor Definitions
****************************************************************************/

#define DEVMEM_REGION 8

/****************************************************************************
* Public Data
****************************************************************************/

extern uint8_t _stext[]; /* Start of .text */
extern uint8_t _etext[]; /* End_1 of .text + .rodata */
extern uint8_t _sdata[]; /* Start of .data */
extern uint8_t _edata[]; /* End+1 of .data */
extern uint8_t _sbss[]; /* Start of .bss */
extern uint8_t _ebss[]; /* End+1 of .bss */

/****************************************************************************
* Private Function Prototypes
****************************************************************************/

/* Character driver methods */

static ssize_t devmem_read(FAR struct file *filep, FAR char *buffer,
size_t buflen);
static ssize_t devmem_write(FAR struct file *filep, FAR const char *buffer,
size_t buflen);
static int devmem_mmap(FAR struct file *filep,
FAR struct mm_map_entry_s *map);

/****************************************************************************
* Private Data
****************************************************************************/

static const struct file_operations g_devmem_fops =
{
NULL, /* open */
NULL, /* close */
devmem_read, /* read */
devmem_write, /* write */
NULL, /* seek */
NULL, /* ioctl */
devmem_mmap, /* mmap */
};

/****************************************************************************
* Private Functions
****************************************************************************/

/****************************************************************************
* Name: devmem_read
****************************************************************************/

static ssize_t devmem_read(FAR struct file *filep, FAR char *buffer,
size_t buflen)
{
FAR struct memory_region_s *region = filep->f_inode->i_private;
uintptr_t src = filep->f_pos;
uintptr_t start;
uintptr_t end;
ssize_t len;
int i;

DEBUGASSERT(region && src);

for (i = 0; i < DEVMEM_REGION; i++)
{
if (region[i].start == 0 && region[i].end == 0)
{
break;
}

start = MAX(src, region[i].start);
end = MIN(src + buflen, region[i].end);
len = end - start;
if (len > 0 && (region[i].flags & PROT_READ))
{
memcpy(buffer, (FAR const void *)start, len);
return len;
}
}

return -EINVAL;
}

/****************************************************************************
* Name: devmem_write
****************************************************************************/

static ssize_t devmem_write(FAR struct file *filep, FAR const char *buffer,
size_t buflen)
{
FAR struct memory_region_s *region = filep->f_inode->i_private;
uintptr_t dest = filep->f_pos;
uintptr_t start;
uintptr_t end;
ssize_t len;
int i;

DEBUGASSERT(region && dest);

for (i = 0; i < DEVMEM_REGION; i++)
{
if (region[i].start == 0 && region[i].end == 0)
{
break;
}

start = MAX(dest, region[i].start);
end = MIN(dest + buflen, region[i].end);
len = end - start;
if (len > 0 && (region[i].flags & PROT_WRITE))
{
memcpy((FAR void *)start, buffer, len);
return len;
}
}

return -EINVAL;
}

/****************************************************************************
* Name: devmem_mmap
****************************************************************************/

static int devmem_mmap(FAR struct file *filep,
FAR struct mm_map_entry_s *map)
{
FAR struct memory_region_s *region = filep->f_inode->i_private;
uintptr_t start;
uintptr_t end;
int i;

DEBUGASSERT(region);

if (map->offset < 0)
{
return -EINVAL;
}

start = map->offset;
end = start + map->length;

for (i = 0; i < DEVMEM_REGION; i++)
{
if (region[i].start == 0 && region[i].end == 0)
{
break;
}

if (start >= region[i].start && end <= region[i].end)
{
map->vaddr = (FAR void *)start;
return 0;
}
}

return -EINVAL;
}

/****************************************************************************
* Public Functions
****************************************************************************/

/****************************************************************************
* Name: devmem_register
*
* Description:
* Create an MEM driver.
*
* Returned Value:
* Zero (OK) on success; A negated errno value on failure.
*
****************************************************************************/

int devmem_register(void)
{
FAR struct memory_region_s *region;
bool merge = (_edata == _sbss);
ssize_t len = 0;
int ret;

region = kmm_calloc(DEVMEM_REGION, sizeof(*region));
if (region == NULL)
{
return -ENOMEM;
}

#ifdef CONFIG_BOARD_MEMORY_RANGE
len = parse_memory_region(CONFIG_BOARD_MEMORY_RANGE, region,
DEVMEM_REGION - 1);
if (len < 0)
{
kmm_free(region);
return len;
}
#endif

if (len + (4 - merge) > DEVMEM_REGION)
{
len = DEVMEM_REGION - (4 - merge);
}

region[len].flags = PROT_EXEC | PROT_READ;
region[len].start = (uintptr_t)_stext;
region[len++].end = (uintptr_t)_etext;
region[len].flags = PROT_WRITE | PROT_READ;
region[len].start = (uintptr_t)_sdata;
region[len++].end = (uintptr_t)_edata;

if (merge)
{
region[len - 1].end = (uintptr_t)_ebss;
}
else
{
region[len].flags = PROT_WRITE | PROT_READ;
region[len].start = (uintptr_t)_sbss;
region[len++].end = (uintptr_t)_ebss;
}

/* register the new MEM driver */

ret = register_driver("/dev/mem", &g_devmem_fops, 0666, region);
if (ret < 0)
{
kmm_free(region);
return -ENOMEM;
}

return ret;
}
12 changes: 12 additions & 0 deletions include/nuttx/drivers/drivers.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,18 @@ void devurandom_register(void);

void devcrypto_register(void);

/****************************************************************************
* Name: devmem_register
*
* Description:
* Register devmem driver
*
****************************************************************************/

#ifdef CONFIG_DEV_MEM
int devmem_register(void);
#endif

/****************************************************************************
* Name: devzero_register
*
Expand Down

0 comments on commit b054771

Please sign in to comment.