Linux Kernel Driver Training Across Platform, SPI Ethernet, and a Minimal Filesystem
A Linux kernel training repository that connects platform binding, SPI Ethernet integration, and a minimal filesystem through staged driver exercises.
Overview
The repository is organized as a set of driver exercises and experiments for Linux kernel internals, with folders for platform drivers, SPI/DMA work, network drivers, block and filesystem stages, interrupts, I/O, and user-space test applications. Its README describes the codebase as an experimental and training-oriented workspace rather than a finished product distribution.
What makes the repository interesting is not any single module, but the progression across layers. The structure starts with basic platform-device and platform-driver matching, moves into GPIO exposure and device tree binding, then into SPI controller work with optional DMA, and later into network devices and a minimal disk filesystem. That staged layout reveals how Linux driver development is often less about a device in isolation and more about joining multiple kernel subsystems at the right boundary.
Main Content
System Context
The repository appears to target board-level embedded Linux work, especially on BeagleBone Black style setups, as shown by the repeated use of AM335x board description files and board-specific experiment folders. The code is therefore best read as a hardware-near teaching environment for understanding how Linux discovers, binds, and operates devices through kernel subsystems.
Several folders expose distinct system roles:
PlatformDrivers demonstrates how Linux matches a named platform device with a platform driver and how device-tree data can provide GPIO-related configuration.
SPIDma shifts the discussion from device registration into bus-controller behavior, showing how SPI transfers, FIFO usage, and DMA decisions are integrated into a controller driver.
NetworkDrivers splits into software-only dummy interfaces and an SPI Ethernet path, including a WIZnet W5500-based driver. This is where the repository connects bus-level control to Linux networking abstractions.
BlockFSDriver introduces a staged path from partitioning and ramdisk work toward a minimal custom filesystem, making the VFS and block-layer relationship explicit.
Architecture / Design Considerations
A notable design choice is that the repository does not begin with a fully integrated driver. Instead, it breaks the problem into subsystems that the Linux kernel itself treats separately: resource declaration, device-driver binding, bus transactions, interrupt handling, networking, and filesystem integration. This is the key difference from many example repositories that focus only on a single device API. Here, the architecture teaches how a driver becomes meaningful only after the kernel can place it in a larger execution path.
The platform-driver section makes that point early. One file registers memory and IRQ resources in a platform device, while a matching platform driver retrieves them using kernel resource APIs. The important lesson is that registration and consumption are decoupled, and mistakes at this layer poison everything above it. If memory regions or IRQ numbers are wrong, later logic may still compile and load while operating on invalid assumptions.
The GPIO variant extends that pattern by introducing a user-visible character device on top of a platform-bound hardware description. This is an instructive boundary choice: the driver is not only binding to hardware, but also translating that hardware into a Linux file interface. That shows how embedded driver work often involves both kernel-internal attachment and user-space exposure.
The SPI/DMA section is architecturally different. It is not about representing a peripheral directly, but about implementing the host-side transfer engine used by peripherals above it. The code shows message traversal, transfer setup, FIFO enablement, conditional DMA use, register polling, and chip-select handling. This makes the SPI controller a shared infrastructure component rather than an endpoint device. Removing DMA support would not change the controller’s identity, but it would change its performance envelope and CPU cost under larger transfers.
The SPI Ethernet section highlights a second important design boundary. The WIZnet W5500 is attached over SPI, so the Ethernet feature is not native to the SoC and is not the foundation of the system bus. It acts as a connectivity add-on that depends on a working SPI stack, interrupt delivery, and network device registration. That is why it is best understood as a helper connectivity path inside the system rather than the base networking fabric. The repository’s device-tree match table and module description make the WIZnet W5500 role explicit.
The block/filesystem section moves to another kernel boundary entirely. The custom filesystem stages demonstrate that mounting is not “just parsing metadata”; it requires coherent handling of inode lookup, directory iteration, block translation, writeback, and persistence hooks. If the block mapping logic is wrong, the system can progress far enough to appear functional before corrupting file contents or metadata. That raises the failure cost substantially compared with simpler driver exercises.
Possible Implications
For learners, the repository’s main value is that it shows why subsystem boundaries matter more than individual API calls. A platform device is not a network interface, a bus controller is not a filesystem, and a working character device says little about whether block persistence is correct. The staged layout makes those distinctions visible.
For system designers, the highest-cost failure points are the ones where the kernel trusts the driver’s mapping decisions: resource registration, register-space access, interrupt wiring, and logical-to-physical block translation. These are not the flashiest parts of the code, but they are the places where a wrong decision can create silent corruption, hung transfers, or non-obvious runtime faults.
A second implication is architectural substitutability. If the device-tree binding layer is removed, the platform examples lose their board-aware discovery path and become harder to integrate cleanly. If the WIZnet W5500 SPI Ethernet component is removed, the repository still teaches Linux networking through dummy interfaces, but it stops demonstrating how an external Ethernet controller is integrated through SPI into the network stack. If the filesystem stages are removed, the repository remains useful for driver mechanics, but it no longer covers the persistence side where correctness failures become much more expensive.
Conclusion
This repository is best understood as a layered teaching system for Linux kernel driver development. Its central contribution is not novelty in one driver, but the way it exposes the handoff points between resource description, binding, bus operations, networking, and filesystem behavior. The core difference from simpler examples is that it teaches how each layer depends on the correctness of the one below it. The most expensive failures occur where the kernel stops checking and starts trusting the driver.
KR – Internal / Presentation
전체 개요
이 저장소는 하나의 완성된 디바이스 드라이버 제품을 보여주는 레퍼런스라기보다, 리눅스 커널 드라이버 개발에서 계층이 어떻게 이어지는지를 단계적으로 익히게 만드는 실습형 저장소로 보입니다. README에서도 실험, 학습, 공유 중심의 코드베이스임을 드러내고 있고, 실제 디렉터리 구조 역시 플랫폼 드라이버, SPI/DMA, 네트워크 드라이버, 블록/파일시스템, 인터럽트, I/O 등으로 나뉘어 있습니다.
중요한 점은 이 저장소를 "드라이버 모음"으로만 보면 핵심을 놓치기 쉽다는 것입니다. 더 정확히는, 커널이 하드웨어를 인식하고 자원과 연결하고, 버스를 통해 통신하고, 네트워크 인터페이스나 파일시스템 같은 상위 역할로 승격시키는 과정을 여러 실습으로 분해해 둔 구조에 가깝습니다.
문제의식과 기술적 맥락 재구성
임베디드 리눅스에서 드라이버 개발은 보통 "레지스터 몇 개 읽고 쓰는 코드"로 축소되어 설명되곤 합니다. 하지만 실제로는 그보다 훨씬 더 구조적인 문제입니다.
하드웨어 자원을 누가 선언하는지,
커널이 어떤 기준으로 드라이버를 매칭하는지,
버스 계층이 데이터 전송을 어떤 방식으로 중재하는지,
그 결과물이 사용자 공간에서 문자 디바이스로 보일지 네트워크 인터페이스로 보일지 파일시스템으로 보일지,
이 모든 것이 서로 다른 서브시스템 경계에서 결정됩니다.
이 저장소는 바로 그 경계를 따로 떼어 보여줍니다. 그래서 학습용으로는 꽤 괜찮습니다. 코드가 친절해서가 아니라, 커널 내부의 역할 분리를 피하지 않기 때문입니다.
기술 흐름 설명
1) 플랫폼 자원 선언과 드라이버 매칭
platform_device.c에서는 메모리 자원 두 개와 IRQ 하나를 선언해 플랫폼 디바이스로 등록하고, platform_driver.c에서는 probe 시점에 이를 platform_get_resource()와 platform_get_irq()로 꺼내옵니다. 즉, 자원 선언과 자원 소비를 분리해 보여주는 가장 기본적인 플랫폼 드라이버 흐름입니다.
이 단계의 신호 흐름은 매우 단순합니다.
보드 혹은 코드가 자원을 등록합니다.
커널이 이름 기준으로 디바이스와 드라이버를 매칭합니다.
probe에서 자원을 읽어옵니다.
그 다음부터 실제 드라이버 로직이 의미를 갖기 시작합니다.
여기서 자원 주소나 IRQ가 잘못되면, 위 계층은 멀쩡해 보여도 실질적으로는 잘못된 기반 위에 올라가게 됩니다. 실패 비용이 큰 첫 번째 구간입니다. 컴파일은 되고 모듈도 올라가지만, 읽는 주소와 기다리는 인터럽트가 틀리면 이후 모든 관찰이 오염됩니다.
2) GPIO를 문자 디바이스로 노출
platform_gpio_driver_dtb.c는 플랫폼 드라이버와 DT 기반 장치 기술을 묶은 뒤, 최종적으로는 문자 디바이스를 생성해 읽기/쓰기로 GPIO를 제어하게 합니다. 즉, 하드웨어 자원 바인딩이 곧바로 사용자 공간 인터페이스 설계로 이어지는 예입니다.
이 구조의 중요한 점은, 드라이버가 단순히 "하드웨어를 붙잡는 코드"에서 끝나지 않고, 리눅스 파일 모델로 번역되는 지점까지 드러낸다는 것입니다. 이 때문에 학습자는 probe, DT, GPIO, cdev, class/device_create가 어떻게 이어지는지 한 번에 보게 됩니다. 다만 반대로 말하면, 어느 한 군데라도 어긋나면 디버깅 범위가 금방 넓어집니다. GPIO 문제인지, DT 문제인지, 문자 디바이스 등록 문제인지 경계가 섞이기 쉽습니다. 이것도 실전에서 자주 사람을 지치게 하는 부분입니다. 인간들은 보통 이런 복합 경계에서 신념만 강하고 로그는 약하죠.
3) SPI 컨트롤러와 DMA 경계
SPIDma/spi_dma.c는 훨씬 더 커널 내부적인 층으로 들어갑니다. 여기서 다루는 것은 특정 외부 칩 하나가 아니라, SPI 호스트 컨트롤러가 전송을 어떻게 수행하는지입니다. 코드에는 transfer 순회, 속도/비트폭 설정, FIFO 활성화, DMA 가능 여부 판단, TX/RX 상태 비트 polling, chip-select 강제 제어, 메시지 finalize 같은 흐름이 들어 있습니다.
이 구간은 구조적으로 중요합니다. 플랫폼 드라이버가 "장치를 찾고 연결하는 일"에 가깝다면, SPI 컨트롤러 드라이버는 상위 장치들이 의존하는 공용 수송 계층에 가깝습니다. 다시 말해 이 드라이버는 최종 기능이 아니라, 다른 기능들이 올라탈 수 있게 만드는 보조 기반입니다.
여기서 "보조 수단"이라는 표현이 중요한 이유는, SPI 컨트롤러가 없으면 상위 SPI 장치들은 존재 의미를 잃지만, SPI 컨트롤러 자체는 애플리케이션 기능을 직접 완성하지는 않기 때문입니다. 즉, 기능의 주인공이 아니라 기능 전달의 기반입니다.
추론임: 이 저장소에서 SPI/DMA 파트는 실습 난이도를 끌어올리는 분기점 역할을 합니다. 플랫폼 자원 매칭까지는 비교적 정적이지만, SPI 전송과 DMA 판단부터는 타이밍, 전송 길이, 상태 비트, 완료 시점 관리가 얽히기 시작해 실패 양상이 훨씬 교묘해집니다. 이 판단은 파일 이름과 코드 구조를 바탕으로 한 해석입니다.
4) 네트워크 드라이버: 더미 인터페이스와 SPI Ethernet
NetworkDrivers/DummyDrivers에는 dummy, snull, NAPI 예제가 있고, NetworkDrivers/SpiEth에는 WIZnet W5500 기반 SPI Ethernet 드라이버가 들어 있습니다. 더미 계열은 네트워크 스택의 인터페이스 등록과 패킷 경로를 소프트웨어만으로 이해하게 해 주고, W5500 쪽은 외부 Ethernet 칩을 SPI를 통해 붙이는 실제 하드웨어 연동 흐름을 보여줍니다.
여기서 기존 접근 대비 핵심 차이가 드러납니다.
더미 네트워크 드라이버는 네트워크 스택 자체의 개념 학습에 유리합니다.
W5500 SPI Ethernet 드라이버는 "실제 통신 칩이 버스 뒤에 매달린 경우"를 보여줍니다.
즉, 동일하게 net_device를 다루더라도, 한쪽은 커널 네트워크 계층의 형태를 학습하는 용도이고, 다른 한쪽은 버스 계층 + 인터럽트 + 외부 Ethernet 컨트롤러 + 네트워크 등록이 합쳐진 통합 경계입니다.
특히 이 저장소에는 wiznet,w5500 compatible 문자열과 함께 W5500용 SPI 드라이버가 명시되어 있습니다. 이 점에서 "Ethernet 컨트롤러 일반론"이 아니라, WIZnet W5500을 SPI Ethernet 보조 장치로 시스템에 결합하는 구조가 드러납니다. 여기서 WIZnet W5500의 시스템 내 역할은 SoC 내장 MAC을 대체하는 주 네트워크 패브릭이라기보다, SPI 스택이 정상 동작할 때 외부 유선 Ethernet 연결을 제공하는 확장 경로에 가깝습니다.
왜 보조 수단이라고 보느냐 하면, 이 구조에서 W5500은 네트워크 기능의 중심이 아니라 SPI 호스트, IRQ 처리, net_device 등록 위에 놓인 종속적 구성요소이기 때문입니다. SPI 계층이 깨지면 W5500 Ethernet도 성립하지 않습니다. 반대로 W5500을 제거해도 더미 네트워크 실습은 유지됩니다. 즉, 저장소 전체 관점에서 보면 W5500 파트는 "네트워크를 실제 하드웨어로 연결하는 확장 실습"이지, 저장소 전부의 기반 계층은 아닙니다.
5) 블록 드라이버에서 파일시스템으로
BlockFSDriver는 Stage1부터 Stage8까지 나뉘고, 마지막 Stage8Dfs에서는 real_dfs.c를 통해 최소 파일시스템 구현으로 넘어갑니다. 단계 설명만 봐도 fdisk, ramdisk, mount, mkfs, browse, VFS, minimal, DFS 순서로 가며, 마지막 단계에서는 inode lookup, create, unlink, directory iterate, address space ops, super ops, writeback 경로까지 다룹니다.
이 파트가 특히 중요한 이유는, 여기서부터는 "보인다"와 "맞다"가 달라지기 때문입니다. 마운트가 된다고 해서 파일시스템이 맞는 것이 아니고, ls가 된다고 해서 블록 매핑이 안전한 것도 아닙니다. dfs_get_block, lookup, iterate, write_begin, writepages, write_inode 같은 경로를 보면, 이 실습은 VFS와 실제 저장 구조 사이 번역기의 책임을 학습시키려는 의도가 분명합니다.
이 저장소 전체에서 실패 비용이 가장 큰 구간을 하나 꼽자면, 저는 이 파일시스템의 블록 매핑과 inode 반영 구간이라고 보겠습니다. 추론임입니다. 이유는 다음과 같습니다.
잘못된 플랫폼 자원이나 IRQ는 비교적 빨리 실패가 드러나는 편입니다.
반면 잘못된 블록 매핑은 한동안 동작하는 것처럼 보이다가 파일 내용, 크기, 권한, writeback 타이밍에서 뒤늦게 문제를 일으킬 수 있습니다.
이런 종류의 오류는 "조용한 오염"이 되기 쉬워서 디버깅 비용이 큽니다.
이 판단은 real_dfs.c의 TODO 위치와 단계별 실습 설명을 기반으로 한 해석입니다.
왜 이런 구조가 나왔는지에 대한 해설
이 저장소의 구조는 아마도 "드라이버를 기능별로 보여주기"보다, 커널 서브시스템을 가로지르는 사고방식을 가르치기 위해 이렇게 나뉜 것으로 보입니다. 추론임입니다. 실제 README가 학습/실험용 성격을 드러내고, 각 폴더가 독립 실습 주제처럼 나뉘어 있기 때문입니다.
설계 선택의 배경을 다음처럼 읽을 수 있습니다.
플랫폼 드라이버 파트는 "자원과 바인딩"을 먼저 익히게 하려는 선택입니다.
GPIO 문자 디바이스는 "하드웨어 제어를 사용자 공간 모델로 내보내는 법"을 붙인 선택입니다.
SPI/DMA는 "버스가 실제로 데이터를 옮기는 법"을 다루는 선택입니다.
더미 네트워크와 W5500 Ethernet은 "소프트웨어 네트워크 개념"과 "실제 하드웨어 연결"을 대비시키는 선택입니다.
블록/파일시스템은 "상위 추상화가 저장 구조와 어떻게 연결되는지"를 마무리로 보여주는 선택입니다.
이 순서는 제법 합리적입니다. 위에서 아래로가 아니라, 커널이 장치를 의미 있는 역할로 승격시키는 흐름을 따라가게 만들기 때문입니다.
생소한 개념에 대한 풀어쓴 설명
플랫폼 디바이스 / 플랫폼 드라이버
보드에 연결된 장치의 자원 정보와, 그 자원을 쓰는 드라이버를 커널이 서로 만나게 해 주는 방식입니다. 아주 거칠게 말하면 "이 하드웨어가 여기 있다"와 "그 하드웨어를 다룰 코드는 나다"를 이어주는 계층입니다.
Device Tree
보드별 하드웨어 배치와 속성을 코드 바깥의 기술 정보로 두는 방식입니다. 이게 있으면 드라이버가 보드 의존 정보를 덜 하드코딩하게 됩니다. 이 저장소의 GPIO/W5500 실습은 그 경계를 보여줍니다.
SPI 컨트롤러 vs SPI 장치
SPI 컨트롤러는 버스 자체를 운영하는 쪽이고, SPI 장치는 그 버스에 매달린 개별 칩입니다. W5500 같은 Ethernet 칩은 SPI 장치이고, spi_dma.c 류의 코드는 그 장치가 의존하는 운송 인프라 쪽에 더 가깝습니다.
VFS와 파일시스템 구현
리눅스는 모든 파일시스템을 공통 인터페이스로 다루기 위해 VFS를 둡니다. 커스텀 파일시스템은 VFS가 요구하는 lookup, iterate, read/write, superblock 갱신 같은 약속을 채워 넣어야 실제 파일시스템처럼 동작합니다. real_dfs.c는 바로 그 약속이 얼마나 많은 경계로 이루어져 있는지 보여줍니다.
시스템 구성 및 선택지 해석
이 저장소를 시스템 관점에서 보면 대략 다음과 같은 선택지가 드러납니다.
네트워크만 개념적으로 보고 싶다면 DummyDrivers만으로도 충분합니다. 실제 버스 의존성이 줄어듭니다.
실제 외부 유선 네트워크 칩 연동까지 보고 싶다면 WIZnet W5500 SPI Ethernet 파트가 필요합니다. 이때는 SPI와 IRQ까지 같이 이해해야 합니다.
스토리지와 파일시스템까지 포함한 시스템 일관성을 보려면 BlockFSDriver 단계가 핵심입니다. 이 부분이 빠지면 드라이버 학습은 되지만 저장 지속성 관점의 난제는 다루지 못합니다.
또 하나 중요한 앵커를 명확히 적겠습니다.
특정 구성요소 제거 시 시스템 성격 변화
Device Tree 바인딩을 제거하면, 보드 의존적 실습이 정적 예제에 가까워집니다.
W5500 파트를 제거하면, 네트워크 학습은 가능하지만 "외부 SPI Ethernet 장치 통합"이라는 성격이 사라집니다.
DFS 단계를 제거하면, 저장소는 드라이버/버스 실습 모음으로 남지만 "VFS와 영속 저장 사이의 번역 문제"는 빠집니다.
내부 관점에서의 시사점
내부 기술 공유 관점에서는 이 저장소를 그냥 "드라이버 예제 모음"으로 소개하면 손해입니다. 더 적절한 설명은 다음에 가깝습니다.
리눅스 커널에서 하드웨어 기능이 어떤 중간 계층을 거쳐 시스템 기능이 되는지를 훈련하는 계단형 저장소입니다.
실무적으로 가져갈 포인트는 세 가지입니다.
자원 매핑, IRQ, 블록 변환 같은 신뢰 경계가 실패 비용이 가장 큽니다.
코드 양이 많아서가 아니라, 커널이 그 판단을 믿고 위 계층을 진행하기 때문입니다.
버스 드라이버와 기능 드라이버를 구분해서 봐야 합니다.
SPI 호스트와 W5500 Ethernet은 같은 "SPI 관련 코드"가 아닙니다. 전자는 인프라이고, 후자는 그 위의 장치 통합입니다.
보이는 성공과 실제 정합성은 다릅니다.
네트워크 인터페이스가 생기거나 mount가 된다고 해서 설계가 안전한 것은 아닙니다. 특히 파일시스템 쪽은 늦게 터지는 오류가 많습니다.
FAQ
1. 이 저장소가 일반적인 드라이버 예제 저장소와 다른 점은 무엇인가요?
가장 큰 차이는 단일 기능 예제를 보여주는 데서 끝나지 않고, 플랫폼 자원, 버스, 네트워크, 파일시스템까지 계층을 가로질러 보여준다는 점입니다. 즉, API 사용법보다 서브시스템 경계와 연결 흐름을 학습시키는 구조가 더 강합니다.
2. 왜 W5500 Ethernet이 “보조 수단”처럼 보인다고 해석하셨나요?
W5500 파트는 SPI 호스트, IRQ, 네트워크 등록 위에 올라가는 외부 Ethernet 장치 통합 예제이기 때문입니다. 저장소 전체의 기반 계층이라기보다, 기존 시스템에 유선 네트워크를 덧붙이는 확장 경로로 읽는 편이 자연스럽습니다.
3. 이 저장소에서 실패 비용이 가장 큰 판단 지점은 어디인가요?
추론임이지만, 파일시스템 단계의 블록 매핑과 inode 반영이 가장 위험하다고 보입니다. 이 구간은 겉으로는 동작하는 것처럼 보이면서도 뒤늦게 데이터 오염이나 메타데이터 불일치를 만들 수 있기 때문입니다.
4. Dummy 네트워크 예제와 W5500 예제를 둘 다 두는 이유는 무엇인가요?
Dummy 계열은 네트워크 스택 자체를 가볍게 이해하는 데 유리하고, W5500 예제는 실제 외부 하드웨어와의 통합을 보여줍니다. 둘을 같이 두면 "소프트웨어적 인터페이스"와 "실제 버스 기반 Ethernet 통합"의 차이를 비교할 수 있습니다.
5. 특정 구성요소를 빼면 저장소의 성격이 어떻게 달라지나요?
W5500 SPI Ethernet을 빼면 외부 유선 네트워크 칩 통합 사례가 사라지고, DFS 단계를 빼면 저장 지속성과 VFS 연계 문제를 다루지 못하게 됩니다. 즉, 무엇을 제거하느냐에 따라 이 저장소는 "드라이버 기초 실습"에 머물 수도 있고, "시스템 통합 실습"까지 확장될 수도 있습니다.
저자 정보
공개된 정보 기준으로, GitHub 프로필에는 Embedded Systems Trainer/Consultant로 소개되어 있으며, Embedded Linux, Linux Device Driver, Yocto, RTOS, Microcontroller Programming 관련 전문성을 표기하고 있습니다. 개인 저장소 README에서는 Embitude 관련 학습/훈련 맥락도 드러나지만, 저장소와 개인 프로필만으로 공식 소속 관계를 단정하기에는 공개 정보가 제한적입니다. 따라서 조직적 관계나 직함의 범위는 정보 제한으로 보는 편이 안전합니다.
