Skip to content

Commit 0398656

Browse files
authored
Merge pull request #13 from choco-technologies/copilot/update-readme-installation-methods
Document dmod_link_modules installation, configuration file mechanism, and device numbering
2 parents d599c97 + e4fe204 commit 0398656

1 file changed

Lines changed: 326 additions & 6 deletions

File tree

README.md

Lines changed: 326 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,20 +86,21 @@ See the [tests/README.md](tests/README.md) for more information about testing.
8686

8787
## Usage
8888

89-
The module can be loaded and mounted using DMVFS:
89+
The module can be loaded and mounted using DMVFS. **Important:** DMDEVFS requires a configuration path to be specified during mounting.
9090

9191
```c
9292
#include "dmvfs.h"
9393

9494
// Initialize DMVFS
9595
dmvfs_init(16, 32);
9696

97-
// Mount the driver filesystem at /mnt
98-
dmvfs_mount_fs("dmdevfs", "/mnt", NULL);
97+
// Mount the driver filesystem at /mnt with configuration path
98+
// The configuration path must point to a directory containing driver configuration files
99+
dmvfs_mount_fs("dmdevfs", "/mnt", "/etc/dmdevfs");
99100

100101
// Use standard file operations
101102
void* fp;
102-
dmvfs_fopen(&fp, "/mnt/file.txt", DMFSI_O_RDONLY, 0, 0);
103+
dmvfs_fopen(&fp, "/mnt/device0/file.txt", DMFSI_O_RDONLY, 0, 0);
103104
// ... use file ...
104105
dmvfs_fclose(fp);
105106

@@ -108,6 +109,305 @@ dmvfs_unmount_fs("/mnt");
108109
dmvfs_deinit();
109110
```
110111
112+
**Note:** The configuration parameter cannot be NULL or empty. It must contain a valid path to a directory with driver configuration files. See the [Configuration Files](#configuration-files) section below for detailed information.
113+
114+
## Configuration Files
115+
116+
DMDEVFS uses configuration files to define and initialize device drivers. This is a critical mechanism that allows the filesystem to dynamically discover and configure hardware drivers at mount time.
117+
118+
### Overview
119+
120+
When DMDEVFS is mounted with a configuration path, it:
121+
1. Scans the configuration directory for `.ini` files
122+
2. Reads each configuration file to determine which driver to load
123+
3. Initializes the driver with parameters from the configuration
124+
4. Maps the driver to a device path within the filesystem
125+
126+
### Configuration File Format
127+
128+
Configuration files use the INI format with a `[main]` section:
129+
130+
```ini
131+
[main]
132+
driver_name = your_driver_name
133+
# Additional driver-specific parameters
134+
parameter1 = value1
135+
parameter2 = value2
136+
```
137+
138+
#### Required Fields
139+
140+
- **`driver_name`**: The name of the DMOD driver module to load (must implement dmdrvi interface)
141+
142+
#### Optional Fields
143+
144+
Any additional parameters in the configuration file are passed to the driver's initialization function. The interpretation of these parameters depends on the specific driver implementation.
145+
146+
### Configuration Directory Structure
147+
148+
DMDEVFS supports both flat and hierarchical configuration layouts:
149+
150+
#### Flat Structure
151+
```
152+
/etc/dmdevfs/
153+
├── spi_flash.ini # Configuration for SPI flash driver
154+
├── i2c_eeprom.ini # Configuration for I2C EEPROM driver
155+
└── uart_storage.ini # Configuration for UART storage driver
156+
```
157+
158+
#### Hierarchical Structure
159+
```
160+
/etc/dmdevfs/
161+
├── flash/
162+
│ ├── spi0.ini # SPI flash on bus 0
163+
│ └── spi1.ini # SPI flash on bus 1
164+
└── eeprom/
165+
├── i2c0.ini # EEPROM on I2C bus 0
166+
└── i2c1.ini # EEPROM on I2C bus 1
167+
```
168+
169+
The hierarchical structure is useful for organizing drivers by type or bus.
170+
171+
### Example Configuration Files
172+
173+
#### Example 1: SPI Flash Driver
174+
175+
**File:** `/etc/dmdevfs/spi_flash.ini`
176+
177+
```ini
178+
[main]
179+
driver_name = dmspiflash
180+
spi_bus = 0
181+
chip_select = 1
182+
speed_hz = 1000000
183+
mode = 0
184+
```
185+
186+
#### Example 2: I2C EEPROM Driver
187+
188+
**File:** `/etc/dmdevfs/eeprom.ini`
189+
190+
```ini
191+
[main]
192+
driver_name = dmi2ceeprom
193+
i2c_bus = 0
194+
device_address = 0x50
195+
page_size = 64
196+
total_size = 8192
197+
```
198+
199+
#### Example 3: UART Storage Driver
200+
201+
**File:** `/etc/dmdevfs/uart_storage.ini`
202+
203+
```ini
204+
[main]
205+
driver_name = dmuartstorage
206+
uart_port = 2
207+
baud_rate = 115200
208+
data_bits = 8
209+
parity = none
210+
stop_bits = 1
211+
```
212+
213+
### How Configuration Files Are Interpreted
214+
215+
1. **File Discovery**: DMDEVFS recursively scans the configuration directory
216+
2. **INI Parsing**: Each `.ini` file is parsed using the dmini module
217+
3. **Driver Loading**: The `driver_name` parameter determines which driver module to load
218+
4. **Driver Initialization**: The entire INI context is passed to the driver's `dmdrvi_create()` function
219+
5. **Device Mapping**: The driver is registered and becomes accessible through the filesystem
220+
221+
### Driver Name Resolution
222+
223+
DMDEVFS determines which driver module to load using a priority-based resolution mechanism. The driver name can be specified in three ways, checked in the following order:
224+
225+
#### 1. From INI File Content (Highest Priority)
226+
227+
The `driver_name` field in the `[main]` section explicitly specifies which driver to load:
228+
229+
```ini
230+
# File: /etc/dmdevfs/storage.ini
231+
[main]
232+
driver_name = dmspiflash
233+
# ... other parameters
234+
```
235+
236+
This loads the `dmspiflash` driver module, regardless of the filename or directory.
237+
238+
#### 2. From Configuration Filename (Fallback)
239+
240+
If `driver_name` is not specified in the INI file, the basename of the configuration file (without `.ini` extension) is used:
241+
242+
```ini
243+
# File: /etc/dmdevfs/dmi2ceeprom.ini
244+
[main]
245+
# No driver_name specified
246+
i2c_bus = 0
247+
device_address = 0x50
248+
```
249+
250+
This loads the `dmi2ceeprom` driver module based on the filename.
251+
252+
#### 3. From Directory Name (Hierarchical Configuration)
253+
254+
When configuration files are organized in subdirectories, the directory name can be passed to nested configurations:
255+
256+
```
257+
/etc/dmdevfs/
258+
└── dmspiflash/
259+
├── device0.ini # Uses "dmspiflash" from directory name
260+
└── device1.ini # Uses "dmspiflash" from directory name
261+
```
262+
263+
Each `.ini` file in the `dmspiflash/` directory will use `dmspiflash` as the default driver name unless overridden by the `driver_name` field in the file itself.
264+
265+
**Example of Combined Usage:**
266+
267+
```
268+
/etc/dmdevfs/
269+
├── dmflash.ini # Uses filename: "dmflash" driver
270+
├── dmspiflash/
271+
│ ├── device0.ini # Uses directory: "dmspiflash" driver
272+
│ └── device1.ini # Uses directory: "dmspiflash" driver
273+
└── custom.ini # Contains driver_name=dmi2ceeprom in file
274+
```
275+
276+
### Device Numbering and Path Generation
277+
278+
When a driver is initialized through its `dmdrvi_create()` function, it returns a device number structure (`dev_num`) that controls how the driver appears in the filesystem. This mechanism allows multiple instances of the same driver with different configurations.
279+
280+
#### Device Number Structure
281+
282+
The device number consists of:
283+
- **major**: Primary device identifier (typically for device type or bus)
284+
- **minor**: Secondary device identifier (typically for device instance)
285+
- **flags**: Indicates which numbers are provided (`DMDRVI_NUM_MAJOR`, `DMDRVI_NUM_MINOR`)
286+
287+
#### Path Generation Rules
288+
289+
The resulting filesystem path depends on which device numbers the driver provides:
290+
291+
| Major | Minor | Resulting Path | Example |
292+
|-------|-------|----------------|---------|
293+
||| `<driver_name><major>/<minor>` | `dmspiflash0/1` |
294+
||| `<driver_name>x/<minor>` | `dmspiflashx/0` |
295+
||| `<driver_name><major>` | `dmspiflash0` |
296+
||| `<driver_name>` | `dmspiflash` |
297+
298+
#### Examples
299+
300+
**Example 1: Both Major and Minor Provided**
301+
302+
Configuration file: `/etc/dmdevfs/spi0.ini`
303+
```ini
304+
[main]
305+
driver_name = dmspiflash
306+
spi_bus = 0 # Driver uses this to set major=0
307+
chip_select = 1 # Driver uses this to set minor=1
308+
```
309+
310+
Resulting path: `/mnt/dmspiflash0/1` (assuming mounted at `/mnt`)
311+
312+
**Example 2: Only Minor Provided**
313+
314+
Configuration file: `/etc/dmdevfs/eeprom.ini`
315+
```ini
316+
[main]
317+
driver_name = dmi2ceeprom
318+
device_address = 0x50 # Driver uses this to set minor=0
319+
```
320+
321+
Resulting path: `/mnt/dmi2ceepromx/0`
322+
323+
**Example 3: Only Major Provided**
324+
325+
Configuration file: `/etc/dmdevfs/uart.ini`
326+
```ini
327+
[main]
328+
driver_name = dmuartstorage
329+
uart_port = 2 # Driver uses this to set major=2
330+
```
331+
332+
Resulting path: `/mnt/dmuartstorage2`
333+
334+
**Example 4: No Device Numbers**
335+
336+
Configuration file: `/etc/dmdevfs/generic.ini`
337+
```ini
338+
[main]
339+
driver_name = dmgenericdriver
340+
```
341+
342+
Resulting path: `/mnt/dmgenericdriver`
343+
344+
#### Multiple Device Instances
345+
346+
You can configure multiple instances of the same driver by using separate configuration files:
347+
348+
```
349+
/etc/dmdevfs/
350+
├── spi_flash0.ini # major=0, minor=0 → /mnt/dmspiflash0/0
351+
├── spi_flash1.ini # major=0, minor=1 → /mnt/dmspiflash0/1
352+
└── spi_flash2.ini # major=1, minor=0 → /mnt/dmspiflash1/0
353+
```
354+
355+
Or using hierarchical organization:
356+
357+
```
358+
/etc/dmdevfs/dmspiflash/
359+
├── bus0_cs0.ini # major=0, minor=0 → /mnt/dmspiflash0/0
360+
├── bus0_cs1.ini # major=0, minor=1 → /mnt/dmspiflash0/1
361+
└── bus1_cs0.ini # major=1, minor=0 → /mnt/dmspiflash1/0
362+
```
363+
364+
#### Understanding the 'x' Notation
365+
366+
When only a minor number is provided (major not set), the path uses `x` as a placeholder. This is useful when the driver doesn't use a major/minor hierarchy but still wants to enumerate devices:
367+
368+
```
369+
/mnt/dmspiflashx/0
370+
/mnt/dmspiflashx/1
371+
/mnt/dmspiflashx/2
372+
```
373+
374+
This convention keeps paths consistent and prevents naming collisions.
375+
376+
#### Driver Implementation Notes
377+
378+
The device numbers are determined by the driver itself based on the configuration parameters. For example:
379+
- An SPI flash driver might use `spi_bus` as the major number and `chip_select` as the minor number
380+
- An I2C driver might use only the `device_address` as the minor number
381+
- A generic driver might not use device numbers at all
382+
383+
Consult your specific driver's documentation to understand how it uses configuration parameters to set device numbers.
384+
385+
### Best Practices
386+
387+
1. **Use Descriptive Names**: Name configuration files to reflect their purpose (e.g., `spi_flash_boot.ini`)
388+
2. **Document Parameters**: Add comments in INI files to explain parameter meanings
389+
3. **Validate Configuration**: Ensure driver modules exist before deploying configuration files
390+
4. **Organize by Function**: Use subdirectories to group related drivers
391+
5. **Test Individually**: Test each driver configuration independently before integrating
392+
393+
### Troubleshooting
394+
395+
Common configuration issues:
396+
397+
- **"Config path is NULL/empty"**: Ensure you provide a valid path when mounting
398+
- **"Failed to open config directory"**: Verify the configuration directory exists and is accessible
399+
- **"Failed to read driver for config"**: Check INI file syntax and format
400+
- **"Failed to configure driver"**: Verify the driver module is available and implements dmdrvi interface
401+
- **Driver module not found**: Ensure the driver module is loaded or available in the module repository
402+
403+
### Dynamic Reconfiguration
404+
405+
Currently, DMDEVFS loads configuration at mount time. To apply new configurations:
406+
407+
1. Unmount the filesystem: `dmvfs_unmount_fs("/mnt")`
408+
2. Update configuration files
409+
3. Remount the filesystem: `dmvfs_mount_fs("dmdevfs", "/mnt", "/etc/dmdevfs")`
410+
111411
## API
112412

113413
The module implements the full DMFSI interface:
@@ -158,7 +458,27 @@ dmdevfs/
158458

159459
## Integration into Your Project
160460

161-
### Using CMake FetchContent
461+
### Method 1: Using `dmod_link_modules` (Recommended)
462+
463+
The most convenient way to add dmdevfs to your DMOD-based project (in module mode) is to use the `dmod_link_modules` CMake macro:
464+
465+
```cmake
466+
# In your CMakeLists.txt, after setting up your DMOD module
467+
468+
# Link DMDEVFS module to your project
469+
dmod_link_modules(your_module_name
470+
dmdevfs
471+
# ... other modules
472+
)
473+
```
474+
475+
This macro automatically:
476+
- Downloads the dmdevfs module from the repository
477+
- Configures it for DMOD module mode
478+
- Links it to your target
479+
- Handles all dependencies (dmfsi, dmdrvi, dmini, dmlist)
480+
481+
### Method 2: Using CMake FetchContent
162482

163483
```cmake
164484
include(FetchContent)
@@ -179,7 +499,7 @@ FetchContent_MakeAvailable(dmdevfs)
179499
target_link_libraries(your_target PRIVATE dmdevfs)
180500
```
181501

182-
### Manual Integration
502+
### Method 3: Manual Integration
183503

184504
1. Clone the repository: `git clone https://github.com/choco-technologies/dmdfs.git`
185505
2. Add as subdirectory: `add_subdirectory(dmdevfs)`

0 commit comments

Comments
 (0)