Hi, Frist, I attached my code if it can help.
A couple of month ago we started developing a driver for the ts-can1 board. (http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1). I just restarted the development of the driver and I have a problem that I hope you guys will understand. Everything started when I got a segfault calling *"rmmod tscan1*" I started debugging and found that the segfault occurred when calling *"release_mem_region(res->start, (res->end - res->start + 1));" *(line 352) Debugging further showed me that *res == NULL*. I looked at the resources. There were still 2 resources, but the flags were not as I set them (IORESOURCE_IO or IORESOURCE_IRQ). Their values were like 0 and -97575452... This explains why *platform_get_resource()* was returning *NULL*. I started debugging were this struct was getting messed up and I figured it was right after calling *register_sja1000dev()* (line 317); I traced until *register_netdev(). *I stopped there because I didn't want to recompile my kernel :D. I also got this when probing the module: ... *WARNING: at net/core/rtnetlink.c:1232 rtmsg_ifinfo() [<c0024134>] (dump_stack+0x0/0x14) from [<c018e480>] (rtmsg_ifinfo+0xe4/0xf4) [<c018e39c>] (rtmsg_ifinfo+0x0/0xf4) from [<c018e75c>] (rtnetlink_event+0x84/0xb0) [<c018e6d8>] (rtnetlink_event+0x0/0xb0) from [<c0058d84>] (notifier_call_chain+0x48/0x88) [<c0058d3c>] (notifier_call_chain+0x0/0x88) from [<c005908c>] (__raw_notifier_call_chain+0x1c/0x20) r8:bf0582e8 r7:c5087800 r6:c02bb860 r5:c5087800 r4:00000000 [<c0059070>] (__raw_notifier_call_chain+0x0/0x20) from [<c00590b0>] (raw_notifier_call_chain+0x20/0x24) [<c0059090>] (raw_notifier_call_chain+0x0/0x24) from [<c018076c>] (call_netdevice_notifiers+0x20/0x28) [<c018074c>] (call_netdevice_notifiers+0x0/0x28) from [<c01846e0>] (register_netdevice+0x1d8/0x350) [<c0184508>] (register_netdevice+0x0/0x350) from [<c01848a4>] (register_netdev+0x4c/0x5c) r6:c5079f30 r5:c5087800 r4:00000000 [<c0184858>] (register_netdev+0x0/0x5c) from [<bf04df18>] (register_candev+0x18/0x20 [can_dev]) r5:c5087800 r4:c5087b60 [<bf04df00>] (register_candev+0x0/0x20 [can_dev]) from [<bf051ea8>] (register_sja1000dev+0x140/0x17c [sja1000]) [<bf051d68>] (register_sja1000dev+0x0/0x17c [sja1000]) from [<bf05a118>] (tscan1_probe+0x118/0x224 [tscan1]) r5:bf0582f0 r4:c5087b60 [<bf05a000>] (tscan1_probe+0x0/0x224 [tscan1]) from [<c0128e84>] (platform_drv_probe+0x20/0x24) [<c0128e64>] (platform_drv_probe+0x0/0x24) from [<c0126e70>] (driver_probe_device+0xe8/0x1a4) [<c0126d88>] (driver_probe_device+0x0/0x1a4) from [<c0126f3c>] (__device_attach+0x10/0x14) r8:00000021 r7:c0126f2c r6:bf0582f0 r5:c5079e5c r4:00000000 [<c0126f2c>] (__device_attach+0x0/0x14) from [<c012601c>] (bus_for_each_drv+0x60/0x8c) [<c0125fbc>] (bus_for_each_drv+0x0/0x8c) from [<c0126fe0>] (device_attach+0xa0/0xac) r7:bf058378 r6:00000000 r5:bf058394 r4:bf0582f0 [<c0126f40>] (device_attach+0x0/0xac) from [<c01263a8>] (bus_attach_device+0x7c/0x9c) r5:c029a178 r4:bf0582f0 [<c012632c>] (bus_attach_device+0x0/0x9c) from [<c01244e4>] (device_add+0x1e4/0x634) r6:00000000 r5:00000000 r4:bf0582f0 [<c0124300>] (device_add+0x0/0x634) from [<c0128c38>] (platform_device_add+0x100/0x188) [<c0128b38>] (platform_device_add+0x0/0x188) from [<c0128ce0>] (platform_device_register+0x20/0x24) r7:bf057370 r6:bf0582e0 r5:bf0582e8 r4:c60101b3 [<c0128cc0>] (platform_device_register+0x0/0x24) from [<bf05a360>] (tscan1_init+0x13c/0x214 [tscan1]) r5:c5079f30 [<bf05a224>] (tscan1_init+0x0/0x214 [tscan1]) from [<c0062538>] (sys_init_module+0xfc/0x144) r8:c0020124 r7:00000080 r6:2aac9000 r5:00000000 r4:bf058180 [<c006243c>] (sys_init_module+0x0/0x144) from [<c001ff80>] (ret_fast_syscall+0x0/0x2c) r6:00000000 r5:0000d0bc r4:0000a8c8* *tscan1 tscan1: device registered (reg_base=c6012100, irq=33)* I can tell you that I also use *rt73usb* driver for my ASUS wifi dongle. Don't know if it can conflict or whatever... I don't know where to debug now... Hope you guys can help me. Thanks ------- Alexandre Vézina [email protected] Pensez à l'environnement, avez-vous vraiment besoin d'imprimer ce courriel?
/* * tscan1.c. Support for the TS-CAN1 PC104 card * (http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1) * * Thanks a lot to the Ocera project (http://sourceforge.net/projects/ocera). * This driver is highly inspired from the lincan packsage of this project. * * Copyright (C) 2009 Alexandre Vézina <[email protected]> * Copyright (C) 2009 Benjamin Vanheuverzwijn <[email protected]> * * This program is free software; you can redistribute it and/or modify * it under the terms of the version 2 of the GNU General Public License * as published by the Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/kernel.h> #include <linux/version.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/delay.h> #include <linux/pci.h> #include <linux/platform_device.h> #include <linux/irq.h> #include <socketcan/can.h> #include <socketcan/can/dev.h> #include <socketcan/can/platform/sja1000.h> #include <linux/io.h> #include "sja1000.h" #define DRV_NAME "tscan1" // TSCAN1 basic options #define BASE_ADDR 0x11E00000 #define TSCAN1_RANGE 0x64 // SJA1000 Configuration #define TSCAN1_CAN_CLOCK (16000000 / 2) #define TSCAN1_OCR (OCR_MODE_NORMAL | OCR_TX0_PUSHPULL) #define TSCAN1_CDR (CDR_CBP | CDR_CLK_OFF) // SJA1000 I/O #define TSCAN1_SJA1000_IO_ADDR 0x100 #define TSCAN1_SJA1000_REG_RANGE 0x20 /* * TSCAN1 provides a jumper with 4 possibilities of I/O address. These are the 4 possible * addresses depending on the jumper configurations. Add this value to BASE_ADDR to map it. */ #define IO_ADDR1 0x150 #define IO_ADDR2 0x158 #define IO_ADDR3 0x160 #define IO_ADDR4 0x168 /* * This is the TSCAN1 Register Map. Add these values to your virtual address (tscan1->addr) * to get their values. */ #define TSCAN1_REG_ID1 0x0 #define TSCAN1_REG_ID2 0x1 #define TSCAN1_REG_PLD_VERSION 0x2 #define TSCAN1_REG_LED_STATUS 0x3 #define TSCAN1_REG_PAGE_SELECT 0x4 #define TSCAN1_REG_MODE_CONTROL 0x5 #define TSCAN1_REG_JUMPER_STATUS 0x6 // These are the value of TSCAN1 board identifier (2 first bytes) #define TSCAN1_ID1 0xF6 #define TSCAN1_ID2 0xB9 // These are the values of IRQ. IRQ value is bits 4 and 5 of TSCAN1_REG_JUMPER_STATUS #define TSCAN1_IRQ5 0x30 #define TSCAN1_IRQ6 0x10 #define TSCAN1_IRQ7 0x20 // Set up the mode control #define TSCAN1_MODE_CONTROL 0x60 // These are IRQ values depending on architecture // ARM #if defined(CONFIG_ARM) #define TSCAN1_IRQ5_VALUE 21 #define TSCAN1_IRQ6_VALUE 33 #define TSCAN1_IRQ7_VALUE 40 #else // x86 and others #define TSCAN1_IRQ5_VALUE 5 #define TSCAN1_IRQ6_VALUE 6 #define TSCAN1_IRQ7_VALUE 7 #endif static struct tscan1_board { void *sja1000_reg; void *tscan1_reg; struct platform_device tscan1_device; struct platform_driver tscan1_driver; } board; /** * This will simply turn the led on if off and off if on. */ static void tscan1_switch_led(void) { // 0 == 0 = 1 and 1 == 0 = 0 writeb(readb(board.tscan1_reg + TSCAN1_REG_LED_STATUS) == 0, board.tscan1_reg + TSCAN1_REG_LED_STATUS); } static u8 tscan1_read_reg(const struct sja1000_priv *priv, int reg) { char page = 0; // Register page (0 to 3) int offset = 0; // Translated register (0 to 31) // Compute the page and offset page = reg / 32; offset = reg % 32; // Write the registries to access the page and offset needed writeb((readb(priv->priv + TSCAN1_REG_PAGE_SELECT) & page), priv->priv + TSCAN1_REG_PAGE_SELECT); // Return the value return readb(priv->reg_base + offset); } static void tscan1_write_reg(const struct sja1000_priv *priv, int reg, u8 val) { char page = 0; // Register page (0 to 3) int offset = 0; // Translated register (0 to 31) // Compute the page and offset page = reg / 32; offset = reg % 32; // Write the registries to access the page and offset needed writeb((readb(priv->priv + TSCAN1_REG_PAGE_SELECT) & page), priv->priv + TSCAN1_REG_PAGE_SELECT); printk(KERN_DEBUG "%s: write sja1000 register. Reg: %x - Page: %d - Offset: %d\n", DRV_NAME, reg, page, offset); // Write in the sja10000 register writeb(val, priv->reg_base + offset); } /** * This will test if we have the right address by finding the board identifiers. * This will also ioremap the region if found. * * param reg - The I/O Region of the device * * return - The virtual I/O address of the device if found; NULL otherwise */ static void *test_tscan1_ioaddr(int reg) { // Pointer to test on virtual addresses void *ptr; // Get the memory address if ((ptr = ioremap(reg, TSCAN1_RANGE)) == NULL) { printk(KERN_ERR "%s: ioremap failed", DRV_NAME); return NULL; } // Test if this region contains the device IDs if (readb(ptr + TSCAN1_REG_ID1) != TSCAN1_ID1 || readb(ptr + TSCAN1_REG_ID2) != TSCAN1_ID2) { iounmap(ptr); return NULL; } return ptr; } /** * This will find (and ioremap) the address of the TSCAN1 device depending on * its jumper layout * * return - The virtual I/O address of the device if found; NULL otherwise */ static void *find_tscan1_ioaddr(void) { // Pointer to test on virtual addresses void *ptr; // Try the 4 jumper layouts if ((ptr = test_tscan1_ioaddr(BASE_ADDR + IO_ADDR1)) == NULL) { if ((ptr = test_tscan1_ioaddr(BASE_ADDR + IO_ADDR2)) == NULL) { if ((ptr = test_tscan1_ioaddr(BASE_ADDR + IO_ADDR3)) == NULL) { if ((ptr = test_tscan1_ioaddr(BASE_ADDR + IO_ADDR4)) == NULL) { printk(KERN_DEBUG "%s: no device found\n", DRV_NAME); return NULL; } } } } return ptr; } /** * Find the IRQ value depending on jumpers configuration. * * param - int representing the base address * return - The IRQ value */ static int find_tscan1_irq(void *addr) { int jumper_status, irq; // Read the jumper status register. jumper_status = readb(addr + TSCAN1_REG_JUMPER_STATUS); // Verify the 4th and 5th bits to obtain the IRQ if ((jumper_status & TSCAN1_IRQ5) == TSCAN1_IRQ5) { irq = TSCAN1_IRQ5_VALUE; } else if ((jumper_status & TSCAN1_IRQ6) == TSCAN1_IRQ6) { irq = TSCAN1_IRQ6_VALUE; } else if ((jumper_status & TSCAN1_IRQ7) == TSCAN1_IRQ7) { irq = TSCAN1_IRQ7_VALUE; } else { irq = -1; } return irq; } /** * This will setup and ioremap the sja1000 registers * * param addr The address of tscan1 registers * * return The address of the sja1000 registers. NULL if not found */ static void *find_sja1000_ioaddr(void *addr) { writeb(TSCAN1_MODE_CONTROL, addr + TSCAN1_REG_MODE_CONTROL); return ioremap(BASE_ADDR + TSCAN1_SJA1000_IO_ADDR, TSCAN1_SJA1000_REG_RANGE); } static int __init tscan1_probe(struct platform_device *p_pdev) { int err; void __iomem *addr; struct net_device *dev; struct sja1000_priv *priv; struct resource *res_io, *res_irq; int res_size; res_io = platform_get_resource(p_pdev, IORESOURCE_IO, 0); res_irq = platform_get_resource(p_pdev, IORESOURCE_IRQ, 0); if (!res_io || !res_irq) { printk(KERN_ERR "%s: Error retrieving data from resource.\n", DRV_NAME); err = -ENODEV; goto exit; } res_size = (res_io->end - res_io->start + 1); if (!request_mem_region(res_io->start, res_size, DRV_NAME)) { printk(KERN_ERR "%s: Cannot request mem region.\n", DRV_NAME); err = -EBUSY; goto exit; } addr = ioremap_nocache(res_io->start, res_size); if (!addr) { printk(KERN_ERR "%s: Cannot ioremap mem region.\n", DRV_NAME); err = -ENOMEM; goto exit_release; } dev = alloc_sja1000dev(0); if (!dev) { printk(KERN_ERR "%s: Cannot allocate sja1000 device.\n", DRV_NAME); err = -ENOMEM; goto exit_iounmap; } priv = netdev_priv(dev); dev->irq = res_irq->start; priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; priv->reg_base = board.sja1000_reg; priv->read_reg = tscan1_read_reg; priv->write_reg = tscan1_write_reg; priv->can.clock.freq = TSCAN1_CAN_CLOCK; priv->ocr = TSCAN1_OCR; priv->cdr = TSCAN1_CDR; priv->priv = board.tscan1_reg; dev_set_drvdata(&p_pdev->dev, dev); SET_NETDEV_DEV(dev, &p_pdev->dev); err = register_sja1000dev(dev); if (err) { dev_err(&p_pdev->dev, "registering %s failed (err=%d)\n", DRV_NAME, err); goto exit_free; } dev_info(&p_pdev->dev, "device registered (reg_base=%p, irq=%d)\n", priv->reg_base, dev->irq); return 0; exit_free: free_sja1000dev(dev); exit_iounmap: iounmap(addr); exit_release: release_mem_region(res_io->start, res_size); exit: return err; } static int __exit tscan1_remove(struct platform_device *p_pdev) { struct net_device *dev = dev_get_drvdata(&p_pdev->dev); struct sja1000_priv *priv = netdev_priv(dev); struct resource *res; unregister_sja1000dev(dev); dev_set_drvdata(&p_pdev->dev, NULL); if (priv->reg_base) iounmap(priv->reg_base); res = platform_get_resource(p_pdev, IORESOURCE_IO, 0); release_mem_region(res->start, (res->end - res->start + 1)); free_sja1000dev(dev); return 0; } static int __init tscan1_init(void) { int irq; void *reg_end; struct resource tscan1_res[2]; // Create the driver board.tscan1_driver.probe = tscan1_probe; board.tscan1_driver.remove = tscan1_remove; board.tscan1_driver.driver.name = DRV_NAME; board.tscan1_driver.driver.owner = THIS_MODULE; // Register the driver if(platform_driver_register(&board.tscan1_driver)) { printk(KERN_ERR "%s: Unable to register driver.\n", DRV_NAME); return 1; } // Map the TSCAN1 reg address if ((board.tscan1_reg = find_tscan1_ioaddr()) == NULL) { printk(KERN_ERR "%s: No TSCAN1 device\n", DRV_NAME); return 1; } // Find the IRQ if ((irq = find_tscan1_irq(board.tscan1_reg)) < 0) { printk(KERN_ERR "%s: No IRQ found. Verify your jumpers.\n", DRV_NAME); return 1; } // Map the SJA1000 reg address if ((board.sja1000_reg = find_sja1000_ioaddr(board.tscan1_reg)) == NULL) { printk(KERN_ERR "%s: Unable to find sja1000 registers\n", DRV_NAME); return 1; } // Compute the registry end address reg_end = board.tscan1_reg + TSCAN1_RANGE - 1; // Fill in resources memset(&tscan1_res, 0, sizeof(tscan1_res)); memcpy(&tscan1_res[0].start, &board.tscan1_reg, sizeof(board.tscan1_reg)); memcpy(&tscan1_res[0].end, &(reg_end), sizeof(reg_end)); tscan1_res[0].name = DRV_NAME; tscan1_res[0].flags = IORESOURCE_IO; tscan1_res[1].start = irq; tscan1_res[1].end = irq; tscan1_res[1].name = DRV_NAME; tscan1_res[1].flags = IORESOURCE_IRQ; // Create the device board.tscan1_device.name = DRV_NAME; board.tscan1_device.id = -1; board.tscan1_device.num_resources = ARRAY_SIZE(tscan1_res); board.tscan1_device.resource = tscan1_res; // Register the device if (platform_device_register(&board.tscan1_device)) { printk(KERN_ERR "%s: Unable to register device.\n", DRV_NAME); return 1; } // Turn off the LED tscan1_switch_led(); return 0; } static void __exit tscan1_exit(void) { // Turn on the LED tscan1_switch_led(); // FIXME platform_driver_unregister(&board.tscan1_driver); platform_device_unregister(&board.tscan1_device); } module_init(tscan1_init); module_exit(tscan1_exit); MODULE_AUTHOR("Alexandre Vezina <[email protected]>, Benjamin Vanheuverzwijn [email protected]"); MODULE_DESCRIPTION("Socket-CAN driver for TS-CAN1 PC104 module"); MODULE_SUPPORTED_DEVICE("TS-CAN1 module"); MODULE_LICENSE("GPL v2");
_______________________________________________ Socketcan-users mailing list [email protected] https://lists.berlios.de/mailman/listinfo/socketcan-users
