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

Reply via email to