#include <linux/cdev.h>
#include <linux/device.h>
#include "../dev.h"

static int major = 0;
module_param( major, int, S_IRUGO );

MODULE_AUTHOR( "Timur G. Baymatov" );

static const struct file_operations hello_fops = {
   .owner = THIS_MODULE,
   .read  = hello_read,
};

#define DEVICE_FIRST  0
#define DEVICE_COUNT  1
#define MODNAME "dyndev_mod"

static dev_t dev;
static struct cdev hcdev;
static struct class *devclass;

static int __init hello_init( void ) {
   int ret;
   if( major != 0 ) {
      dev = MKDEV( major, DEVICE_FIRST );
      ret = register_chrdev_region( dev, DEVICE_COUNT, MODNAME );
   }
   else {
      ret = alloc_chrdev_region( &dev, DEVICE_FIRST, DEVICE_COUNT, MODNAME );
      major = MAJOR( dev );  // не забыть зафиксировать!
   }
   if( ret < 0 ) {
      printk( KERN_ERR "Can not register char device region\n" );
      goto err;
   }
   cdev_init( &hcdev, &hello_fops );
   hcdev.owner = THIS_MODULE;
   hcdev.ops = &hello_fops;   // обязательно! - cdev_init() недостаточно?
   ret = cdev_add( &hcdev, dev, DEVICE_COUNT );
   if( ret < 0 ) {
      unregister_chrdev_region( MKDEV( major, DEVICE_FIRST ), DEVICE_COUNT );
      printk( KERN_ERR "Can not add char device\n" );
      goto err;
   }
   devclass = class_create( THIS_MODULE, "dyn_class" );
#define DEVNAME "dyndev"
   device_create( devclass, NULL, dev, "%s", DEVNAME );
   printk( KERN_INFO "=========== module installed %d:%d ==============\n",
           MAJOR( dev ), MINOR( dev ) );
err:
   return ret;
}

static void __exit hello_exit( void ) {
   device_destroy( devclass, dev );
   class_destroy( devclass );
   cdev_del( &hcdev );
   unregister_chrdev_region( MKDEV( major, DEVICE_FIRST ), DEVICE_COUNT );
   printk( KERN_INFO "=============== module removed ==================\n" );
}
