Skip to content

Instantly share code, notes, and snippets.

@olbat
Created September 19, 2011 12:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save olbat/1226414 to your computer and use it in GitHub Desktop.
Save olbat/1226414 to your computer and use it in GitHub Desktop.
GNU/Linux Kernel module sample that read the current time on the RTC chip
obj-m += realtimeclock.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -c /lib/modules/$(shell uname -r)/build M=$(PWD) clean
#include "realtimeclock.h"
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luc Sarzyniec <mail@olbat.net>");
MODULE_DESCRIPTION("real time clock module");
module_init(rtc_init);
module_exit(rtc_cleanup);
#define DEVICE_NAME "realtimeclock"
/* sec, min, hour, day, month, year */
#define TIME_BUFFER_SIZE 6
static int device_major;
static int device_status;
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
static struct proc_dir_entry *proc_file;
static __u8 time[TIME_BUFFER_SIZE];
static __u8 *time_ptr;
#define RTC_UPDATE(t) \
t[0] = CMOS_READ(RTC_SECONDS); \
t[1] = CMOS_READ(RTC_MINUTES); \
t[2] = CMOS_READ(RTC_HOURS); \
t[3] = CMOS_READ(RTC_DAY_OF_MONTH); \
t[4] = CMOS_READ(RTC_MONTH); \
t[5] = CMOS_READ(RTC_YEAR);
static int __init rtc_init(void)
{
device_major = register_chrdev(0,DEVICE_NAME,&fops);
if (unlikely(device_major < 0)) {
printk(KERN_ALERT "failed register %s errno %d\n",
DEVICE_NAME,device_major);
return device_major;
}
proc_file = create_proc_entry(DEVICE_NAME, 0644, NULL);
if (unlikely(proc_file == NULL)) {
remove_proc_entry(DEVICE_NAME,&proc_root);
printk(KERN_ALERT "failed create /proc/%s\n",DEVICE_NAME);
return -ENOMEM;
}
printk(KERN_INFO "%s registered and ready to use\n"
"major device number : %d\n"
"use 'mknod /dev/%s c %d 0' to create a device file\n"
"device output format : ssmmhhDDMMYY\n"
"you can use /proc/%s to get informations\n",
DEVICE_NAME,device_major,DEVICE_NAME,device_major,DEVICE_NAME);
device_status = 0;
proc_file->read_proc = procfile_read;
proc_file->owner = THIS_MODULE;
proc_file->mode = S_IFREG | S_IRUGO;
proc_file->uid = 0;
proc_file->gid = 0;
proc_file->size = 0;
return 0;
}
static void __exit rtc_cleanup(void)
{
int ret = unregister_chrdev(device_major,DEVICE_NAME);
if (unlikely(ret < 0))
printk(KERN_ALERT "failed unregister %s, errno %d\n",
DEVICE_NAME,ret);
else
printk(KERN_INFO "%s unregistred\n"
"don't forget to remove the device file if there is one\n",
DEVICE_NAME);
remove_proc_entry(DEVICE_NAME,&proc_root);
}
static int device_open(struct inode *inode, struct file *file)
{
if (unlikely(device_status)) {
return -EBUSY;
}
device_status++;
RTC_UPDATE(time)
time_ptr = time;
try_module_get(THIS_MODULE);
return 0;
}
static int device_release(struct inode *inode, struct file *file)
{
device_status--;
module_put(THIS_MODULE);
return 0;
}
static ssize_t
device_read(struct file *file, char *buff, size_t len, loff_t *offset)
{
ssize_t bytes_read = 0;
while (len && (time_ptr < (time + TIME_BUFFER_SIZE))) {
put_user(*(time_ptr++),buff++);
len--;
bytes_read++;
}
return bytes_read;
}
static ssize_t
device_write(struct file *file,const char *buff, size_t len, loff_t *offset)
{
printk(KERN_ALERT "You can't write in that device.\n");
return -EINVAL;
}
static int
procfile_read(char *buff, char **buff_location,
off_t offset, int buff_len, int *eof, void *data)
{
int ret;
if (offset > 0) {
return 0;
}
RTC_UPDATE(time);
ret = sprintf(buff,"%.2d:%.2d:%.2d %.2d/%.2d/%.2d\n",
time[2],time[1],time[0],time[3],time[4],time[5]);
return ret;
}
#ifndef _REALTIMECLOCK_H
#define _REALTIMECLOCK_H
#include <linux/types.h>
#include <linux/io.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#define CMOS_BASE_PORT 0x70
#define RTC_SECONDS 0
#define RTC_MINUTES 2
#define RTC_HOURS 4
#define RTC_DAY_OF_MONTH 7
#define RTC_MONTH 8
#define RTC_YEAR 9
#define RTC_PORT(x) (CMOS_BASE_PORT + (x))
#define CMOS_READ(addr) rtc_cmos_read(addr)
static inline __u8 rtc_cmos_read(__u8 addr)
{
outb_p(addr,RTC_PORT(0));
return (__u8) inb_p(RTC_PORT(1));
}
static int rtc_init(void);
static void rtc_cleanup(void);
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
static int procfile_read(char *,char **, off_t, int, int *, void *);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment