├── Chapter_1_Introduction_to_Device_Drivers.md
├── Chapter_2_Building_and_Running_Modules.md
├── Chapter_3_Char_Drivers.md
├── Chapter_4_Debugging_Techniques.md
├── Chapter_5_Concurrency_and_Race.md
├── Chapter_6_Advanced_Char_Drivers.md
├── Chapter_7_Time_Delays_DeferedWork.md
├── Chapter_8_Allocating_Memory.md
├── Chapter_9_Communicating_with_Hardware.md
├── Chapter__10_Interrupt_Handling.md
├── Chapter__11_Data_Types.md
├── Chapter__12_PCI_Drivers.md
├── Chapter__13_USB_Drivers.md
├── Chapter__14_Device_Model.md
├── Chapter__15_Memory_Mapping_DMA.md
├── Chapter__16_Block_Drivers.md
├── Chapter__17_Network_Drivers.md
├── Chapter__18_TTY_Drivers.md
├── Code_Examples
├── Block_Driver
│ ├── Makefile
│ ├── README.md
│ ├── domblockdev.c
│ ├── fun_text
│ └── sonnet
├── Char_Driver
│ ├── Makefile
│ ├── README.md
│ └── main.c
├── Hello_World
│ ├── Makefile
│ ├── README.md
│ └── hello.c
├── Net_Driver
│ ├── Makefile
│ ├── README.md
│ └── filter.c
├── README.md
├── scull
│ ├── Makefile
│ ├── Module.symvers
│ ├── README.md
│ ├── access.c
│ ├── access_ok_version.h
│ ├── lddbus.h
│ ├── main.c
│ ├── modules.order
│ ├── pipe.c
│ ├── scull.h
│ ├── scull.init
│ ├── scull_load
│ └── scull_unload
├── socketCAN
│ ├── README.md
│ ├── ReceiveRawPacket.c
│ └── SendRawPacket.c
└── tty
│ ├── Makefile
│ ├── README.md
│ ├── tiny_serial.c
│ └── tiny_tty.c
└── README.md
/Chapter_1_Introduction_to_Device_Drivers.md:
--------------------------------------------------------------------------------
1 | # LDD3 Chapter 1 Notes
2 |
3 | ## Brief Overview:
4 | This book consists of 18 chapters, each of which will be covered in this note set. The book covers up to linux kernel version 2.6.10, which was released 12/25/2004. This is really old, and the most recent version of the linux kernel as of January 2020 is the 5.4.13 kernel. Many important changes have been made over the years, and this note set will attempt to add in as much new detail as possible.
5 |
6 | The first part of the book moves from the software-oriented concepts to the hardware-related ones. This organization is meant to allow you to test the software on your own computer as far as possible without the need to plug external hardware into the machine.
7 |
8 | The second half of the book (chapters 12-18) describes block drivers and network interfaces and goes deeper into more advanced topics, such as working with the virtual memory subsystem and with the PCI and USB buses. Many developers do not need all of this material, but it is interesting as a view into how the Linux kernel works.
9 |
10 | ## Chapter 1. An Introduction to Device Drivers
11 |
12 | The Linux kernel is a large and complex body of code. People who desire to work with the kernel need an entry point where they can approach the code without being overwhelmed. Device drivers are one good place to start exploring.
13 |
14 | Device drivers are treated like distinct "black boxes" that make a piece of hardware respond to an internal programming interface. User activities are performed with a set of standardized calls that are independent of a specific driver. Mapping these calls to device-specific operations is the job of the driver. Drivers are made such that they can be built separately from the rest of the kernal and "plugged in" at runtime when needed. This modularity is supposed to make the drivers easy to write.
15 |
16 | This book attempts to explain drivers as generically as possible, without going into the specifics for one piece of hardware in too much detail. Many of the generic techniques can be applied to most drivers, though, which makes this book useful for setting up the general framework of any driver.
17 |
18 | This chapter does not introduce any code, but reviews important topics for future chapters.
19 |
20 | ### The distinction between Mechanism and Policy
21 |
22 | One of the best ideas behind Unix design, most programming problems can be split into two parts:
23 |
24 | 1. The mechanism - What capabilities are to be provided?
25 | 2. The policy - How those capabilities can be used?
26 |
27 | If these two issues are addressed by different parts of the program, or even different programs, the software package is easier to adapt and develop for particular needs.
28 |
29 | A programmer needs to pay attention to this distinction. Write kernel code to access hardware, but don't force policies on the user because different users have different needs. It should offer all the capability of the hardware without adding constraints. The trade-off then becomes a balance between adding as many possible options for the user and possible while keeping it simple so bugs and weird errors don't happen.
30 |
31 | Policy-free drivers have the following characteristics:
32 |
33 | 1. Support for both synchronous and asynchronous operation
34 | 2. The ability to be opened multiple times
35 | 3. The ability to use the full capabilities of the hardware
36 | 4. Lack of software layers to "simply things"
37 | 5. Tend to work better for end users
38 | 6. End up being easier to write and maintain
39 |
40 | Being policy-free is often a target for many designers. Many drivers are even released with user programs to help configure and connect to the target device. They can be simple command line utilities or fancy GUIs to help the user. The aim of this book is to cover the kernel, without much detail on the application programs or support library.
41 |
42 | In real life, you should always include configuration files that apply a default behavior to underlying mechanisms.
43 |
44 | ### Splitting the Kernel
45 |
46 | In a Unix-based system, several concurrent processes attend to different tasks. The kernel handles all of the requests that processes make for various system resources. The kernels role can be split into the following parts:
47 |
48 | 1. Process Management
49 | 2. Memory Management
50 | 3. Filesystems
51 | 4. Device Control
52 | 5. Networking
53 |
54 | #### 1. Process Management
55 |
56 | The kernel is in charge of creating, destroying, and connecting processes. It also schedules the CPU to be shared among many processes.
57 |
58 | #### 2. Memory Management
59 |
60 | The kernel builds up the virtual address space for each process. The different parts of the kernel interact with the memory-management subsystem through function calls such as malloc/free among many others.
61 |
62 | #### 3. Filesystems
63 |
64 | Almost everything in Unix can be treated as a file. The kernel builds a structured filesystem on top of of unstructured hardware. Linux also supports multiple file system types - all of which must be compatible with the kernel.
65 |
66 | #### 4. Device Control
67 |
68 | Device control operations are performed by code that is specific to the device being addressed. That code is called the device driver. Every peripheral on the system must have a driver for it embedded within the kernel. This part of the kernel operation is the focus of this book.
69 |
70 | #### Networking
71 |
72 | Most network operations are not specific to a process, and incoming packets are asynchronous events. The system is in charge of delivering packets across program and network interfaces, and must control the execution of programs according to their network activity. All routing and addressing issues also go through the kernel.
73 |
74 | ### Loadable Modules
75 |
76 | A piece of code that can be added to the kernel at runtime is called a module. There are many classes of modules, including device drivers.
77 |
78 | ### Classes of Devices
79 |
80 | There are three fundamental device types:
81 |
82 | 1. char module
83 | 2. block module
84 | 3. network module
85 |
86 | #### 1. Character Devices
87 |
88 | A device that can be accessed as a stream of bytes (like a file). A char driver is responsible for implementing this behavior. It usually implements open, close, read, and write system calls. The text console and serial ports are examples of char devices. Char devices are accessed by filesystem nodes, such as /dev/tty1 and dev/lp0. The difference between a char device and a regular file is that you can always move back and forth in a regular file, while most char devices are just data channels that can only be accessed sequentially. However, there are still some char devices that look like data areas and can be explored back and forth.
89 |
90 | #### 2. Block Devices
91 |
92 | A block device is a device that can host a filesystem. These are also accessed by filesystem nodes in the /dev directory. In Unix, they can usually only handle I/O operations that transfer one or more whole blocks, which may be 512 bytes in length. In Linux, they allow an application to read/write a block like a char device. This means that for Linux, char and block devices only differ in how they are managed internally by the kernel. They have completely different interface to the kernel than char drivers.
93 |
94 | #### 3. Network Interfaces
95 |
96 | Any network transaction is made through an interface. Functionally, one device is
97 | able to exchange data with other hosts. Usually, an interface is a hardware
98 | device, but it might also be a pure software device, e.g. the loopback interface. A network driver knows nothing about individual connections; it only handles the sending and receiving of packets. Since this is not stream oriented, a network interface cannot be easily mapped to a node in the filesystem. Instead of read/write functions like char and block drivers, the kernel calls special functions related to packet transmission.
99 |
100 | ### Security
101 |
102 | Any security check in the system is enforced by kernel code. Security is a policy issue that is often best handled at higher levels within the kernel under the control of the system administrator. There are some exceptions, though:
103 |
104 | - Avoid introducing security bugs
105 | - Input from a user process should be treated with great suspicion
106 | - Any memory obtained from the kernel should be zeroed or initialized before the user can access it
107 | - Avoid running unofficial kernels
108 |
109 | ### Linux Version Numbering
110 |
111 | Odd numbered kernels (2.7.x) are not stable. They are short lived development versions.
112 | Even numbered kernels (2.6.x) are stable and should be used for long-term development.
113 | This is no longer true! Linux 5.5 is stable, just like 5.4 and 5.3. Don't pay attention to the even/odd numbers anymore.
114 |
115 |
--------------------------------------------------------------------------------
/Chapter_8_Allocating_Memory.md:
--------------------------------------------------------------------------------
1 | # LDD3 Chapter 8 Notes
2 |
3 | ## Chapter 8: Allocating Memory
4 |
5 | Chapter goal: learn the kernel set of memory primitives
6 |
7 | So far we have used kmalloc() and kfree() to allocate and free memory. The kernel offers much better memory management tools though, as this chapter will describe in more detail.
8 |
9 | ### The Real Story of kmalloc
10 |
11 | kmalloc is powerful and simple to use because of its similarity to malloc. It is fast and does not clear the memory it obtains. The allocated region is also contiguous in physical memory. Here are more details on kmalloc:
12 |
13 | The prototype for kmalloc is:
14 |
15 | ```c
16 | #include
17 | void *kmalloc(size_t size, int flags);
18 | ```
19 |
20 | - The first argument is the size of the block to be allocated
21 | - The second argument controls to behavior of kmalloc in a number of different ways
22 |
23 | The most commonly used flag is `GFP_KERNEL` and it means that the calling function is executing a system call on behalf of a process. This means kmalloc can put the current process to sleep waiting for a page when called in low-memory situations.
24 |
25 | `GFP_KERNEL` is not always the best option, however, because sometimes kmalloc is called from outside a process’s context. This can happen with interrupt handlers, tasklets, and kernel timers. In this case we do not want to sleep the process and the driver should use a flag of `GFP_ATOMIC`. `GFP_ATOMIC` will use the last free page, and will fail if the allocation could not happen.
26 |
27 | There are symbols that represent frequently used combinations of flags. These are:
28 |
29 | ```
30 | GFP_ATOMIC
31 | Used to allocate memory from interrupt handlers and other code outside of a
32 | process context. Never sleeps.
33 |
34 | GFP_KERNEL
35 | Normal allocation of kernel memory. May sleep.
36 |
37 | GFP_USER
38 | Used to allocate memory for user-space pages. It may sleep.
39 |
40 | GFP_HIGHUSER
41 | Like GFP_USER, but allocates from high memory, if any. High memory is
42 | described in the next subsection.
43 |
44 | GFP_NOIO
45 | GFP_NOFS
46 | These flags function like GFP_KERNEL, but they add restrictions on what the kernel
47 | can do to satisfy the request. A GFP_NOFS allocation is not allowed to perform any
48 | filesystem calls, while GFP_NOIO disallows the initiation of any I/O at all.
49 | They are used primarily in the filesystem and virtual memory code where an
50 | allocation may be allowed to sleep, but recursive filesystem calls would be a bad
51 | idea.
52 | ```
53 |
54 | You can also use a boolean OR operator with any of the following flags:
55 |
56 | ```
57 | __GFP_DMA
58 | This flag requests allocation to happen in the DMA-capable memory zone. The
59 | exact meaning is platform-dependent and is explained in the following section.
60 |
61 | __GFP_HIGHMEM
62 | This flag indicates that the allocated memory may be located in high memory.
63 |
64 | __GFP_COLD
65 | Normally, the memory allocator tries to return “cache warm” pages—pages that
66 | are likely to be found in the processor cache. Instead, this flag requests a
67 | “cold” page, which has not been used in some time. It is useful for allocating
68 | pages for DMA reads, where presence in the processor cache is not useful.
69 |
70 | __GFP_NOWARN
71 | This rarely used flag prevents the kernel from issuing warnings (with printk)
72 | when an allocation cannot be satisfied.
73 |
74 | __GFP_HIGH
75 | This flag marks a high-priority request, which is allowed to consume even the
76 | last pages of memory set aside by the kernel for emergencies.
77 |
78 | __GFP_REPEAT
79 | __GFP_NOFAIL
80 | __GFP_NORETRY
81 | These flags modify how the allocator behaves when it has difficulty satisfying an
82 | allocation. __GFP_REPEAT means “try a little harder” by repeating the attempt—
83 | but the allocation can still fail. The __GFP_NOFAIL flag tells the allocator
84 | never to fail. It works as hard as needed to satisfy the request. __GFP_NORETRY
85 | tells the allocator to give up immediately if the requested memory is not
86 | available.
87 | ```
88 |
89 | #### Memory Zones
90 |
91 | Both `__GFP_DMA` and `__GFP_HIGHMEM` have a platform-dependent role, although their
92 | use is valid on all platforms.
93 |
94 | The Linux kernel knows about a minimum of three memory zones:
95 |
96 | 1. DMA-capable memory
97 | 2. normal memory
98 | 3. high memory
99 |
100 | While allocation happens in the `normal` memory zone most of the time, setting either of the bits just mentioned requires memory to be allocated from a different zone. We have special memory ranges that fall into the abstraction (a higher abstraction layer than considering all RAM equivalents).
101 |
102 | DMA-capable memory is memory that lives in a preferential address range where peripherals can perform DMA access. On most sane platforms, all memory lives in
103 | this zone. (what if we are insane???)
104 |
105 | High memory is a mechanism used to allow access to (relatively) large amounts of
106 | memory on 32-bit platforms. Only use this if you need a large section of memory - it is a little trickier to work with.
107 |
108 | Whenever a new page is allocated to fulfill a memory allocation request, the kernel
109 | builds a list of zones that can be used in the search. With `__GFP_DMA` specified, only the DMA zone is searched. Different flags can present different combinations of zones to look at. It is important to note that kmalloc cannot allocate high memory.
110 |
111 | In NUMA systems, the allocator attempts to locate memory local to the processor performing the allocation, but there are ways to change this.
112 |
113 | This will be visited again in chapter 15.
114 |
115 | ### The Size Argument
116 |
117 | The kernel takes care of managing the system's physical memory, which is available only in page-sized chunks. Thus, kmalloc is different than normal malloc from user space programs. A simple heap-oriented allocation technique would very quickly run into trouble if everyone needed their own page for everything.
118 |
119 | Linux handles memory allocation by creating a set of pools of memory objects of
120 | fixed sizes. Allocation requests are handled by going to a pool that holds sufficiently large objects and handing an entire memory chunk back to the requester. This technique is very complex, and normally we don't care very much about it with respect to device drivers. It is important to remember that the kernel can allocate only certain predefined, fixed-size byte arrays. The smallest allocation that kmalloc can handle might be 32 or 64 bytes depending on the page size of the system.
121 |
122 | There is also a maximum amount of memory that kmalloc can allocate at once, maybe around 128kB (but there are better ways to allocate larger chuncks that this chapter will cover later).
123 |
124 | ### Lookaside Caches
125 |
126 | A device driver often ends up allocating many objects of the same size, over and over again. We can create special pools of this size called a lookaside cache. Drivers usually do not use these, but USB and SCSI do so we will look at it.
127 |
128 | The cache allocator in Linux is sometimes called a "slab allocator". This is why the functions are declared in ``. The slab allocator implements caches that have a type `kmem_cache_t` and are created with a call to `kmem_cache_create`:
129 |
130 | ```c
131 | kmem_cache_t *kmem_cache_create(const char *name, size_t size,
132 | size_t offset,
133 | unsigned long flags,
134 | void (*constructor)(void *, kmem_cache_t *,
135 | unsigned long flags),
136 | void (*destructor)(void *, kmem_cache_t *,
137 | unsigned long flags));
138 | ```
139 |
140 | Wow that is a big constructor!
141 |
142 | - The function creates a new cache object that can host any number of memory areas all of the same size specified by the `size` argument
143 | - The `name` argument is associated with this cache and functions as housekeeping information usable in tracking problems
144 | - Usually it is set to the name of the type of structure that is cached
145 | - The `offset` is the offset of the first object in the page. You will probably use 0 to request the default value.
146 | - `flags` controls how allocation is done and is a bit mask of the following flags:
147 |
148 | ```
149 | SLAB_NO_REAP
150 | Setting this flag protects the cache from being reduced when the system is
151 | looking for memory. Setting this flag is normally a bad idea; it is important to
152 | avoid restricting the memory allocator’s freedom of action unnecessarily.
153 |
154 | SLAB_HWCACHE_ALIGN
155 | This flag requires each data object to be aligned to a cache line; actual
156 | alignment depends on the cache layout of the host platform. This option can be a
157 | good choice if your cache contains items that are frequently accessed on SMP
158 | machines. The padding required to achieve cache line alignment can end up
159 | wasting significant amounts of memory, however.
160 |
161 | SLAB_CACHE_DMA
162 | This flag requires each data object to be allocated in the DMA memory zone.
163 | ```
164 |
165 | The constructor and destructor arguments to the function are optional functions but must both be used (you can't just use one or the other). They can be useful, but there are a few constraints you need to keep in mind:
166 |
167 | - A constructor is called when the memory for a set of objects is allocated
168 | - because that memory may hold several objects, the constructor may be called multiple times
169 | - You cannot assume that the constructor will be called as an immediate effect of allocating an object
170 | - Destructors can be called at some unknown future time
171 | - not immediately after an object has been freed
172 | - Constructors and destructors may or may not be allowed to sleep
173 | - This is according to whether they are passed the SLAB_CTOR_ATOMIC flag
174 |
175 | Once a cache of objects is created, you can allocate objects from it by calling `kmem_cache_alloc`. The prototype is:
176 |
177 | ```c
178 | void *kmem_cache_alloc(kmem_cache_t *cache, int flags);
179 | ```
180 |
181 | The `cache` argument is the cache you have created previously and the flags are the same as the ones you would pass to kmalloc. To free an object, use `kmem_cache_free` with the following prototype:
182 |
183 | ```c
184 | void kmem_cache_free(kmem_cache_t *cache, const void *obj);
185 | ```
186 |
187 | When the module is unloaded, it should free the cache with:
188 |
189 | ```c
190 | int kmem_cache_destroy(kmem_cache_t *cache);
191 | ```
192 |
193 | The destroy operation succeeds only if all objects allocated from the cache have been returned to it, so you should check this value as a failure would indicate a leak within the module.
194 |
195 | ### A scull Based on the Slab Caches: scullc :skull:
196 |
197 | scullc is a trimmed-down version of the scull module that implements only the bare device, which is the persistent memory region. While scull uses kmalloc, scullc uses memory caches.
198 |
199 | First, it needs to declare the slab cache:
200 |
201 | ```c
202 | /* declare one cache pointer: use it for all devices */
203 | kmem_cache_t *scullc_cache;
204 | ```
205 |
206 | The creation of the slab cache is handled in this way:
207 |
208 | ```c
209 | /* scullc_init: create a cache for our quanta */
210 | scullc_cache = kmem_cache_create("scullc", scullc_quantum,
211 | 0, SLAB_HWCACHE_ALIGN, NULL, NULL); /* no ctor/dtor */
212 |
213 | if (!scullc_cache) {
214 | scullc_cleanup();
215 | return -ENOMEM;
216 | }
217 | ```
218 |
219 | And allocating memory quanta (the made up unit of space):
220 |
221 | ```c
222 | /* Allocate a quantum using the memory cache */
223 | if (!dptr->data[s_pos]) {
224 | dptr->data[s_pos] = kmem_cache_alloc(scullc_cache, GFP_KERNEL);
225 | if (!dptr->data[s_pos])
226 | goto nomem;
227 | memset(dptr->data[s_pos], 0, scullc_quantum);
228 | }
229 | ```
230 |
231 | And releasing the memory as:
232 |
233 | ```c
234 | for (i = 0; i < qset; i++)
235 | if (dptr->data[i])
236 | kmem_cache_free(scullc_cache, dptr->data[i]);
237 | ```
238 |
239 | Then, at unload time, we return the cache to the system with:
240 |
241 | ```c
242 | /* scullc_cleanup: release the cache of our quanta */
243 | if (scullc_cache)
244 | kmem_cache_destroy(scullc_cache);
245 | ```
246 |
247 | This method is more efficient and slightly faster than kmalloc.
248 |
249 | ### Memory Pools
250 |
251 | There are places in the kernel where memory allocations cannot be allowed to fail. TO guarantee allocations, developers created an abstraction known as a memory pool. It is really just a form of a lookaside cache that tries to always keep a list of free memory around for use in emergencies. How nice of it to do that.
252 |
253 | A memory pool has a type of `mempool_t` defined in ``. You can create one with `mempool_create` as follows:
254 |
255 | ```c
256 | mempool_t *mempool_create(int min_nr,
257 | mempool_alloc_t *alloc_fn,
258 | mempool_free_t *free_fn,
259 | void *pool_data);
260 | ```
261 |
262 | - `min_nr` is the minimum number of allocated objects that the pool should always keep around
263 | - actual allocation and freeing of objects is handled by alloc_fn and free_fn with the following prototypes:
264 |
265 | ```c
266 | typedef void *(mempool_alloc_t)(int gfp_mask, void *pool_data);
267 | typedef void (mempool_free_t)(void *element, void *pool_data);
268 | ```
269 |
270 | - And the final parameter to mempool_create (pool_data) is passed to alloc_fn and free_fn.
271 |
272 | There are two functions (mempool_alloc_slab and mempool_free_slab) that perform the impedance matching between the memory pool allocation prototypes and kmem_cache_alloc and kmem_cache_free. Code that sets up memory pools often looks like this:
273 |
274 | ```c
275 | cache = kmem_cache_create(. . .);
276 | pool = mempool_create(MY_POOL_MINIMUM,
277 | mempool_alloc_slab, mempool_free_slab,
278 | cache);
279 | ```
280 |
281 | When the pool has been created, objects can be allocated and freed with:
282 |
283 | ```c
284 | void *mempool_alloc(mempool_t *pool, int gfp_mask);
285 | void mempool_free(void *element, mempool_t *pool);
286 | ```
287 |
288 | When a mempool is created, there will be a pool of pre-allocated objects created that can be used should future calls to mempool_alloc fail. When one of these preallocated pools is freed with mempool free, it is kept in the pool. This also happens if a successfully initialized pool is freed but the total number of preallocated objects is currently below some minimum value. A mempool can be resized with the following call:
289 |
290 | ```c
291 | int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask);
292 | ```
293 |
294 | - If successful, it resizes the pool to have at least `new_min_nr` objects.
295 |
296 | A mempool can be returned to the system with:
297 |
298 | ```c
299 | void mempool_destroy(mempool_t *pool);
300 | ```
301 |
302 | - Remember to return all allocated objects before destroying a mempool.
303 |
304 | Using mempools is drivers should be rare because they consume a lot of memory. Allocating and dealing with allocating failures is probably the better route to go.
305 |
306 | ### get_free_page and Friends (friends? what are those?)
307 |
308 | If your module needs a lot of memory, it is better to use a page-oriented technique instead of mempools. To allocate entire pages, use the following:
309 |
310 | ```c
311 | get_zeroed_page(unsigned int flags);
312 | // Returns the pointer to a new page and fills the page with zeros.
313 |
314 | __get_free_page(unsigned int flags);
315 | // Similar to get_zeroed_page, but doesn’t clear the page. This seems like a security bug to me.
316 |
317 | __get_free_pages(unsigned int flags, unsigned int order);
318 | // Allocates and returns a pointer to the first byte of a memory area that is
319 | // potentially several (physically contiguous) pages long but doesn’t zero the area.
320 | ```
321 |
322 | - `flags` argument is similar to kmalloc. Use `GFP_KERNEL` or `GFP_ATOMIC` and maybe add the `__GFP_DMA` flag for direct-memory-access operations or `__GFP_HIGHMEM` when high memory can be used
323 | - `order` is the base-two logarithm of the number of pages you are requesting or freeing. If order is too big, allocation fails (usually is 10 or 11)
324 |
325 | You can free pages with either of the following functions:
326 |
327 | ```c
328 | void free_page(unsigned long addr); // this is a macro of the function below it
329 | void free_pages(unsigned long addr, unsigned long order);
330 | ```
331 |
332 | ### A scull Using Whole Pages: scullp
333 |
334 | Memory quanta allocated in the scullp module are whole pages or page sets. The `scullp_order` variable defaults to 0 but can be changed. This is how scullp allocates and deallocates memory:
335 |
336 | ```c
337 | /* Here's the allocation of a single quantum */
338 | if (!dptr->data[s_pos]) {
339 | dptr->data[s_pos] =
340 | (void *)__get_free_pages(GFP_KERNEL, dptr->order);
341 | if (!dptr->data[s_pos])
342 | goto nomem;
343 | memset(dptr->data[s_pos], 0, PAGE_SIZE << dptr->order);
344 | }
345 |
346 | /* This code frees a whole quantum-set */
347 | for (i = 0; i < qset; i++)
348 | if (dptr->data[i])
349 | free_pages((unsigned long)(dptr->data[i]),
350 | dptr->order);
351 | ```
352 |
353 | The main advantage of this method over kmalloc is efficiency of memory usage. Allocating by pages wastes no memory, while kmalloc wastes an unpredictable amount of memory because of allocation granularity.
354 |
355 | ### The alloc_pages Interface
356 |
357 | The real core of the Linux page allocator is the function alloc_pages_node with prototypes:
358 |
359 | ```c
360 | struct page *alloc_pages_node(int nid, unsigned int flags,
361 | unsigned int order);
362 |
363 | // Additional macro versions:
364 | struct page *alloc_pages(unsigned int flags, unsigned int order);
365 | struct page *alloc_page(unsigned int flags);
366 | ```
367 |
368 | - `nid` is the NUMA node ID
369 | - `flags` is the usual `GFP_` allocation flags
370 | - `order` is the size of the allocation (again, in 2^order format)
371 | - The return value is a pointer to the first page structure of the allocated memory or NULL for a failed allocation
372 | - `alloc_pages` simplifies this by putting the memory on the current NUMA node
373 | - `alloc_page` only allocates one page
374 |
375 | To release pages, you should use one of these functions:
376 |
377 | ```c
378 | void __free_page(struct page *page);
379 | void __free_pages(struct page *page, unsigned int order);
380 | void free_hot_page(struct page *page);
381 | void free_cold_page(struct page *page);
382 | ```
383 |
384 | - The hot page versions are for cache-resident pages
385 |
386 | ### vmalloc and Friends (again, where are these friends coming from?)
387 |
388 | vmalloc allocates a contiguous memory region in *virtual* address space that might be nonconsecutive in physical memory. It returns 0 if an error occurs, and a pointer to a linear memory area of size at least `size` on success. You shouldn't choose vmalloc as your first choice in development because it is slightly less efficient to work with. Try to work with individual pages rather than vmalloc. But here are the prototypes for vmalloc:
389 |
390 | ```c
391 | #include
392 |
393 | void *vmalloc(unsigned long size);
394 | void vfree(void * addr);
395 | void *ioremap(unsigned long offset, unsigned long size);
396 | void iounmap(void * addr);
397 | ```
398 |
399 | Important notes on vmalloc:
400 |
401 | - Remember: addresses returned by kmalloc, `_get_free_pages`, and vmalloc are virtual addresses
402 | - kmalloc and `_get_free_pages` have a one-to-one mapping to physical memory while vmalloc and ioremap do not follow this
403 | - Use vmalloc for allocating memory for a large sequential buffer that exists only in software
404 | - Memory allocated with vmalloc is released by vfree
405 | - ioremap builds new page tables like vmalloc but does not actually allocate any memory
406 | - The return value of ioremap is a special virtual address
407 | - The virtual address obtained is eventually released by calling iounmap
408 | - ioremap is most useful for mapping the (physical) address of a PCI buffer to (virtual) kernel space
409 | - vmalloc cannot be used in atomic context!
410 |
411 | ### A scull that uses Virtual Addresses: scullv
412 |
413 | The module scullv provides sample code for using vmalloc. The module allocates memory 16 pages at a time. The only difference between scullv and scullp is allocation management.
414 |
415 | How scullv obtains new memory and releases it:
416 |
417 | ```c
418 | /* Allocate a quantum using virtual addresses */
419 | if (!dptr->data[s_pos]) {
420 | dptr->data[s_pos] =
421 | (void *)vmalloc(PAGE_SIZE << dptr->order);
422 | if (!dptr->data[s_pos])
423 | goto nomem;
424 | memset(dptr->data[s_pos], 0, PAGE_SIZE << dptr->order);
425 | }
426 |
427 | /* Release the quantum-set */
428 | for (i = 0; i < qset; i++)
429 | if (dptr->data[i])
430 | vfree(dptr->data[i]);
431 | ```
432 |
433 | ### Per-CPU Variables
434 |
435 | When you create a per-CPU variable, each processor on the system gets its own copy of that variable. This is nice because:
436 |
437 | - It requires almost no locking because each CPU works with its own copy
438 | - Per-CPU variables can remain in their respective processors’ caches to speed up programs
439 |
440 | A good example of these variables is found in networking drivers. Rather than deal with the caching and locking issues with the many counters in networking, the we put the statistics counters into per-CPU variables. Updates are lockless and fast. On the rare occasion that user space requests to see the values of the counters, you can simply add up each processor’s version and return the total.
441 |
442 | Declarations for per-CPU variables are found in `` and they can be created with the following macro:
443 |
444 | ```c
445 | DEFINE_PER_CPU(type, name);
446 |
447 | // Can also be used with an array like:
448 | DEFINE_PER_CPU(int[3], my_percpu_array);
449 | ```
450 |
451 | The main locking feature needed with these variables is to use the `get_cpu_var` macro to access the current processor’s copy of a given variable, and call `put_cpu_var` when you are done. `get_cpu_var` returns an lvalue for the current processor’s version of the variable and disables preemption. The lvalue can also be changed directly. For example:
452 |
453 | ```c
454 | get_cpu_var(sockets_in_use)++;
455 | put_cpu_var(sockets_in_use);
456 |
457 | // And you can access another processors copy with:
458 | per_cpu(variable, int cpu_id);
459 | ```
460 |
461 | You can dynamically allocate per-CPU variables with:
462 |
463 | ```c
464 | void *alloc_percpu(type); //works most of the time
465 | void *__alloc_percpu(size_t size, size_t align);
466 | ```
467 |
468 | - The variables can be freed with a call to free_percpu
469 | - Access to these variables is done with:
470 |
471 | ```c
472 | per_cpu_ptr(void *per_cpu_var, int cpu_id);
473 | ```
474 |
475 | This macro returns a pointer to the version of `per_cpu_var` corresponding to the given `cpu_id`.
476 |
477 | Code using dynamic per-CPU variables tends to look like this:
478 |
479 | ```c
480 | int cpu;
481 | cpu = get_cpu( )
482 | ptr = per_cpu_ptr(per_cpu_var, cpu);
483 | /* work with ptr */
484 | put_cpu( );
485 | ```
486 |
487 | Per-CPU variables can be exported to modules, but you must use a special version of the macros:
488 |
489 | ```c
490 | EXPORT_PER_CPU_SYMBOL(per_cpu_var);
491 | EXPORT_PER_CPU_SYMBOL_GPL(per_cpu_var);
492 |
493 | // And to access these variables within a module, declare it with:
494 | DECLARE_PER_CPU(type, name);
495 | ```
496 |
497 | There is usually not much space for per-CPU variables in a system, so keep them small!
498 |
499 | ### Obtaining Large Buffers (getting super buff requires heavy lifting)
500 |
501 | Allocations of large, contiguous memory buffers are prone to failure. So - before you go about trying to allocate a huge region of memory, look at scatter/gather operations in chapter 1.
502 |
503 | #### Acquiring a Dedicated Buffer at Boot Time
504 |
505 | If you really need to do this - you should request it at boot time to have the best odds at actually getting a sufficient memory chunck free. This is the dirty way to do it but can be less prone to failure. A module cannot allocate memory at boot time - only drivers linked directly to the kernel can do that.
506 |
507 | Boot time allocation is performed with one of the following functions:
508 |
509 | ```c
510 | #include
511 |
512 | void *alloc_bootmem(unsigned long size);
513 | void *alloc_bootmem_low(unsigned long size);
514 | void *alloc_bootmem_pages(unsigned long size);
515 | void *alloc_bootmem_low_pages(unsigned long size);
516 | ```
517 |
518 | Use the low versions if you need DMA operations in your driver. Usually you do not free this memory, but there is a mechanism to do it with:
519 |
520 | ```c
521 | void free_bootmem(unsigned long addr, unsigned long size);
522 | ```
523 |
524 | It is probably best to avoid this technique altogether for now. Only use it if you *really* *really* need to. And then go to the internet to find out how to best do this.
525 |
--------------------------------------------------------------------------------
/Chapter_9_Communicating_with_Hardware.md:
--------------------------------------------------------------------------------
1 | # LDD3 Chapter 9 Notes
2 |
3 | ## Chapter 9: Communicating with Hardware
4 |
5 | Chapter goal: Understand how a driver can access I/O ports and I/O memory while being portable across Linux platforms. This chapter mainly works with the parallel port found on older machines. It may not apply to current computers as much, but the concepts are still important to understand.
6 |
7 | ### I/O Ports and I/O Memory
8 |
9 | Every single peripheral device is controlled by writing and reading its registers (wow, that was simple!). Almost all the time a device has many registers which are accessed at consecutive addresses in either the memory space or the I/O address space.
10 |
11 | At the hardware level, memory regions and I/O regions are the same. Both are accessed by asserting electrical signals on the address bus and control bus and by reading from or writing to the data bus.
12 |
13 | Because peripheral devices are built to fit a peripheral bus, the most popular I/O buses are modeled on the personal computer. Linux implements I/O ports on all computer platforms it runs on, even where the CPU implements a single address space. The use of I/O ports is common for ISA peripheral boards, most PCI devices map registers into a memory address region for speed and effiency purposes with the CPU.
14 |
15 | ### I/O Registers and Conventional Memory
16 |
17 | Someone accessing I/O registers must be careful to avoid being tricked by CPU optimizations that can modify expected I/O behavior. The compiler can cache data into CPU registers without writing them to actual memory. Both write and read operations can operate on cache memory without ever reaching physical RAM! Thus, a driver must ensure that no caching is performed and no read or write reordering takes place when accessing registers.
18 |
19 | To fix this issue, we place a memory barrier between operations that need to be visible to hardware in a particular order. There are four macros to do this:
20 |
21 | ```c
22 | #include
23 | void barrier(void)
24 | /*This function tells the compiler to insert a memory barrier but has no effect on
25 | the hardware. Compiled code stores to memory all values that are currently
26 | modified and resident in CPU registers, and rereads them later when they are
27 | needed. A call to barrier prevents compiler optimizations across the barrier but
28 | leaves the hardware free to do its own reordering. */
29 |
30 | #include
31 | void rmb(void);
32 | void read_barrier_depends(void);
33 | void wmb(void);
34 | void mb(void);
35 | /*These functions insert hardware memory barriers in the compiled instruction
36 | flow. An rmb (read memory barrier) guarantees that any reads appearing before the
37 | barrier are completed prior to the execution of any subsequent read. wmb
38 | guarantees ordering in write operations, and the mb instruction guarantees both.
39 | Each of these functions is a superset of barrier. */
40 |
41 | /*read_barrier_depends is a special, weaker form of read barrier. rmb prevents the
42 | reordering of all reads across the barrier, read_barrier_depends blocks
43 | only the reordering of reads that depend on data from other reads. You should
44 | stick to using rmb. */
45 |
46 | void smp_rmb(void);
47 | void smp_read_barrier_depends(void);
48 | void smp_wmb(void);
49 | void smp_mb(void);
50 | /*These insert hardware barriers only when the kernel is compiled for SMP systems.
51 | Otherwise, they all expand to a simple barrier call.*/
52 |
53 | //And a typical use of memory barriers in a device driver may have this general form:
54 | writel(dev->registers.addr, io_destination_address);
55 | writel(dev->registers.size, io_size);
56 | writel(dev->registers.operation, DEV_READ);
57 | wmb( );
58 | writel(dev->registers.control, DEV_GO);
59 | ```
60 |
61 | Memory buses slow down performance in general, so only use them when you need to. The kernel provides a few useful combinations of variable assignment and memory barrier specification in `` as shown:
62 |
63 | ```c
64 | #define set_mb(var, value) do {var = value; mb( );} while 0
65 | #define set_wmb(var, value) do {var = value; wmb( );} while 0
66 | #define set_rmb(var, value) do {var = value; rmb( );} while 0
67 | ```
68 |
69 | ### Using I/O Ports
70 |
71 | #### I/O Port Allocation
72 |
73 | You should first get exlusive access to I/O ports before using them. The kernel has a registration interface to allow your driver to claim the port it needs. The core function in that interface is request_region:
74 |
75 | ```c
76 | #include
77 |
78 | struct resource *request_region(unsigned long first, unsigned long n,
79 | const char *name);
80 | ```
81 |
82 | - Tell the kernel to make use of `n`ports
83 | - Start with the port `first`
84 | - `name` is the name of your device
85 | - Return is non-NULL if allocation succeeds
86 | - If you get a return of NULL, you will not be able to access the ports
87 | - Ports show up in /proc/ioports
88 |
89 | When you are done with I/O ports, return them to the system with:
90 |
91 | ```c
92 | void release_region(unsigned long start, unsigned long n);
93 | ```
94 |
95 | You can check if a set of I/O ports is available with:
96 |
97 | ```c
98 | int check_region(unsigned long first, unsigned long n);
99 | ```
100 |
101 | - This will return negative error code if the port is not available
102 | - This function has been deprecated. Do not use it anymore
103 | - Many old drivers use this code
104 |
105 | #### Manipulating I/O Ports
106 |
107 | After a driver has locked the use of I/O ports, it must read and/or wrtie to those ports. Most hardware differentiates between 8, 16, and 32 bit systems. Some examples:
108 |
109 | - Microchip and the DSPIC line of 8 and 16 bit microcontrollers are very popular
110 | - They were the "bees knees" of the early 2000s
111 | - The STM32 family by ST Microelectronics is a popular 32 bit platform
112 | - This is an up and coming platform. ST has recently developed an all-in-one environment for the programming and debugging of these chips. See STMCubeIDE for more info.
113 | - Arduino Uno is an 8 bit microcontroller based on the ATmega328P chip
114 | - Better versions have better hardware, but this is just for reference.
115 | - The Teensy 4.0 microcontroller has a ARM Cortex-M7 processor at 600 MHz and is one of the fastest available today (2020).
116 | - This thing is REALLY powerful for a microcontroller
117 | - Texas Instruments has everything and does everything well. The only downside is that they are really expensive to use in commercial products. They want the big contracts. ST is more likely to do the smaller scale stuff.
118 |
119 | A c program must call different functions to access different size ports. The Linux kernel headers define the following inline functions to access I/O ports:
120 |
121 | ```c
122 | unsigned inb(unsigned port);
123 | void outb(unsigned char byte, unsigned port);
124 | /*Read or write byte ports (eight bits wide). The port argument is defined as
125 | unsigned long for some platforms and unsigned short for others. The return
126 | type of inb is also different across architectures.*/
127 |
128 | unsigned inw(unsigned port);
129 | void outw(unsigned short word, unsigned port);
130 | /*These functions access 16-bit ports (one word wide); they are not available
131 | when compiling for the S390 platform, which supports only byte I/O. */
132 |
133 | unsigned inl(unsigned port);
134 | void outl(unsigned longword, unsigned port);
135 | /*These functions access 32-bit ports. longword is declared as either unsigned
136 | long or unsigned int, according to the platform. Like word I/O, “long” I/O is
137 | not available on S390.*/
138 | ```
139 |
140 | Note: no 64-bit port I/O operations are defined, even on 64-bit systems. The port address space is at max a 32-bit data path.
141 |
142 | #### I/O Port Access from User Space
143 |
144 | The functions mentioned just before this are mainly meant to be used by device drivers, but they can also be sued from user space. The GNU C library defines them in ``. The following conditions should apply to use them in user space:
145 |
146 | - The program must be compiled with the -O option to force expansion of inline functions
147 | - The ioperm or iopl system calls must be used to get permission to perform I/O operations on ports. ioperm gets permission for individual ports, while iopl gets permission for the entire I/O space.
148 | - The program must run as root to invoke ioperm or iopl. Alternatively, one of its ancestors must have gained port access running as root.
149 |
150 | #### String Operations
151 |
152 | Some processors implement special instructions to transfer a sequence of bytes, words, or longs to and from a single I/O port of the same size. These are called string instructions and they perform a task quicker than C can. The prototypes for string functions are:
153 |
154 | ```c
155 | void insb(unsigned port, void *addr, unsigned long count);
156 | void outsb(unsigned port, void *addr, unsigned long count);
157 | /*Read or write count bytes starting at the memory address addr. Data is read
158 | from or written to the single port port.*/
159 |
160 | void insw(unsigned port, void *addr, unsigned long count);
161 | void outsw(unsigned port, void *addr, unsigned long count);
162 | //Read or write 16-bit values to a single 16-bit port.
163 |
164 | void insl(unsigned port, void *addr, unsigned long count);
165 | void outsl(unsigned port, void *addr, unsigned long count);
166 | //Read or write 32-bit values to a single 32-bit port.
167 | ```
168 |
169 | #### Pausing I/O
170 |
171 | Some platforms have problems with timing between the processor and peripheral device. In these situations, a small delay can be inserted after each I/O instruction if another I/O instruction immediately follows. On x86, this is done by performing an `out b` instruction to port 0x80, a normally unused port. Pausing functions are exactly like all of the ones listed above, but they have a `_p` added to the end of them (example: `outb_p` instead of `outb`).
172 |
173 | #### Platform Dependencies
174 |
175 | Here are some more relevant details on the platforms that I am most concerned with:
176 |
177 | ```
178 | x86_64
179 | The architecture supports all the functions described in this chapter. Port
180 | numbers are of type unsigned short.
181 |
182 | ARM
183 | Ports are memory-mapped, and all functions are supported. String functions are
184 | implemented in C. Ports are of type unsigned int.
185 | ```
186 |
187 | ### An I/O Port Example
188 |
189 | The sample code we use to show port I/O from within a device driver acts on general-purpose digital I/O ports. These ports are found in most computer systems (are they still?)
190 |
191 | Typically, I/O pins are controlled by two I/O locations: one that allows selecting what pins are used as input and what pins are used as output and one in which you can actually read or write logic levels. This makes the GPIO (general purpose input output). Other times, ports can be only read or only write. Then they may only be controlled by one register telling them to do their function.
192 |
193 | ### An Overview of the Parallel Port
194 |
195 | [Picture of a Parallel Port](https://en.wikipedia.org/wiki/Parallel_port#/media/File:Parallel_computer_printer_port.jpg)
196 |
197 | I won't go into a ton of detail on this port because I don't think they are really used at all anymore. But here are some basics:
198 |
199 | The parallel interface, in its minimal configuration, is made up of three 8-bit ports. The PC standard starts the I/O ports for the first parallel interface at 0x378 and for the second at 0x278.
200 |
201 | - 0x378 is a bidirectional data register
202 | - It connects directly to pins 2–9 on the physical connector
203 | - 0x278 is a read-only status register
204 | - The third port is an output-only control register which mainly controls whether interrupts are enabled or not
205 | - All ports are on the 0-5V TTL logic level
206 |
207 | ### Using I/O Memory
208 |
209 | The main mechanism used to communicate with devices is memory-mapped registers and device memory. Both of these are called I/O memory because the difference between registers and memory is transparent to software.
210 |
211 | I/O memory is a region of RAM-like locations that the device makes available
212 | to the processor over the bus. It can be used for things like holding video data, holding ethernet packets, and implementing registers that behave like I/O ports.
213 |
214 | This chapter focuses mainly on ISA and PCI memory, but other types should be similar in implementation. PCI is discussed in more detail in chapter 12.
215 |
216 | I/O memory may or may not be accessed through page tables. When access does pass through page tables, the kernel must first arrange for the physical address to be visible from your driver. This usually means that you must call ioremap before doing any I/O operations. If no page tables are needed, I/O memory locations look like I/O ports. You can then just read and write to them using proper wrapper functions.
217 |
218 | Whether or not ioremap is required to access I/O memory, direct use of pointers to I/O memory is discouraged. The kernel provides wrapper functions used to access I/O memory that is safe on all platforms and optimized away whenever straight pointer dereferencing can perform the operation.
219 |
220 | ### I/O Memory Allocation and Mapping
221 |
222 | I/O memory regions need to be allocated prior to use. The interface for allocation of memory regions is described in `` and has prototype:
223 |
224 | ```c
225 | struct resource *request_mem_region(unsigned long start, unsigned long len,
226 | char *name);
227 | ```
228 |
229 | - Allocates a memory region of `len` bytes
230 | - Allocates starting at the bit `start`
231 | - On success, a non-NULL pointer is returned.
232 | - On failure, the return value is NULL.
233 |
234 | All I/O memory allocations are listed in /proc/iomem.
235 |
236 | Memory regions should be free when no longer needed with:
237 |
238 | ```c
239 | void release_mem_region(unsigned long start, unsigned long len);
240 | ```
241 |
242 | There is also an old, now outdated method to check I/O memory region availability with:
243 |
244 | ```c
245 | int check_mem_region(unsigned long start, unsigned long len);
246 | ```
247 |
248 | It still shows up sometimes, so it is included here for completeness.
249 |
250 | Next, virtual addresses must be assigned to I/O memory regions with ioremap. Once equipped with ioremap and iounmap, a device driver can access any I/O memory address whether or not it is directly mapped to virtual address space. Here are the prototypes for ioremp:
251 |
252 | ```c
253 | #include
254 |
255 | void *ioremap(unsigned long phys_addr, unsigned long size);
256 | void *ioremap_nocache(unsigned long phys_addr, unsigned long size);
257 | void iounmap(void * addr);
258 | ```
259 |
260 | - The nocache version is often just identical to ioremap. It was meant to be useful if some control registers were in such an area that write combining or read caching was not desirable. This is rare and often not used.
261 |
262 | ### Accessing I/O Memory
263 |
264 | On some platforms, you may get away with using the return value from ioremap as a
265 | pointer. This is not good though. Instead, a more portable version with functions has been designed as follows:
266 |
267 | To read from I/O memory, use one of the following:
268 |
269 | ```c
270 | unsigned int ioread8(void *addr);
271 | unsigned int ioread16(void *addr);
272 | unsigned int ioread32(void *addr);
273 | ```
274 |
275 | Where `addr` is an address obtained from ioremap. The return value is what was read from the given I/O memory.
276 |
277 | To write to I/O memory, use one of the following:
278 |
279 | ```c
280 | void iowrite8(u8 value, void *addr);
281 | void iowrite16(u16 value, void *addr);
282 | void iowrite32(u32 value, void *addr);
283 | ```
284 |
285 | For reading or writing multiple values, use the following:
286 |
287 | ```c
288 | void ioread8_rep(void *addr, void *buf, unsigned long count);
289 | void ioread16_rep(void *addr, void *buf, unsigned long count);
290 | void ioread32_rep(void *addr, void *buf, unsigned long count);
291 | void iowrite8_rep(void *addr, const void *buf, unsigned long count);
292 | void iowrite16_rep(void *addr, const void *buf, unsigned long count);
293 | void iowrite32_rep(void *addr, const void *buf, unsigned long count);
294 | ```
295 |
296 | - These functions read or write `count` values from the given `buf` to the given `addr`
297 | - `count` is expressed in the size of the data being written
298 | - Ex: ioread32_rep reads `count` 32-bit values starting at `buf`
299 |
300 | If you need to operate on a block of memory instead, use one of the following:
301 |
302 | ```c
303 | void memset_io(void *addr, u8 value, unsigned int count);
304 | void memcpy_fromio(void *dest, void *source, unsigned int count);
305 | void memcpy_toio(void *dest, void *source, unsigned int count);
306 | ```
307 |
308 | - These functions behave like their C library analogs
309 |
310 | There are some older read/write functions in legacy kernel code that you should watch out for. Some 64-bit platforms also offer readq and writeq, for quad-word (8-byte) memory operations on the PCI bus.
311 |
312 | ### Ports as I/O Memory
313 |
314 | Some hardware has an interesting feature: some versions use I/O ports, while others
315 | use I/O memory. This seems really confusing to me as to why you would do both. The registers exported to the processor are the same in both cases, but the access method is different (this just sounds like a bad time). To minimize the difference between these two access methods, the kernel provides a function called ioport_map with prototype:
316 |
317 | ```c
318 | void *ioport_map(unsigned long port, unsigned int count);
319 | ```
320 |
321 | - It remaps `count` I/O ports and makes them appear to be I/O memory
322 | - From there on the driver can use ioread8 and related functions on the returned addresses
323 | - This makes it forget that it is using I/O ports at all
324 |
325 | The mapping should be undone when no longer needed with:
326 |
327 | ```c
328 | void ioport_unmap(void *addr);
329 | ```
330 |
331 | Note: I/O ports must still be allocated with request_region before they can be remapped in this way.
332 |
333 | ### ISA Memory Below 1 MB
334 |
335 | One of the most well-known I/O memory regions is the ISA range found on personal computers. It has a range between 640 KB (0xA0000) and 1 MB (0x100000). This position is due to the fact that in the 1980s 640KB of memory seemed like more than anybody would ever be able to use. Quote Bill Gates:
336 |
337 | "640K ought to be enough for anybody" - he denies ever saying this (probably embarrased about it)
338 |
339 | Anyways, the ISA memory range belongs to the non-directly-mapped class of memory. To demonstrate access to ISA memory, the driver called silly does the trick. The module supplements the functionality of the module short by giving access to the whole 384-KB memory space and by showing all the different I/O functions.
340 |
341 | Because silly provides access to ISA memory, it must first map the physical
342 | ISA addresses into kernel virtual addresses. This is done with ioremap and explained earlier. Code:
343 |
344 | ```c
345 | #define ISA_BASE 0xA0000
346 | #define ISA_MAX 0x100000 /* for general memory access */
347 |
348 | /* this line appears in silly_init */
349 | io_base = ioremap(ISA_BASE, ISA_MAX - ISA_BASE);
350 | ```
351 | - ioremap returns a pointer value that can be used with ioread8 and the other functions
352 |
353 | The following code shows the implementation for read. It makes the address range 0xA0000-0xFFFFF available as a virtual file in the range 0-0x5FFFF. It is structured as a switch case statement for the different access modes. Here is the sillyb case:
354 |
355 | ```c
356 | case M_8:
357 | while (count) {
358 | *ptr = ioread8(add);
359 | add++;
360 | count--;
361 | ptr++;
362 | }
363 | break;
364 | ```
365 |
366 | The next two devices are /dev/sillyw and /dev/sillyl. They act the same as sillyb, but use 16 and 32-bit functions, respectively. Here is the write implementation of sillyl:
367 |
368 | ```c
369 | case M_32:
370 | while (count >= 4) {
371 | iowrite8(*(u32 *)ptr, add);
372 | add += 4;
373 | count -= 4;
374 | ptr += 4;
375 | }
376 | break;
377 | ```
378 |
379 | The last device that is a part of the module is /dev/sillycp. It uses `memcpy_*io` functions to perform the same task.
380 |
381 | ```c
382 | case M_memcpy:
383 | memcpy_fromio(ptr, add, count);
384 | break;
385 | ```
386 | Because ioremap was used to provide access to the ISA memory area, silly must
387 | invoke iounmap when the module is unloaded with:
388 |
389 | ```c
390 | iounmap(io_base);
391 | ```
392 |
393 | ### isa_readb and Friends (again, what is with the Friends? :two_men_holding_hands: )
394 |
395 | A look at the kernel source code will show another set of routines with names like isa_readb. Each function just described has an `isa_` equivalent. These functions provide access to ISA memory without the need for a separate ioremap step. Avoid using these! They are temporary band-aids for driver-porting that should be used anymore. It would be sloppy to use these.
--------------------------------------------------------------------------------
/Chapter__11_Data_Types.md:
--------------------------------------------------------------------------------
1 | # LDD3 Chapter 11 Notes
2 |
3 | ## Chapter 11: Data Types in the Kernel
4 |
5 | I feel like this chapter should have come sooner in the book (like chapter 2 or 3) but it is fine to mention it in detail here.
6 |
7 | Chapter Goal: Understand portability issues that arise related to the differences in the same data types between platforms.
8 |
9 | Since Linux is meant to be highly portable, it is important to understand the steps you need to take to ensure that your driver will run the same on several different platforms (if necessary).
10 |
11 | Several issues with kernel developers porting code to x86 came from incorrect data typing. Strict data typing and compiling with the `-Wall` and `-Wstrict-prototypes` flags can prevent most bugs. Data types in the kernel fall into three main types:
12 |
13 | 1. Standard C types such as `int`
14 | 2. Explicitly sized types such as `u32`
15 | 3. Types used for specific kernel objects like `pid_t`
16 |
17 | If you follow this chapter carefully, you should be able to develop drivers that work on platforms that you might not even be able to test on.
18 |
19 | ### Use of Standard C Types
20 |
21 | Many programmers through around types like int and long willy nilly without regard to any specifics. Writing good drivers requires a little more attention to avoid typing conflicts and really bizarre bugs. Issues arise when you try to use things like a 2 byte filler or something representing a 4 byte string because normal C data types are not the same size on all architechures. See the included file `datasize` to see the size of various data types on your specific platform. Here is the output from my x86_64 machine:
22 |
23 | ```bash
24 | arch Size: char short int long ptr long-long u8 u16 u32 u64
25 | x86_64 1 2 4 8 8 8 1 2 4 8
26 | ```
27 |
28 | And here is the output for an i386 computer:
29 |
30 | ```bash
31 | arch Size: char short int long ptr long-long u8 u16 u32 u64
32 | i686 1 2 4 4 4 8 1 2 4 8
33 | ```
34 |
35 | Already, we can see differences between the long and ptr data types. Here is a more complete table of what happens when you run the program on many different platforms:
36 |
37 | ```bash
38 | arch Size: char short int long ptr long-long u8 u16 u32 u64
39 | i386 1 2 4 4 4 8 1 2 4 8
40 | alpha 1 2 4 8 8 8 1 2 4 8
41 | armv4l 1 2 4 4 4 8 1 2 4 8
42 | ia64 1 2 4 8 8 8 1 2 4 8
43 | m68k 1 2 4 4 4 8 1 2 4 8
44 | mips 1 2 4 4 4 8 1 2 4 8
45 | ppc 1 2 4 4 4 8 1 2 4 8
46 | sparc 1 2 4 4 4 8 1 2 4 8
47 | sparc64 1 2 4 4 4 8 1 2 4 8
48 | x86_64 1 2 4 8 8 8 1 2 4 8
49 | ```
50 |
51 | Generic memory addresses in the kernel are usually `unsigned long` to exploit that fact that pointers and long ints are always the same size for all the platforms supported by Linux. Think of memory addresses as just an index into a huge memory array.
52 |
53 | ### Assigning an Explicit Size to Data Items
54 |
55 | Sometimes you need to know the size of your data to communicate with user space. The kernel offers the following data types whenever you need to know the size of your data. They are found in `` and included automatically in ``:
56 |
57 | ```c
58 | u8; /* unsigned byte (8 bits) */
59 | u16; /* unsigned word (16 bits) */
60 | u32; /* unsigned 32-bit value */
61 | u64; /* unsigned 64-bit value */
62 | ```
63 |
64 | Signed versions of all of these types exist but are rarely used. Simply replace the `u` with an `s` to get the signed version.
65 |
66 | If your are working in user space, you can access these data types with a double underscore like this: `__u8`. These are defined independent of `__KERNEL__`. For example - let's say a driver needs to exchange binary structures with a program running in user space using ioctl. The header files should declare 32 bit fields in the structures as `__u32`.
67 |
68 | These types are Linux specific and may hinder portability to other Unix flavors. Oh well. I hope I don't need to develop for multiple Unix flavors anytime soon. If you do, you can use C99-standard types (there has to be more updated types now?) such as `uint8_t` and `uint32_t`.
69 |
70 | If you see conventional types like `unsigned int` it is likely done for backwards compatibility to the days when Linux had loosy typed structures.
71 |
72 | ### Interface-Specific Types
73 |
74 | Some common kernel data types have their own typedef statements to prevent portability issues. One example is using `pid_t` instead of `int`. By *interface specific*, we mean a type defined by a library in order to provide an interface to a specific data structure.
75 |
76 | A lot of developers (including me) really hate the use of typedefs and would rather see the real type information used directly in the code. However, a lot of legacy code still uses a lot of typedef stuff.
77 |
78 | Many `_t` types are defined in ``. This list is not often useful, however, because when you need a specific data type you will find it in the prototype of the functions you are trying to use. When a driver uses custom types that don't follow the convention, the compiler issues a warning. If you use `-Wall` and are careful to remove warnings, you have a good shot at making portable code.
79 |
80 | One problem comes with printing `_t` data types, since it is not easy to choose the right printk or printf format if these types are architechure dependent. A safe way to do this is to cast the value as the largest possible value to avoid data truncation.
81 |
82 | ### Other Portability Issues
83 |
84 | Besides data typing, portability issues can arise with explicit constant values. Typically code is parameterized using preprocessor macros. Magic numbers = bad!
85 |
86 | #### Time Intervals
87 |
88 | When dealing with time intervals, don't assume there are 1000 jiffies per second. When you calculate time intervals using jiffies, scale your times using `HZ`. The number of jiffies corresponding to `msec` milliseconds is `msec*HZ/1000`.
89 |
90 | #### Page Size
91 |
92 | A memory page is PAGE_SIZE bytes, NOT 4 KB. Use macros PAGE_SIZE and PAGE_SHIFT instead of hard coding numbers for page sizes. PAGE_SHIFT contains the number of bits to shift an address to get its page number.
93 |
94 | Here is one example of the page size issues being made portable:
95 |
96 | If a driver needs 16 KB for temp data, it should not specify and order of 2 to get_free_pages(). You need a more portable solution found by calling get_order:
97 |
98 | ```c
99 | #include
100 | int order = get_order(16*1024);
101 | buf = get_free_pages(GFP_KERNEL, order);
102 | ```
103 |
104 | - The argument to get_order must be a power of two
105 |
106 | ### Byte Order
107 |
108 | First, here is a good example comparing little and big endian:
109 | [Big Endian and Little Endian Online Reference](https://chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_3.html)
110 |
111 | While most PCs store multibyte values with little endian formatting, some high-level platforms use big-endian formatting. Your code should be written so that it doesn't care about byte ordering. The kernel defines a set of macros that handle conversions between the processors native byte ordering and the data you need to store or load in a specific byte order. Here is one set of macros:
112 |
113 | ```c
114 | //converts a value from whatever the CPU uses to an unsigned, little endian, 32-bit quantity
115 | u32 cpu_to_le32 (u32);
116 |
117 | // converts from the little endian value back to the CPU value
118 | u32 le32_to_cpu (u32);
119 | ```
120 |
121 | - This works no matter if your CPU uses little/big endian
122 | - ALso works on non-32-bit platforms.
123 | - You can do this with MANY different kinds of little and big endian data types
124 | - These are defined in `` and ``
125 |
126 | ### Data Alignment
127 |
128 | One final problem to consider is what to do with unaligned data. For example - reading a 4-byte word value stored at an address that isn't a multiple of 4 bytes. To do this, use the following macros:
129 |
130 | ```c
131 | #include
132 | get_unaligned(ptr);
133 | put_unaligned(val, ptr);
134 | ```
135 |
136 | - These macros are typeless
137 | - They work for every data item, no matter the byte length
138 | - They are defined with any kernel version
139 |
140 | To write data structures for data items that can be moved across architechures, always enforce natural alignment of the data items along with standardizing on a specific endianness.
141 |
142 | - Natural alignment means storing data items at an address that is a multiple of their size (for example, 8-byte items go in an address multiple of 8).
143 | - Then use filler fields to avoid leaving holes in that data structure.
144 |
145 | See the sample program dataalign in the misc-progs directory of the sample code to show how alignment is enforced by the compiler.
146 |
147 | The output from my system is:
148 |
149 | ```bash
150 | arch Align: char short int long ptr long-long u8 u16 u32 u64
151 | x86_64 1 2 4 8 8 8 1 2 4 8
152 | ```
153 |
154 | And the output from the kdataalign kernel module for my system is shown below:
155 |
156 | ```bash
157 | [Mar17 19:42] kdataalign: unknown parameter 'kdataalign' ignored
158 | [ +0.000048] arch Align: char short int long ptr long-long u8 u16 u32 u64
159 | [ +0.000002] x86_64 1 2 4 8 8 8 1 2 4 8
160 | ```
161 |
162 | A compiler may also automatically pad without telling you, and this could cause issues. So be aware of this. The workaround for this issue is to tell the compiler that the structure must be packed with no fillers added. One example is found in the kernel header file `` which defines data structures used in interfacing with the x86 BIOS:
163 |
164 | ```c
165 | struct {
166 | u16 id;
167 | u64 lun;
168 | u16 reserved1;
169 | u32 reserved2;
170 | } __attribute__ ((packed)) scsi;
171 | ```
172 |
173 | Without the `__attribute__ ((packed))`, the lun field would be preceded by two filler bytes or six if we compile the structure on a 64-bit platform.
174 |
175 | ### Pointers and Error Values (I can point to errors all day long)
176 |
177 | Several internal kernel functions return a pointer value to the caller. These functions can also fail (welcome to the club). In most cases, failure is indicated by returning a NULL pointer value. While this works, it does very little to describe the actual nature of the problem. There are times when the caller needs an actual error code so that the right decision can be made as to what to do next in a program.
178 |
179 | A function returning a pointer type can return an error value with:
180 |
181 | ```c
182 | void *ERR_PTR(long error);
183 | ```
184 |
185 | - Error is the usual negative error code
186 |
187 | The caller can use `IS_ERR` to test whether a returned pointer is an error code or not with:
188 |
189 | ```c
190 | long IS_ERR(const void *ptr);
191 | ```
192 |
193 | THe actual error code can be extracted with:
194 |
195 | ```c
196 | long PTR_ERR(const void *ptr);
197 | ```
198 |
199 | - Only use `PTR_ERR` on a value for which `IS_ERR` returns a true value.
200 |
201 |
202 | ### Linked Lists
203 |
204 | OS kernels often need to maintain lists of data structures. Developers have created a standard implementation of circular, doubly linked lists. People who need to manipulate lists are encouraged to use this facility.
205 |
206 | Linked lists in the kernel do not perform locking. You need to implement your own locking to use these responsibly. To use the list mechanism, include the file `` and look for the structure of type `list_head`:
207 |
208 | ```c
209 | struct list_head {
210 | struct list_head *next, *prev;
211 | };
212 | ```
213 |
214 | - Linked lists used in real code are usually made up of some type of structure
215 | - Each one describes one entry in the list
216 | - You need only embed a `list_head` inside the structures that make up the list
217 |
218 | An example in your code may look like this:
219 |
220 | ```c
221 | struct todo_struct {
222 | struct list_head list;
223 | int priority; /* driver specific */
224 | /* ... add other driver-specific fields */
225 | };
226 | ```
227 |
228 | List heads must be initialized prior to use with the INIT_LIST_HEAD macro. A “to do” list head could be declared and initialized with:
229 |
230 | ```c
231 | struct list_head todo_list;
232 | INIT_LIST_HEAD(&todo_list);
233 | ```
234 |
235 | Alternatively, lists can be initialized at compile time:
236 |
237 | ```c
238 | LIST_HEAD(todo_list);
239 | ```
240 |
241 | Review of doubly linked lists:
242 | [Doubly Linked List \| Set 1 (Introduction and Insertion) - GeeksforGeeks](https://www.geeksforgeeks.org/doubly-linked-list/)
243 |
244 | Several functions are defined in `` that work with lists:
245 |
246 | ```
247 | list_add(struct list_head *new, struct list_head *head);
248 | Adds the new entry immediately after the list head—normally at the beginning of
249 | the list. Therefore, it can be used to build stacks. Note, however, that the head
250 | need not be the nominal head of the list. If you pass a list_head structure that
251 | happens to be in the middle of the list somewhere, the new entry goes immediately
252 | after it. Since Linux lists are circular, the head of the list is not generally
253 | different from any other entry.
254 |
255 | list_add_tail(struct list_head *new, struct list_head *head);
256 | Adds a new entry just before the given list head—at the end of the list, in other
257 | words. list_add_tail can, thus, be used to build first-in first-out queues.
258 |
259 | list_del(struct list_head *entry);
260 | list_del_init(struct list_head *entry);
261 | The given entry is removed from the list. If the entry might ever be reinserted
262 | into another list, you should use list_del_init, which reinitializes the linked list
263 | pointers.
264 |
265 | list_move(struct list_head *entry, struct list_head *head);
266 | list_move_tail(struct list_head *entry, struct list_head *head);
267 | The given entry is removed from its current list and added to the beginning of
268 | head. To put the entry at the end of the new list, use list_move_tail instead.
269 |
270 | list_empty(struct list_head *head);
271 | Returns a nonzero value if the given list is empty.
272 |
273 | list_splice(struct list_head *list, struct list_head *head);
274 | Joins two lists by inserting list immediately after head.
275 |
276 | ```
277 |
278 | The `list_head` structures are good for implementing a list of like structures. However, the invoking program is usually more interested in the larger structures that make up the list as a whole.
279 |
280 | A macro called list_entry is provided that maps a list_head structure pointer back into a pointer to the structure that contains it. It is used like this:
281 |
282 | ```c
283 | list_entry(struct list_head *ptr, type_of_struct, field_name);
284 | ```
285 |
286 | - `ptr` is a pointer to the `struct list_head` being used
287 | - `type_of_struct` is the type of the structure containing the `ptr`
288 | - `field_name` is the name of the list field within the structure
289 |
290 | To turn a list entry into its containing structure, you could do this (where tehe list field is just called `list`):
291 |
292 | ```c
293 | struct todo_struct *todo_ptr =
294 | list_entry(listptr, struct todo_struct, list);
295 | ```
296 |
297 | The author claims that the traversal of linked lists is easy. We will see. Here is an example given for keeping the list of todo_struct items sorted in descending priority order. A function to add a new entry would look like this:
298 |
299 | ```c
300 | void todo_add_entry(struct todo_struct *new)
301 | {
302 | struct list_head *ptr;
303 | struct todo_struct *entry;
304 | for (ptr = todo_list.next; ptr != &todo_list; ptr = ptr->next) {
305 | entry = list_entry(ptr, struct todo_struct, list);
306 | if (entry->priority < new->priority) {
307 | list_add_tail(&new->list, ptr);
308 | return;
309 | }
310 | }
311 | list_add_tail(&new->list, &todo_struct)
312 | }
313 | ```
314 |
315 | However, instead of doing this there is a better method using predefined macros for creating and iterating through linked lists. The previous example could be rewritten as:
316 |
317 | ```c
318 | void todo_add_entry(struct todo_struct *new)
319 | {
320 | struct list_head *ptr;
321 | struct todo_struct *entry;
322 |
323 | list_for_each(ptr, &todo_list) {
324 | entry = list_entry(ptr, struct todo_struct, list);
325 | if (entry->priority < new->priority) {
326 | list_add_tail(&new->list, ptr);
327 | return;
328 | }
329 | }
330 | list_add_tail(&new->list, &todo_struct)
331 | }
332 | ```
333 |
334 | Use the macros as much as possible. It will probably work better than your code and you will make less mistakes. A few variants of these macros exist:
335 |
336 | ```
337 | list_for_each(struct list_head *cursor, struct list_head *list)
338 | Creates a for loop that executes once with cursor pointing at each
339 | successive entry in the list. Be careful about changing the list while iterating
340 | through it.
341 |
342 | list_for_each_prev(struct list_head *cursor, struct list_head *list)
343 | This one iterates backwards through the list
344 |
345 | list_for_each_safe(struct list_head *cursor, struct list_head *next, struct list_head *list)
346 | If your loop may delete entries in the list, use this version. It simply stores the
347 | next entry in the list in next at the beginning of the loop, so it does not get
348 | confused if the entry pointed to by cursor is deleted.
349 |
350 | list_for_each_entry(type *cursor, struct list_head *list, member)
351 | list_for_each_entry_safe(type *cursor, type *next, struct list_head *list, member)
352 | These ease the process of dealing with a list containing a given type of
353 | structure. Cursor is a pointer to the containing structure type. Member
354 | is the name of the list_head structure within the containing structure. With
355 | these macros, there is no need to put list_entry calls inside the loop.
356 | ```
357 |
358 | Inside `` are additional declarations. hlist is a doubly linked list with a separate, single-pointer list head type used for hash tables. There is some other stuff related to a Read-Copy-Update mechanism. You have options if you need them.
359 |
--------------------------------------------------------------------------------
/Code_Examples/Block_Driver/Makefile:
--------------------------------------------------------------------------------
1 | MODULE_NAME := domsblockdev
2 | obj-m := $(MODULE_NAME).o
3 |
4 | OBJ_LIST := domblockdev.o
5 | $(MODULE_NAME)-y += $(OBJ_LIST)
6 |
7 | ccflags-y := -O2
8 |
9 | KERNELDIR := /lib/modules/$(shell uname -r)/build
10 |
11 | all: domblockdev
12 |
13 | domblockdev:
14 | make -C $(KERNELDIR) M=$(PWD) modules
15 |
--------------------------------------------------------------------------------
/Code_Examples/Block_Driver/README.md:
--------------------------------------------------------------------------------
1 | # The Block Party
2 |
3 | Let's have some fun with block devices and Shakespeare. I promise this is more fun than it sounds. Well, for me it is anyways.
4 |
5 | Start by downloading the four files here: `domblockdev.c`, the `Makefile`, `fun_text`, and `sonnet`. Next, use `make` from the command line to create the usual kernel object. This time it will be called `domsblockdev.ko` (creatively named after some person named Dom). Insert the module like usual:
6 |
7 | ```shell
8 | $ insmod domsblockdev.ko
9 | ```
10 |
11 | With dmesg looking like this:
12 |
13 | ```shell
14 | [ +13.834971] domblockdev: The block device was created! Congrats!
15 | ```
16 |
17 | First, let's check on some info about our ramdisk that was just created:
18 |
19 | ```shell
20 | $ cat /sys/block/domblockdev-0/uevent
21 |
22 | MAJOR=252
23 | MINOR=0
24 | DEVNAME=domblockdev-0
25 | DEVTYPE=disk
26 | ```
27 |
28 | This all looks good. Now, let's write some info to the disk. Let's start with the sample text found in `fun_text`:
29 |
30 | ```shell
31 | $ dd if=fun_text of=/dev/domblockdev-0 bs=512 count=1 seek=0
32 | ```
33 |
34 | - This takes the text from the file fun_text and writes it to the start of domblockdev-0
35 | - We have set the block size to 512 (a good default because the kernel counts in 512 byte increments for file transfer)
36 | - We set the count to 1 (number of blocks to transfer)
37 | - We set seek to 0 (the offest of where to start writing, in 512-byte chunks)
38 |
39 | dmesg will look like this while the write takes place:
40 |
41 | ```shell
42 | [Apr26 14:41] domblockdev: Device was opened
43 | [ +0.000101] domblockdev: Request start from sector 0
44 | [ +0.000004] domblockdev: Request process 4096 bytes
45 | [ +0.000143] domblockdev: Request start from sector 0
46 | [ +0.000006] domblockdev: Request process 4096 bytes
47 | [ +0.000098] domblockdev: Device was closed
48 | ```
49 |
50 | And we can read our ramdisk now with this command to see the contents of that file:
51 |
52 | ```
53 | $ cat /dev/domblockdev-0
54 |
55 | Hello! You are copying this data from the disk in user space
56 | into your block driver! If you can read all of this, you did it correctly!
57 | ```
58 |
59 | Now, let's have a bit more fun with Shakespeare. I have included one of his wonderful sonnets in a file called `sonnet` that is about 619 bytes long (longer than that magic 512 byte size thing that the kernel likes). Let's start by writing the sonnet to the ram disk AFTER our current text that we have. We do that with:
60 |
61 | ```shell
62 | $ dd if=sonnet of=/dev/domblockdev-0 bs=512 count=2 seek=1
63 |
64 |
65 | 1+1 records in
66 | 1+1 records out
67 | 619 bytes copied, 0.00066355 s, 933 kB/s
68 | ```
69 |
70 | - We use sonnet as the `if` argument for dd to write that data to the disk (see `man dd` for more info).
71 | - We use the same block size of 512 bytes
72 | - We use a count of 2 because our file is larger than the 512 size
73 | - We set seek to 1 to write AFTER the first block of 512 bytes that we already wrote to before
74 |
75 | The result is the ram disk looks like this:
76 |
77 | ```shell
78 | $ cat /dev/domblockdev-0
79 |
80 | Hello! You are copying this data from the disk in user space into your block driver!
81 | If you can read all of this, you did it correctly!
82 | Shall I compare thee to a summer's day?
83 | Thou art more lovely and more temperate:
84 | Rough winds do shake the darling buds of May,
85 | And summer's lease hath all too short a date:
86 | Sometime too hot the eye of heaven shines,
87 | And often is his gold complexion dimm'd;
88 | And every fair from fair sometime declines,
89 | By chance or nature's changing course untrimm'd;
90 | But thy eternal summer shall not fade
91 | Nor lose possession of that fair thou owest;
92 | Nor shall Death brag thou wander'st in his shade,
93 | When in eternal lines to time thou growest:
94 | So long as men can breathe or eyes can see,
95 | So long lives this and this gives life to thee.
96 | ```
97 |
98 | There we have it! We have now stored multiple different files into different locations on the ramdisk. Now, lets dump all of the ramdisk data into a file on our real disk:
99 |
100 | ```shell
101 | $ dd if=/dev/domblockdev-0 of=testoutput bs=512 count=3 seek=0
102 |
103 | 3+0 records in
104 | 3+0 records out
105 | 1536 bytes (1.5 kB, 1.5 KiB) copied, 0.00057702 s, 2.7 MB/s
106 | ```
107 |
108 | - Here we use /dev/domblockdev-0 as the `if` argument
109 | - We want to copy from this device now
110 | - We create a new file called `testoutput` to dump the data into
111 | - Same block size
112 | - Count is now 3 to include ALL the data we wrote
113 | - Seek is 0 because we started writing data at the beginning of our ramdisk
114 |
115 | We can then check the file we just created with:
116 |
117 | ```shell
118 | $ cat testoutput
119 |
120 | Hello! You are copying this data from the disk in user space into your block driver!
121 | If you can read all of this, you did it correctly!
122 | Shall I compare thee to a summer's day?
123 | Thou art more lovely and more temperate:
124 | Rough winds do shake the darling buds of May,
125 | And summer's lease hath all too short a date:
126 | Sometime too hot the eye of heaven shines,
127 | And often is his gold complexion dimm'd;
128 | And every fair from fair sometime declines,
129 | By chance or nature's changing course untrimm'd;
130 | But thy eternal summer shall not fade
131 | Nor lose possession of that fair thou owest;
132 | Nor shall Death brag thou wander'st in his shade,
133 | When in eternal lines to time thou growest:
134 | So long as men can breathe or eyes can see,
135 | So long lives this and this gives life to thee.
136 | ```
137 |
138 | It matched! Look at that! Now, play around with this driver and see how it works in detail with reading and writing. There are a lot of cool things you can do to explore (and break) this driver. Have fun!
139 |
--------------------------------------------------------------------------------
/Code_Examples/Block_Driver/domblockdev.c:
--------------------------------------------------------------------------------
1 | // Sample Ramdisk for Kernel Versions 5.3+
2 | // Based off the example provided by CodeImp for Kernel 5.0
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include //for struct hd_geometry
13 | #include //for CDROM_GET_CAPABILITY
14 |
15 | // constants - instead defines
16 | static const char* _device_name = "domblockdev";
17 | static const size_t _buffer_size = 16 * PAGE_SIZE;
18 |
19 | // types
20 | typedef struct domblockdev_cmd_s {
21 | } domblockdev_cmd_t;
22 |
23 | // The internal representation of our device
24 | typedef struct domblockdev_device_s {
25 | sector_t capacity; // Device size in bytes
26 | u8* data; // The data aray. u8 - 8 bytes
27 | atomic_t open_counter; // How many openers
28 | struct blk_mq_tag_set tag_set;
29 | struct request_queue *queue; // For mutual exclusion
30 | struct gendisk *disk; // The gendisk structure
31 | } domblockdev_device_t;
32 |
33 | // global variables
34 | static int _domblockdev_major = 0;
35 | static domblockdev_device_t* _domblockdev_device = NULL;
36 |
37 | // functions
38 | static int domblockdev_allocate_buffer(domblockdev_device_t* dev) {
39 | dev->capacity = _buffer_size >> SECTOR_SHIFT;
40 | dev->data = kmalloc(dev->capacity << SECTOR_SHIFT, GFP_KERNEL); //
41 | if (dev->data == NULL) {
42 | printk(KERN_WARNING "domblockdev: vmalloc failure\n");
43 | return -ENOMEM;
44 | }
45 |
46 | return 0;
47 | }
48 |
49 | static void domblockdev_free_buffer(domblockdev_device_t* dev) {
50 | if (dev->data) {
51 | kfree(dev->data);
52 | dev->data = NULL;
53 | dev->capacity = 0;
54 | }
55 | }
56 |
57 | static void domblockdev_remove_device(void) {
58 | domblockdev_device_t* dev = _domblockdev_device;
59 | if (dev == NULL)
60 | return;
61 |
62 | if (dev->disk)
63 | del_gendisk(dev->disk);
64 |
65 | if (dev->queue) {
66 | blk_cleanup_queue(dev->queue);
67 | dev->queue = NULL;
68 | }
69 |
70 | if (dev->tag_set.tags)
71 | blk_mq_free_tag_set(&dev->tag_set);
72 |
73 | if (dev->disk) {
74 | put_disk(dev->disk);
75 | dev->disk = NULL;
76 | }
77 |
78 | domblockdev_free_buffer(dev);
79 | kfree(dev);
80 | _domblockdev_device = NULL;
81 | printk(KERN_WARNING "domblockdev: The block device was removed!\n");
82 | }
83 |
84 | static int do_simple_request(struct request *rq, unsigned int *nr_bytes) {
85 | int ret = 0;
86 | struct bio_vec bvec;
87 | struct req_iterator iter;
88 | domblockdev_device_t *dev = rq->q->queuedata;
89 | loff_t pos = blk_rq_pos(rq) << SECTOR_SHIFT;
90 | loff_t dev_size = (loff_t)(dev->capacity << SECTOR_SHIFT);
91 |
92 | printk(KERN_WARNING "domblockdev: Request start from sector %lld \n", blk_rq_pos(rq));
93 |
94 | rq_for_each_segment(bvec, rq, iter) {
95 | unsigned long b_len = bvec.bv_len;
96 | void* b_buf = page_address(bvec.bv_page) + bvec.bv_offset;
97 |
98 | if ((pos + b_len) > dev_size)
99 | b_len = (unsigned long)(dev_size - pos);
100 | if (rq_data_dir(rq)) //WRITE data to ramdisk
101 | memcpy(dev->data + pos, b_buf, b_len);
102 | else //READ data from ramdisk
103 | memcpy(b_buf, dev->data + pos, b_len);
104 |
105 | pos += b_len;
106 | *nr_bytes += b_len;
107 | }
108 |
109 | return ret;
110 | }
111 |
112 | static blk_status_t _queue_rq(struct blk_mq_hw_ctx *hctx, const struct blk_mq_queue_data* bd) {
113 | unsigned int nr_bytes = 0;
114 | blk_status_t status = BLK_STS_OK;
115 | struct request *rq = bd->rq;
116 | blk_mq_start_request(rq); //we cannot use any locks that make the thread sleep
117 |
118 | if (do_simple_request(rq, &nr_bytes) != 0)
119 | status = BLK_STS_IOERR;
120 |
121 | printk(KERN_WARNING "domblockdev: Request process %d bytes\n", nr_bytes);
122 |
123 | if (blk_update_request(rq, status, nr_bytes)) //GPL-only symbol
124 | BUG();
125 |
126 | __blk_mq_end_request(rq, status);
127 |
128 | return BLK_STS_OK;//always return ok
129 | }
130 |
131 | static struct blk_mq_ops _mq_ops = {
132 | .queue_rq = _queue_rq,
133 | };
134 |
135 | static int _open(struct block_device *bdev, fmode_t mode) {
136 | domblockdev_device_t* dev = bdev->bd_disk->private_data;
137 | if (dev == NULL) {
138 | printk(KERN_WARNING "domblockdev: Invalid disk private_data\n");
139 | return -ENXIO;
140 | }
141 | atomic_inc(&dev->open_counter);
142 | printk(KERN_WARNING "domblockdev: Device was opened\n");
143 |
144 | return 0;
145 | }
146 |
147 | static void _release(struct gendisk *disk, fmode_t mode) {
148 | domblockdev_device_t* dev = disk->private_data;
149 | if (dev) {
150 | atomic_dec(&dev->open_counter);
151 | printk(KERN_WARNING "domblockdev: Device was closed\n");
152 | }
153 | else
154 | printk(KERN_WARNING "domblockdev: Invalid disk private_data\n");
155 | }
156 |
157 | static int _getgeo(domblockdev_device_t* dev, struct hd_geometry* geo) {
158 | sector_t quotient;
159 | geo->start = 0;
160 | if (dev->capacity > 63) {
161 | geo->sectors = 63;
162 | quotient = (dev->capacity + (63 - 1)) / 63;
163 |
164 | if (quotient > 255) {
165 | geo->heads = 255;
166 | geo->cylinders = (unsigned short)((quotient + (255 - 1)) / 255);
167 | }
168 | else {
169 | geo->heads = (unsigned char)quotient;
170 | geo->cylinders = 1;
171 | }
172 | }
173 | else {
174 | geo->sectors = (unsigned char)dev->capacity;
175 | geo->cylinders = 1;
176 | geo->heads = 1;
177 | }
178 | return 0;
179 | }
180 |
181 | static int _ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) {
182 | int ret = -ENOTTY;
183 | domblockdev_device_t* dev = bdev->bd_disk->private_data;
184 | printk(KERN_WARNING "domblockdev: ioctl %x received\n", cmd);
185 |
186 | switch (cmd) {
187 | case HDIO_GETGEO: {
188 | struct hd_geometry geo;
189 | ret = _getgeo(dev, &geo );
190 |
191 | if (copy_to_user((void *)arg, &geo, sizeof(struct hd_geometry)))
192 | ret = -EFAULT;
193 | else
194 | ret = 0;
195 | break;
196 | }
197 | case CDROM_GET_CAPABILITY: {//0x5331 / * get capabilities * /
198 | struct gendisk *disk = bdev->bd_disk;
199 | if (bdev->bd_disk && (disk->flags & GENHD_FL_CD))
200 | ret = 0;
201 | else
202 | ret = -EINVAL;
203 | break;
204 | }
205 | }
206 |
207 | return ret;
208 | }
209 |
210 | static const struct block_device_operations _fops = {
211 | .owner = THIS_MODULE,
212 | .open = _open,
213 | .release = _release,
214 | .ioctl = _ioctl,
215 | };
216 |
217 | // For adding the block device disk to the system
218 | static int domblockdev_add_device(void) {
219 | int ret = 0;
220 |
221 | domblockdev_device_t* dev = kzalloc(sizeof(domblockdev_device_t), GFP_KERNEL);
222 | if (dev == NULL) {
223 | printk(KERN_WARNING "domblockdev: Failed to allocate %ld bytes\n", sizeof(domblockdev_device_t));
224 | return -ENOMEM;
225 | }
226 | _domblockdev_device = dev;
227 |
228 | do{
229 | ret = domblockdev_allocate_buffer(dev);
230 | if(ret)
231 | break;
232 |
233 | {// configure tag_set
234 | dev->tag_set.ops = &_mq_ops;
235 | dev->tag_set.nr_hw_queues = 1;
236 | dev->tag_set.queue_depth = 128;
237 | dev->tag_set.numa_node = NUMA_NO_NODE;
238 | dev->tag_set.cmd_size = sizeof(domblockdev_cmd_t);
239 | dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
240 | dev->tag_set.driver_data = dev;
241 |
242 | ret = blk_mq_alloc_tag_set(&dev->tag_set);
243 | if (ret) {
244 | printk(KERN_WARNING "domblockdev: Failed to allocate tag set\n");
245 | break;
246 | }
247 | }
248 |
249 | {//configure queue
250 | struct request_queue *queue = blk_mq_init_queue(&dev->tag_set);
251 | if (IS_ERR(queue)) {
252 | ret = PTR_ERR(queue);
253 | printk(KERN_WARNING "domblockdev: Failed to allocate queue\n");
254 | break;
255 | }
256 | dev->queue = queue;
257 | }
258 | dev->queue->queuedata = dev;
259 |
260 | {// configure disk
261 | struct gendisk *disk = alloc_disk(1); //only one partition
262 | if (disk == NULL) {
263 | printk(KERN_WARNING "domblockdev: Failed to allocate disk\n");
264 | ret = -ENOMEM;
265 | break;
266 | }
267 | disk->flags |= GENHD_FL_NO_PART_SCAN; //only one partition
268 | disk->flags |= GENHD_FL_REMOVABLE;
269 | disk->major = _domblockdev_major;
270 | disk->first_minor = 0;
271 | disk->fops = &_fops;
272 | disk->private_data = dev;
273 | disk->queue = dev->queue;
274 | sprintf(disk->disk_name, "domblockdev-%d", 0);
275 | set_capacity(disk, dev->capacity);
276 |
277 | dev->disk = disk;
278 | add_disk(disk);
279 | }
280 | printk(KERN_WARNING "domblockdev: The block device was created! Congrats!\n");
281 | }while(false); // The reason for the do...while loop is to add individual break points for each section
282 |
283 | if (ret){
284 | domblockdev_remove_device();
285 | printk(KERN_WARNING "domblockdev: Failed add block device\n");
286 | }
287 |
288 | return ret;
289 | }
290 |
291 | static int __init domblockdev_init(void) {
292 | int ret = 0;
293 |
294 | _domblockdev_major = register_blkdev(_domblockdev_major, _device_name);
295 | if (_domblockdev_major <= 0){
296 | printk(KERN_WARNING "domblockdev: Unable to get major number\n");
297 | return -EBUSY;
298 | }
299 | ret = domblockdev_add_device();
300 | if (ret)
301 | unregister_blkdev(_domblockdev_major, _device_name);
302 |
303 | return ret;
304 | }
305 |
306 | static void __exit domblockdev_exit(void) {
307 | domblockdev_remove_device();
308 | if (_domblockdev_major > 0)
309 | unregister_blkdev(_domblockdev_major, _device_name);
310 | }
311 |
312 | module_init(domblockdev_init);
313 | module_exit(domblockdev_exit);
314 |
315 | MODULE_LICENSE("GPL");
316 | MODULE_AUTHOR("DOM");
317 |
--------------------------------------------------------------------------------
/Code_Examples/Block_Driver/fun_text:
--------------------------------------------------------------------------------
1 | Hello! You are copying this data from the disk in user space into your block driver! If you can read all of this, you did it correctly!
2 |
--------------------------------------------------------------------------------
/Code_Examples/Block_Driver/sonnet:
--------------------------------------------------------------------------------
1 | Shall I compare thee to a summer's day?
2 | Thou art more lovely and more temperate:
3 | Rough winds do shake the darling buds of May,
4 | And summer's lease hath all too short a date:
5 | Sometime too hot the eye of heaven shines,
6 | And often is his gold complexion dimm'd;
7 | And every fair from fair sometime declines,
8 | By chance or nature's changing course untrimm'd;
9 | But thy eternal summer shall not fade
10 | Nor lose possession of that fair thou owest;
11 | Nor shall Death brag thou wander'st in his shade,
12 | When in eternal lines to time thou growest:
13 | So long as men can breathe or eyes can see,
14 | So long lives this and this gives life to thee.
15 |
--------------------------------------------------------------------------------
/Code_Examples/Char_Driver/Makefile:
--------------------------------------------------------------------------------
1 | # If KERNELRELEASE is defined, we've been invoked from the
2 | # kernel build system and can use its language.
3 | ARCH := x86
4 | C_FLAGS := -Wall
5 |
6 | ifneq ($(KERNELRELEASE),)
7 | obj-m := main.o
8 | # Otherwise we were called directly from the command
9 | # line; invoke the kernel build system.
10 | else
11 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
12 | PWD := $(shell pwd)
13 | default:
14 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
15 | endif
16 |
--------------------------------------------------------------------------------
/Code_Examples/Char_Driver/README.md:
--------------------------------------------------------------------------------
1 | ### Alright this is a bit more than Hello_world
2 |
3 | First, take a scroll through the source file. It has many comments!
4 |
5 | First, make main.ko from the source and makefile. When you insert the module you should see this output:
6 |
7 | ```shell
8 | [Apr25 20:52] Successfully started DOMCHARDEV-(237, 0)
9 | [ +0.000094] Successfully started DOMCHARDEV-(237, 1)
10 | [ +0.000101] Successfully started DOMCHARDEV-(237, 2)
11 | [ +0.000081] Successfully started DOMCHARDEV-(237, 3)
12 | ```
13 |
14 | One thing you can do is read from the devices:
15 |
16 | ```
17 | $ head -1 /dev/domchardev-0
18 |
19 | Hello from the kernel world! This is Dom's char device!
20 | ```
21 |
22 | And corresponding dmesg output:
23 |
24 | ```shell
25 | [ +4.833332] DOMCHARDEV-0: Device open
26 | [ +0.000012] Reading device number: (237, 0)
27 | [ +0.000031] DOMCHARDEV-0: Device close
28 | ```
29 |
30 | Another thing you can do is write to the device:
31 |
32 | ```shell
33 | $ echo "hi there!" > /dev/domchardev-0
34 | ```
35 |
36 | And corresponding dmesg output:
37 |
38 | ```shell
39 | [ +15.280692] DOMCHARDEV-0: Device open
40 | [ +0.000027] Writing device number: (237, 0)
41 | [ +0.000002] Copied 10 bytes from the user
42 | [ +0.000003] Data from the user: hi there!
43 | [ +0.000008] DOMCHARDEV-0: Device close
44 | ```
45 |
46 | You can also access the uevent structure:
47 |
48 | ```shell
49 | $ cat /sys/dev/char/237\:0/uevent # replace with your device major/minor numbers!
50 |
51 | MAJOR=237
52 | MINOR=0
53 | DEVNAME=domchardev-0
54 | DEVMODE=0666
55 | ```
56 |
--------------------------------------------------------------------------------
/Code_Examples/Char_Driver/main.c:
--------------------------------------------------------------------------------
1 | // Example Char Driver on Linux
2 | // Originally inspired by Oleg Kutkov
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | //Set this to whatever you want - it will create more/less virtual devices
13 | #define MAX_DEVICES 4
14 |
15 | // Define the functions for open, release, ioctl, read, and write for the char driver
16 | static int dom_chardev_open (struct inode *inode, struct file *file);
17 | static int dom_chardev_release(struct inode *inode, struct file *file);
18 | static long dom_chardev_ioctl (struct file *file, unsigned int cmd, unsigned long arg);
19 | static ssize_t dom_chardev_read (struct file *file, char __user *buf, size_t count, loff_t *offset);
20 | static ssize_t dom_chardev_write (struct file *file, const char __user *buf, size_t count, loff_t *offset);
21 |
22 | // Create and populate a struct for the file operations
23 | static const struct file_operations dom_chardev_fops = {
24 | .owner = THIS_MODULE,
25 | .open = dom_chardev_open,
26 | .release = dom_chardev_release,
27 | .unlocked_ioctl = dom_chardev_ioctl,
28 | .read = dom_chardev_read,
29 | .write = dom_chardev_write
30 | };
31 |
32 | // This creates a cdev struct
33 | struct dom_char_device_data {
34 | struct cdev dom_cdev;
35 | };
36 |
37 | // Setting dev_major to 0 means dynamically allocate a new major device number for the module - whatever is free
38 | // This is a good practice to avoid conflicts with other modules and drivers
39 | static int dev_major = 0;
40 |
41 | // We don't require a class here. Set up as many devices that we wanted earlier with MAX_DEVICES
42 | static struct class *dom_chardev_class = NULL;
43 | static struct dom_char_device_data dom_chardev_data[MAX_DEVICES];
44 |
45 | //This is for the uevent. From what I can tell, performing cat uevent gives info on the particular device
46 | static int dom_chardev_uevent(struct device *dev, struct kobj_uevent_env *env)
47 | {
48 | add_uevent_var(env, "DEVMODE=%#o", 0666);
49 | return 0;
50 | }
51 |
52 | // Initialization function. Only runs at initialization as seen with the __init. This is destroyed when module is loaded
53 | static int __init dom_chardev_init(void)
54 | {
55 | int err, i; //initialize err and i. err is not used later on. i is the iterator number
56 | dev_t dev; //define a new dev of the dev_t type
57 |
58 | // Allocate major and minor numbers for each device
59 | // Start at 0, go up to MAX_DEVICES, name domchardev
60 | err = alloc_chrdev_region(&dev, 0, MAX_DEVICES, "domchardev");
61 |
62 | //Find the major number of the device using the MAJOR() macro
63 | dev_major = MAJOR(dev);
64 |
65 | // Create the class and add the uevent. Not quite sure what this does.
66 | dom_chardev_class = class_create(THIS_MODULE, "domchardev");
67 | dom_chardev_class->dev_uevent = dom_chardev_uevent;
68 |
69 | // Run a for loop to create MAX_DEVICES number of devices
70 | for (i = 0; i < MAX_DEVICES; i++) {
71 |
72 | // The first option is the cdev from the struct for the particular device. Second option is
73 | // the file operations struct defined before
74 | cdev_init(&dom_chardev_data[i].dom_cdev, &dom_chardev_fops);
75 |
76 | // Set the owner to be THIS_MODULE on the device
77 | dom_chardev_data[i].dom_cdev.owner = THIS_MODULE;
78 |
79 | // Add the device to the system. The MKDEV macro makes a device with the major and minor numbers specified
80 | cdev_add(&dom_chardev_data[i].dom_cdev, MKDEV(dev_major, i), 1);
81 |
82 | // Create a device file node and register with sysfs
83 | device_create(dom_chardev_class, NULL, MKDEV(dev_major, i), NULL, "domchardev-%d", i);
84 |
85 | //print that devices have started
86 | printk("Successfully started DOMCHARDEV-(%d, %d)\n", dev_major, i);
87 | }
88 |
89 | return 0;
90 | }
91 |
92 | // Meant only for __exit when closing the driver
93 | static void __exit dom_chardev_exit(void)
94 | {
95 | int i;
96 |
97 | // Destroy the devices and print a message saying so
98 | for (i = 0; i < MAX_DEVICES; i++) {
99 | device_destroy(dom_chardev_class, MKDEV(dev_major, i));
100 | //print that devices have started
101 | printk("Successfully destroyed DOMCHARDEV-(%d, %d)\n", dev_major, i);
102 | }
103 |
104 | // Unregister the class, then destroy it
105 | class_unregister(dom_chardev_class);
106 | class_destroy(dom_chardev_class);
107 |
108 | unregister_chrdev_region(MKDEV(dev_major, 0), MINORMASK);
109 | }
110 |
111 | static int dom_chardev_open(struct inode *inode, struct file *file)
112 | {
113 | // Simply print that the device has been opened
114 | printk("DOMCHARDEV-%d: Device open\n", MINOR(file->f_path.dentry->d_inode->i_rdev));
115 | return 0;
116 | }
117 |
118 | static int dom_chardev_release(struct inode *inode, struct file *file)
119 | {
120 | // Simply print that the device has been closed
121 | printk("DOMCHARDEV-%d: Device close\n", MINOR(file->f_path.dentry->d_inode->i_rdev));
122 | return 0;
123 | }
124 |
125 | static long dom_chardev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
126 | {
127 | // ioctl stuff
128 | printk("DOMCHARDEV-%d: Device ioctl\n", MINOR(file->f_path.dentry->d_inode->i_rdev));
129 | return 0;
130 | }
131 |
132 | // read function for the fops struct
133 | static ssize_t dom_chardev_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
134 | {
135 | uint8_t *data = "Hello from the kernel world! This is Dom's char device!\n";
136 | size_t datalen = strlen(data);
137 |
138 | printk("Reading device number: (%d, %d)\n", dev_major, MINOR(file->f_path.dentry->d_inode->i_rdev));
139 |
140 | // Saturate count to data length if needed
141 | if (count > datalen) {
142 | count = datalen;
143 | }
144 |
145 | // If the copy of data fails, return the EFault. The copy_to_user should also give the user the data
146 | if (copy_to_user(buf, data, count)) {
147 | return -EFAULT;
148 | }
149 |
150 | // This should return the number of bytes transferred to the read
151 | return count;
152 | }
153 |
154 | static ssize_t dom_chardev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
155 | {
156 | //Check my counting logic here. I could be off
157 | size_t maxdatalen = 10;
158 | unsigned long ncopied;
159 | uint8_t databuf[10];
160 | size_t overflow = 0;
161 |
162 | // Use this for debugging count stuff
163 | //printk("Size of count: %zd\n", count);
164 |
165 | printk("Writing device number: (%d, %d)\n", dev_major, MINOR(file->f_path.dentry->d_inode->i_rdev));
166 |
167 | //truncate maxdatalen if the bytes to send is less than maxdatalen
168 | if (maxdatalen > count) {
169 | maxdatalen = count;
170 | }
171 | //Warn if too much data is trying to be written
172 | else if (maxdatalen < (count)){
173 | overflow = count - maxdatalen;
174 | printk("Too big of an input. Unable to copy %ld byte(s) from the user\n", (overflow));
175 | }
176 |
177 | ncopied = copy_from_user(databuf, buf, maxdatalen);
178 |
179 | //Print the number of copied bytes from the user
180 | printk("Copied %zd bytes from the user\n", maxdatalen);
181 | databuf[maxdatalen] = 0;
182 |
183 | //Print the copied bytes from the user
184 | printk("Data from the user: %s\n", databuf);
185 |
186 | return count;
187 | }
188 |
189 | module_init(dom_chardev_init);
190 | module_exit(dom_chardev_exit);
191 |
192 | MODULE_LICENSE("Dual MIT/GPL");
193 | MODULE_AUTHOR("Dom");
194 |
--------------------------------------------------------------------------------
/Code_Examples/Hello_World/Makefile:
--------------------------------------------------------------------------------
1 | # If KERNELRELEASE is defined, we've been invoked from the
2 | # kernel build system and can use its language.
3 | ifneq ($(KERNELRELEASE),)
4 | obj-m := hello.o
5 | # Otherwise we were called directly from the command
6 | # line; invoke the kernel build system.
7 | else
8 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
9 | PWD := $(shell pwd)
10 | default:
11 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
12 | endif
13 |
--------------------------------------------------------------------------------
/Code_Examples/Hello_World/README.md:
--------------------------------------------------------------------------------
1 | ### Your First Driver (have fun, get frustrated, break stuff, fix stuff)
2 |
3 | This is my version of the hello_world that you will see for just about every programming language. It is meant to introduce the concepts of compiling, loading, and viewing a kernel module in action.
4 |
5 | First, make sure you have the proper kernel source files on your machine:
6 |
7 | ```shell
8 | $ sudo apt install build-essential linux-headers-$(uname -r)
9 | ```
10 |
11 | Next, put these files into a separate directory (can be wherever). You will need `hello.c` and `Makefile`. Next, login as root using:
12 |
13 | ```shell
14 | $ sudo -s
15 | ```
16 |
17 | And then run:
18 |
19 | ```shell
20 | $ make
21 | ```
22 |
23 | Your output may look similar to this:
24 |
25 | ```shell
26 | make -C /lib/modules/5.3.0-7648-generic/build M=/home/dom/LDD3-Notes/Code_Examples/Hello_World modules
27 | make[1]: Entering directory '/usr/src/linux-headers-5.3.0-7648-generic'
28 | CC [M] /home/dom/LDD3-Notes/Code_Examples/Hello_World/hello.o
29 | Building modules, stage 2.
30 | MODPOST 1 modules
31 | CC /home/dom/LDD3-Notes/Code_Examples/Hello_World/hello.mod.o
32 | LD [M] /home/dom/LDD3-Notes/Code_Examples/Hello_World/hello.ko
33 | make[1]: Leaving directory '/usr/src/linux-headers-5.3.0-7648-generic'
34 | ```
35 |
36 | Running a simple ls -l reveals a lot of files!
37 |
38 | ```shell
39 | $ ls -l
40 |
41 | -rw-r--r-- 1 dom dom 2271 Feb 12 12:20 hello.c
42 | -rw-r--r-- 1 root root 7984 Apr 25 15:25 hello.ko
43 | -rw-r--r-- 1 root root 56 Apr 25 15:25 hello.mod
44 | -rw-r--r-- 1 root root 646 Apr 25 15:25 hello.mod.c
45 | -rw-r--r-- 1 root root 2800 Apr 25 15:25 hello.mod.o
46 | -rw-r--r-- 1 root root 6072 Apr 25 15:25 hello.o
47 | -rw-r--r-- 1 dom dom 378 Feb 12 12:20 Makefile
48 | -rw-r--r-- 1 root root 56 Apr 25 15:25 modules.order
49 | -rw-r--r-- 1 root root 0 Apr 25 15:25 Module.symvers
50 | ```
51 |
52 | The one we are interested in now is called `hello.ko`. This is our kernel object. Now we can load it into the kernel with:
53 |
54 | ```shell
55 | $ insmod hello.ko
56 | ```
57 |
58 | Now, in another terminal, we can look at the output of the module to the kernel log with:
59 |
60 | ```shell
61 | $ dmesg -wH
62 |
63 | [Apr25 17:27] Hello, world
64 | =============
65 | [ +0.000004] short integer: 1
66 | [ +0.000002] integer: 56
67 | [ +0.000002] long integer: 1900
68 | [ +0.000002] string: test string
69 | [ +0.000002] intArray[0] = 1
70 | [ +0.000001] intArray[1] = 2
71 | [ +0.000002] intArray[2] = 3
72 | [ +0.000001] intArray[3] = 4
73 | [ +0.000002] intArray[4] = 5
74 | [ +0.000001] intArray[5] = -8
75 | [ +0.000002] got 0 arguments for intArray.
76 | ```
77 |
78 | The module can be removed with:
79 |
80 | ```shell
81 | $ rmmod hello
82 | ```
83 |
84 | And the resulting output in dmesg will look like:
85 |
86 | ```shell
87 | [Apr25 18:14] Goodbye, cruel world!
88 | ```
89 |
90 | Now for some fun - passing command line arguments to a module:
91 |
92 | ```shell
93 | $ insmod hello.ko short_int=4 reg_int=5 long_int=56789 sample_string="The_answer_is_42" intArray=9,9,9
94 | ```
95 |
96 |
97 | ```shell
98 | [ +5.091416] Hello, world
99 | =============
100 | [ +0.000004] short integer: 4
101 | [ +0.000002] integer: 5
102 | [ +0.000002] long integer: 56789
103 | [ +0.000002] string: The_answer_is_42
104 | [ +0.000002] intArray[0] = 9
105 | [ +0.000002] intArray[1] = 9
106 | [ +0.000001] intArray[2] = 9
107 | [ +0.000002] intArray[3] = 4
108 | [ +0.000002] intArray[4] = 5
109 | [ +0.000002] intArray[5] = -8
110 | [ +0.000002] got 3 arguments for intArray.
111 | ```
112 |
--------------------------------------------------------------------------------
/Code_Examples/Hello_World/hello.c:
--------------------------------------------------------------------------------
1 | // Hello.c file demonstartes command line argument passing with the kernel
2 |
3 | // Start by including the appropriate header files
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | // Give it some sort of license and author so that the kernel does not complain
11 | MODULE_LICENSE("GPL");
12 | MODULE_AUTHOR("DSR");
13 |
14 | // Lets initialize some variables of a bunch of different types to play with
15 | static short int short_int = 1;
16 | static int reg_int = 56;
17 | static long int long_int = 1900;
18 | static char *sample_string = "test string";
19 | static int intArray[6] = {1,2,3,4,5,-8};
20 | static int arr_argc = 0;
21 |
22 |
23 | /* This part introduces command line parameter passing
24 | * module_param(foo, int, 0000)
25 | * The first param is the parameters name
26 | * The second param is it's data type
27 | * The final argument is the permissions bits,
28 | * for exposing parameters in sysfs (if non-zero) at a later stage.
29 | */
30 | module_param(short_int, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
31 | MODULE_PARM_DESC(short_int, "A short integer example");
32 | module_param(reg_int, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
33 | MODULE_PARM_DESC(reg_int, "A normal integer example");
34 | module_param(long_int, long, S_IRUSR);
35 | MODULE_PARM_DESC(long_int, "A long integer example");
36 | module_param(sample_string, charp, 0000);
37 | MODULE_PARM_DESC(sample_string, "A character string example");
38 |
39 | /* There is a slightly different setup for passing an array of parameters
40 | * module_param_array(name, type, num, perm);
41 | * The first param is the parameter's (in this case the array's) name
42 | * The second param is the data type of the elements of the array
43 | * The third argument is a pointer to the variable that will store the number
44 | * of elements of the array initialized by the user at module loading time
45 | * The fourth argument is the permission bits
46 | */
47 | module_param_array(intArray, int, &arr_argc, 0000);
48 | MODULE_PARM_DESC(intArray, "An array of integers");
49 |
50 | static int __init hello_init(void)
51 | {
52 | int i;
53 | printk(KERN_INFO "Hello, world \n============= \n");
54 | printk(KERN_INFO "short integer: %hd\n", short_int);
55 | printk(KERN_INFO "integer: %d\n", reg_int);
56 | printk(KERN_INFO "long integer: %ld\n", long_int);
57 | printk(KERN_INFO "string: %s\n", sample_string);
58 | for (i = 0; i < (sizeof intArray / sizeof (int)); i++)
59 | {
60 | printk(KERN_INFO "intArray[%d] = %d\n", i, intArray[i]);
61 | }
62 | printk(KERN_INFO "got %d arguments for intArray.\n", arr_argc);
63 | return 0;
64 | }
65 |
66 | static void __exit hello_exit(void)
67 | {
68 | printk(KERN_INFO "Goodbye, cruel world!\n");
69 | }
70 |
71 | module_init(hello_init);
72 | module_exit(hello_exit);
73 |
--------------------------------------------------------------------------------
/Code_Examples/Net_Driver/Makefile:
--------------------------------------------------------------------------------
1 | MODULE_NAME := domnetfilter
2 | obj-m := $(MODULE_NAME).o
3 |
4 | OBJ_LIST := filter.o
5 | $(MODULE_NAME)-y += $(OBJ_LIST)
6 |
7 | ccflags-y := -O2
8 |
9 | KERNELDIR := /lib/modules/$(shell uname -r)/build
10 |
11 | all: filter
12 |
13 | filter:
14 | make -C $(KERNELDIR) M=$(PWD) modules
15 |
--------------------------------------------------------------------------------
/Code_Examples/Net_Driver/README.md:
--------------------------------------------------------------------------------
1 | # Networking Fun
2 | #### No, not the kind where you have to meet a lot of people
3 |
4 | If you want to be really mean to one of your roomates - here is a way to disable all TCP connections on a computer at the kernel level. Start by downloading the two source files, running `make` and inserting the module into the kernel. The module has one input parameter that will enable/disable TCP blocking. First, let's do the normal case:
5 |
6 | ```shell
7 | $ insmod domnetfilter.ko
8 | ```
9 |
10 | With corresponding output in dmesg as:
11 |
12 | ```shell
13 | [Apr26 19:22] domnetfilter: Doms Network Filter Started!
14 | [ +0.000004] domnetfilter: Major number 510
15 | [ +13.188771] domnetfilter: TCP connection initiated from 192.168.1.XXX:XXXXX
16 | [ +0.000003] domnetfilter: Packets allowed to pass!
17 | ```
18 |
19 | - I replaced the exact IP address with X's to denote that these will be different for your machine
20 | - Notice: the module says "Packets allowed to pass!"
21 | - Blocking has not been enabled yet
22 |
23 | Next, we are going to have some fun. To block all TCP, run the module with the following input:
24 |
25 | ```shell
26 | insmod domnetfilter.ko toggle_string="block"
27 | ```
28 |
29 | Now you will see the following in dmesg:
30 |
31 | ```shell
32 | [ +0.447914] domnetfilter: TCP connection initiated from 192.168.1.XXX:XXXXX
33 | [ +0.000047] domnetfilter: Packets being blocked!
34 | ```
35 |
36 | Try and browse the web. Nothing should happen. You will need to run the module again without the blocking flag set to restore TCP packets being delivered.
37 |
38 | Have fun, and don't use this for (pure) evil.
39 |
--------------------------------------------------------------------------------
/Code_Examples/Net_Driver/filter.c:
--------------------------------------------------------------------------------
1 | // Kernel module that blocks/allows tcp connections
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | #include
19 | #include
20 | #include
21 |
22 | #define IOCTL_FILTER_ADDRESS _IOW('k', 1, unsigned int) // Used for creating the ioctl command number
23 |
24 | static char *toggle_string = "no_block";
25 | module_param(toggle_string, charp, 0000);
26 | MODULE_PARM_DESC(toggle_string, "Toggle Blocker on/off");
27 |
28 | static int dom_netfilter_open(struct inode *inode, struct file *file);
29 | static int dom_netfilter_release(struct inode *inode, struct file *file);
30 | static long dom_netfilter_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
31 |
32 | static const struct file_operations fops = {
33 | .owner = THIS_MODULE,
34 | .open = dom_netfilter_open,
35 | .release = dom_netfilter_release,
36 | .unlocked_ioctl = dom_netfilter_ioctl
37 | };
38 |
39 | static unsigned int dom_netfilter_hookfn(void *priv, struct sk_buff *skb, const struct nf_hook_state *state);
40 |
41 | static struct nf_hook_ops net_nfho = {
42 | .hook = dom_netfilter_hookfn,
43 | .hooknum = NF_INET_LOCAL_OUT,
44 | .pf = PF_INET,
45 | .priority = NF_IP_PRI_FIRST
46 | };
47 |
48 | static struct cdev dom_cdev;
49 | static int dev_major = 0;
50 | static atomic_t ioctl_set;
51 | static unsigned int ioctl_set_addr;
52 |
53 | // Test ioctl_set_addr if it has been set.
54 | static int test_daddr(unsigned int dst_addr) {
55 | int ret = 0;
56 |
57 | if (atomic_read(&ioctl_set) == 1)
58 | ret = (ioctl_set_addr == dst_addr);
59 | else
60 | ret = 1;
61 |
62 | return ret;
63 | }
64 |
65 | static unsigned int dom_netfilter_hookfn(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) {
66 | // get IP header
67 | struct iphdr *iph = ip_hdr(skb);
68 |
69 | if (iph->protocol == IPPROTO_TCP && test_daddr(iph->daddr)) {
70 | // then get the TCP header
71 | struct tcphdr *tcph = tcp_hdr(skb);
72 |
73 | // see if the packet was for initiation
74 | if (tcph->syn && !tcph->ack) {
75 | printk("domnetfilter: TCP connection initiated from " "%pI4:%u\n", &iph->saddr, ntohs(tcph->source));
76 | if (!strcmp(toggle_string, "block"))
77 | printk("domnetfilter: Packets being blocked!");
78 | else
79 | printk("domnetfilter: Packets allowed to pass!");
80 | }
81 | }
82 |
83 | // what to do with the packets...
84 | if (!strcmp(toggle_string, "block"))
85 | return NF_DROP;
86 | else
87 | return NF_ACCEPT;
88 | }
89 |
90 | static int dom_netfilter_open(struct inode *inode, struct file *file) {
91 | return 0;
92 | }
93 |
94 | static int dom_netfilter_release(struct inode *inode, struct file *file) {
95 | return 0;
96 | }
97 |
98 | static long dom_netfilter_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
99 | switch (cmd) {
100 | case IOCTL_FILTER_ADDRESS:
101 | if (copy_from_user(&ioctl_set_addr, (void *) arg, sizeof(ioctl_set_addr)))
102 | return -EFAULT;
103 | atomic_set(&ioctl_set, 1);
104 | break;
105 |
106 | default:
107 | return -ENOTTY; //indicates ioctl is not setup properly
108 | }
109 |
110 | return 0;
111 | }
112 |
113 | int __init domnet_init(void) {
114 | int err;
115 | dev_t dev;
116 | err = alloc_chrdev_region(&dev, 0, 1, "domnetfilter");
117 |
118 | //Find the major number of the device using the MAJOR() macro
119 | dev_major = MAJOR(dev);
120 | printk("domnetfilter: Doms Network Filter Started!");
121 | printk("domnetfilter: Major number %d", dev_major);
122 |
123 | atomic_set(&ioctl_set, 0);
124 | ioctl_set_addr = 0;
125 |
126 | cdev_init(&dom_cdev, &fops);
127 | cdev_add(&dom_cdev, MKDEV(dev_major, 0), 1);
128 |
129 | err = nf_register_net_hook(&init_net, &net_nfho);
130 |
131 | if (err)
132 | goto out;
133 |
134 | return 0;
135 |
136 | out:
137 | // cleanup the device if init not successful
138 | printk("domnetfilter: Doms Network Filter Destroyed!");
139 | cdev_del(&dom_cdev);
140 | unregister_chrdev_region(MKDEV(dev_major, 0), 1);
141 | return err;
142 | }
143 |
144 | void __exit domnet_exit(void) {
145 | printk("domnetfilter: Doms Network Filter Destroyed!");
146 | nf_unregister_net_hook(&init_net, &net_nfho);
147 | cdev_del(&dom_cdev);
148 | unregister_chrdev_region(MKDEV(dev_major, 0), 1);
149 | }
150 |
151 | module_init(domnet_init);
152 | module_exit(domnet_exit);
153 |
154 | MODULE_DESCRIPTION("TCP netfilter module");
155 | MODULE_AUTHOR("Dom");
156 | MODULE_LICENSE("GPL");
157 |
--------------------------------------------------------------------------------
/Code_Examples/README.md:
--------------------------------------------------------------------------------
1 | # Code Examples for LDD3 Notes
2 |
3 | ### What You Will Find Here
4 |
5 | The examples you see here are ones that I had to create/modify that you probably won't be able to find an exact version of on someone else's repo.
6 |
7 | ### Other Good Repos
8 |
9 | There appears to be a few people maintaining their own versions of the original LDD3 examples. Here are links to two really good repos to look at for the book examples:
10 |
11 | - [Javier Martinez Canillas LDD3](https://github.com/martinezjavier/ldd3)
12 | - [CU Boulder Fork of the Previous Repo](https://github.com/cu-ecen-5013/ldd3) (this one can sometimes work better)
13 |
14 | ### How to Use These Files
15 |
16 | I am currently using kernel 5.3.0-7648 to run these examples. Each individual example should have its own readme. In general, you should just have to run make in the main directory.
17 |
--------------------------------------------------------------------------------
/Code_Examples/scull/Makefile:
--------------------------------------------------------------------------------
1 | # Comment/uncomment the following line to disable/enable debugging
2 | #DEBUG = y
3 |
4 |
5 | # Add your debugging flag (or not) to CFLAGS
6 | ifeq ($(DEBUG),y)
7 | DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
8 | else
9 | DEBFLAGS = -O2
10 | endif
11 |
12 | LDDINC=$(PWD)/../include
13 |
14 | EXTRA_CFLAGS += $(DEBFLAGS)
15 | EXTRA_CFLAGS += -I$(LDDINC)
16 |
17 | ifneq ($(KERNELRELEASE),)
18 | # call from kernel build system
19 |
20 | scull-objs := main.o pipe.o access.o
21 |
22 | obj-m := scull.o
23 |
24 | else
25 |
26 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
27 | PWD := $(shell pwd)
28 |
29 | modules:
30 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
31 |
32 | endif
33 |
34 |
35 |
36 | clean:
37 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
38 |
39 | depend .depend dep:
40 | $(CC) $(EXTRA_CFLAGS) -M *.c > .depend
41 |
42 |
43 | ifeq (.depend,$(wildcard .depend))
44 | include .depend
45 | endif
46 |
--------------------------------------------------------------------------------
/Code_Examples/scull/Module.symvers:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ropellad/LDD3-Notes/c9a39592a7cd4b162c8d77e5a1f011f7452939df/Code_Examples/scull/Module.symvers
--------------------------------------------------------------------------------
/Code_Examples/scull/README.md:
--------------------------------------------------------------------------------
1 | # Scull :skull:
2 |
3 | This functions the same as the book describes. See the book chapters for more notes on how to play around with this driver. I have not made any changes to it.
4 |
--------------------------------------------------------------------------------
/Code_Examples/scull/access.c:
--------------------------------------------------------------------------------
1 | /*
2 | * access.c -- the files with access control on open
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | * $Id: access.c,v 1.17 2004/09/26 07:29:56 gregkh Exp $
16 | */
17 |
18 | /* FIXME: cloned devices as a use for kobjects? */
19 |
20 | #include /* printk() */
21 | #include
22 | #include /* kmalloc() */
23 | #include /* everything... */
24 | #include /* error codes */
25 | #include /* size_t */
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include /* current_uid(), current_euid() */
32 | #include
33 | #include
34 |
35 | #include "scull.h" /* local definitions */
36 |
37 | static dev_t scull_a_firstdev; /* Where our range begins */
38 |
39 | /*
40 | * These devices fall back on the main scull operations. They only
41 | * differ in the implementation of open() and close()
42 | */
43 |
44 |
45 |
46 | /************************************************************************
47 | *
48 | * The first device is the single-open one,
49 | * it has an hw structure and an open count
50 | */
51 |
52 | static struct scull_dev scull_s_device;
53 | static atomic_t scull_s_available = ATOMIC_INIT(1);
54 |
55 | static int scull_s_open(struct inode *inode, struct file *filp)
56 | {
57 | struct scull_dev *dev = &scull_s_device; /* device information */
58 |
59 | if (! atomic_dec_and_test (&scull_s_available)) {
60 | atomic_inc(&scull_s_available);
61 | return -EBUSY; /* already open */
62 | }
63 |
64 | /* then, everything else is copied from the bare scull device */
65 | if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
66 | scull_trim(dev);
67 | filp->private_data = dev;
68 | return 0; /* success */
69 | }
70 |
71 | static int scull_s_release(struct inode *inode, struct file *filp)
72 | {
73 | atomic_inc(&scull_s_available); /* release the device */
74 | return 0;
75 | }
76 |
77 |
78 | /*
79 | * The other operations for the single-open device come from the bare device
80 | */
81 | struct file_operations scull_sngl_fops = {
82 | .owner = THIS_MODULE,
83 | .llseek = scull_llseek,
84 | .read = scull_read,
85 | .write = scull_write,
86 | .unlocked_ioctl = scull_ioctl,
87 | .open = scull_s_open,
88 | .release = scull_s_release,
89 | };
90 |
91 |
92 | /************************************************************************
93 | *
94 | * Next, the "uid" device. It can be opened multiple times by the
95 | * same user, but access is denied to other users if the device is open
96 | */
97 |
98 | static struct scull_dev scull_u_device;
99 | static int scull_u_count; /* initialized to 0 by default */
100 | static uid_t scull_u_owner; /* initialized to 0 by default */
101 | static DEFINE_SPINLOCK(scull_u_lock);
102 |
103 | static int scull_u_open(struct inode *inode, struct file *filp)
104 | {
105 | struct scull_dev *dev = &scull_u_device; /* device information */
106 |
107 | spin_lock(&scull_u_lock);
108 | if (scull_u_count &&
109 | (scull_u_owner != current_uid().val) && /* allow user */
110 | (scull_u_owner != current_euid().val) && /* allow whoever did su */
111 | !capable(CAP_DAC_OVERRIDE)) { /* still allow root */
112 | spin_unlock(&scull_u_lock);
113 | return -EBUSY; /* -EPERM would confuse the user */
114 | }
115 |
116 | if (scull_u_count == 0)
117 | scull_u_owner = current_uid().val; /* grab it */
118 |
119 | scull_u_count++;
120 | spin_unlock(&scull_u_lock);
121 |
122 | /* then, everything else is copied from the bare scull device */
123 |
124 | if ((filp->f_flags & O_ACCMODE) == O_WRONLY)
125 | scull_trim(dev);
126 | filp->private_data = dev;
127 | return 0; /* success */
128 | }
129 |
130 | static int scull_u_release(struct inode *inode, struct file *filp)
131 | {
132 | spin_lock(&scull_u_lock);
133 | scull_u_count--; /* nothing else */
134 | spin_unlock(&scull_u_lock);
135 | return 0;
136 | }
137 |
138 |
139 |
140 | /*
141 | * The other operations for the device come from the bare device
142 | */
143 | struct file_operations scull_user_fops = {
144 | .owner = THIS_MODULE,
145 | .llseek = scull_llseek,
146 | .read = scull_read,
147 | .write = scull_write,
148 | .unlocked_ioctl = scull_ioctl,
149 | .open = scull_u_open,
150 | .release = scull_u_release,
151 | };
152 |
153 |
154 | /************************************************************************
155 | *
156 | * Next, the device with blocking-open based on uid
157 | */
158 |
159 | static struct scull_dev scull_w_device;
160 | static int scull_w_count; /* initialized to 0 by default */
161 | static uid_t scull_w_owner; /* initialized to 0 by default */
162 | static DECLARE_WAIT_QUEUE_HEAD(scull_w_wait);
163 | static DEFINE_SPINLOCK(scull_w_lock);
164 |
165 | static inline int scull_w_available(void)
166 | {
167 | return scull_w_count == 0 ||
168 | scull_w_owner == current_uid().val ||
169 | scull_w_owner == current_euid().val ||
170 | capable(CAP_DAC_OVERRIDE);
171 | }
172 |
173 |
174 | static int scull_w_open(struct inode *inode, struct file *filp)
175 | {
176 | struct scull_dev *dev = &scull_w_device; /* device information */
177 |
178 | spin_lock(&scull_w_lock);
179 | while (! scull_w_available()) {
180 | spin_unlock(&scull_w_lock);
181 | if (filp->f_flags & O_NONBLOCK) return -EAGAIN;
182 | if (wait_event_interruptible (scull_w_wait, scull_w_available()))
183 | return -ERESTARTSYS; /* tell the fs layer to handle it */
184 | spin_lock(&scull_w_lock);
185 | }
186 | if (scull_w_count == 0)
187 | scull_w_owner = current_uid().val; /* grab it */
188 | scull_w_count++;
189 | spin_unlock(&scull_w_lock);
190 |
191 | /* then, everything else is copied from the bare scull device */
192 | if ((filp->f_flags & O_ACCMODE) == O_WRONLY)
193 | scull_trim(dev);
194 | filp->private_data = dev;
195 | return 0; /* success */
196 | }
197 |
198 | static int scull_w_release(struct inode *inode, struct file *filp)
199 | {
200 | int temp;
201 |
202 | spin_lock(&scull_w_lock);
203 | scull_w_count--;
204 | temp = scull_w_count;
205 | spin_unlock(&scull_w_lock);
206 |
207 | if (temp == 0)
208 | wake_up_interruptible_sync(&scull_w_wait); /* awake other uid's */
209 | return 0;
210 | }
211 |
212 |
213 | /*
214 | * The other operations for the device come from the bare device
215 | */
216 | struct file_operations scull_wusr_fops = {
217 | .owner = THIS_MODULE,
218 | .llseek = scull_llseek,
219 | .read = scull_read,
220 | .write = scull_write,
221 | .unlocked_ioctl = scull_ioctl,
222 | .open = scull_w_open,
223 | .release = scull_w_release,
224 | };
225 |
226 | /************************************************************************
227 | *
228 | * Finally the `cloned' private device. This is trickier because it
229 | * involves list management, and dynamic allocation.
230 | */
231 |
232 | /* The clone-specific data structure includes a key field */
233 |
234 | struct scull_listitem {
235 | struct scull_dev device;
236 | dev_t key;
237 | struct list_head list;
238 |
239 | };
240 |
241 | /* The list of devices, and a lock to protect it */
242 | static LIST_HEAD(scull_c_list);
243 | static DEFINE_SPINLOCK(scull_c_lock);
244 |
245 | /* A placeholder scull_dev which really just holds the cdev stuff. */
246 | static struct scull_dev scull_c_device;
247 |
248 | /* Look for a device or create one if missing */
249 | static struct scull_dev *scull_c_lookfor_device(dev_t key)
250 | {
251 | struct scull_listitem *lptr;
252 |
253 | list_for_each_entry(lptr, &scull_c_list, list) {
254 | if (lptr->key == key)
255 | return &(lptr->device);
256 | }
257 |
258 | /* not found */
259 | lptr = kmalloc(sizeof(struct scull_listitem), GFP_KERNEL);
260 | if (!lptr)
261 | return NULL;
262 |
263 | /* initialize the device */
264 | memset(lptr, 0, sizeof(struct scull_listitem));
265 | lptr->key = key;
266 | scull_trim(&(lptr->device)); /* initialize it */
267 | mutex_init(&lptr->device.lock);
268 |
269 | /* place it in the list */
270 | list_add(&lptr->list, &scull_c_list);
271 |
272 | return &(lptr->device);
273 | }
274 |
275 | static int scull_c_open(struct inode *inode, struct file *filp)
276 | {
277 | struct scull_dev *dev;
278 | dev_t key;
279 |
280 | if (!current->signal->tty) {
281 | PDEBUG("Process \"%s\" has no ctl tty\n", current->comm);
282 | return -EINVAL;
283 | }
284 | key = tty_devnum(current->signal->tty);
285 |
286 | /* look for a scullc device in the list */
287 | spin_lock(&scull_c_lock);
288 | dev = scull_c_lookfor_device(key);
289 | spin_unlock(&scull_c_lock);
290 |
291 | if (!dev)
292 | return -ENOMEM;
293 |
294 | /* then, everything else is copied from the bare scull device */
295 | if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
296 | scull_trim(dev);
297 | filp->private_data = dev;
298 | return 0; /* success */
299 | }
300 |
301 | static int scull_c_release(struct inode *inode, struct file *filp)
302 | {
303 | /*
304 | * Nothing to do, because the device is persistent.
305 | * A `real' cloned device should be freed on last close
306 | */
307 | return 0;
308 | }
309 |
310 |
311 |
312 | /*
313 | * The other operations for the device come from the bare device
314 | */
315 | struct file_operations scull_priv_fops = {
316 | .owner = THIS_MODULE,
317 | .llseek = scull_llseek,
318 | .read = scull_read,
319 | .write = scull_write,
320 | .unlocked_ioctl = scull_ioctl,
321 | .open = scull_c_open,
322 | .release = scull_c_release,
323 | };
324 |
325 | /************************************************************************
326 | *
327 | * And the init and cleanup functions come last
328 | */
329 |
330 | static struct scull_adev_info {
331 | char *name;
332 | struct scull_dev *sculldev;
333 | struct file_operations *fops;
334 | } scull_access_devs[] = {
335 | { "scullsingle", &scull_s_device, &scull_sngl_fops },
336 | { "sculluid", &scull_u_device, &scull_user_fops },
337 | { "scullwuid", &scull_w_device, &scull_wusr_fops },
338 | { "scullpriv", &scull_c_device, &scull_priv_fops }
339 | };
340 | #define SCULL_N_ADEVS 4
341 |
342 | /*
343 | * Set up a single device.
344 | */
345 | static void scull_access_setup (dev_t devno, struct scull_adev_info *devinfo)
346 | {
347 | struct scull_dev *dev = devinfo->sculldev;
348 | int err;
349 |
350 | /* Initialize the device structure */
351 | dev->quantum = scull_quantum;
352 | dev->qset = scull_qset;
353 | mutex_init(&dev->lock);
354 |
355 | /* Do the cdev stuff. */
356 | cdev_init(&dev->cdev, devinfo->fops);
357 | kobject_set_name(&dev->cdev.kobj, devinfo->name);
358 | dev->cdev.owner = THIS_MODULE;
359 | err = cdev_add (&dev->cdev, devno, 1);
360 | /* Fail gracefully if need be */
361 | if (err) {
362 | printk(KERN_NOTICE "Error %d adding %s\n", err, devinfo->name);
363 | kobject_put(&dev->cdev.kobj);
364 | } else
365 | printk(KERN_NOTICE "%s registered at %x\n", devinfo->name, devno);
366 | }
367 |
368 |
369 | int scull_access_init(dev_t firstdev)
370 | {
371 | int result, i;
372 |
373 | /* Get our number space */
374 | result = register_chrdev_region (firstdev, SCULL_N_ADEVS, "sculla");
375 | if (result < 0) {
376 | printk(KERN_WARNING "sculla: device number registration failed\n");
377 | return 0;
378 | }
379 | scull_a_firstdev = firstdev;
380 |
381 | /* Set up each device. */
382 | for (i = 0; i < SCULL_N_ADEVS; i++)
383 | scull_access_setup (firstdev + i, scull_access_devs + i);
384 | return SCULL_N_ADEVS;
385 | }
386 |
387 | /*
388 | * This is called by cleanup_module or on failure.
389 | * It is required to never fail, even if nothing was initialized first
390 | */
391 | void scull_access_cleanup(void)
392 | {
393 | struct scull_listitem *lptr, *next;
394 | int i;
395 |
396 | /* Clean up the static devs */
397 | for (i = 0; i < SCULL_N_ADEVS; i++) {
398 | struct scull_dev *dev = scull_access_devs[i].sculldev;
399 | cdev_del(&dev->cdev);
400 | scull_trim(scull_access_devs[i].sculldev);
401 | }
402 |
403 | /* And all the cloned devices */
404 | list_for_each_entry_safe(lptr, next, &scull_c_list, list) {
405 | list_del(&lptr->list);
406 | scull_trim(&(lptr->device));
407 | kfree(lptr);
408 | }
409 |
410 | /* Free up our number space */
411 | unregister_chrdev_region(scull_a_firstdev, SCULL_N_ADEVS);
412 | return;
413 | }
414 |
--------------------------------------------------------------------------------
/Code_Examples/scull/access_ok_version.h:
--------------------------------------------------------------------------------
1 | /*
2 | * @file access_ok_version.h
3 | * @date 10/13/2019
4 | *
5 | */
6 |
7 | #include
8 |
9 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
10 | #define access_ok_wrapper(type,arg,cmd) \
11 | access_ok(type, arg, cmd)
12 | #else
13 | #define access_ok_wrapper(type,arg,cmd) \
14 | access_ok(arg, cmd)
15 | #endif
16 |
--------------------------------------------------------------------------------
/Code_Examples/scull/lddbus.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Definitions for the virtual LDD bus.
3 | *
4 | * $Id: lddbus.h,v 1.4 2004/08/20 18:49:44 corbet Exp $
5 | */
6 |
7 | //extern struct device ldd_bus;
8 | extern struct bus_type ldd_bus_type;
9 |
10 |
11 | /*
12 | * The LDD driver type.
13 | */
14 |
15 | struct ldd_driver {
16 | char *version;
17 | struct module *module;
18 | struct device_driver driver;
19 | struct driver_attribute version_attr;
20 | };
21 |
22 | #define to_ldd_driver(drv) container_of(drv, struct ldd_driver, driver);
23 |
24 | /*
25 | * A device type for things "plugged" into the LDD bus.
26 | */
27 |
28 | struct ldd_device {
29 | char *name;
30 | struct ldd_driver *driver;
31 | struct device dev;
32 | };
33 |
34 | #define to_ldd_device(dev) container_of(dev, struct ldd_device, dev);
35 |
36 | extern int register_ldd_device(struct ldd_device *);
37 | extern void unregister_ldd_device(struct ldd_device *);
38 | extern int register_ldd_driver(struct ldd_driver *);
39 | extern void unregister_ldd_driver(struct ldd_driver *);
40 |
--------------------------------------------------------------------------------
/Code_Examples/scull/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | * main.c -- the bare scull char module
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | */
16 |
17 | #include
18 | #include
19 | #include
20 |
21 | #include /* printk() */
22 | #include /* kmalloc() */
23 | #include /* everything... */
24 | #include /* error codes */
25 | #include /* size_t */
26 | #include
27 | #include /* O_ACCMODE */
28 | #include
29 | #include
30 |
31 | #include /* copy_*_user */
32 |
33 | #include "scull.h" /* local definitions */
34 | #include "access_ok_version.h"
35 |
36 | /*
37 | * Our parameters which can be set at load time.
38 | */
39 |
40 | int scull_major = SCULL_MAJOR;
41 | int scull_minor = 0;
42 | int scull_nr_devs = SCULL_NR_DEVS; /* number of bare scull devices */
43 | int scull_quantum = SCULL_QUANTUM;
44 | int scull_qset = SCULL_QSET;
45 |
46 | module_param(scull_major, int, S_IRUGO);
47 | module_param(scull_minor, int, S_IRUGO);
48 | module_param(scull_nr_devs, int, S_IRUGO);
49 | module_param(scull_quantum, int, S_IRUGO);
50 | module_param(scull_qset, int, S_IRUGO);
51 |
52 | MODULE_AUTHOR("Alessandro Rubini, Jonathan Corbet");
53 | MODULE_LICENSE("Dual BSD/GPL");
54 |
55 | struct scull_dev *scull_devices; /* allocated in scull_init_module */
56 |
57 |
58 | /*
59 | * Empty out the scull device; must be called with the device
60 | * semaphore held.
61 | */
62 | int scull_trim(struct scull_dev *dev)
63 | {
64 | struct scull_qset *next, *dptr;
65 | int qset = dev->qset; /* "dev" is not-null */
66 | int i;
67 |
68 | for (dptr = dev->data; dptr; dptr = next) { /* all the list items */
69 | if (dptr->data) {
70 | for (i = 0; i < qset; i++)
71 | kfree(dptr->data[i]);
72 | kfree(dptr->data);
73 | dptr->data = NULL;
74 | }
75 | next = dptr->next;
76 | kfree(dptr);
77 | }
78 | dev->size = 0;
79 | dev->quantum = scull_quantum;
80 | dev->qset = scull_qset;
81 | dev->data = NULL;
82 | return 0;
83 | }
84 | #ifdef SCULL_DEBUG /* use proc only if debugging */
85 | /*
86 | * The proc filesystem: function to read and entry
87 | */
88 |
89 | int scull_read_procmem(struct seq_file *s, void *v)
90 | {
91 | int i, j;
92 | int limit = s->size - 80; /* Don't print more than this */
93 |
94 | for (i = 0; i < scull_nr_devs && s->count <= limit; i++) {
95 | struct scull_dev *d = &scull_devices[i];
96 | struct scull_qset *qs = d->data;
97 | if (mutex_lock_interruptible(&d->lock))
98 | return -ERESTARTSYS;
99 | seq_printf(s,"\nDevice %i: qset %i, q %i, sz %li\n",
100 | i, d->qset, d->quantum, d->size);
101 | for (; qs && s->count <= limit; qs = qs->next) { /* scan the list */
102 | seq_printf(s, " item at %p, qset at %p\n",
103 | qs, qs->data);
104 | if (qs->data && !qs->next) /* dump only the last item */
105 | for (j = 0; j < d->qset; j++) {
106 | if (qs->data[j])
107 | seq_printf(s, " % 4i: %8p\n",
108 | j, qs->data[j]);
109 | }
110 | }
111 | mutex_unlock(&scull_devices[i].lock);
112 | }
113 | return 0;
114 | }
115 |
116 |
117 |
118 | /*
119 | * Here are our sequence iteration methods. Our "position" is
120 | * simply the device number.
121 | */
122 | static void *scull_seq_start(struct seq_file *s, loff_t *pos)
123 | {
124 | if (*pos >= scull_nr_devs)
125 | return NULL; /* No more to read */
126 | return scull_devices + *pos;
127 | }
128 |
129 | static void *scull_seq_next(struct seq_file *s, void *v, loff_t *pos)
130 | {
131 | (*pos)++;
132 | if (*pos >= scull_nr_devs)
133 | return NULL;
134 | return scull_devices + *pos;
135 | }
136 |
137 | static void scull_seq_stop(struct seq_file *s, void *v)
138 | {
139 | /* Actually, there's nothing to do here */
140 | }
141 |
142 | static int scull_seq_show(struct seq_file *s, void *v)
143 | {
144 | struct scull_dev *dev = (struct scull_dev *) v;
145 | struct scull_qset *d;
146 | int i;
147 |
148 | if (mutex_lock_interruptible(&dev->lock))
149 | return -ERESTARTSYS;
150 | seq_printf(s, "\nDevice %i: qset %i, q %i, sz %li\n",
151 | (int) (dev - scull_devices), dev->qset,
152 | dev->quantum, dev->size);
153 | for (d = dev->data; d; d = d->next) { /* scan the list */
154 | seq_printf(s, " item at %p, qset at %p\n", d, d->data);
155 | if (d->data && !d->next) /* dump only the last item */
156 | for (i = 0; i < dev->qset; i++) {
157 | if (d->data[i])
158 | seq_printf(s, " % 4i: %8p\n",
159 | i, d->data[i]);
160 | }
161 | }
162 | mutex_unlock(&dev->lock);
163 | return 0;
164 | }
165 |
166 | /*
167 | * Tie the sequence operators up.
168 | */
169 | static struct seq_operations scull_seq_ops = {
170 | .start = scull_seq_start,
171 | .next = scull_seq_next,
172 | .stop = scull_seq_stop,
173 | .show = scull_seq_show
174 | };
175 |
176 | /*
177 | * Now to implement the /proc files we need only make an open
178 | * method which sets up the sequence operators.
179 | */
180 | static int scullmem_proc_open(struct inode *inode, struct file *file)
181 | {
182 | return single_open(file, scull_read_procmem, NULL);
183 | }
184 |
185 | static int scullseq_proc_open(struct inode *inode, struct file *file)
186 | {
187 | return seq_open(file, &scull_seq_ops);
188 | }
189 |
190 | /*
191 | * Create a set of file operations for our proc files.
192 | */
193 | static struct file_operations scullmem_proc_ops = {
194 | .owner = THIS_MODULE,
195 | .open = scullmem_proc_open,
196 | .read = seq_read,
197 | .llseek = seq_lseek,
198 | .release = single_release
199 | };
200 |
201 | static struct file_operations scullseq_proc_ops = {
202 | .owner = THIS_MODULE,
203 | .open = scullseq_proc_open,
204 | .read = seq_read,
205 | .llseek = seq_lseek,
206 | .release = seq_release
207 | };
208 |
209 |
210 | /*
211 | * Actually create (and remove) the /proc file(s).
212 | */
213 |
214 | static void scull_create_proc(void)
215 | {
216 | proc_create_data("scullmem", 0 /* default mode */,
217 | NULL /* parent dir */, &scullmem_proc_ops,
218 | NULL /* client data */);
219 | proc_create("scullseq", 0, NULL, &scullseq_proc_ops);
220 | }
221 |
222 | static void scull_remove_proc(void)
223 | {
224 | /* no problem if it was not registered */
225 | remove_proc_entry("scullmem", NULL /* parent dir */);
226 | remove_proc_entry("scullseq", NULL);
227 | }
228 |
229 |
230 | #endif /* SCULL_DEBUG */
231 |
232 |
233 |
234 |
235 |
236 | /*
237 | * Open and close
238 | */
239 |
240 | int scull_open(struct inode *inode, struct file *filp)
241 | {
242 | struct scull_dev *dev; /* device information */
243 |
244 | dev = container_of(inode->i_cdev, struct scull_dev, cdev);
245 | filp->private_data = dev; /* for other methods */
246 |
247 | /* now trim to 0 the length of the device if open was write-only */
248 | if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {
249 | if (mutex_lock_interruptible(&dev->lock))
250 | return -ERESTARTSYS;
251 | scull_trim(dev); /* ignore errors */
252 | mutex_unlock(&dev->lock);
253 | }
254 | return 0; /* success */
255 | }
256 |
257 | int scull_release(struct inode *inode, struct file *filp)
258 | {
259 | return 0;
260 | }
261 | /*
262 | * Follow the list
263 | */
264 | struct scull_qset *scull_follow(struct scull_dev *dev, int n)
265 | {
266 | struct scull_qset *qs = dev->data;
267 |
268 | /* Allocate first qset explicitly if need be */
269 | if (! qs) {
270 | qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
271 | if (qs == NULL)
272 | return NULL; /* Never mind */
273 | memset(qs, 0, sizeof(struct scull_qset));
274 | }
275 |
276 | /* Then follow the list */
277 | while (n--) {
278 | if (!qs->next) {
279 | qs->next = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
280 | if (qs->next == NULL)
281 | return NULL; /* Never mind */
282 | memset(qs->next, 0, sizeof(struct scull_qset));
283 | }
284 | qs = qs->next;
285 | continue;
286 | }
287 | return qs;
288 | }
289 |
290 | /*
291 | * Data management: read and write
292 | */
293 |
294 | ssize_t scull_read(struct file *filp, char __user *buf, size_t count,
295 | loff_t *f_pos)
296 | {
297 | struct scull_dev *dev = filp->private_data;
298 | struct scull_qset *dptr; /* the first listitem */
299 | int quantum = dev->quantum, qset = dev->qset;
300 | int itemsize = quantum * qset; /* how many bytes in the listitem */
301 | int item, s_pos, q_pos, rest;
302 | ssize_t retval = 0;
303 |
304 | if (mutex_lock_interruptible(&dev->lock))
305 | return -ERESTARTSYS;
306 | if (*f_pos >= dev->size)
307 | goto out;
308 | if (*f_pos + count > dev->size)
309 | count = dev->size - *f_pos;
310 |
311 | /* find listitem, qset index, and offset in the quantum */
312 | item = (long)*f_pos / itemsize;
313 | rest = (long)*f_pos % itemsize;
314 | s_pos = rest / quantum; q_pos = rest % quantum;
315 |
316 | /* follow the list up to the right position (defined elsewhere) */
317 | dptr = scull_follow(dev, item);
318 |
319 | if (dptr == NULL || !dptr->data || ! dptr->data[s_pos])
320 | goto out; /* don't fill holes */
321 |
322 | /* read only up to the end of this quantum */
323 | if (count > quantum - q_pos)
324 | count = quantum - q_pos;
325 |
326 | if (copy_to_user(buf, dptr->data[s_pos] + q_pos, count)) {
327 | retval = -EFAULT;
328 | goto out;
329 | }
330 | *f_pos += count;
331 | retval = count;
332 |
333 | out:
334 | mutex_unlock(&dev->lock);
335 | return retval;
336 | }
337 |
338 | ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,
339 | loff_t *f_pos)
340 | {
341 | struct scull_dev *dev = filp->private_data;
342 | struct scull_qset *dptr;
343 | int quantum = dev->quantum, qset = dev->qset;
344 | int itemsize = quantum * qset;
345 | int item, s_pos, q_pos, rest;
346 | ssize_t retval = -ENOMEM; /* value used in "goto out" statements */
347 |
348 | if (mutex_lock_interruptible(&dev->lock))
349 | return -ERESTARTSYS;
350 |
351 | /* find listitem, qset index and offset in the quantum */
352 | item = (long)*f_pos / itemsize;
353 | rest = (long)*f_pos % itemsize;
354 | s_pos = rest / quantum; q_pos = rest % quantum;
355 |
356 | /* follow the list up to the right position */
357 | dptr = scull_follow(dev, item);
358 | if (dptr == NULL)
359 | goto out;
360 | if (!dptr->data) {
361 | dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);
362 | if (!dptr->data)
363 | goto out;
364 | memset(dptr->data, 0, qset * sizeof(char *));
365 | }
366 | if (!dptr->data[s_pos]) {
367 | dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
368 | if (!dptr->data[s_pos])
369 | goto out;
370 | }
371 | /* write only up to the end of this quantum */
372 | if (count > quantum - q_pos)
373 | count = quantum - q_pos;
374 |
375 | if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) {
376 | retval = -EFAULT;
377 | goto out;
378 | }
379 | *f_pos += count;
380 | retval = count;
381 |
382 | /* update the size */
383 | if (dev->size < *f_pos)
384 | dev->size = *f_pos;
385 |
386 | out:
387 | mutex_unlock(&dev->lock);
388 | return retval;
389 | }
390 |
391 | /*
392 | * The ioctl() implementation
393 | */
394 |
395 | long scull_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
396 | {
397 |
398 | int err = 0, tmp;
399 | int retval = 0;
400 |
401 | /*
402 | * extract the type and number bitfields, and don't decode
403 | * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
404 | */
405 | if (_IOC_TYPE(cmd) != SCULL_IOC_MAGIC) return -ENOTTY;
406 | if (_IOC_NR(cmd) > SCULL_IOC_MAXNR) return -ENOTTY;
407 |
408 | /*
409 | * the direction is a bitmask, and VERIFY_WRITE catches R/W
410 | * transfers. `Type' is user-oriented, while
411 | * access_ok is kernel-oriented, so the concept of "read" and
412 | * "write" is reversed
413 | */
414 | if (_IOC_DIR(cmd) & _IOC_READ)
415 | err = !access_ok_wrapper(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
416 | else if (_IOC_DIR(cmd) & _IOC_WRITE)
417 | err = !access_ok_wrapper(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
418 | if (err) return -EFAULT;
419 |
420 | switch(cmd) {
421 |
422 | case SCULL_IOCRESET:
423 | scull_quantum = SCULL_QUANTUM;
424 | scull_qset = SCULL_QSET;
425 | break;
426 |
427 | case SCULL_IOCSQUANTUM: /* Set: arg points to the value */
428 | if (! capable (CAP_SYS_ADMIN))
429 | return -EPERM;
430 | retval = __get_user(scull_quantum, (int __user *)arg);
431 | break;
432 |
433 | case SCULL_IOCTQUANTUM: /* Tell: arg is the value */
434 | if (! capable (CAP_SYS_ADMIN))
435 | return -EPERM;
436 | scull_quantum = arg;
437 | break;
438 |
439 | case SCULL_IOCGQUANTUM: /* Get: arg is pointer to result */
440 | retval = __put_user(scull_quantum, (int __user *)arg);
441 | break;
442 |
443 | case SCULL_IOCQQUANTUM: /* Query: return it (it's positive) */
444 | return scull_quantum;
445 |
446 | case SCULL_IOCXQUANTUM: /* eXchange: use arg as pointer */
447 | if (! capable (CAP_SYS_ADMIN))
448 | return -EPERM;
449 | tmp = scull_quantum;
450 | retval = __get_user(scull_quantum, (int __user *)arg);
451 | if (retval == 0)
452 | retval = __put_user(tmp, (int __user *)arg);
453 | break;
454 |
455 | case SCULL_IOCHQUANTUM: /* sHift: like Tell + Query */
456 | if (! capable (CAP_SYS_ADMIN))
457 | return -EPERM;
458 | tmp = scull_quantum;
459 | scull_quantum = arg;
460 | return tmp;
461 |
462 | case SCULL_IOCSQSET:
463 | if (! capable (CAP_SYS_ADMIN))
464 | return -EPERM;
465 | retval = __get_user(scull_qset, (int __user *)arg);
466 | break;
467 |
468 | case SCULL_IOCTQSET:
469 | if (! capable (CAP_SYS_ADMIN))
470 | return -EPERM;
471 | scull_qset = arg;
472 | break;
473 |
474 | case SCULL_IOCGQSET:
475 | retval = __put_user(scull_qset, (int __user *)arg);
476 | break;
477 |
478 | case SCULL_IOCQQSET:
479 | return scull_qset;
480 |
481 | case SCULL_IOCXQSET:
482 | if (! capable (CAP_SYS_ADMIN))
483 | return -EPERM;
484 | tmp = scull_qset;
485 | retval = __get_user(scull_qset, (int __user *)arg);
486 | if (retval == 0)
487 | retval = put_user(tmp, (int __user *)arg);
488 | break;
489 |
490 | case SCULL_IOCHQSET:
491 | if (! capable (CAP_SYS_ADMIN))
492 | return -EPERM;
493 | tmp = scull_qset;
494 | scull_qset = arg;
495 | return tmp;
496 |
497 | /*
498 | * The following two change the buffer size for scullpipe.
499 | * The scullpipe device uses this same ioctl method, just to
500 | * write less code. Actually, it's the same driver, isn't it?
501 | */
502 |
503 | case SCULL_P_IOCTSIZE:
504 | scull_p_buffer = arg;
505 | break;
506 |
507 | case SCULL_P_IOCQSIZE:
508 | return scull_p_buffer;
509 |
510 |
511 | default: /* redundant, as cmd was checked against MAXNR */
512 | return -ENOTTY;
513 | }
514 | return retval;
515 |
516 | }
517 |
518 |
519 |
520 | /*
521 | * The "extended" operations -- only seek
522 | */
523 |
524 | loff_t scull_llseek(struct file *filp, loff_t off, int whence)
525 | {
526 | struct scull_dev *dev = filp->private_data;
527 | loff_t newpos;
528 |
529 | switch(whence) {
530 | case 0: /* SEEK_SET */
531 | newpos = off;
532 | break;
533 |
534 | case 1: /* SEEK_CUR */
535 | newpos = filp->f_pos + off;
536 | break;
537 |
538 | case 2: /* SEEK_END */
539 | newpos = dev->size + off;
540 | break;
541 |
542 | default: /* can't happen */
543 | return -EINVAL;
544 | }
545 | if (newpos < 0) return -EINVAL;
546 | filp->f_pos = newpos;
547 | return newpos;
548 | }
549 |
550 |
551 |
552 | struct file_operations scull_fops = {
553 | .owner = THIS_MODULE,
554 | .llseek = scull_llseek,
555 | .read = scull_read,
556 | .write = scull_write,
557 | .unlocked_ioctl = scull_ioctl,
558 | .open = scull_open,
559 | .release = scull_release,
560 | };
561 |
562 | /*
563 | * Finally, the module stuff
564 | */
565 |
566 | /*
567 | * The cleanup function is used to handle initialization failures as well.
568 | * Thefore, it must be careful to work correctly even if some of the items
569 | * have not been initialized
570 | */
571 | void scull_cleanup_module(void)
572 | {
573 | int i;
574 | dev_t devno = MKDEV(scull_major, scull_minor);
575 |
576 | /* Get rid of our char dev entries */
577 | if (scull_devices) {
578 | for (i = 0; i < scull_nr_devs; i++) {
579 | scull_trim(scull_devices + i);
580 | cdev_del(&scull_devices[i].cdev);
581 | }
582 | kfree(scull_devices);
583 | }
584 |
585 | #ifdef SCULL_DEBUG /* use proc only if debugging */
586 | scull_remove_proc();
587 | #endif
588 |
589 | /* cleanup_module is never called if registering failed */
590 | unregister_chrdev_region(devno, scull_nr_devs);
591 |
592 | /* and call the cleanup functions for friend devices */
593 | scull_p_cleanup();
594 | scull_access_cleanup();
595 |
596 | }
597 |
598 |
599 | /*
600 | * Set up the char_dev structure for this device.
601 | */
602 | static void scull_setup_cdev(struct scull_dev *dev, int index)
603 | {
604 | int err, devno = MKDEV(scull_major, scull_minor + index);
605 |
606 | cdev_init(&dev->cdev, &scull_fops);
607 | dev->cdev.owner = THIS_MODULE;
608 | dev->cdev.ops = &scull_fops;
609 | err = cdev_add (&dev->cdev, devno, 1);
610 | /* Fail gracefully if need be */
611 | if (err)
612 | printk(KERN_NOTICE "Error %d adding scull%d", err, index);
613 | }
614 |
615 |
616 | int scull_init_module(void)
617 | {
618 | int result, i;
619 | dev_t dev = 0;
620 |
621 | /*
622 | * Get a range of minor numbers to work with, asking for a dynamic
623 | * major unless directed otherwise at load time.
624 | */
625 | if (scull_major) {
626 | dev = MKDEV(scull_major, scull_minor);
627 | result = register_chrdev_region(dev, scull_nr_devs, "scull");
628 | } else {
629 | result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs,
630 | "scull");
631 | scull_major = MAJOR(dev);
632 | }
633 | if (result < 0) {
634 | printk(KERN_WARNING "scull: can't get major %d\n", scull_major);
635 | return result;
636 | }
637 |
638 | /*
639 | * allocate the devices -- we can't have them static, as the number
640 | * can be specified at load time
641 | */
642 | scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL);
643 | if (!scull_devices) {
644 | result = -ENOMEM;
645 | goto fail; /* Make this more graceful */
646 | }
647 | memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev));
648 |
649 | /* Initialize each device. */
650 | for (i = 0; i < scull_nr_devs; i++) {
651 | scull_devices[i].quantum = scull_quantum;
652 | scull_devices[i].qset = scull_qset;
653 | mutex_init(&scull_devices[i].lock);
654 | scull_setup_cdev(&scull_devices[i], i);
655 | }
656 |
657 | /* At this point call the init function for any friend device */
658 | dev = MKDEV(scull_major, scull_minor + scull_nr_devs);
659 | dev += scull_p_init(dev);
660 | dev += scull_access_init(dev);
661 |
662 | #ifdef SCULL_DEBUG /* only when debugging */
663 | scull_create_proc();
664 | #endif
665 |
666 | return 0; /* succeed */
667 |
668 | fail:
669 | scull_cleanup_module();
670 | return result;
671 | }
672 |
673 | module_init(scull_init_module);
674 | module_exit(scull_cleanup_module);
675 |
--------------------------------------------------------------------------------
/Code_Examples/scull/modules.order:
--------------------------------------------------------------------------------
1 | /home/dom/LDD3-Notes/Code_Examples/temp/scull.ko
2 |
--------------------------------------------------------------------------------
/Code_Examples/scull/pipe.c:
--------------------------------------------------------------------------------
1 | /*
2 | * pipe.c -- fifo driver for scull
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | */
16 |
17 | #include
18 | #include
19 |
20 | #include /* printk(), min() */
21 | #include /* kmalloc() */
22 | #include /* everything... */
23 | #include
24 | #include /* error codes */
25 | #include /* size_t */
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 |
34 | #include "scull.h" /* local definitions */
35 |
36 | struct scull_pipe {
37 | wait_queue_head_t inq, outq; /* read and write queues */
38 | char *buffer, *end; /* begin of buf, end of buf */
39 | int buffersize; /* used in pointer arithmetic */
40 | char *rp, *wp; /* where to read, where to write */
41 | int nreaders, nwriters; /* number of openings for r/w */
42 | struct fasync_struct *async_queue; /* asynchronous readers */
43 | struct mutex lock; /* mutual exclusion mutex */
44 | struct cdev cdev; /* Char device structure */
45 | };
46 |
47 | /* parameters */
48 | static int scull_p_nr_devs = SCULL_P_NR_DEVS; /* number of pipe devices */
49 | int scull_p_buffer = SCULL_P_BUFFER; /* buffer size */
50 | dev_t scull_p_devno; /* Our first device number */
51 |
52 | module_param(scull_p_nr_devs, int, 0); /* FIXME check perms */
53 | module_param(scull_p_buffer, int, 0);
54 |
55 | static struct scull_pipe *scull_p_devices;
56 |
57 | static int scull_p_fasync(int fd, struct file *filp, int mode);
58 | static int spacefree(struct scull_pipe *dev);
59 | /*
60 | * Open and close
61 | */
62 |
63 |
64 | static int scull_p_open(struct inode *inode, struct file *filp)
65 | {
66 | struct scull_pipe *dev;
67 |
68 | dev = container_of(inode->i_cdev, struct scull_pipe, cdev);
69 | filp->private_data = dev;
70 |
71 | if (mutex_lock_interruptible(&dev->lock))
72 | return -ERESTARTSYS;
73 | if (!dev->buffer) {
74 | /* allocate the buffer */
75 | dev->buffer = kmalloc(scull_p_buffer, GFP_KERNEL);
76 | if (!dev->buffer) {
77 | mutex_unlock(&dev->lock);
78 | return -ENOMEM;
79 | }
80 | }
81 | dev->buffersize = scull_p_buffer;
82 | dev->end = dev->buffer + dev->buffersize;
83 | dev->rp = dev->wp = dev->buffer; /* rd and wr from the beginning */
84 |
85 | /* use f_mode,not f_flags: it's cleaner (fs/open.c tells why) */
86 | if (filp->f_mode & FMODE_READ)
87 | dev->nreaders++;
88 | if (filp->f_mode & FMODE_WRITE)
89 | dev->nwriters++;
90 | mutex_unlock(&dev->lock);
91 |
92 | return nonseekable_open(inode, filp);
93 | }
94 |
95 |
96 |
97 | static int scull_p_release(struct inode *inode, struct file *filp)
98 | {
99 | struct scull_pipe *dev = filp->private_data;
100 |
101 | /* remove this filp from the asynchronously notified filp's */
102 | scull_p_fasync(-1, filp, 0);
103 | mutex_lock(&dev->lock);
104 | if (filp->f_mode & FMODE_READ)
105 | dev->nreaders--;
106 | if (filp->f_mode & FMODE_WRITE)
107 | dev->nwriters--;
108 | if (dev->nreaders + dev->nwriters == 0) {
109 | kfree(dev->buffer);
110 | dev->buffer = NULL; /* the other fields are not checked on open */
111 | }
112 | mutex_unlock(&dev->lock);
113 | return 0;
114 | }
115 |
116 |
117 | /*
118 | * Data management: read and write
119 | */
120 |
121 | static ssize_t scull_p_read (struct file *filp, char __user *buf, size_t count,
122 | loff_t *f_pos)
123 | {
124 | struct scull_pipe *dev = filp->private_data;
125 |
126 | if (mutex_lock_interruptible(&dev->lock))
127 | return -ERESTARTSYS;
128 |
129 | while (dev->rp == dev->wp) { /* nothing to read */
130 | mutex_unlock(&dev->lock); /* release the lock */
131 | if (filp->f_flags & O_NONBLOCK)
132 | return -EAGAIN;
133 | PDEBUG("\"%s\" reading: going to sleep\n", current->comm);
134 | if (wait_event_interruptible(dev->inq, (dev->rp != dev->wp)))
135 | return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
136 | /* otherwise loop, but first reacquire the lock */
137 | if (mutex_lock_interruptible(&dev->lock))
138 | return -ERESTARTSYS;
139 | }
140 | /* ok, data is there, return something */
141 | if (dev->wp > dev->rp)
142 | count = min(count, (size_t)(dev->wp - dev->rp));
143 | else /* the write pointer has wrapped, return data up to dev->end */
144 | count = min(count, (size_t)(dev->end - dev->rp));
145 | if (copy_to_user(buf, dev->rp, count)) {
146 | mutex_unlock (&dev->lock);
147 | return -EFAULT;
148 | }
149 | dev->rp += count;
150 | if (dev->rp == dev->end)
151 | dev->rp = dev->buffer; /* wrapped */
152 | mutex_unlock (&dev->lock);
153 |
154 | /* finally, awake any writers and return */
155 | wake_up_interruptible(&dev->outq);
156 | PDEBUG("\"%s\" did read %li bytes\n",current->comm, (long)count);
157 | return count;
158 | }
159 |
160 | /* Wait for space for writing; caller must hold device semaphore. On
161 | * error the semaphore will be released before returning. */
162 | static int scull_getwritespace(struct scull_pipe *dev, struct file *filp)
163 | {
164 | while (spacefree(dev) == 0) { /* full */
165 | DEFINE_WAIT(wait);
166 |
167 | mutex_unlock(&dev->lock);
168 | if (filp->f_flags & O_NONBLOCK)
169 | return -EAGAIN;
170 | PDEBUG("\"%s\" writing: going to sleep\n",current->comm);
171 | prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE);
172 | if (spacefree(dev) == 0)
173 | schedule();
174 | finish_wait(&dev->outq, &wait);
175 | if (signal_pending(current))
176 | return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
177 | if (mutex_lock_interruptible(&dev->lock))
178 | return -ERESTARTSYS;
179 | }
180 | return 0;
181 | }
182 |
183 | /* How much space is free? */
184 | static int spacefree(struct scull_pipe *dev)
185 | {
186 | if (dev->rp == dev->wp)
187 | return dev->buffersize - 1;
188 | return ((dev->rp + dev->buffersize - dev->wp) % dev->buffersize) - 1;
189 | }
190 |
191 | static ssize_t scull_p_write(struct file *filp, const char __user *buf, size_t count,
192 | loff_t *f_pos)
193 | {
194 | struct scull_pipe *dev = filp->private_data;
195 | int result;
196 |
197 | if (mutex_lock_interruptible(&dev->lock))
198 | return -ERESTARTSYS;
199 |
200 | /* Make sure there's space to write */
201 | result = scull_getwritespace(dev, filp);
202 | if (result)
203 | return result; /* scull_getwritespace called up(&dev->sem) */
204 |
205 | /* ok, space is there, accept something */
206 | count = min(count, (size_t)spacefree(dev));
207 | if (dev->wp >= dev->rp)
208 | count = min(count, (size_t)(dev->end - dev->wp)); /* to end-of-buf */
209 | else /* the write pointer has wrapped, fill up to rp-1 */
210 | count = min(count, (size_t)(dev->rp - dev->wp - 1));
211 | PDEBUG("Going to accept %li bytes to %p from %p\n", (long)count, dev->wp, buf);
212 | if (copy_from_user(dev->wp, buf, count)) {
213 | mutex_unlock(&dev->lock);
214 | return -EFAULT;
215 | }
216 | dev->wp += count;
217 | if (dev->wp == dev->end)
218 | dev->wp = dev->buffer; /* wrapped */
219 | mutex_unlock(&dev->lock);
220 |
221 | /* finally, awake any reader */
222 | wake_up_interruptible(&dev->inq); /* blocked in read() and select() */
223 |
224 | /* and signal asynchronous readers, explained late in chapter 5 */
225 | if (dev->async_queue)
226 | kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
227 | PDEBUG("\"%s\" did write %li bytes\n",current->comm, (long)count);
228 | return count;
229 | }
230 |
231 | static unsigned int scull_p_poll(struct file *filp, poll_table *wait)
232 | {
233 | struct scull_pipe *dev = filp->private_data;
234 | unsigned int mask = 0;
235 |
236 | /*
237 | * The buffer is circular; it is considered full
238 | * if "wp" is right behind "rp" and empty if the
239 | * two are equal.
240 | */
241 | mutex_lock(&dev->lock);
242 | poll_wait(filp, &dev->inq, wait);
243 | poll_wait(filp, &dev->outq, wait);
244 | if (dev->rp != dev->wp)
245 | mask |= POLLIN | POLLRDNORM; /* readable */
246 | if (spacefree(dev))
247 | mask |= POLLOUT | POLLWRNORM; /* writable */
248 | mutex_unlock(&dev->lock);
249 | return mask;
250 | }
251 |
252 |
253 |
254 |
255 |
256 | static int scull_p_fasync(int fd, struct file *filp, int mode)
257 | {
258 | struct scull_pipe *dev = filp->private_data;
259 |
260 | return fasync_helper(fd, filp, mode, &dev->async_queue);
261 | }
262 |
263 |
264 |
265 | /* FIXME this should use seq_file */
266 | #ifdef SCULL_DEBUG
267 |
268 | static int scull_read_p_mem(struct seq_file *s, void *v)
269 | {
270 | int i;
271 | struct scull_pipe *p;
272 |
273 | #define LIMIT (PAGE_SIZE-200) /* don't print any more after this size */
274 | seq_printf(s, "Default buffersize is %i\n", scull_p_buffer);
275 | for(i = 0; icount <= LIMIT; i++) {
276 | p = &scull_p_devices[i];
277 | if (mutex_lock_interruptible(&p->lock))
278 | return -ERESTARTSYS;
279 | seq_printf(s, "\nDevice %i: %p\n", i, p);
280 | /* seq_printf(s, " Queues: %p %p\n", p->inq, p->outq);*/
281 | seq_printf(s, " Buffer: %p to %p (%i bytes)\n", p->buffer, p->end, p->buffersize);
282 | seq_printf(s, " rp %p wp %p\n", p->rp, p->wp);
283 | seq_printf(s, " readers %i writers %i\n", p->nreaders, p->nwriters);
284 | mutex_unlock(&p->lock);
285 | }
286 | return 0;
287 | }
288 |
289 | static int scullpipe_proc_open(struct inode *inode, struct file *file)
290 | {
291 | return single_open(file, scull_read_p_mem, NULL);
292 | }
293 |
294 | static struct file_operations scullpipe_proc_ops = {
295 | .owner = THIS_MODULE,
296 | .open = scullpipe_proc_open,
297 | .read = seq_read,
298 | .llseek = seq_lseek,
299 | .release = single_release
300 | };
301 |
302 | #endif
303 |
304 |
305 |
306 | /*
307 | * The file operations for the pipe device
308 | * (some are overlayed with bare scull)
309 | */
310 | struct file_operations scull_pipe_fops = {
311 | .owner = THIS_MODULE,
312 | .llseek = no_llseek,
313 | .read = scull_p_read,
314 | .write = scull_p_write,
315 | .poll = scull_p_poll,
316 | .unlocked_ioctl = scull_ioctl,
317 | .open = scull_p_open,
318 | .release = scull_p_release,
319 | .fasync = scull_p_fasync,
320 | };
321 |
322 |
323 | /*
324 | * Set up a cdev entry.
325 | */
326 | static void scull_p_setup_cdev(struct scull_pipe *dev, int index)
327 | {
328 | int err, devno = scull_p_devno + index;
329 |
330 | cdev_init(&dev->cdev, &scull_pipe_fops);
331 | dev->cdev.owner = THIS_MODULE;
332 | err = cdev_add (&dev->cdev, devno, 1);
333 | /* Fail gracefully if need be */
334 | if (err)
335 | printk(KERN_NOTICE "Error %d adding scullpipe%d", err, index);
336 | }
337 |
338 |
339 |
340 | /*
341 | * Initialize the pipe devs; return how many we did.
342 | */
343 | int scull_p_init(dev_t firstdev)
344 | {
345 | int i, result;
346 |
347 | result = register_chrdev_region(firstdev, scull_p_nr_devs, "scullp");
348 | if (result < 0) {
349 | printk(KERN_NOTICE "Unable to get scullp region, error %d\n", result);
350 | return 0;
351 | }
352 | scull_p_devno = firstdev;
353 | scull_p_devices = kmalloc(scull_p_nr_devs * sizeof(struct scull_pipe), GFP_KERNEL);
354 | if (scull_p_devices == NULL) {
355 | unregister_chrdev_region(firstdev, scull_p_nr_devs);
356 | return 0;
357 | }
358 | memset(scull_p_devices, 0, scull_p_nr_devs * sizeof(struct scull_pipe));
359 | for (i = 0; i < scull_p_nr_devs; i++) {
360 | init_waitqueue_head(&(scull_p_devices[i].inq));
361 | init_waitqueue_head(&(scull_p_devices[i].outq));
362 | mutex_init(&scull_p_devices[i].lock);
363 | scull_p_setup_cdev(scull_p_devices + i, i);
364 | }
365 | #ifdef SCULL_DEBUG
366 | proc_create("scullpipe", 0, NULL, &scullpipe_proc_ops);
367 | #endif
368 | return scull_p_nr_devs;
369 | }
370 |
371 | /*
372 | * This is called by cleanup_module or on failure.
373 | * It is required to never fail, even if nothing was initialized first
374 | */
375 | void scull_p_cleanup(void)
376 | {
377 | int i;
378 |
379 | #ifdef SCULL_DEBUG
380 | remove_proc_entry("scullpipe", NULL);
381 | #endif
382 |
383 | if (!scull_p_devices)
384 | return; /* nothing else to release */
385 |
386 | for (i = 0; i < scull_p_nr_devs; i++) {
387 | cdev_del(&scull_p_devices[i].cdev);
388 | kfree(scull_p_devices[i].buffer);
389 | }
390 | kfree(scull_p_devices);
391 | unregister_chrdev_region(scull_p_devno, scull_p_nr_devs);
392 | scull_p_devices = NULL; /* pedantic */
393 | }
394 |
--------------------------------------------------------------------------------
/Code_Examples/scull/scull.h:
--------------------------------------------------------------------------------
1 | /*
2 | * scull.h -- definitions for the char module
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | * $Id: scull.h,v 1.15 2004/11/04 17:51:18 rubini Exp $
16 | */
17 |
18 | #ifndef _SCULL_H_
19 | #define _SCULL_H_
20 |
21 | #include /* needed for the _IOW etc stuff used later */
22 |
23 | /*
24 | * Macros to help debugging
25 | */
26 |
27 | #undef PDEBUG /* undef it, just in case */
28 | #ifdef SCULL_DEBUG
29 | # ifdef __KERNEL__
30 | /* This one if debugging is on, and kernel space */
31 | # define PDEBUG(fmt, args...) printk( KERN_DEBUG "scull: " fmt, ## args)
32 | # else
33 | /* This one for user space */
34 | # define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
35 | # endif
36 | #else
37 | # define PDEBUG(fmt, args...) /* not debugging: nothing */
38 | #endif
39 |
40 | #undef PDEBUGG
41 | #define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */
42 |
43 | #ifndef SCULL_MAJOR
44 | #define SCULL_MAJOR 0 /* dynamic major by default */
45 | #endif
46 |
47 | #ifndef SCULL_NR_DEVS
48 | #define SCULL_NR_DEVS 4 /* scull0 through scull3 */
49 | #endif
50 |
51 | #ifndef SCULL_P_NR_DEVS
52 | #define SCULL_P_NR_DEVS 4 /* scullpipe0 through scullpipe3 */
53 | #endif
54 |
55 | /*
56 | * The bare device is a variable-length region of memory.
57 | * Use a linked list of indirect blocks.
58 | *
59 | * "scull_dev->data" points to an array of pointers, each
60 | * pointer refers to a memory area of SCULL_QUANTUM bytes.
61 | *
62 | * The array (quantum-set) is SCULL_QSET long.
63 | */
64 | #ifndef SCULL_QUANTUM
65 | #define SCULL_QUANTUM 4000
66 | #endif
67 |
68 | #ifndef SCULL_QSET
69 | #define SCULL_QSET 1000
70 | #endif
71 |
72 | /*
73 | * The pipe device is a simple circular buffer. Here its default size
74 | */
75 | #ifndef SCULL_P_BUFFER
76 | #define SCULL_P_BUFFER 4000
77 | #endif
78 |
79 | /*
80 | * Representation of scull quantum sets.
81 | */
82 | struct scull_qset {
83 | void **data;
84 | struct scull_qset *next;
85 | };
86 |
87 | struct scull_dev {
88 | struct scull_qset *data; /* Pointer to first quantum set */
89 | int quantum; /* the current quantum size */
90 | int qset; /* the current array size */
91 | unsigned long size; /* amount of data stored here */
92 | unsigned int access_key; /* used by sculluid and scullpriv */
93 | struct mutex lock; /* mutual exclusion semaphore */
94 | struct cdev cdev; /* Char device structure */
95 | };
96 |
97 | /*
98 | * Split minors in two parts
99 | */
100 | #define TYPE(minor) (((minor) >> 4) & 0xf) /* high nibble */
101 | #define NUM(minor) ((minor) & 0xf) /* low nibble */
102 |
103 |
104 | /*
105 | * The different configurable parameters
106 | */
107 | extern int scull_major; /* main.c */
108 | extern int scull_nr_devs;
109 | extern int scull_quantum;
110 | extern int scull_qset;
111 |
112 | extern int scull_p_buffer; /* pipe.c */
113 |
114 |
115 | /*
116 | * Prototypes for shared functions
117 | */
118 |
119 | int scull_p_init(dev_t dev);
120 | void scull_p_cleanup(void);
121 | int scull_access_init(dev_t dev);
122 | void scull_access_cleanup(void);
123 |
124 | int scull_trim(struct scull_dev *dev);
125 |
126 | ssize_t scull_read(struct file *filp, char __user *buf, size_t count,
127 | loff_t *f_pos);
128 | ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,
129 | loff_t *f_pos);
130 | loff_t scull_llseek(struct file *filp, loff_t off, int whence);
131 | long scull_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
132 |
133 |
134 | /*
135 | * Ioctl definitions
136 | */
137 |
138 | /* Use 'k' as magic number */
139 | #define SCULL_IOC_MAGIC 'k'
140 | /* Please use a different 8-bit number in your code */
141 |
142 | #define SCULL_IOCRESET _IO(SCULL_IOC_MAGIC, 0)
143 |
144 | /*
145 | * S means "Set" through a ptr,
146 | * T means "Tell" directly with the argument value
147 | * G means "Get": reply by setting through a pointer
148 | * Q means "Query": response is on the return value
149 | * X means "eXchange": switch G and S atomically
150 | * H means "sHift": switch T and Q atomically
151 | */
152 | #define SCULL_IOCSQUANTUM _IOW(SCULL_IOC_MAGIC, 1, int)
153 | #define SCULL_IOCSQSET _IOW(SCULL_IOC_MAGIC, 2, int)
154 | #define SCULL_IOCTQUANTUM _IO(SCULL_IOC_MAGIC, 3)
155 | #define SCULL_IOCTQSET _IO(SCULL_IOC_MAGIC, 4)
156 | #define SCULL_IOCGQUANTUM _IOR(SCULL_IOC_MAGIC, 5, int)
157 | #define SCULL_IOCGQSET _IOR(SCULL_IOC_MAGIC, 6, int)
158 | #define SCULL_IOCQQUANTUM _IO(SCULL_IOC_MAGIC, 7)
159 | #define SCULL_IOCQQSET _IO(SCULL_IOC_MAGIC, 8)
160 | #define SCULL_IOCXQUANTUM _IOWR(SCULL_IOC_MAGIC, 9, int)
161 | #define SCULL_IOCXQSET _IOWR(SCULL_IOC_MAGIC,10, int)
162 | #define SCULL_IOCHQUANTUM _IO(SCULL_IOC_MAGIC, 11)
163 | #define SCULL_IOCHQSET _IO(SCULL_IOC_MAGIC, 12)
164 |
165 | /*
166 | * The other entities only have "Tell" and "Query", because they're
167 | * not printed in the book, and there's no need to have all six.
168 | * (The previous stuff was only there to show different ways to do it.
169 | */
170 | #define SCULL_P_IOCTSIZE _IO(SCULL_IOC_MAGIC, 13)
171 | #define SCULL_P_IOCQSIZE _IO(SCULL_IOC_MAGIC, 14)
172 | /* ... more to come */
173 |
174 | #define SCULL_IOC_MAXNR 14
175 |
176 | #endif /* _SCULL_H_ */
177 |
--------------------------------------------------------------------------------
/Code_Examples/scull/scull.init:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Sample init script for the scull driver module
3 |
4 | DEVICE="scull"
5 | SECTION="misc"
6 |
7 | # The list of filenames and minor numbers: $PREFIX is prefixed to all names
8 | PREFIX="scull"
9 | FILES=" 0 0 1 1 2 2 3 3 priv 16
10 | pipe0 32 pipe1 33 pipe2 34 pipe3 35
11 | single 48 uid 64 wuid 80"
12 |
13 | INSMOD=/sbin/insmod; # use /sbin/modprobe if you prefer
14 |
15 | function device_specific_post_load () {
16 | true; # fill at will
17 | }
18 | function device_specific_pre_unload () {
19 | true; # fill at will
20 | }
21 |
22 | # Everything below this line should work unchanged for any char device.
23 | # Obviously, however, no options on the command line: either in
24 | # /etc/${DEVICE}.conf or /etc/modules.conf (if modprobe is used)
25 |
26 | # Optional configuration file: format is
27 | # owner
28 | # group
29 | # mode
30 | # options
31 | CFG=/etc/${DEVICE}.conf
32 |
33 | # kernel version, used to look for modules
34 | KERNEL=`uname -r`
35 |
36 | #FIXME: it looks like there is no misc section. Where should it be?
37 | MODDIR="/lib/modules/${KERNEL}/kernel/drivers/${SECTION}"
38 | if [ ! -d $MODDIR ]; then MODDIR="/lib/modules/${KERNEL}/${SECTION}"; fi
39 |
40 | # Root or die
41 | if [ "$(id -u)" != "0" ]
42 | then
43 | echo "You must be root to load or unload kernel modules"
44 | exit 1
45 | fi
46 |
47 | # Read configuration file
48 | if [ -r $CFG ]; then
49 | OWNER=`awk "\\$1==\"owner\" {print \\$2}" $CFG`
50 | GROUP=`awk "\\$1==\"group\" {print \\$2}" $CFG`
51 | MODE=`awk "\\$1==\"mode\" {print \\$2}" $CFG`
52 | # The options string may include extra blanks or only blanks
53 | OPTIONS=`sed -n '/^options / s/options //p' $CFG`
54 | fi
55 |
56 |
57 | # Create device files
58 | function create_files () {
59 | cd /dev
60 | local devlist=""
61 | local file
62 | while true; do
63 | if [ $# -lt 2 ]; then break; fi
64 | file="${DEVICE}$1"
65 | mknod $file c $MAJOR $2
66 | devlist="$devlist $file"
67 | shift 2
68 | done
69 | if [ -n "$OWNER" ]; then chown $OWNER $devlist; fi
70 | if [ -n "$GROUP" ]; then chgrp $GROUP $devlist; fi
71 | if [ -n "$MODE" ]; then chmod $MODE $devlist; fi
72 | }
73 |
74 | # Remove device files
75 | function remove_files () {
76 | cd /dev
77 | local devlist=""
78 | local file
79 | while true; do
80 | if [ $# -lt 2 ]; then break; fi
81 | file="${DEVICE}$1"
82 | devlist="$devlist $file"
83 | shift 2
84 | done
85 | rm -f $devlist
86 | }
87 |
88 | # Load and create files
89 | function load_device () {
90 |
91 | if [ -f $MODDIR/$DEVICE.ko ]; then
92 | devpath=$MODDIR/$DEVICE.ko
93 | else if [ -f ./$DEVICE.ko ]; then
94 | devpath=./$DEVICE.ko
95 | else
96 | devpath=$DEVICE; # let insmod/modprobe guess
97 | fi; fi
98 | if [ "$devpath" != "$DEVICE" ]; then
99 | echo -n " (loading file $devpath)"
100 | fi
101 |
102 | if $INSMOD $devpath $OPTIONS; then
103 | MAJOR=`awk "\\$2==\"$DEVICE\" {print \\$1}" /proc/devices`
104 | remove_files $FILES
105 | create_files $FILES
106 | device_specific_post_load
107 | else
108 | echo " FAILED!"
109 | fi
110 | }
111 |
112 | # Unload and remove files
113 | function unload_device () {
114 | device_specific_pre_unload
115 | /sbin/rmmod $DEVICE
116 | remove_files $FILES
117 | }
118 |
119 |
120 | case "$1" in
121 | start)
122 | echo -n "Loading $DEVICE"
123 | load_device
124 | echo "."
125 | ;;
126 | stop)
127 | echo -n "Unloading $DEVICE"
128 | unload_device
129 | echo "."
130 | ;;
131 | force-reload|restart)
132 | echo -n "Reloading $DEVICE"
133 | unload_device
134 | load_device
135 | echo "."
136 | ;;
137 | *)
138 | echo "Usage: $0 {start|stop|restart|force-reload}"
139 | exit 1
140 | esac
141 |
142 | exit 0
143 |
--------------------------------------------------------------------------------
/Code_Examples/scull/scull_load:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # $Id: scull_load,v 1.4 2004/11/03 06:19:49 rubini Exp $
3 | module="scull"
4 | device="scull"
5 | mode="664"
6 |
7 | # Group: since distributions do it differently, look for wheel or use staff
8 | if grep -q '^staff:' /etc/group; then
9 | group="staff"
10 | else
11 | group="wheel"
12 | fi
13 |
14 | # invoke insmod with all arguments we got
15 | # and use a pathname, as insmod doesn't look in . by default
16 | insmod ./$module.ko $* || exit 1
17 |
18 | # retrieve major number
19 | major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices)
20 |
21 | # Remove stale nodes and replace them, then give gid and perms
22 | # Usually the script is shorter, it's scull that has several devices in it.
23 |
24 | rm -f /dev/${device}[0-3]
25 | mknod /dev/${device}0 c $major 0
26 | mknod /dev/${device}1 c $major 1
27 | mknod /dev/${device}2 c $major 2
28 | mknod /dev/${device}3 c $major 3
29 | ln -sf ${device}0 /dev/${device}
30 | chgrp $group /dev/${device}[0-3]
31 | chmod $mode /dev/${device}[0-3]
32 |
33 | rm -f /dev/${device}pipe[0-3]
34 | mknod /dev/${device}pipe0 c $major 4
35 | mknod /dev/${device}pipe1 c $major 5
36 | mknod /dev/${device}pipe2 c $major 6
37 | mknod /dev/${device}pipe3 c $major 7
38 | ln -sf ${device}pipe0 /dev/${device}pipe
39 | chgrp $group /dev/${device}pipe[0-3]
40 | chmod $mode /dev/${device}pipe[0-3]
41 |
42 | rm -f /dev/${device}single
43 | mknod /dev/${device}single c $major 8
44 | chgrp $group /dev/${device}single
45 | chmod $mode /dev/${device}single
46 |
47 | rm -f /dev/${device}uid
48 | mknod /dev/${device}uid c $major 9
49 | chgrp $group /dev/${device}uid
50 | chmod $mode /dev/${device}uid
51 |
52 | rm -f /dev/${device}wuid
53 | mknod /dev/${device}wuid c $major 10
54 | chgrp $group /dev/${device}wuid
55 | chmod $mode /dev/${device}wuid
56 |
57 | rm -f /dev/${device}priv
58 | mknod /dev/${device}priv c $major 11
59 | chgrp $group /dev/${device}priv
60 | chmod $mode /dev/${device}priv
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/Code_Examples/scull/scull_unload:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module="scull"
3 | device="scull"
4 |
5 | # invoke rmmod with all arguments we got
6 | rmmod $module $* || exit 1
7 |
8 | # Remove stale nodes
9 |
10 | rm -f /dev/${device} /dev/${device}[0-3]
11 | rm -f /dev/${device}priv
12 | rm -f /dev/${device}pipe /dev/${device}pipe[0-3]
13 | rm -f /dev/${device}single
14 | rm -f /dev/${device}uid
15 | rm -f /dev/${device}wuid
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Code_Examples/socketCAN/README.md:
--------------------------------------------------------------------------------
1 | # Playing with SocketCAN
2 |
3 | Alright folks, some bonus content for you.
4 |
5 | While this section is not specifically a kernel module, it is a user-space program set that heavily uses the Linux SocketCAN API (which is a lot of kernel code relating to networking). This is like 1 step above kernel programming so I wanted to include it here.
6 |
7 | First, you will need the two source files: ReceiveRawPacket.c and SendRawPacket.c. The first file receives CAN data continuously, and the second file sends a one-time CAN message.
8 |
9 | Start by compiling both programs with:
10 |
11 | ```shell
12 | $ gcc -o CanReceive ReceiveRawPacket.c
13 | $ gcc -o CanSend SendRawPacket.c
14 | ```
15 |
16 | Now, you will need to setup a virtual CAN bus, called vcan0:
17 |
18 | ```shell
19 | $ modprobe can
20 | $ modprobe can_raw
21 | $ modprobe vcan
22 | $ sudo ip link add dev vcan0 type vcan
23 | $ sudo ip link set up vcan0
24 | $ ip link show vcan0
25 | ```
26 |
27 | Start by executing CanReceive and then CanSend. You should see this from the CanSend terminal:
28 |
29 | ```shell
30 | $ ./CanSend vcan0
31 |
32 | vcan0 at index 4
33 | Wrote 16 bytes
34 | ```
35 |
36 | And see this from the CanReceive terminal output:
37 |
38 | ```shell
39 | $ ./CanReceive vcan0
40 | vcan0 at index 4
41 | Read 16 bytes
42 | CAN ID: 123
43 | CAN DLC: 8
44 | CAN DATA:
45 | de ad be ef 12 34 56 78
46 | ```
47 |
48 | The CanReceive file will keep listening for more data, while the CanSend will only send once. You can run the CanSend file multiple times to see data sent multiple times. You can also monitor the CAN bus with a built-in tool called candump:
49 |
50 | ```shell
51 | $ candump vcan0
52 |
53 | vcan0 123 [8] DE AD BE EF 12 34 56 78
54 | ```
55 |
--------------------------------------------------------------------------------
/Code_Examples/socketCAN/ReceiveRawPacket.c:
--------------------------------------------------------------------------------
1 | // Code to test sending manual messages over a virtual can interface
2 |
3 | // Use these headers to communicate with a raw can data frame
4 | #include
5 | #include
6 |
7 | // Additional socket stuff needed by the socketCAN library
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | // And finally, the regular c types for having some fun!
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | int main(int argc, char *argv[])
20 | {
21 | int fd; //file descriptor for reading and writing
22 | int bytes_read; //number of bytes received over CAN
23 | int i; //used in a loop later on for printing
24 |
25 | // structure for CAN sockets includes:
26 | // address family, interface index, specific address info
27 | struct sockaddr_can addr;
28 |
29 | // structure for an individual frame in CAN
30 | struct can_frame frame;
31 |
32 | // Linux supports some standard ioctls to configure network devices.
33 | // They can be used on any socket's file descriptor regardless of the
34 | // family or type. Most of them pass an ifreq structure:
35 | struct ifreq ifr;
36 |
37 | // Check to make sure we have entered a CAN interface to use
38 | if (argc < 2)
39 | {
40 | printf("Please enter CAN bus to write to (ex: vcan0)\n");
41 | printf("Args: Canbus\n");
42 | return -1;
43 | }
44 |
45 | // Get the interface name from command line arguments
46 | const char *ifname = argv[1];
47 |
48 | // Now we create a new socket endpoint for communication
49 | // Args: domain, type, protocol
50 | // returns a file descriptor
51 | if((fd = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
52 | perror("Error while opening socket");
53 | return -2;
54 | }
55 |
56 | // Here we pass the ifreq structure to ioctl
57 | strcpy(ifr.ifr_name, ifname);
58 | ioctl(fd, SIOCGIFINDEX, &ifr);
59 |
60 | // Set address family and network interface index of CAN socket
61 | addr.can_family = AF_CAN;
62 | addr.can_ifindex = ifr.ifr_ifindex;
63 |
64 | // Print the name of the interface and the index
65 | printf("%s at index %d\n", ifname, ifr.ifr_ifindex);
66 |
67 | // Bind the file descriptor name to the socket
68 | if(bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
69 | perror("Error in socket bind");
70 | return -3;
71 | }
72 |
73 | while(1)
74 | {
75 | // Write the data to the CAN bus and record the number of bytes written
76 | bytes_read = read(fd, &frame, sizeof(struct can_frame));
77 |
78 | printf("Read %d bytes\n", bytes_read);
79 | printf("CAN ID: %x \n", frame.can_id);
80 | printf("CAN DLC: %d \n", frame.can_dlc);
81 | printf("CAN DATA: \n");
82 | for (i = 0; i < frame.can_dlc; i++)
83 | {
84 | printf("%x ", frame.data[i]);
85 | }
86 | printf("\n");
87 | }
88 |
89 | return 0;
90 | }
91 |
--------------------------------------------------------------------------------
/Code_Examples/socketCAN/SendRawPacket.c:
--------------------------------------------------------------------------------
1 | // Code to test sending manual messages over a virtual can interface
2 |
3 | // Use these headers to communicate with a raw can data frame
4 | #include
5 | #include
6 |
7 | // Additional socket stuff needed by the socketCAN library
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | // And finally, the regular c types for having some fun!
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | int main(int argc, char *argv[])
20 | {
21 | int fd; //file descriptor for reading and writing
22 | int bytes_transferred; //number of bytes sent over CAN
23 |
24 | // structure for CAN sockets includes:
25 | // address family, interface index, specific address info
26 | struct sockaddr_can addr;
27 |
28 | // structure for an individual frame in CAN
29 | struct can_frame frame;
30 |
31 | // Linux supports some standard ioctls to configure network devices.
32 | // They can be used on any socket's file descriptor regardless of the
33 | // family or type. Most of them pass an ifreq structure:
34 | struct ifreq ifr;
35 |
36 | // Check to make sure we have entered a CAN interface to use
37 | if (argc < 2)
38 | {
39 | printf("Please enter CAN bus to write to (ex: vcan0)\n");
40 | printf("Args: Canbus\n");
41 | return -1;
42 | }
43 |
44 | // Get the interface name from command line arguments
45 | const char *ifname = argv[1];
46 |
47 | // Now we create a new socket endpoint for communication
48 | // Args: domain, type, protocol
49 | // returns a file descriptor
50 | if((fd = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
51 | perror("Error while opening socket");
52 | return -2;
53 | }
54 |
55 | // Here we pass the ifreq structure to ioctl
56 | strcpy(ifr.ifr_name, ifname);
57 | ioctl(fd, SIOCGIFINDEX, &ifr);
58 |
59 | // Set address family and network interface index of CAN socket
60 | addr.can_family = AF_CAN;
61 | addr.can_ifindex = ifr.ifr_ifindex;
62 |
63 | // Print the name of the interface and the index
64 | printf("%s at index %d\n", ifname, ifr.ifr_ifindex);
65 |
66 | // Bind the file descriptor name to the socket
67 | if(bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
68 | perror("Error in socket bind");
69 | return -3;
70 | }
71 |
72 | // Setup the can frame with the correct ID, DLC, and values
73 | frame.can_id = 0x123; // 32-bit CAN_ID + EFF/RTR/ERR flags
74 | frame.can_dlc = 8; //data length code - we want 8 bytes here (the MAX!)
75 | frame.data[0] = 0xde; //first data byte
76 | frame.data[1] = 0xad; //second data byte
77 | frame.data[2] = 0xbe; //third data byte
78 | frame.data[3] = 0xef; //fourth data byte ...
79 | frame.data[4] = 0x12;
80 | frame.data[5] = 0x34;
81 | frame.data[6] = 0x56;
82 | frame.data[7] = 0x78;
83 |
84 | // Write the data to the CAN bus and record the number of bytes written
85 | bytes_transferred = write(fd, &frame, sizeof(struct can_frame));
86 |
87 | printf("Wrote %d bytes\n", bytes_transferred);
88 |
89 | return 0;
90 | }
91 |
--------------------------------------------------------------------------------
/Code_Examples/tty/Makefile:
--------------------------------------------------------------------------------
1 | # Comment/uncomment the following line to disable/enable debugging
2 | #DEBUG = y
3 |
4 |
5 | # Add your debugging flag (or not) to CFLAGS
6 | ifeq ($(DEBUG),y)
7 | DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
8 | else
9 | DEBFLAGS = -O2
10 | endif
11 |
12 | EXTRA_CFLAGS += $(DEBFLAGS)
13 | EXTRA_CFLAGS += -I..
14 |
15 | ifneq ($(KERNELRELEASE),)
16 | # call from kernel build system
17 |
18 | obj-m := tiny_tty.o tiny_serial.o
19 |
20 | else
21 |
22 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
23 | PWD := $(shell pwd)
24 |
25 | default:
26 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
27 |
28 | endif
29 |
30 |
31 |
32 | clean:
33 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
34 |
35 | depend .depend dep:
36 | $(CC) $(EXTRA_CFLAGS) -M *.c > .depend
37 |
38 |
39 | ifeq (.depend,$(wildcard .depend))
40 | include .depend
41 | endif
42 |
--------------------------------------------------------------------------------
/Code_Examples/tty/README.md:
--------------------------------------------------------------------------------
1 | # Why are these here?
2 |
3 | I added the tty drivers from the sample repos with some slight modifications to make them run better. I made the device major number dynamic and added a close method to the serial version.
4 |
5 | ### Current Bugs
6 |
7 | If you insert the tty driver, then remove it, then try to reinsert it there will be an error because it still doesn't clean itself up properly. You should be able to use it on the first try though. See my book notes on tty drivers for some more details.
8 |
--------------------------------------------------------------------------------
/Code_Examples/tty/tiny_serial.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Tiny Serial driver
3 | *
4 | * Copyright (C) 2002-2004 Greg Kroah-Hartman (greg@kroah.com)
5 | *
6 | * This program is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, version 2 of the License.
9 | *
10 | * This driver shows how to create a minimal serial driver. It does not rely on
11 | * any backing hardware, but creates a timer that emulates data being received
12 | * from some kind of hardware.
13 | */
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | #define DRIVER_AUTHOR "Greg Kroah-Hartman "
27 | #define DRIVER_DESC "Tiny serial driver"
28 |
29 | /* Module information */
30 | MODULE_AUTHOR( DRIVER_AUTHOR );
31 | MODULE_DESCRIPTION( DRIVER_DESC );
32 | MODULE_LICENSE("GPL");
33 |
34 | #define DELAY_TIME HZ * 2 /* 2 seconds per character */
35 | #define TINY_DATA_CHARACTER 't'
36 |
37 | #define TINY_SERIAL_MAJOR 0 /* experimental range */
38 | #define TINY_SERIAL_MINORS 1 /* only have one minor */
39 | #define UART_NR 1 /* only use one port */
40 |
41 | #define TINY_SERIAL_NAME "ttytiny"
42 |
43 | #define MY_NAME TINY_SERIAL_NAME
44 |
45 | static struct timer_list *timer;
46 |
47 | static void tiny_stop_tx(struct uart_port *port)
48 | {
49 | }
50 |
51 | static void tiny_stop_rx(struct uart_port *port)
52 | {
53 | }
54 |
55 | static void tiny_enable_ms(struct uart_port *port)
56 | {
57 | }
58 |
59 | static void tiny_tx_chars(struct uart_port *port)
60 | {
61 | struct circ_buf *xmit = &port->state->xmit;
62 | int count;
63 |
64 | if (port->x_char) {
65 | pr_debug("wrote %2x", port->x_char);
66 | port->icount.tx++;
67 | port->x_char = 0;
68 | return;
69 | }
70 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
71 | tiny_stop_tx(port);
72 | return;
73 | }
74 |
75 | count = port->fifosize >> 1;
76 | do {
77 | pr_debug("wrote %2x", xmit->buf[xmit->tail]);
78 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
79 | port->icount.tx++;
80 | if (uart_circ_empty(xmit))
81 | break;
82 | } while (--count > 0);
83 |
84 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
85 | uart_write_wakeup(port);
86 |
87 | if (uart_circ_empty(xmit))
88 | tiny_stop_tx(port);
89 | }
90 |
91 | static void tiny_start_tx(struct uart_port *port)
92 | {
93 | }
94 |
95 | static void tiny_timer(unsigned long data)
96 | {
97 | struct uart_port *port;
98 | struct tty_struct *tty;
99 | struct tty_port *tty_port;
100 |
101 |
102 | port = (struct uart_port *)data;
103 | if (!port)
104 | return;
105 | if (!port->state)
106 | return;
107 | tty = port->state->port.tty;
108 | if (!tty)
109 | return;
110 |
111 | tty_port = tty->port;
112 |
113 | /* add one character to the tty port */
114 | /* this doesn't actually push the data through unless tty->low_latency is set */
115 | tty_insert_flip_char(tty_port, TINY_DATA_CHARACTER, 0);
116 |
117 | tty_flip_buffer_push(tty_port);
118 |
119 | /* resubmit the timer again */
120 | timer->expires = jiffies + DELAY_TIME;
121 | add_timer(timer);
122 |
123 | /* see if we have any data to transmit */
124 | tiny_tx_chars(port);
125 | }
126 |
127 | static unsigned int tiny_tx_empty(struct uart_port *port)
128 | {
129 | return 0;
130 | }
131 |
132 | static unsigned int tiny_get_mctrl(struct uart_port *port)
133 | {
134 | return 0;
135 | }
136 |
137 | static void tiny_set_mctrl(struct uart_port *port, unsigned int mctrl)
138 | {
139 | }
140 |
141 | static void tiny_break_ctl(struct uart_port *port, int break_state)
142 | {
143 | }
144 |
145 | static void tiny_set_termios(struct uart_port *port,
146 | struct ktermios *new, struct ktermios *old)
147 | {
148 | int baud, quot, cflag = new->c_cflag;
149 | /* get the byte size */
150 | switch (cflag & CSIZE) {
151 | case CS5:
152 | printk(KERN_DEBUG " - data bits = 5\n");
153 | break;
154 | case CS6:
155 | printk(KERN_DEBUG " - data bits = 6\n");
156 | break;
157 | case CS7:
158 | printk(KERN_DEBUG " - data bits = 7\n");
159 | break;
160 | default: // CS8
161 | printk(KERN_DEBUG " - data bits = 8\n");
162 | break;
163 | }
164 |
165 | /* determine the parity */
166 | if (cflag & PARENB)
167 | if (cflag & PARODD)
168 | pr_debug(" - parity = odd\n");
169 | else
170 | pr_debug(" - parity = even\n");
171 | else
172 | pr_debug(" - parity = none\n");
173 |
174 | /* figure out the stop bits requested */
175 | if (cflag & CSTOPB)
176 | pr_debug(" - stop bits = 2\n");
177 | else
178 | pr_debug(" - stop bits = 1\n");
179 |
180 | /* figure out the flow control settings */
181 | if (cflag & CRTSCTS)
182 | pr_debug(" - RTS/CTS is enabled\n");
183 | else
184 | pr_debug(" - RTS/CTS is disabled\n");
185 |
186 | /* Set baud rate */
187 | baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
188 | quot = uart_get_divisor(port, baud);
189 |
190 | //UART_PUT_DIV_LO(port, (quot & 0xff));
191 | //UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8));
192 | }
193 |
194 | static int tiny_startup(struct uart_port *port)
195 | {
196 | /* this is the first time this port is opened */
197 | /* do any hardware initialization needed here */
198 |
199 | /* create our timer and submit it */
200 | if (!timer) {
201 | timer = kmalloc(sizeof(*timer), GFP_KERNEL);
202 | if (!timer)
203 | return -ENOMEM;
204 | }
205 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
206 | timer->data = (unsigned long)port;
207 | timer->function = tiny_timer;
208 | #else
209 | timer_setup(timer, (void *) tiny_timer, (unsigned long) port);
210 | timer->function = (void *) tiny_timer;
211 | #endif
212 | timer->expires = jiffies + DELAY_TIME;
213 | add_timer(timer);
214 | return 0;
215 | }
216 |
217 | static void tiny_shutdown(struct uart_port *port)
218 | {
219 | /* The port is being closed by the last user. */
220 | /* Do any hardware specific stuff here */
221 |
222 | /* shut down our timer */
223 | del_timer(timer);
224 | }
225 |
226 | static const char *tiny_type(struct uart_port *port)
227 | {
228 | return "tinytty";
229 | }
230 |
231 | static void tiny_release_port(struct uart_port *port)
232 | {
233 |
234 | }
235 |
236 | static int tiny_request_port(struct uart_port *port)
237 | {
238 | return 0;
239 | }
240 |
241 | static void tiny_config_port(struct uart_port *port, int flags)
242 | {
243 | }
244 |
245 | static int tiny_verify_port(struct uart_port *port, struct serial_struct *ser)
246 | {
247 | return 0;
248 | }
249 |
250 | static struct uart_ops tiny_ops = {
251 | .tx_empty = tiny_tx_empty,
252 | .set_mctrl = tiny_set_mctrl,
253 | .get_mctrl = tiny_get_mctrl,
254 | .stop_tx = tiny_stop_tx,
255 | .start_tx = tiny_start_tx,
256 | .stop_rx = tiny_stop_rx,
257 | .enable_ms = tiny_enable_ms,
258 | .break_ctl = tiny_break_ctl,
259 | .startup = tiny_startup,
260 | .shutdown = tiny_shutdown,
261 | .set_termios = tiny_set_termios,
262 | .type = tiny_type,
263 | .release_port = tiny_release_port,
264 | .request_port = tiny_request_port,
265 | .config_port = tiny_config_port,
266 | .verify_port = tiny_verify_port,
267 | };
268 |
269 | static struct uart_port tiny_port = {
270 | .ops = &tiny_ops,
271 | };
272 |
273 | static struct uart_driver tiny_reg = {
274 | .owner = THIS_MODULE,
275 | .driver_name = TINY_SERIAL_NAME,
276 | .dev_name = TINY_SERIAL_NAME,
277 | .major = TINY_SERIAL_MAJOR,
278 | .minor = TINY_SERIAL_MINORS,
279 | .nr = UART_NR,
280 | };
281 |
282 | static int __init tiny_init(void)
283 | {
284 | int result;
285 |
286 | printk(KERN_INFO "Tiny serial driver loaded\n");
287 |
288 | result = uart_register_driver(&tiny_reg);
289 | if (result)
290 | return result;
291 |
292 | result = uart_add_one_port(&tiny_reg, &tiny_port);
293 | if (result)
294 | uart_unregister_driver(&tiny_reg);
295 |
296 | return result;
297 | }
298 |
299 | static void __exit tiny_exit(void)
300 | {
301 | uart_remove_one_port(&tiny_reg, &tiny_port);
302 | uart_unregister_driver(&tiny_reg);
303 | }
304 |
305 | module_init(tiny_init);
306 | module_exit(tiny_exit);
307 |
--------------------------------------------------------------------------------
/Code_Examples/tty/tiny_tty.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Tiny TTY driver
3 | *
4 | * Copyright (C) 2002-2004 Greg Kroah-Hartman (greg@kroah.com)
5 | *
6 | * This program is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, version 2 of the License.
9 | *
10 | * This driver shows how to create a minimal tty driver. It does not rely on
11 | * any backing hardware, but creates a timer that emulates data being received
12 | * from some kind of hardware.
13 | */
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | #define DRIVER_VERSION "v2.0"
31 | #define DRIVER_AUTHOR "Greg Kroah-Hartman "
32 | #define DRIVER_DESC "Tiny TTY driver"
33 |
34 | /* Module information */
35 | MODULE_AUTHOR(DRIVER_AUTHOR);
36 | MODULE_DESCRIPTION(DRIVER_DESC);
37 | MODULE_LICENSE("GPL");
38 |
39 | #define DELAY_TIME (HZ * 2) /* 2 seconds per character */
40 | #define TINY_DATA_CHARACTER 't'
41 |
42 | #define TINY_TTY_MAJOR 0 /* experimental range */
43 | #define TINY_TTY_MINORS 4 /* only have 4 devices */
44 |
45 | struct tiny_serial {
46 | struct tty_struct *tty; /* pointer to the tty for this device */
47 | int open_count; /* number of times this port has been opened */
48 | struct mutex mutex; /* locks this structure */
49 | struct timer_list timer;
50 |
51 | /* for tiocmget and tiocmset functions */
52 | int msr; /* MSR shadow */
53 | int mcr; /* MCR shadow */
54 |
55 | /* for ioctl fun */
56 | struct serial_struct serial;
57 | wait_queue_head_t wait;
58 | struct async_icount icount;
59 | };
60 |
61 | static struct tiny_serial *tiny_table[TINY_TTY_MINORS]; /* initially all NULL */
62 | static struct tty_port tiny_tty_port[TINY_TTY_MINORS];
63 |
64 |
65 | static void tiny_timer(struct timer_list *t)
66 | {
67 | struct tiny_serial *tiny = from_timer(tiny, t, timer);
68 | struct tty_struct *tty;
69 | struct tty_port *port;
70 | int i;
71 | char data[1] = {TINY_DATA_CHARACTER};
72 | int data_size = 1;
73 |
74 | if (!tiny)
75 | return;
76 |
77 | tty = tiny->tty;
78 | port = tty->port;
79 |
80 | /* send the data to the tty layer for users to read. This doesn't
81 | * actually push the data through unless tty->low_latency is set */
82 | for (i = 0; i < data_size; ++i) {
83 | if (!tty_buffer_request_room(port, 1))
84 | tty_flip_buffer_push(port);
85 | tty_insert_flip_char(port, data[i], TTY_NORMAL);
86 | }
87 | tty_flip_buffer_push(port);
88 |
89 | /* resubmit the timer again */
90 | tiny->timer.expires = jiffies + DELAY_TIME;
91 | add_timer(&tiny->timer);
92 | }
93 |
94 | static int tiny_open(struct tty_struct *tty, struct file *file)
95 | {
96 | struct tiny_serial *tiny;
97 | int index;
98 |
99 | /* initialize the pointer in case something fails */
100 | tty->driver_data = NULL;
101 |
102 | /* get the serial object associated with this tty pointer */
103 | index = tty->index;
104 | tiny = tiny_table[index];
105 | if (tiny == NULL) {
106 | /* first time accessing this device, let's create it */
107 | tiny = kmalloc(sizeof(*tiny), GFP_KERNEL);
108 | if (!tiny)
109 | return -ENOMEM;
110 |
111 | mutex_init(&tiny->mutex);
112 | tiny->open_count = 0;
113 |
114 | tiny_table[index] = tiny;
115 | }
116 |
117 | mutex_lock(&tiny->mutex);
118 |
119 | /* save our structure within the tty structure */
120 | tty->driver_data = tiny;
121 | tiny->tty = tty;
122 |
123 | ++tiny->open_count;
124 | if (tiny->open_count == 1) {
125 | /* this is the first time this port is opened */
126 | /* do any hardware initialization needed here */
127 |
128 | /* create our timer and submit it */
129 | timer_setup(&tiny->timer, tiny_timer, 0);
130 | tiny->timer.expires = jiffies + DELAY_TIME;
131 | add_timer(&tiny->timer);
132 | }
133 |
134 | mutex_unlock(&tiny->mutex);
135 | return 0;
136 | }
137 |
138 | static void do_close(struct tiny_serial *tiny)
139 | {
140 | mutex_lock(&tiny->mutex);
141 |
142 | if (!tiny->open_count) {
143 | /* port was never opened */
144 | goto exit;
145 | }
146 |
147 | --tiny->open_count;
148 | if (tiny->open_count <= 0) {
149 | /* The port is being closed by the last user. */
150 | /* Do any hardware specific stuff here */
151 |
152 | /* shut down our timer */
153 | del_timer(&tiny->timer);
154 | }
155 | exit:
156 | mutex_unlock(&tiny->mutex);
157 | }
158 |
159 | static void tiny_close(struct tty_struct *tty, struct file *file)
160 | {
161 | struct tiny_serial *tiny = tty->driver_data;
162 |
163 | if (tiny)
164 | do_close(tiny);
165 | }
166 |
167 | static int tiny_write(struct tty_struct *tty,
168 | const unsigned char *buffer, int count)
169 | {
170 | struct tiny_serial *tiny = tty->driver_data;
171 | int i;
172 | int retval = -EINVAL;
173 |
174 | if (!tiny)
175 | return -ENODEV;
176 |
177 | mutex_lock(&tiny->mutex);
178 |
179 | if (!tiny->open_count)
180 | /* port was not opened */
181 | goto exit;
182 |
183 | /* fake sending the data out a hardware port by
184 | * writing it to the kernel debug log.
185 | */
186 | pr_debug("%s - ", __func__);
187 | for (i = 0; i < count; ++i)
188 | pr_info("%02x ", buffer[i]);
189 | pr_info("\n");
190 |
191 | exit:
192 | mutex_unlock(&tiny->mutex);
193 | return retval;
194 | }
195 |
196 | static int tiny_write_room(struct tty_struct *tty)
197 | {
198 | struct tiny_serial *tiny = tty->driver_data;
199 | int room = -EINVAL;
200 |
201 | if (!tiny)
202 | return -ENODEV;
203 |
204 | mutex_lock(&tiny->mutex);
205 |
206 | if (!tiny->open_count) {
207 | /* port was not opened */
208 | goto exit;
209 | }
210 |
211 | /* calculate how much room is left in the device */
212 | room = 255;
213 |
214 | exit:
215 | mutex_unlock(&tiny->mutex);
216 | return room;
217 | }
218 |
219 | #define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
220 |
221 | static void tiny_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
222 | {
223 | unsigned int cflag;
224 |
225 | cflag = tty->termios.c_cflag;
226 |
227 | /* check that they really want us to change something */
228 | if (old_termios) {
229 | if ((cflag == old_termios->c_cflag) &&
230 | (RELEVANT_IFLAG(tty->termios.c_iflag) ==
231 | RELEVANT_IFLAG(old_termios->c_iflag))) {
232 | pr_debug(" - nothing to change...\n");
233 | return;
234 | }
235 | }
236 |
237 | /* get the byte size */
238 | switch (cflag & CSIZE) {
239 | case CS5:
240 | pr_debug(" - data bits = 5\n");
241 | break;
242 | case CS6:
243 | pr_debug(" - data bits = 6\n");
244 | break;
245 | case CS7:
246 | pr_debug(" - data bits = 7\n");
247 | break;
248 | default:
249 | case CS8:
250 | pr_debug(" - data bits = 8\n");
251 | break;
252 | }
253 |
254 | /* determine the parity */
255 | if (cflag & PARENB)
256 | if (cflag & PARODD)
257 | pr_debug(" - parity = odd\n");
258 | else
259 | pr_debug(" - parity = even\n");
260 | else
261 | pr_debug(" - parity = none\n");
262 |
263 | /* figure out the stop bits requested */
264 | if (cflag & CSTOPB)
265 | pr_debug(" - stop bits = 2\n");
266 | else
267 | pr_debug(" - stop bits = 1\n");
268 |
269 | /* figure out the hardware flow control settings */
270 | if (cflag & CRTSCTS)
271 | pr_debug(" - RTS/CTS is enabled\n");
272 | else
273 | pr_debug(" - RTS/CTS is disabled\n");
274 |
275 | /* determine software flow control */
276 | /* if we are implementing XON/XOFF, set the start and
277 | * stop character in the device */
278 | if (I_IXOFF(tty) || I_IXON(tty)) {
279 | unsigned char stop_char = STOP_CHAR(tty);
280 | unsigned char start_char = START_CHAR(tty);
281 |
282 | /* if we are implementing INBOUND XON/XOFF */
283 | if (I_IXOFF(tty))
284 | pr_debug(" - INBOUND XON/XOFF is enabled, "
285 | "XON = %2x, XOFF = %2x", start_char, stop_char);
286 | else
287 | pr_debug(" - INBOUND XON/XOFF is disabled");
288 |
289 | /* if we are implementing OUTBOUND XON/XOFF */
290 | if (I_IXON(tty))
291 | pr_debug(" - OUTBOUND XON/XOFF is enabled, "
292 | "XON = %2x, XOFF = %2x", start_char, stop_char);
293 | else
294 | pr_debug(" - OUTBOUND XON/XOFF is disabled");
295 | }
296 |
297 | /* get the baud rate wanted */
298 | pr_debug(" - baud rate = %d", tty_get_baud_rate(tty));
299 | }
300 |
301 | /* Our fake UART values */
302 | #define MCR_DTR 0x01
303 | #define MCR_RTS 0x02
304 | #define MCR_LOOP 0x04
305 | #define MSR_CTS 0x08
306 | #define MSR_CD 0x10
307 | #define MSR_RI 0x20
308 | #define MSR_DSR 0x40
309 |
310 | static int tiny_tiocmget(struct tty_struct *tty)
311 | {
312 | struct tiny_serial *tiny = tty->driver_data;
313 |
314 | unsigned int result = 0;
315 | unsigned int msr = tiny->msr;
316 | unsigned int mcr = tiny->mcr;
317 |
318 | result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) | /* DTR is set */
319 | ((mcr & MCR_RTS) ? TIOCM_RTS : 0) | /* RTS is set */
320 | ((mcr & MCR_LOOP) ? TIOCM_LOOP : 0) | /* LOOP is set */
321 | ((msr & MSR_CTS) ? TIOCM_CTS : 0) | /* CTS is set */
322 | ((msr & MSR_CD) ? TIOCM_CAR : 0) | /* Carrier detect is set*/
323 | ((msr & MSR_RI) ? TIOCM_RI : 0) | /* Ring Indicator is set */
324 | ((msr & MSR_DSR) ? TIOCM_DSR : 0); /* DSR is set */
325 |
326 | return result;
327 | }
328 |
329 | static int tiny_tiocmset(struct tty_struct *tty, unsigned int set,
330 | unsigned int clear)
331 | {
332 | struct tiny_serial *tiny = tty->driver_data;
333 | unsigned int mcr = tiny->mcr;
334 |
335 | if (set & TIOCM_RTS)
336 | mcr |= MCR_RTS;
337 | if (set & TIOCM_DTR)
338 | mcr |= MCR_RTS;
339 |
340 | if (clear & TIOCM_RTS)
341 | mcr &= ~MCR_RTS;
342 | if (clear & TIOCM_DTR)
343 | mcr &= ~MCR_RTS;
344 |
345 | /* set the new MCR value in the device */
346 | tiny->mcr = mcr;
347 | return 0;
348 | }
349 |
350 | static int tiny_proc_show(struct seq_file *m, void *v)
351 | {
352 | struct tiny_serial *tiny;
353 | int i;
354 |
355 | seq_printf(m, "tinyserinfo:1.0 driver:%s\n", DRIVER_VERSION);
356 | for (i = 0; i < TINY_TTY_MINORS; ++i) {
357 | tiny = tiny_table[i];
358 | if (tiny == NULL)
359 | continue;
360 |
361 | seq_printf(m, "%d\n", i);
362 | }
363 |
364 | return 0;
365 | }
366 |
367 | #define tiny_ioctl tiny_ioctl_tiocgserial
368 | static int tiny_ioctl(struct tty_struct *tty, unsigned int cmd,
369 | unsigned long arg)
370 | {
371 | struct tiny_serial *tiny = tty->driver_data;
372 |
373 | if (cmd == TIOCGSERIAL) {
374 | struct serial_struct tmp;
375 |
376 | if (!arg)
377 | return -EFAULT;
378 |
379 | memset(&tmp, 0, sizeof(tmp));
380 |
381 | tmp.type = tiny->serial.type;
382 | tmp.line = tiny->serial.line;
383 | tmp.port = tiny->serial.port;
384 | tmp.irq = tiny->serial.irq;
385 | tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
386 | tmp.xmit_fifo_size = tiny->serial.xmit_fifo_size;
387 | tmp.baud_base = tiny->serial.baud_base;
388 | tmp.close_delay = 5*HZ;
389 | tmp.closing_wait = 30*HZ;
390 | tmp.custom_divisor = tiny->serial.custom_divisor;
391 | tmp.hub6 = tiny->serial.hub6;
392 | tmp.io_type = tiny->serial.io_type;
393 |
394 | if (copy_to_user((void __user *)arg, &tmp, sizeof(struct serial_struct)))
395 | return -EFAULT;
396 | return 0;
397 | }
398 | return -ENOIOCTLCMD;
399 | }
400 | #undef tiny_ioctl
401 |
402 | #define tiny_ioctl tiny_ioctl_tiocmiwait
403 | static int tiny_ioctl(struct tty_struct *tty, unsigned int cmd,
404 | unsigned long arg)
405 | {
406 | struct tiny_serial *tiny = tty->driver_data;
407 |
408 | if (cmd == TIOCMIWAIT) {
409 | DECLARE_WAITQUEUE(wait, current);
410 | struct async_icount cnow;
411 | struct async_icount cprev;
412 |
413 | cprev = tiny->icount;
414 | while (1) {
415 | add_wait_queue(&tiny->wait, &wait);
416 | set_current_state(TASK_INTERRUPTIBLE);
417 | schedule();
418 | remove_wait_queue(&tiny->wait, &wait);
419 |
420 | /* see if a signal woke us up */
421 | if (signal_pending(current))
422 | return -ERESTARTSYS;
423 |
424 | cnow = tiny->icount;
425 | if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
426 | cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
427 | return -EIO; /* no change => error */
428 | if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
429 | ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
430 | ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
431 | ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
432 | return 0;
433 | }
434 | cprev = cnow;
435 | }
436 |
437 | }
438 | return -ENOIOCTLCMD;
439 | }
440 | #undef tiny_ioctl
441 |
442 | #define tiny_ioctl tiny_ioctl_tiocgicount
443 | static int tiny_ioctl(struct tty_struct *tty, unsigned int cmd,
444 | unsigned long arg)
445 | {
446 | struct tiny_serial *tiny = tty->driver_data;
447 |
448 | if (cmd == TIOCGICOUNT) {
449 | struct async_icount cnow = tiny->icount;
450 | struct serial_icounter_struct icount;
451 |
452 | icount.cts = cnow.cts;
453 | icount.dsr = cnow.dsr;
454 | icount.rng = cnow.rng;
455 | icount.dcd = cnow.dcd;
456 | icount.rx = cnow.rx;
457 | icount.tx = cnow.tx;
458 | icount.frame = cnow.frame;
459 | icount.overrun = cnow.overrun;
460 | icount.parity = cnow.parity;
461 | icount.brk = cnow.brk;
462 | icount.buf_overrun = cnow.buf_overrun;
463 |
464 | if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))
465 | return -EFAULT;
466 | return 0;
467 | }
468 | return -ENOIOCTLCMD;
469 | }
470 | #undef tiny_ioctl
471 |
472 | /* the real tiny_ioctl function. The above is done to get the small functions in the book */
473 | static int tiny_ioctl(struct tty_struct *tty, unsigned int cmd,
474 | unsigned long arg)
475 | {
476 | switch (cmd) {
477 | case TIOCGSERIAL:
478 | return tiny_ioctl_tiocgserial(tty, cmd, arg);
479 | case TIOCMIWAIT:
480 | return tiny_ioctl_tiocmiwait(tty, cmd, arg);
481 | case TIOCGICOUNT:
482 | return tiny_ioctl_tiocgicount(tty, cmd, arg);
483 | }
484 |
485 | return -ENOIOCTLCMD;
486 | }
487 |
488 |
489 | static const struct tty_operations serial_ops = {
490 | .open = tiny_open,
491 | .close = tiny_close,
492 | .write = tiny_write,
493 | .write_room = tiny_write_room,
494 | .set_termios = tiny_set_termios,
495 | .proc_show = tiny_proc_show,
496 | .tiocmget = tiny_tiocmget,
497 | .tiocmset = tiny_tiocmset,
498 | .ioctl = tiny_ioctl,
499 | };
500 |
501 | static struct tty_driver *tiny_tty_driver;
502 |
503 | static int __init tiny_init(void)
504 | {
505 | int retval;
506 | int i;
507 |
508 | /* allocate the tty driver */
509 | tiny_tty_driver = alloc_tty_driver(TINY_TTY_MINORS);
510 | if (!tiny_tty_driver)
511 | return -ENOMEM;
512 |
513 | /* initialize the tty driver */
514 | tiny_tty_driver->owner = THIS_MODULE;
515 | tiny_tty_driver->driver_name = "tiny_tty";
516 | tiny_tty_driver->name = "ttty";
517 | tiny_tty_driver->major = TINY_TTY_MAJOR,
518 | tiny_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
519 | tiny_tty_driver->subtype = SERIAL_TYPE_NORMAL,
520 | tiny_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV,
521 | tiny_tty_driver->init_termios = tty_std_termios;
522 | tiny_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
523 | tty_set_operations(tiny_tty_driver, &serial_ops);
524 | for (i = 0; i < TINY_TTY_MINORS; i++) {
525 | tty_port_init(tiny_tty_port + i);
526 | tty_port_link_device(tiny_tty_port + i, tiny_tty_driver, i);
527 | }
528 |
529 | /* register the tty driver */
530 | retval = tty_register_driver(tiny_tty_driver);
531 | if (retval) {
532 | pr_err("failed to register tiny tty driver");
533 | put_tty_driver(tiny_tty_driver);
534 | return retval;
535 | }
536 |
537 | for (i = 0; i < TINY_TTY_MINORS; ++i)
538 | tty_register_device(tiny_tty_driver, i, NULL);
539 |
540 | pr_info(DRIVER_DESC " " DRIVER_VERSION);
541 | return retval;
542 | }
543 |
544 | static void __exit tiny_exit(void)
545 | {
546 | struct tiny_serial *tiny;
547 | int i;
548 |
549 | for (i = 0; i < TINY_TTY_MINORS; ++i)
550 | tty_unregister_device(tiny_tty_driver, i);
551 | tty_unregister_driver(tiny_tty_driver);
552 |
553 | /* shut down all of the timers and free the memory */
554 | for (i = 0; i < TINY_TTY_MINORS; ++i) {
555 | tiny = tiny_table[i];
556 | if (tiny) {
557 | /* close the port */
558 | while (tiny->open_count)
559 | do_close(tiny);
560 |
561 | /* shut down our timer and free the memory */
562 | del_timer(&tiny->timer);
563 | kfree(tiny);
564 | tiny_table[i] = NULL;
565 | }
566 | }
567 | }
568 |
569 | module_init(tiny_init);
570 | module_exit(tiny_exit);
571 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LDD3-Notes
2 | Notes on the book Linux Device Drivers, 3rd Edition, by Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman. My notes from this book will attempt to add updated information for Linux 5.x.
3 |
4 | Each chapter in the book is covered in detail in this note set. There is also a folder with example code to run some fun drivers as examples. See additional folders for more details.
5 |
--------------------------------------------------------------------------------