Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/init.h>
- #include <asm/uaccess.h>
- #include <asm/io.h>
- #include <linux/proc_fs.h>
- #include <linux/seq_file.h>
- #include <linux/platform_device.h>
- #include <linux/timer.h>
- #include <linux/jiffies.h>
- #define DRIVER_NAME "danh_led"
- struct resource *resource;
- unsigned long remap_size;
- unsigned long *base_addr;
- static struct timer_list timer;
- void timer_callback( unsigned long data ) {
- static int cnt = 0;
- iowrite32( cnt, base_addr );
- cnt = (cnt + 1) % 128;
- int ret = mod_timer( &timer, jiffies + msecs_to_jiffies( 1000 ) );
- if ( ret )
- printk( KERN_ALERT "ERROR: Cannot mod_timer\n" );
- }
- static ssize_t proc_danhled_write( struct file *file, const char __user *buf,
- size_t count, loff_t ppos ) {
- printk( KERN_INFO "BEGIN: proc_danhled_write\n" );
- char str[ 16 ];
- if ( count < 11 ) {
- if ( copy_from_user( str, buf, count ) )
- return -EFAULT;
- str[ count ] = '\0';
- }
- int danhled_val = simple_strtoul( str, NULL, 0 );
- wmb();
- iowrite32( danhled_val, base_addr );
- printk( KERN_INFO "END: proc_danhled_write\n" );
- return count;
- }
- static int proc_danhled_show( struct seq_file *m, void *v ) {
- printk( KERN_INFO "BEGIN: proc_danhled_show\n" );
- u32 danhled_val = ioread32( base_addr );
- seq_printf( m, "0x%x", danhled_val );
- printk( KERN_INFO "END: proc_danhled_show\n" );
- return 0;
- }
- static int proc_danhled_open( struct inode *inode, struct file *file ) {
- printk( KERN_INFO "BEGIN: proc_danhled_open\n" );
- unsigned int size = 16;
- char *buf;
- struct seq_file *m;
- buf = (char *) kmalloc( size * sizeof(char), GFP_KERNEL );
- if ( buf == NULL )
- return -ENOMEM;
- int ret = single_open( file, proc_danhled_show, NULL );
- if ( !ret ) {
- m = file->private_data;
- m->buf = buf;
- m->size = size;
- }
- else
- kfree( buf );
- printk( KERN_INFO "END: proc_danhled_open\n" );
- return ret;
- }
- static const struct file_operations proc_danhled_operations = {
- .open = proc_danhled_open,
- .write = proc_danhled_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release= single_release
- };
- static int __init danhled_probe( struct platform_device *pdev ) {
- printk( KERN_INFO "BEGIN: danhled_probe\n" );
- int ret = 0;
- resource = platform_get_resource( pdev, IORESOURCE_MEM, 0 );
- if ( resource == NULL ) {
- dev_err( &pdev->dev, "No Memory Resource\n" );
- return -ENODEV;
- }
- remap_size = resource->end - resource->start + 1;
- if ( request_mem_region( resource->start, remap_size, pdev->name ) == NULL ) {
- dev_err( &pdev->dev, "Cannot request IO\n" );
- return -ENXIO;
- }
- base_addr = ioremap( resource->start, remap_size );
- if ( base_addr == NULL ) {
- dev_err( &pdev->dev, "Could not Re-map Memory at 0x08lx\n",
- ( unsigned long) resource->start );
- ret = -ENOMEM;
- goto err_release_region;
- }
- struct proc_dir_entry *danhled_proc_entry = proc_create(
- DRIVER_NAME, 0, NULL, &proc_danhled_operations
- );
- if ( danhled_proc_entry == NULL ) {
- dev_err( &pdev->dev, "Could not Create Proc Entry\n");
- ret = -ENOMEM;
- goto err_create_proc_entry;
- }
- printk( KERN_INFO DRIVER_NAME " probed at VA 0x%08lx\n",
- (unsigned long) base_addr
- );
- setup_timer( &timer, timer_callback, 0 );
- int ret_ = mod_timer( &timer, jiffies + msecs_to_jiffies( 1000 ) );
- if ( ret_ )
- printk( KERN_ALERT "ERROR: Cannot mod_timer\n" );
- printk( KERN_INFO "END: danhled_probe\n" );
- return 0;
- err_create_proc_entry:
- iounmap( base_addr );
- err_release_region:
- release_mem_region( resource->start, remap_size );
- return ret;
- }
- static void danhled_shutdown( struct platform_device *pdev ) {
- iowrite32( 0, base_addr );
- }
- static int __exit danhled_remove( struct platform_device *pdev ) {
- printk( KERN_INFO "BEGIN: danhled_remove\n" );
- danhled_shutdown( pdev );
- remove_proc_entry( DRIVER_NAME, NULL );
- iounmap( base_addr );
- release_mem_region( resource->start, remap_size );
- printk( KERN_INFO "END: danhled_remove\n" );
- return 0;
- }
- static const struct of_device_id danhled_of_match[] __initconst = {
- {
- .compatible = "danh-ipcore,myled-1.00.a"
- },
- {}
- };
- MODULE_DEVICE_TABLE( of, danhled_of_match );
- static struct platform_driver danhled_driver = {
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- .of_match_table = danhled_of_match
- },
- .probe = danhled_probe,
- .remove = danhled_remove,
- .shutdown = danhled_shutdown
- };
- module_platform_driver( danhled_driver );
- MODULE_AUTHOR( "Danh Doan" );
- MODULE_LICENSE( "GPL" );
- MODULE_ALIAS( DRIVER_NAME );
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement