Fakultas Ilmu Komputer UI
Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Ardhi Putra Pratama
teaching
Commits
14c3c7f2
Commit
14c3c7f2
authored
Nov 17, 2017
by
Ardhi Putra Pratama
Browse files
init device driver
parent
c93c04d9
Changes
3
Hide whitespace changes
Inline
Side-by-side
sys-programming/dev-driver/Makefile
0 → 100644
View file @
14c3c7f2
obj-m
+=
lkm-drivers.o
all
:
make
-C
/lib/modules/
$(
shell
uname
-r
)
/build/
M
=
$(PWD)
modules
$(CC)
test-driver.c
-o
test
clean
:
make
-C
/lib/modules/
$(
shell
uname
-r
)
/build/
M
=
$(PWD)
clean
rm test
sys-programming/dev-driver/lkm-drivers.c
0 → 100644
View file @
14c3c7f2
#include
<linux/init.h>
// Macros used to mark up functions e.g. __init __exit
#include
<linux/module.h>
// Core header for loading LKMs into the kernel
#include
<linux/device.h>
// Header to support the kernel Driver Model
#include
<linux/kernel.h>
// Contains types, macros, functions for the kernel
#include
<linux/fs.h>
// Header for the Linux file system support
#include
<asm/uaccess.h>
// Required for the copy to user function
#define DEVICE_NAME "rdchardrv" ///< The device will appear at /dev/rdchardrv using this value
#define CLASS_NAME "rdc" ///< The device class -- this is a character device driver
MODULE_LICENSE
(
"GPL"
);
///< The license type -- this affects available functionality
MODULE_AUTHOR
(
"Ardhi Putra Pratama"
);
///< The author -- visible when you use modinfo
MODULE_DESCRIPTION
(
"A simple Linux char driver"
);
///< The description -- see modinfo
MODULE_VERSION
(
"0.1"
);
///< A version number to inform users
static
int
majorNumber
;
///< Stores the device number -- determined automatically
static
char
message
[
256
]
=
{
0
};
///< Memory for the string that is passed from userspace
static
short
size_of_message
;
///< Used to remember the size of the string stored
static
int
numberOpens
=
0
;
///< Counts the number of times the device is opened
static
struct
class
*
classptr
=
NULL
;
///< The device-driver class struct pointer
static
struct
device
*
dvcptr
=
NULL
;
///< The device-driver device struct pointer
// The prototype functions for the character driver
static
int
dev_open
(
struct
inode
*
,
struct
file
*
);
static
int
dev_release
(
struct
inode
*
,
struct
file
*
);
static
ssize_t
dev_read
(
struct
file
*
,
char
*
,
size_t
,
loff_t
*
);
static
ssize_t
dev_write
(
struct
file
*
,
const
char
*
,
size_t
,
loff_t
*
);
static
struct
file_operations
fops
=
{
.
open
=
dev_open
,
.
read
=
dev_read
,
.
write
=
dev_write
,
.
release
=
dev_release
,
};
static
int
__init
rdchardrv_init
(
void
){
printk
(
KERN_INFO
"RD-Char Device: Initializing the RD-Char Device LKM
\n
"
);
// Try to dynamically allocate a major number for the device -- more difficult but worth it
majorNumber
=
register_chrdev
(
0
,
DEVICE_NAME
,
&
fops
);
if
(
majorNumber
<
0
){
printk
(
KERN_ALERT
"RD-Char Device failed to register a major number
\n
"
);
return
majorNumber
;
}
printk
(
KERN_INFO
"RD-Char Device: registered correctly with major number %d
\n
"
,
majorNumber
);
// Register the device class
classptr
=
class_create
(
THIS_MODULE
,
CLASS_NAME
);
if
(
IS_ERR
(
classptr
)){
// Check for error and clean up if there is
unregister_chrdev
(
majorNumber
,
DEVICE_NAME
);
printk
(
KERN_ALERT
"Failed to register device class
\n
"
);
return
PTR_ERR
(
classptr
);
// Correct way to return an error on a pointer
}
printk
(
KERN_INFO
"RD-Char Device: device class registered correctly
\n
"
);
// Register the device driver
dvcptr
=
device_create
(
classptr
,
NULL
,
MKDEV
(
majorNumber
,
0
),
NULL
,
DEVICE_NAME
);
if
(
IS_ERR
(
dvcptr
)){
// Clean up if there is an error
class_destroy
(
classptr
);
// Repeated code but the alternative is goto statements
unregister_chrdev
(
majorNumber
,
DEVICE_NAME
);
printk
(
KERN_ALERT
"Failed to create the device
\n
"
);
return
PTR_ERR
(
dvcptr
);
}
printk
(
KERN_INFO
"RD-Char Device: device class created correctly
\n
"
);
// Made it! device was initialized
return
0
;
}
static
void
__exit
rdchardrv_exit
(
void
){
device_destroy
(
classptr
,
MKDEV
(
majorNumber
,
0
));
// remove the device
class_unregister
(
classptr
);
// unregister the device class
class_destroy
(
classptr
);
// remove the device class
unregister_chrdev
(
majorNumber
,
DEVICE_NAME
);
// unregister the major number
printk
(
KERN_INFO
"RD-Char Device: Goodbye from the LKM!
\n
"
);
}
static
int
dev_open
(
struct
inode
*
inodep
,
struct
file
*
filep
){
numberOpens
++
;
printk
(
KERN_INFO
"RD-Char Device: Device has been opened %d time(s)
\n
"
,
numberOpens
);
return
0
;
}
// static ssize_t dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset){
// int error_count = 0;
// // copy_to_user has the format ( * to, *from, size) and returns 0 on success
// error_count = copy_to_user(buffer, message, size_of_message);
//
// if (error_count==0){ // if true then have success
// printk(KERN_INFO "RD-Char Device: Sent %d characters to the user\n", size_of_message);
// return (size_of_message=0); // clear the position to the start and return 0
// }
// else {
// printk(KERN_INFO "RD-Char Device: Failed to send %d characters to the user\n", error_count);
// return -EFAULT; // Failed -- return a bad address message (i.e. -14)
// }
// }
static
ssize_t
dev_read
(
struct
file
*
filep
,
char
*
buffer
,
size_t
len
,
loff_t
*
offset
){
//Always return size_of_message or len bytes, whichever is less
size_t
bytesToCopy
=
len
>=
size_of_message
?
size_of_message
:
len
;
size_t
bytesNotCopied
=
0
;
//If size_of_message == 0, do nothing and return zero.
if
(
!
bytesToCopy
)
return
0
;
bytesNotCopied
=
copy_to_user
(
buffer
,
message
,
bytesToCopy
);
if
(
bytesToCopy
-
bytesNotCopied
)
printk
(
KERN_INFO
"RD-Char Device: Sent %d characters to the user
\n
"
,
bytesToCopy
-
bytesNotCopied
);
if
(
bytesNotCopied
){
printk
(
KERN_INFO
"RD-Char Device: Failed to send %d characters to the user
\n
"
,
bytesNotCopied
);
return
-
EFAULT
;
}
size_of_message
=
0
;
return
bytesToCopy
;
}
static
ssize_t
dev_write
(
struct
file
*
filep
,
const
char
*
buffer
,
size_t
len
,
loff_t
*
offset
){
/* 14 is the max length of the output of sprintf() below,
and we take one more byte out of maxLen to leave room
for the terminating NULL-character. */
const
size_t
maxLen
=
256
-
14
-
1
;
size_t
bytesToCopy
=
len
>=
maxLen
?
maxLen
:
len
;
//If len is 255 or more, copy only 255 bytes
size_t
bytesNotCopied
=
0
;
bytesNotCopied
=
copy_from_user
(
message
,
buffer
,
bytesToCopy
);
sprintf
(
message
+
bytesToCopy
-
bytesNotCopied
,
"(%zu letters)"
,
bytesToCopy
-
bytesNotCopied
);
size_of_message
=
bytesToCopy
-
bytesNotCopied
+
1
;
printk
(
KERN_INFO
"RD-Char Device: Received %zu characters from the user
\n
"
,
bytesToCopy
-
bytesNotCopied
);
if
(
bytesNotCopied
){
printk
(
KERN_INFO
"RD-Char Device: Failed to receive %zu characters, -EFAULT!
\n
"
,
bytesNotCopied
);
return
-
EFAULT
;
}
return
bytesToCopy
;
}
// static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset){
// sprintf(message, "%s(%zu letters)", buffer, len); // appending received string with its length
// size_of_message = strlen(message); // store the length of the stored message
// printk(KERN_INFO "RD-Char Device: Received %zu characters from the user\n", len);
// return len;
// }
static
int
dev_release
(
struct
inode
*
inodep
,
struct
file
*
filep
){
printk
(
KERN_INFO
"RD-Char Device: Device successfully closed
\n
"
);
return
0
;
}
module_init
(
rdchardrv_init
);
module_exit
(
rdchardrv_exit
);
sys-programming/dev-driver/test-driver.c
0 → 100644
View file @
14c3c7f2
#include
<stdio.h>
#include
<stdlib.h>
#include
<errno.h>
#include
<fcntl.h>
#include
<string.h>
#include
<unistd.h>
#define BUFFER_LENGTH 256
static
char
receive
[
BUFFER_LENGTH
];
int
main
(){
int
ret
,
fd
;
char
stringToSend
[
BUFFER_LENGTH
];
printf
(
"Starting device test code example...
\n
"
);
fd
=
open
(
"/dev/rdchardrv"
,
O_RDWR
);
// Open the device with read/write access
if
(
fd
<
0
){
perror
(
"Failed to open the device..."
);
return
errno
;
}
printf
(
"Type in a short string to send to the kernel module:
\n
"
);
scanf
(
"%[^
\n
]%*c"
,
stringToSend
);
// Read in a string (with spaces)
printf
(
"Writing message to the device [%s].
\n
"
,
stringToSend
);
ret
=
write
(
fd
,
stringToSend
,
strlen
(
stringToSend
));
// Send the string to the LKM
if
(
ret
<
0
){
perror
(
"Failed to write the message to the device."
);
return
errno
;
}
printf
(
"Press ENTER to read back from the device...
\n
"
);
getchar
();
printf
(
"Reading from the device...
\n
"
);
ret
=
read
(
fd
,
receive
,
BUFFER_LENGTH
);
// Read the response from the LKM
if
(
ret
<
0
){
perror
(
"Failed to read the message from the device."
);
return
errno
;
}
printf
(
"The received message is: [%s]
\n
"
,
receive
);
printf
(
"End of the program
\n
"
);
return
0
;
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment