3 * modules/driver/device_driver.c
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 * Copyright (C) Samsung Electronics, 2013
21 * 2013 Alexander Aksenov <a.aksenov@samsung.com>: SWAP device driver implement
25 #include <linux/types.h>
27 #include <linux/cdev.h>
28 #include <linux/err.h>
29 #include <linux/device.h>
30 #include <linux/ioctl.h>
31 #include <linux/slab.h>
33 #include <linux/splice.h>
34 #include <linux/sched.h>
35 #include <linux/module.h>
36 #include <linux/wait.h>
37 #include <linux/workqueue.h>
38 #include <asm/uaccess.h>
40 #include <ksyms/ksyms.h>
42 #include "device_driver.h"
43 #include "swap_driver_errors.h"
44 #include "driver_to_buffer.h"
45 #include "swap_ioctl.h"
46 #include "driver_defs.h"
47 #include "device_driver_to_driver_to_buffer.h"
48 #include "driver_to_buffer.h"
49 #include "driver_to_msg.h"
51 #define SWAP_DEVICE_NAME "swap_device"
53 #define MAXIMUM_SUBBUFFER_SIZE (64 * 1024)
55 /* swap_device driver routines */
56 static int swap_device_open(struct inode *inode, struct file *filp);
57 static int swap_device_release(struct inode *inode, struct file *file);
58 static ssize_t swap_device_read(struct file *filp, char __user *buf,
59 size_t count, loff_t *f_pos);
60 static long swap_device_ioctl(struct file *filp, unsigned int cmd,
62 static ssize_t swap_device_splice_read(struct file *filp, loff_t *ppos,
63 struct pipe_inode_info *pipe, size_t len,
66 /* File operations structure */
67 const struct file_operations swap_device_fops = {
69 .read = swap_device_read,
70 .open = swap_device_open,
71 .release = swap_device_release,
72 .unlocked_ioctl = swap_device_ioctl,
73 .splice_read = swap_device_splice_read,
76 /* Typedefs for splice_* funcs. Prototypes are for linux-3.8.6 */
77 typedef ssize_t(*splice_to_pipe_p_t)(struct pipe_inode_info *pipe,
78 struct splice_pipe_desc *spd);
79 typedef int(*splice_grow_spd_p_t)(const struct pipe_inode_info *pipe,
80 struct splice_pipe_desc *spd);
82 static splice_to_pipe_p_t splice_to_pipe_p = NULL;
83 static splice_grow_spd_p_t splice_grow_spd_p = NULL;
85 static msg_handler_t msg_handler = NULL;
88 static dev_t swap_device_no = 0;
90 /* Device cdev struct */
91 static struct cdev *swap_device_cdev = NULL;
93 /* Device class struct */
94 static struct class *swap_device_class = NULL;
96 /* Device device struct */
97 static struct device *swap_device_device = NULL;
99 /* Reading tasks queue */
100 static DECLARE_WAIT_QUEUE_HEAD(swap_device_wait);
103 static atomic_t flag_wake_up = ATOMIC_INIT(0);
105 static void __bottom_wake_up(void)
107 if (waitqueue_active(&swap_device_wait))
108 wake_up_interruptible(&swap_device_wait);
111 static void bottom_wake_up(struct work_struct *work)
113 if (atomic_read(&flag_wake_up)) {
114 atomic_set(&flag_wake_up, 0);
119 static DECLARE_WORK(w_wake_up, bottom_wake_up);
121 static void exit_w_wake_up(void)
123 flush_scheduled_work();
128 /* We need this realization of splice_shrink_spd() because of the its desing
129 * frequent changes that I have encountered in custom kernels */
130 void swap_device_splice_shrink_spd(struct pipe_inode_info *pipe,
131 struct splice_pipe_desc *spd)
133 if (pipe->buffers <= PIPE_DEF_BUFFERS)
141 /* Register device TODO Think of permanent major */
142 int swap_device_init(void)
146 /* Allocating device major and minor nums for swap_device */
147 result = alloc_chrdev_region(&swap_device_no, 0, 1, SWAP_DEVICE_NAME);
149 print_crit("Major number allocation has failed\n");
150 result = -E_SD_ALLOC_CHRDEV_FAIL;
154 /* Creating device class. Using IS_ERR, because class_create returns ERR_PTR
156 swap_device_class = class_create(THIS_MODULE, SWAP_DEVICE_NAME);
157 if (IS_ERR(swap_device_class)) {
158 print_crit("Class creation has failed\n");
159 result = -E_SD_CLASS_CREATE_FAIL;
163 /* Cdev allocation */
164 swap_device_cdev = cdev_alloc();
165 if (!swap_device_cdev) {
166 print_crit("Cdev structure allocation has failed\n");
167 result = -E_SD_CDEV_ALLOC_FAIL;
171 /* Cdev intialization and setting file operations */
172 cdev_init(swap_device_cdev, &swap_device_fops);
174 /* Adding cdev to system */
175 result = cdev_add(swap_device_cdev, swap_device_no, 1);
177 print_crit("Device adding has failed\n");
178 result = -E_SD_CDEV_ADD_FAIL;
182 /* Create device struct */
183 swap_device_device = device_create(swap_device_class, NULL, swap_device_no,
184 "%s", SWAP_DEVICE_NAME);
185 if (IS_ERR(swap_device_device)) {
186 print_crit("Device struct creating has failed\n");
187 result = -E_SD_DEVICE_CREATE_FAIL;
191 /* Find splice_* funcs addresses */
192 splice_to_pipe_p = (splice_to_pipe_p_t)swap_ksyms("splice_to_pipe");
193 if (!splice_to_pipe_p) {
194 print_err("splice_to_pipe() not found!\n");
195 result = -E_SD_NO_SPLICE_FUNCS;
199 splice_grow_spd_p = (splice_grow_spd_p_t)swap_ksyms("splice_grow_spd");
200 if (!splice_grow_spd_p) {
201 print_err("splice_grow_spd() not found!\n");
202 result = -E_SD_NO_SPLICE_FUNCS;
209 if (swap_device_cdev) {
210 cdev_del(swap_device_cdev);
212 if (swap_device_class) {
213 class_destroy(swap_device_class);
215 if (swap_device_no) {
216 unregister_chrdev_region(swap_device_no, 1);
221 /* Unregister device TODO Check wether driver is registered */
222 void swap_device_exit(void)
226 splice_to_pipe_p = NULL;
227 splice_grow_spd_p = NULL;
229 device_destroy(swap_device_class, swap_device_no);
230 cdev_del(swap_device_cdev);
231 class_destroy(swap_device_class);
232 unregister_chrdev_region(swap_device_no, 1);
235 static int swap_device_open(struct inode *inode, struct file *filp)
237 // TODO MOD_INC_USE_COUNT
241 static int swap_device_release(struct inode *inode, struct file *filp)
243 // TODO MOD_DEC_USE_COUNT
247 static ssize_t swap_device_read(struct file *filp, char __user *buf,
248 size_t count, loff_t *f_pos)
250 /* Wait queue item that consists current task. It is used to be added in
251 * swap_device_wait queue if there is no data to be read. */
255 //TODO : Think about spin_locks to prevent reading race condition.
256 while((result = driver_to_buffer_next_buffer_to_read()) != E_SD_SUCCESS) {
258 /* Add process to the swap_device_wait queue and set the current task
259 * state TASK_INTERRUPTIBLE. If there is any data to be read, then the
260 * current task is removed from the swap_device_wait queue and its state
261 * is changed to this. */
262 prepare_to_wait(&swap_device_wait, &wait, TASK_INTERRUPTIBLE);
266 goto swap_device_read_error;
267 } else if (result == E_SD_NO_DATA_TO_READ) {
268 /* Yes, E_SD_NO_DATA_TO_READ should be positive, cause it's not
270 if (filp->f_flags & O_NONBLOCK) {
272 goto swap_device_read_error;
274 if (signal_pending(current)) {
275 result = -ERESTARTSYS;
276 goto swap_device_read_error;
279 finish_wait(&swap_device_wait, &wait);
283 result = driver_to_buffer_read(buf, count);
284 /* If there is an error - return 0 */
291 swap_device_read_error:
292 finish_wait(&swap_device_wait, &wait);
297 static long swap_device_ioctl(struct file *filp, unsigned int cmd,
303 case SWAP_DRIVER_BUFFER_INITIALIZE:
305 struct buffer_initialize initialize_struct;
307 result = copy_from_user(&initialize_struct, (void*)arg,
308 sizeof(struct buffer_initialize));
313 if (initialize_struct.size > MAXIMUM_SUBBUFFER_SIZE) {
314 print_err("Wrong subbuffer size\n");
315 result = -E_SD_WRONG_ARGS;
319 result = driver_to_buffer_initialize(initialize_struct.size,
320 initialize_struct.count);
322 print_err("Buffer initialization failed %d\n", result);
325 result = E_SD_SUCCESS;
329 case SWAP_DRIVER_BUFFER_UNINITIALIZE:
331 result = driver_to_buffer_uninitialize();
333 print_err("Buffer uninitialization failed %d\n", result);
336 case SWAP_DRIVER_NEXT_BUFFER_TO_READ:
338 /* Use this carefully */
339 result = driver_to_buffer_next_buffer_to_read();
340 if (result == E_SD_NO_DATA_TO_READ) {
341 /* TODO Do what we usually do when there are no subbuffers to
342 * read (make daemon sleep ?) */
346 case SWAP_DRIVER_FLUSH_BUFFER:
348 result = driver_to_buffer_flush();
351 case SWAP_DRIVER_MSG:
354 result = msg_handler((void __user *)arg);
356 print_warn("msg_handler() is not register\n");
361 case SWAP_DRIVER_WAKE_UP:
363 swap_device_wake_up_process();
364 result = E_SD_SUCCESS;
368 print_warn("Unknown command %d\n", cmd);
376 static void swap_device_pipe_buf_release(struct pipe_inode_info *inode,
377 struct pipe_buffer *pipe)
379 __free_page(pipe->page);
382 static void swap_device_page_release(struct splice_pipe_desc *spd,
385 __free_page(spd->pages[i]);
388 static const struct pipe_buf_operations swap_device_pipe_buf_ops = {
390 .map = generic_pipe_buf_map,
391 .unmap = generic_pipe_buf_unmap,
392 .confirm = generic_pipe_buf_confirm,
393 .release = swap_device_pipe_buf_release,
394 .steal = generic_pipe_buf_steal,
395 .get = generic_pipe_buf_get
398 static ssize_t swap_device_splice_read(struct file *filp, loff_t *ppos,
399 struct pipe_inode_info *pipe,
400 size_t len, unsigned int flags)
402 /* Wait queue item that consists current task. It is used to be added in
403 * swap_device_wait queue if there is no data to be read. */
407 struct page *pages[PIPE_DEF_BUFFERS];
408 struct partial_page partial[PIPE_DEF_BUFFERS];
409 struct splice_pipe_desc spd = {
412 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 5))
413 .nr_pages_max = PIPE_DEF_BUFFERS,
417 .ops = &swap_device_pipe_buf_ops,
418 .spd_release = swap_device_page_release,
421 /* Get next buffer to read */
422 //TODO : Think about spin_locks to prevent reading race condition.
423 while((result = driver_to_buffer_next_buffer_to_read()) != E_SD_SUCCESS) {
425 /* Add process to the swap_device_wait queue and set the current task
426 * state TASK_INTERRUPTIBLE. If there is any data to be read, then the
427 * current task is removed from the swap_device_wait queue and its state
429 prepare_to_wait(&swap_device_wait, &wait, TASK_INTERRUPTIBLE);
431 print_err("driver_to_buffer_next_buffer_to_read error %d\n", result);
432 //TODO Error return to OS
434 goto swap_device_splice_read_error;
435 } else if (result == E_SD_NO_DATA_TO_READ) {
436 if (filp->f_flags & O_NONBLOCK) {
438 goto swap_device_splice_read_error;
440 if (signal_pending(current)) {
441 result = -ERESTARTSYS;
442 goto swap_device_splice_read_error;
445 finish_wait(&swap_device_wait, &wait);
449 if (splice_grow_spd_p(pipe, &spd)) {
451 goto swap_device_splice_read_out;
454 result = driver_to_buffer_fill_spd(&spd);
456 print_err("Cannot fill spd for splice\n");
457 goto swap_device_shrink_spd;
460 result = splice_to_pipe_p(pipe, &spd);
462 swap_device_shrink_spd:
463 swap_device_splice_shrink_spd(pipe, &spd);
465 swap_device_splice_read_out:
468 swap_device_splice_read_error:
469 finish_wait(&swap_device_wait, &wait);
474 void swap_device_wake_up_process(void)
476 if (atomic_read(&flag_wake_up) == 0) {
477 atomic_set(&flag_wake_up, 1);
478 schedule_work(&w_wake_up);
482 void set_msg_handler(msg_handler_t mh)
486 EXPORT_SYMBOL_GPL(set_msg_handler);