/* * UIO CAN L2 * * (C) Armin Steinhoff * (C) 2007 Hans J. Koch * Original code (C) 2005 Benedikt Spranger * * Licensed under GPL version 2 only. * */ #include #include #include #include #include #include #include #include #define INT_QUEUE_SIZE 64 static unsigned char int_x[2], * int_q[2]; static void __iomem *isr[2]; static unsigned int irq = 11; module_param (irq, uint, 0); MODULE_PARM_DESC (irq, "IRQ (default 11)"); static unsigned long base_addr = 0xd00000; module_param (base_addr, ulong, 0); MODULE_PARM_DESC (base_addr, "Base address (default 0xD0000)"); static unsigned long base_len; module_param (base_len, ulong, 0); MODULE_PARM_DESC (base_len, "Base length (default 0x1)"); static irqreturn_t int_handler(int irq, struct uio_info *dev_info) { int irq_flag = 0; unsigned char ISRstat; ISRstat = readb(isr[0]); if(ISRstat & 0x02) { int_q[0][int_x[0]] = ISRstat; int_x[0] = (int_x[0] + 1) & 0xF ; // modulo 16 irq_flag = 1; } ISRstat = readb(isr[1]); if(ISRstat & 0x02) { int_q[1][int_x[1]] = ISRstat; int_x[1] = (int_x[1] + 1) & 0xF ; // modulo 16 irq_flag = 1; } if(irq_flag) return(IRQ_HANDLED); else return(IRQ_NONE); } static int jand_probe(struct platform_device *dev) { struct uio_info *info; dev_info(&dev->dev, "start probe %d\n", 1); info = kzalloc(sizeof(struct uio_info), GFP_KERNEL); if (!info) { return -ENOMEM; } info->mem[0].addr = base_addr; info->mem[0].size = base_len; info->mem[0].memtype = UIO_MEM_PHYS; if(request_mem_region( info->mem[0].addr, info->mem[0].size, "uio_jand")) { dev_err(&dev->dev, "request_mem_region failed %d\n", 2); goto out_release; } info->mem[0].internal_addr = ioremap(info->mem[0].addr,info->mem[0].size); if (!info->mem[0].internal_addr) { dev_err(&dev->dev, "ioremap failed %d\n", 3); goto out_release; } /* interrupt queue */ info->mem[1].addr = (unsigned long)kmalloc(64, GFP_KERNEL); if (!info->mem[1].addr) goto out_release1; int_q[0] = (unsigned char * )info->mem[1].addr; int_q[1] = (unsigned char * )info->mem[1].addr +32; memset(&int_q[0], 0x00, 16); int_x[0] = 0; memset(&int_q[1], 0x00, 16); int_x[1] = 0; info->mem[1].memtype = UIO_MEM_LOGICAL; info->mem[1].size = 64; isr[0] = info->mem[0].internal_addr + 3; /* interrupt reg channel 1 */ isr[1] = info->mem[0].internal_addr + 3 + 0x200; /* interrupt reg channel 2 */ if( request_irq(irq, int_handler, IRQF_DISABLED,"uio_jand", NULL) ) { goto out_release2; } info->name = "uio_jand"; info->version = "0.0.2"; info->irq = irq; info->irq_flags = 0; info->handler = int_handler; // different ptr types ? platform_set_drvdata(dev, info); if (uio_register_device(&dev->dev, info)) { dev_err(&dev->dev, "uio_register_device failed %d\n", 4); goto out_release2; } dev_info(&dev->dev, "uio_jand started! %d\n", 5); return 0; out_release2: kfree((void *)info->mem[1].addr); dev_err(&dev->dev, "uio_register_device failed %d \n", 6); out_release1: free_irq( irq, "uio_jand" ); iounmap(info->mem[0].internal_addr); release_mem_region( base_addr, base_len); out_release: kfree (info); dev_err(&dev->dev, "Error exit ENODEV! %d\n", 7); return -ENODEV; } static int jand_remove(struct platform_device *dev) { struct uio_info *info = platform_get_drvdata(dev); uio_unregister_device(info); iounmap(info->mem[0].internal_addr); release_mem_region( base_addr, base_len); free_irq( irq, "uio_jand" ); kfree((void *)info->mem[1].addr); kfree (info); return 0; } static struct platform_driver uio_jand_driver = { .probe = jand_probe, .remove = jand_remove, .driver = { .name = "uio_jand", .owner = THIS_MODULE, }, }; static int __init uio_jand_init(void) { return platform_driver_register(&uio_jand_driver); } static void __exit uio_jand_exit(void) { platform_driver_unregister(&uio_jand_driver); } module_init( uio_jand_init ); module_exit( uio_jand_exit ); MODULE_LICENSE("GPL"); MODULE_AUTHOR("A. Steinhoff"); MODULE_DESCRIPTION("UIO Janus-D CAN driver");