#include #include #include #include #include #include #include #include #include #include #include #include #include #include /*for Kmalloc*/ #include struct phy_addr_param { unsigned int addr; unsigned int value; }; #define PHYADDR_IOC_MAGIC 'S' #define PHYADDR_SET_VAL _IOW(PHYADDR_IOC_MAGIC, 0, struct phy_addr_param) #define PHYADDR_GET_VAL _IOR(PHYADDR_IOC_MAGIC, 1, struct phy_addr_param) struct paddr { struct cdev cdev; struct class *phyaddr_class; dev_t dev; }; struct paddr phy_addr_priv; static long phyaddr_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){ int err = 0; struct phy_addr_param param; /* Check type and command number */ if (_IOC_TYPE(cmd) != PHYADDR_IOC_MAGIC) return -ENOTTY; /* Check access direction once here; don't repeat below. * IOC_DIR is from the user perspective, while access_ok is * from the kernel perspective; so they look reversed. */ if (_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); if (err) return -EFAULT; copy_from_user(¶m, (struct phy_addr_param*)arg, sizeof(struct phy_addr_param)); // if (param.index >= YGPIO_MAX_PIN_NR) return -EINVAL; //invalid address return switch(cmd) { case PHYADDR_SET_VAL: //if(param.value) //printk(KERN_INFO "---- write 0x%x from 0x%08x \n", param.value , param.addr); *(volatile unsigned int *)param.addr = param.value; //printk(KERN_INFO "---- test write from 0x%08x \n", *(volatile unsigned int *)param.addr); break; case PHYADDR_GET_VAL: //printk(KERN_INFO "---- read from 0x%08x \n", param.addr); param.value = *(volatile unsigned int *)param.addr; copy_to_user((struct phy_addr_param*)arg, ¶m, sizeof(struct phy_addr_param)); //printk(KERN_INFO "---- test read from 0x%08x \n", *(volatile unsigned int *)param.addr); break; default: return -ENOTTY; } return 0; } static int phyaddr_open(struct inode *inode, struct file *filp) { return 0; } static int phyaddr_release(struct inode *inode, struct file *filp) { return 0; } struct file_operations phyaddr_fops = { .owner = THIS_MODULE, .unlocked_ioctl = phyaddr_ioctl, .open = phyaddr_open, .release = phyaddr_release, }; static int __init phy_addr_init(void) { int err; int result; int major; result = alloc_chrdev_region(&phy_addr_priv.dev, 0, 0, "phyaddr"); major = MAJOR(phy_addr_priv.dev); if (result < 0) { printk(KERN_WARNING "phy_addr: can't get major %d\n", major); return result; } cdev_init(&phy_addr_priv.cdev, &phyaddr_fops); phy_addr_priv.cdev.owner = THIS_MODULE; phy_addr_priv.cdev.ops = &phyaddr_fops; err = cdev_add(&phy_addr_priv.cdev, phy_addr_priv.dev, 1); if (err) { printk(KERN_NOTICE "Error[%d] cdev_add .\n", err); return -1; } phy_addr_priv.phyaddr_class = class_create(THIS_MODULE, "phyaddr"); if (IS_ERR(phy_addr_priv.phyaddr_class)) { printk(KERN_ERR "Failed in create phyaddr_cdev class\n"); return -1; } device_create(phy_addr_priv.phyaddr_class, NULL, phy_addr_priv.dev, NULL, "phyaddr"); return 0; } static void __exit phy_addr_exit(void) { cdev_del(&phy_addr_priv.cdev); unregister_chrdev_region(phy_addr_priv.dev, 1); device_destroy(phy_addr_priv.phyaddr_class, phy_addr_priv.dev); class_destroy(phy_addr_priv.phyaddr_class); } module_init(phy_addr_init); module_exit(phy_addr_exit); MODULE_AUTHOR("songxingjia@china-cpu.com"); MODULE_DESCRIPTION("GSC3280 PHY ADDRESS READ/WRITE Driver"); MODULE_LICENSE("GPL");