lkml.org 
[lkml]   [2003]   [Mar]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
From
Subjectsubmission of CAN driver for i82527 chip
Date
Dear Kernel Maintainer;

Please find enclosed 2 files of a driver for Intel 82527 CAN Controller,
This driver is a simplified version of 'ocan' driver by Allesandro Rubini.

'jcan' is a character driver for kernel 2.4 and up, I inserted it in
linux_root/drivers/char directory.
I tested it on embedded MPC823 platform, but it should be running on other
platforms as well.

This is first time I submit a Linux driver and I would appreciate your
comments.

regards George Cewe.

/*
* jcan.h -- header for the CAN driver
*
* Copyright (C) 2003 George Cewe <gcewe@copper.net>
* Copyright (C) 2003 Advanced Concepts Inc.
* Copyright (C) 2002 Alessandro Rubini <rubini@linux.it>
* Copyright (C) 2001 Ascensit S.p.A <support@ascensit.com>
* Author: Rodolfo Giometti <r.giometti@ascensit.com>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*/

#ifndef __JCAN_H__
#define __JCAN_H__

#include <linux/types.h>

#define CAN_READ_BUFS 64 /* read buffer has 64 messages */


#define I527_XTD_XTD 0x04
#define I527_XTD_STD 0x00

/*
* data structures used in both kernel and user space (mostly for ioctl)
*/
typedef enum
{ B_100K
,B_125K
,B_250K
,B_500K
,B_1M
,BPS_MAX
} BPS;

typedef struct
{
__u8 reg;
__u8 val;
} CAN_REG;

#define CAN_MULTIREG_MAX 16
typedef struct
{
__u8 first, last;
__u8 regs[CAN_MULTIREG_MAX];
} CAN_MULTIREG;

typedef struct
{
__u8 data[256];
} CAN_ALLREGS;

typedef struct
{
__u32 m_msg15;
__u32 m_xtd;
__u16 m_std;
} CAN_MASKS;

/* This structure is both part of the device structure and arg of ioctl */
typedef struct
{
__u32 id;
__u8 msgobj; /* 1..15 */
__u8 flags;
__u8 config; /* same as config register */
__u8 dlc; /* data length counter */
__u8 data[8];
__u16 error; /* also for alignment */
} CAN_MSG;

/* And these are the message flags */
#define CAN_MSGFLAG_WRITE 0x01
#define CAN_MSGFLAG_READ 0x02 /* set either write read */
#define CAN_MSGFLAG_DOREMOTE 0x04 /* send a remote frame, for reading */
#define CAN_MSGFLAG_PEEKONLY 0x08 /* used by IOCPEEK */

#define CAN_ERROR_MASK 0x07 /* Tx error code */
#define CAN_ERROR_MSGLST 0x10 /* Message lost error */
#define CAN_ERROR_OVRFLW 0x80 /* Read buffer overflow */


/*
* ioctl() definitons
*/

/* Use 'z' as magic number */
#define CAN_IOC_MAGIC 'z' /* like other CAN drivers, per ioctl-number.txt */

#define CAN_IOCRESET _IO(CAN_IOC_MAGIC, 0)

/* individual registers */
#define CAN_IOCREADREG _IOWR(CAN_IOC_MAGIC, 1, CAN_REG)
#define CAN_IOCWRITEREG _IOW(CAN_IOC_MAGIC, 2, CAN_REG)

/* range of registers */
#define CAN_IOCREADMULTI _IOWR(CAN_IOC_MAGIC, 3, CAN_MULTIREG)
#define CAN_IOCWRITEMULTI _IOW(CAN_IOC_MAGIC, 4, CAN_MULTIREG)

/* one message */
#define CAN_IOCSETUPMSG _IOW(CAN_IOC_MAGIC, 5, CAN_MSG)
#define CAN_IOCWRITEMSG _IOW(CAN_IOC_MAGIC, 6, CAN_MSG)
#define CAN_IOCTXMSG _IOW(CAN_IOC_MAGIC, 7, unsigned long)
#define CAN_IOCRXMSG _IOWR(CAN_IOC_MAGIC, 8, CAN_MSG)
#define CAN_IOCRELEASEMSG _IOW(CAN_IOC_MAGIC, 9, unsigned long)

/* all registers */
#define CAN_IOCREADALL _IOR(CAN_IOC_MAGIC, 10, CAN_ALLREGS)

/* masks, times, bus configuration */
#define CAN_IOCGETMASKS _IOR(CAN_IOC_MAGIC, 11, CAN_MASKS)
#define CAN_IOCSETMASKS _IOW(CAN_IOC_MAGIC, 12, CAN_MASKS)

#define CAN_IOCGETBPS _IOR(CAN_IOC_MAGIC, 13, unsigned long)
#define CAN_IOCSETBPS _IOW(CAN_IOC_MAGIC, 14, unsigned long)

#define CAN_IOCGETBUSCONF _IOR(CAN_IOC_MAGIC, 15, CAN_REG)
#define CAN_IOCSETBUSCONF _IOW(CAN_IOC_MAGIC, 16, CAN_REG)

/* misc */
#define CAN_IOCSOFTRESET _IO(CAN_IOC_MAGIC, 17)

#define CAN_IOCWRITEQ _IOW(CAN_IOC_MAGIC, 18, CAN_MSG)
#define CAN_IOCGIRQCOUNT _IOR(CAN_IOC_MAGIC, 19, unsigned long)

#define CAN_IOCREQSIGNAL _IOW(CAN_IOC_MAGIC, 20, unsigned long)

/* I/O ports */
#define CAN_IOCINPUT _IOWR(CAN_IOC_MAGIC, 21, CAN_REG)
#define CAN_IOCOUTPUT _IOW(CAN_IOC_MAGIC, 22, CAN_REG)
#define CAN_IOCIOCFG _IOW(CAN_IOC_MAGIC, 23, CAN_REG)

/* peek (like rx) */
#define CAN_IOCPEEKMSG _IOWR(CAN_IOC_MAGIC, 24, CAN_MSG)

#define CAN_IOC_MAXNR 24

#endif /* __JCAN_H__ */



/*
* jcan.c -- CAN driver for i82527
*
* Copyright (C) 2003 George Cewe <gcewe@copper.net>
* Copyright (C) 2003 Advanced Concepts Inc.
* Copyright (C) 2002 Alessandro Rubini <rubini@linux.it>
* Copyright (C) 2002 System SpA <info.electronics@system-group.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*
* This driver is a simplified version of "ocan" driver by Alessandro Rubini.
* It supports one memory mapped Intel i82527 CAN chip, running under J1939
* protocol (250kBps, extended message id).
*
*/

#define __NO_VERSION__
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/interrupt.h>

#include <asm/irq.h>
#include <asm/io.h>
#ifdef __powerpc__
#include <asm-ppc/8xx_immap.h>
#endif
#include "jcan.h"

/*=============================================================================
* Messaging stuff
*/
#undef PDEBUG /* undef it, just in case */

#ifdef CAN_DEBUG
#ifdef __KERNEL__
/* This one if debugging is on, and kernel space */
#define PDEBUG(fmt, args...) printk(KERN_DEBUG CAN_TEXT fmt,##args)
#else
/* This one for user space */
#define PDEBUG(fmt, args...) fprintf(stdout, fmt, ##args)
#endif
#else
/* nothing */
#define PDEBUG(fmt, args...) /* nothing */
#endif /* CAN_DEBUG */

#ifdef CAN_DEBUG
#define debug 1
#else
#define debug 0
#endif

// base address and interrupt number
#define IO_ADDR 0xffff0000
#define IO_RANGE 0x100
#define IRQ_NUM SIU_IRQ3

#ifndef CAN_MAJOR
#define CAN_MAJOR 91
#endif

#define CAN_NAME "jcan"
#define CAN_TEXT "jcan: "

/*
* Sysctl constants
*/
#define DEV_CAN 2658 /* random for /proc/sys/dev/jcan/ */

/* inside /proc/sys/dev/jcan, each backend can use 100 keys */

/*
* minor allocation: each device has 1 general entry point, 15
* message-buffer entry points and a few information/error files.
* So it will need 5 bits. This accounts for up to eight devices
*/

#define CAN_DEV_TYPE(minor) ((minor)&0x1f)
#define CAN_DEV_TYPE_GENERIC 0 /* 1..15 are the message objects */
#define CAN_DEV_TYPE_ERROR 16
#define CAN_DEV_TYPE_IO1 17
#define CAN_DEV_TYPE_IO2 18

#define CAN_DEV_NUM(minor) ((minor)>>5)

/*
* Device structures
*/

#define CAN_BUFSIZE 64 /* 64 pointers for msg packets */

// i82527 related definitions =============================================

#define I527_MSG_OBJS 16 /* 0 is the whole device, 1..15 are objects */
#define I527_FIRST_OBJ 1

/* 82527 address map (referred from base address) & internal bits.
See the 82527 data-sheet page 9 and following */
#define I527_MAP_SIZE 0x100
#define I527_CTRL_REG 0x00
#define I527_CCE 0x40
#define I527_EIE 0x08
#define I527_SIE 0x04
#define I527_IE 0x02
#define I527_INIT 0x01

#define I527_STAT_REG 0x01
#define I527_STAT_REG_DEFAULT 0x07

#define I527_CPU_INT_REG 0x02
#define I527_RSTST 0x80
#define I527_DSC 0x40
#define I527_DMC 0x20
#define I527_PWD 0x10
#define I527_SLEEP 0x08
#define I527_MUX 0x04
#define I527_CEN 0x01

/* Reserved 0x03 */
#define I527_HI_SPEED_RD 0x04
#define I527_GMASK_STD 0x06
#define I527_GMASK_XTD 0x08
#define I527_MSG15_MASK 0x0c

/* Message 1 0x10 */
#define I527_MSG_OFF 0x10 /* No size definition here */
#define I527_MSG_CTRL 0x00
#define I527_MSGVAL_R 0xff7f /* *********************** */
#define I527_MSGVAL_S 0xffbf /* WARNING!!! */
#define I527_TXIE_R 0xffdf /* These masks must be */
#define I527_TXIE_S 0xffef /* &-ed and *NOT* |-ed */
#define I527_RXIE_R 0xfff7 /* */
#define I527_RXIE_S 0xfffb /* */
#define I527_INTPND_R 0xfffd /* */
#define I527_INTPND_S 0xfffe /* */
#define I527_RMTPND_R 0x7fff /* WARNING!!! */
#define I527_RMTPND_S 0xbfff /* These masks must be */
#define I527_TXRQST_R 0xdfff /* &-ed and *NOT* |-ed */
#define I527_TXRQST_S 0xefff /* */
#define I527_MSGLST_R 0xf7ff /* */
#define I527_MSGLST_S 0xfbff /* */
#define I527_CPUUPD_R 0xf7ff /* WARNING!!! */
#define I527_CPUUPD_S 0xfbff /* These masks must be */
#define I527_NEWDAT_R 0xfdff /* &-ed and *NOT* |-ed */
#define I527_NEWDAT_S 0xfeff /* *********************** */
#define I527_MSG_ARBIT 0x02
#define I527_MSG_CFG 0x06
#define I527_DLC_MASK 0xf0
#define I527_DLC_SHIFT 4
#define I527_DLC_MASK0 0x0f
#define I527_DIR 0x08
#define I527_DIR_TX 0x08
#define I527_DIR_RX 0x00
#define I527_XTD 0x04
#define I527_MSG_DATA 0x07 /* 8 bytes */
#define I527_CLKOUT_REG 0x1f
#define I527_SL_MASK 0x30
#define I527_SL_SHIFT 4
#define I527_SL_MASK0 0x03
#define I527_CLKDIV_MASK 0x0f
#define I527_CLKDIV_SHIFT 0
#define I527_CLKDIV_MASK0 0x0f

/* Message 2 0x20 */
#define I527_BUSCFG_REG 0x2f
#define I527_COBY 0x40
#define I527_POL 0x20
#define I527_DCT1 0x08
#define I527_DCR1 0x02
#define I527_DCR0 0x01

/* Message 3 0x30 */
#define I527_BITT0_REG 0x3f
#define I527_SJW_MASK 0xc0
#define I527_SJW_SHIFT 0x06
#define I527_SJW_MASK0 0x03
#define I527_BRP_MASK 0x3f
#define I527_BRP_SHIFT 0
#define I527_BRP_MASK0 0x3f

/* Message 4 0x40 */
#define I527_BITT1_REG 0x4f
#define I527_SPL_MASK 0x80
#define I527_SPL_SHIFT 7
#define I527_SPL_MASK0 0x01
#define I527_TSEG2_MASK 0x70
#define I527_TSEG2_SHIFT 4
#define I527_TSEG2_MASK0 0x07
#define I527_TSEG1_MASK 0x0f
#define I527_TSEG1_SHIFT 0
#define I527_TSEG1_MASK0 0x0f

/* Message 5 0x50 */
#define I527_INT_REG 0x5f

/* Message 6 0x60 */
/* Reserved 0x6f */

/* Message 7 0x70 */
/* Reserved 0x7f */

/* Message 8 0x80 */
/* Reserved 0x8f */

/* Message 9 0x90 */
#define I527_P1CONF 0x9f

/* Message 10 0xa0 */
#define I527_P2CONF 0xaf

/* Message 11 0xb0 */
#define I527_P1IN 0xbf

/* Message 12 0xc0 */
#define I527_P2IN 0xcf

/* Message 13 0xd0 */
#define I527_P1OUT 0xdf

/* Message 14 0xe0 */
#define I527_P2OUT 0xef

/* Message 15 0xf0 */
#define I527_SER_RST_ADD 0xff

typedef struct
{
__u8 cpuint;
__u8 clkout;
__u8 bittm0;
__u8 bittm1;
} CAN_BPS;

/*
* WARNING: can_times fields must all be __u8, because I sometimes
* iniitalize it from arrays of bytes (for example dev->hal->h_defaults)
*/
typedef struct
{
__u8 t_dsc;
__u8 t_dmc;
__u8 t_clkout_div;
__u8 t_clkout_slew;
__u8 t_sjw;
__u8 t_spl;
__u8 t_brp;
__u8 t_tseg1;
__u8 t_tseg2;
} CAN_TIMES;

/* This is the MSGOBJ structure */
typedef struct
{
u32 obj_id; /* current id */
struct file *owner; /* someone is waiting for a message */
volatile u16 obj_flags; /* object-specific flags */
u8 regbase; /* register offset */
volatile u8 error; /* error on message */
spinlock_t lock;
unsigned long flags;
wait_queue_head_t read_q; /* read queue */
struct fasync_struct *async_read_q; /* async read queue */
wait_queue_head_t write_q; /* write queue */
struct fasync_struct *async_write_q; /* async write queue*/
volatile int head;
volatile int tail;
CAN_MSG **msg; /* allocated using CAN_BUFSIZE */;
} CAN_MSGOBJ;

/* object flags and error flags, used internally */
#define CAN_OBJFLAG_WRITE 0x01 /* being used to write/read */
#define CAN_OBJFLAG_READ 0x02 /* (same values as MSGFLAG) */
#define CAN_OBJFLAG_REMOTE 0x04 /* remote flag on */
#define CAN_OBJFLAG_HWBUSY 0x40 /* message is being transmitted */
#define CAN_OBJFLAG_BUSY 0x80 /* message is in use */


/* error notification via signals */
typedef struct
{
struct file *file;
int signal;
pid_t pid;
} CAN_ERROR;
#define CAN_NR_ERROR_FILES 4 /* at most 4 processes can get a signal */

typedef struct
{
u32 base;
volatile u32 irq_count;
u8 usecount;
volatile u8 statusbyte;
u8 registered;
u8 gotirq;
CAN_MSGOBJ *objs[I527_MSG_OBJS];
CAN_ERROR errorinfo[CAN_NR_ERROR_FILES];
wait_queue_head_t error_q;
BPS eBps;
} CAN_DEV;


static kmem_cache_t *gpsCache; // The memory cache for msg packets
static CAN_DEV gsDev; // The device data

static const CAN_BPS gasBps[BPS_MAX] =
{ {0x40, 0x31, 0x03, 0x4d} // 100k
,{0x40, 0x31, 0x03, 0x49} // 125k
,{0x40, 0x31, 0x01, 0x49} // 250k
,{0x40, 0x31, 0x00, 0x49} // 500k
,{0x40, 0x31, 0x00, 0x14} // 1M
};

static spinlock_t can_lock = SPIN_LOCK_UNLOCKED;

/////////////////////////////////////////////////////////////////////////////
static int can_readb(CAN_DEV *dev, u_char reg)
{
return readb((volatile unsigned char *)(dev->base + reg));
}

//---------------------------------------------------------------------------
static int can_writeb(CAN_DEV *dev, u_char reg, unsigned char val)
{
writeb(val, (volatile unsigned char *)(dev->base + reg));
return 0;
}

/*===========================================================================
* basic functions use direct methods
*/
#define i527_read_reg(dev, reg) \
(can_readb((dev), (reg)))

#define i527_write_reg(dev, reg, value) \
(can_writeb((dev), (reg), (value)))

/*
* bit-setting operation and its use
*/
extern inline int i527_bits(CAN_DEV *dev, int reg,
int bits, int value)
{
int res = i527_read_reg(dev, reg);
if (res < 0) return res;
res = (res & ~bits) | (bits & value);
return i527_write_reg(dev, reg, res);
}

#define can_enable_irq(dev) i527_bits((dev), I527_CTRL_REG, \
I527_EIE|I527_IE, I527_EIE|I527_IE)

#define can_disable_irq(dev) i527_bits((dev), I527_CTRL_REG, \
I527_EIE|I527_IE, 0)

#define can_read_msg_dlc(dev, n) \
((i527_read_msgcfg(dev, n) & I527_DLC_MASK) \
>> I527_DLC_SHIFT)

#define can_write_msg_dlc(dev, n, dlc) \
(i527_bits((dev), n * I527_MSG_OFF + I527_MSG_CFG, \
I527_DLC_MASK, (dlc) << I527_DLC_SHIFT))

/*
* Enable/disable configuration changes
*/

/* enable and return previous value */
extern inline int can_enable_cfg(CAN_DEV *dev)
{
int res = i527_read_reg(dev, I527_CTRL_REG);
if (res < 0) return res;
if (res & I527_CCE) return I527_CCE;
res = i527_write_reg(dev, I527_CTRL_REG, res | I527_CCE);
if (res < 0) return res;
return 0;
}

/* disable and return previous value */
extern inline int can_disable_cfg(CAN_DEV *dev)
{
int res = i527_read_reg(dev, I527_CTRL_REG);
if (res < 0) return res;
if (!(res & I527_CCE)) return 0;
res = i527_write_reg(dev, I527_CTRL_REG, res & ~I527_CCE);
if (res < 0) return res;
return I527_CCE;
}

/* restore previous value */
extern inline int can_restore_cfg(CAN_DEV *dev, int prev)
{
return i527_bits(dev, I527_CTRL_REG, I527_CCE, prev);
}

/*
* higher level functions (can't be in i82527.h, for strange dependencies)
*/

extern inline int i527_read_msgcfg(CAN_DEV *dev,
CAN_MSGOBJ *obj)
{
return i527_read_reg(dev, obj->regbase + I527_MSG_CFG);
}

extern inline int i527_write_msgcfg(CAN_DEV *dev,
CAN_MSGOBJ *obj, int val)
{
if (val & ~0xff) return -EINVAL;
return i527_write_reg(dev, obj->regbase + I527_MSG_CFG, val);
}

extern inline u16 i527_read_std_mask(CAN_DEV *dev)
{
/* errors are ignored, hmm... */
u16 ret = i527_read_reg(dev, I527_GMASK_STD) << 8
| i527_read_reg(dev, I527_GMASK_STD + 1);
return ret;
}

extern inline void i527_write_std_mask(CAN_DEV *dev, u16 val)
{
/* errors are ignored, hmm... */
i527_write_reg(dev, I527_GMASK_STD, val >> 8);
i527_write_reg(dev, I527_GMASK_STD + 1, val & 0xff);
}

extern inline u32 i527_read_x_mask(CAN_DEV *dev)
{
/* errors are ignored, hmm... */
u32 ret = i527_read_reg(dev, I527_GMASK_XTD) << 24
| i527_read_reg(dev, I527_GMASK_XTD + 1) << 16
| i527_read_reg(dev, I527_GMASK_XTD + 2) << 8
| i527_read_reg(dev, I527_GMASK_XTD + 3);
return ret;
}

extern inline void i527_write_x_mask(CAN_DEV *dev, u32 val)
{
/* errors are ignored, hmm... */
i527_write_reg(dev, I527_GMASK_XTD, val >> 24);
i527_write_reg(dev, I527_GMASK_XTD + 1, (val >> 16) & 0xff);
i527_write_reg(dev, I527_GMASK_XTD + 2, (val >> 8) & 0xff);
i527_write_reg(dev, I527_GMASK_XTD + 3, (val >> 0) & 0xff);
}


extern inline u32 i527_read_15_mask(CAN_DEV *dev)
{
/* errors are ignored, hmm... */
u32 ret = i527_read_reg(dev, I527_MSG15_MASK) << 24
| i527_read_reg(dev, I527_MSG15_MASK + 1) << 16
| i527_read_reg(dev, I527_MSG15_MASK + 2) << 8
| i527_read_reg(dev, I527_MSG15_MASK + 3);
return ret;
}

extern inline void i527_write_15_mask(CAN_DEV *dev,
u32 val)
{
/* errors are ignored, hmm... */
i527_write_reg(dev, I527_MSG15_MASK, val >> 24);
i527_write_reg(dev, I527_MSG15_MASK + 1, (val >> 16) & 0xff);
i527_write_reg(dev, I527_MSG15_MASK + 2, (val >> 8) & 0xff);
i527_write_reg(dev, I527_MSG15_MASK + 3, (val >> 0) & 0xff);
}

extern inline u16 i527_read_msgctrl(CAN_DEV *dev,
CAN_MSGOBJ *obj)
{
/* FIXME: this is used little-endian, but doesn't need to be 16b */

/* errors are ignored, hmm... */
u16 ret = i527_read_reg(dev, obj->regbase + I527_MSG_CTRL)
| (i527_read_reg(dev, obj->regbase + I527_MSG_CTRL +1 )
<< 8);
return ret;
}

extern inline void i527_write_msgctrl(CAN_DEV *dev,
CAN_MSGOBJ *obj, u16 val)
{
/* FIXME: this is used little-endian, but doesn't need to be 16b */

/* errors are ignored, hmm... */
i527_write_reg(dev, obj->regbase + I527_MSG_CTRL, val & 0xff);
i527_write_reg(dev, obj->regbase + I527_MSG_CTRL + 1, val >> 8);
}

/* write a single byte of msgctrl, twice as fast as the function above */
extern inline void i527_msgflag(CAN_DEV *dev,
CAN_MSGOBJ *obj, u16 act)
{
if ((act & 0xff) == 0xff)
i527_write_reg(dev, obj->regbase + I527_MSG_CTRL + 1, act >> 8);
else
i527_write_reg(dev, obj->regbase + I527_MSG_CTRL, act & 0xff);
}
/* same, but for unallocated objects */
extern inline void i527_msgflag_noobj(CAN_DEV *dev,
int msgnum, u16 act)
{
if ((act & 0xff) == 0xff)
i527_write_reg(dev, msgnum*I527_MSG_OFF + I527_MSG_CTRL + 1,
act >> 8);
else
i527_write_reg(dev, msgnum*I527_MSG_OFF + I527_MSG_CTRL,
act & 0xff);
}
/* read a single byte of msgctrl (use the _S flag. Hm....) */
extern inline int i527_check_msgflag(CAN_DEV *dev,
CAN_MSGOBJ *obj, u16 act)
{
u16 reg;
if ((act & 0xff) == 0xff) {
reg = i527_read_reg(dev, obj->regbase + I527_MSG_CTRL + 1);
return !((reg << 8) & ~act);
}
reg = i527_read_reg(dev, obj->regbase + I527_MSG_CTRL);
return !(reg & ~act);
}

extern inline u32 i527_read_msgarb(CAN_DEV *dev,
CAN_MSGOBJ *obj)
{
int port = obj->regbase + I527_MSG_ARBIT;

/* errors are ignored, hmm... */
u32 ret = i527_read_reg(dev, port) << 24
| i527_read_reg(dev, port + 1) << 16
| i527_read_reg(dev, port + 2) << 8
| i527_read_reg(dev, port + 3);
return ret;
}

extern inline void i527_write_msgarb(CAN_DEV *dev,
CAN_MSGOBJ *obj, u32 val)
{
int port = obj->regbase + I527_MSG_ARBIT;

i527_write_reg(dev, port, val >> 24);
i527_write_reg(dev, port + 1, (val >> 16) & 0xff);
i527_write_reg(dev, port + 2, (val >> 8) & 0xff);
i527_write_reg(dev, port + 3, (val >> 0) & 0xff);
}

extern inline void i527_read_msgdata(CAN_DEV *dev,
CAN_MSGOBJ *obj,
int n, u8 *data)
{
int i;
u8 reg = obj->regbase + I527_MSG_DATA;

for (i=0; i<n; i++)
data[i] = i527_read_reg(dev, reg++);
}

extern inline void i527_write_msgdata(CAN_DEV *dev,
CAN_MSGOBJ *obj,
int n, u8 *data)
{
int i;
u8 reg = obj->regbase + I527_MSG_DATA;

if (!n) return;
i527_msgflag(dev, obj, I527_CPUUPD_S); /* CPU updating */
for (i=0; i<n && i<8; i++)
i527_write_reg(dev, reg++, data[i]);
i527_msgflag(dev, obj, I527_CPUUPD_R);
}

/*===========================================================================
* a collection of quick helper functions (all of them inline)
*/

/* objects can become allocated items, and allocation is hidden here */
extern inline CAN_MSGOBJ *lib_findobj(CAN_DEV *dev, int msgnum, int prio)
{
/* msgnum already checked */
return dev->objs[msgnum];
}

/* if/when allocation is there, release them here */
extern inline void lib_releaseobj(CAN_DEV *dev, int msgnum, CAN_MSGOBJ *obj)
{
int i;
if (!obj) return;
spin_lock(&obj->lock);
obj->owner = NULL;
obj->obj_flags &= ~(CAN_OBJFLAG_BUSY | CAN_OBJFLAG_HWBUSY);
i527_msgflag(dev, obj, I527_MSGVAL_R & I527_TXIE_R & I527_RXIE_R);
for (i=0; i<CAN_BUFSIZE; i++)
if (obj->msg[i]) {
PDEBUG("discarding packet in obj %i\n", msgnum);
kmem_cache_free(gpsCache, obj->msg[i]);
obj->msg[i] = NULL;
}
obj-> head = obj->tail = 0;
spin_unlock(&obj->lock);
}


/* returns 0 or -EINVAL */
extern inline int lib_checkmsgnum(int msgnum, int flags)
{
if (msgnum > 0 && msgnum < 15)
return 0;
if ( (msgnum == 15) && !(flags & CAN_MSGFLAG_WRITE) )
return 0;
printk("lib_checkmsgnum error, num= %d\n", msgnum);
return -EINVAL;
}

/* returns either 0 or -EBUSY, adjusts ownership */
extern inline int lib_setowner(CAN_MSGOBJ *obj,
struct file *filp, int rdwr)
{
spin_lock(&obj->lock);
if ( (obj->obj_flags & CAN_OBJFLAG_BUSY) && (obj->owner != filp) ) {
spin_unlock(&obj->lock);
return -EBUSY;
}
obj->owner = filp;
obj->obj_flags =
(obj->obj_flags & ~(CAN_MSGFLAG_WRITE | CAN_MSGFLAG_READ))
| CAN_OBJFLAG_BUSY | rdwr;
spin_unlock(&obj->lock);
return 0;
}


/* find this file in the errorfiles */
extern inline CAN_ERROR *lib_findfile(CAN_DEV *dev, struct file *file)
{
CAN_ERROR *info = dev->errorinfo;
int i;

for (i = 0; i<CAN_NR_ERROR_FILES; i++, info++)
if (info->file == file)
return info;
return NULL;
}

/*===========================================================================
* Normal management message objects functions
*/

//---------------------------------------------------------------------------
static void can_setbps(CAN_DEV *dev, BPS eBps )
{
int j;
__u8 nTmp;
const CAN_BPS *psBps = gasBps + eBps;

j = can_enable_cfg(dev);

nTmp = i527_read_reg(dev, I527_CPU_INT_REG) & ~(I527_DSC|I527_DMC);
nTmp |= psBps->cpuint;
i527_write_reg(dev, I527_CPU_INT_REG, nTmp);
i527_write_reg(dev, I527_CLKOUT_REG, psBps->clkout);
i527_write_reg(dev, I527_BITT0_REG, psBps->bittm0);
i527_write_reg(dev, I527_BITT1_REG, psBps->bittm1);

PDEBUG("libdrv: index %lx\n", eBps);
PDEBUG("libdrv: cpu_int_reg %x\n", nTmp);
PDEBUG("libdrv: cpu_clk_out %x\n", psBps->clkout);
PDEBUG("libdrv: cpu_bit0_reg %x\n", psBps->bittm0);
PDEBUG("libdrv: cpu_bit1_reg %x\n", psBps->bittm1);

can_restore_cfg(dev, j);
dev->eBps = eBps;
}

/*---------------------------------------------------------------------------
* full-reset function, called by deviceinit or by ioctl(RESET)
--------------------------------------------------------------------------*/
static void can_reset_i82527(CAN_DEV *dev)
{
int i;

PDEBUG("init/reset of i82527 at 0x%08lx\n", (unsigned long)dev->base);

i527_write_reg(dev,I527_CTRL_REG, I527_CCE|I527_INIT); //41
i527_write_reg(dev,I527_CLKOUT_REG, 3 << I527_SL_SHIFT); //30
i527_write_reg(dev, I527_STAT_REG, 0x00);
i527_write_reg(dev, I527_P1CONF, 0x00); /* default is input */
i527_write_reg(dev, I527_P2CONF, 0x00);

i527_write_15_mask(dev, 0xffffffff);
i527_write_std_mask(dev, 0xffff);
i527_write_x_mask(dev, 0xffffffff);

/* Turn off all message objects and clear message identifiers */
for (i = I527_FIRST_OBJ; i < I527_MSG_OBJS; i++)
{
if (dev->objs[i])
{
lib_releaseobj(dev, i, dev->objs[i]); /* useful for reset */
i527_write_msgctrl(dev, dev->objs[i],
I527_MSGVAL_R & I527_TXIE_R &
I527_RXIE_R & I527_INTPND_R &
I527_RMTPND_R & I527_TXRQST_R &
I527_MSGLST_R & I527_NEWDAT_R);
i527_write_msgarb(dev, dev->objs[i], 0);
}
}

/* set default values */
i527_write_reg(dev, I527_BUSCFG_REG, 0x4a);
can_setbps(dev, B_250K);

/* Initialization end */
i527_write_reg(dev, I527_STAT_REG, I527_STAT_REG_DEFAULT);
if (dev->usecount)
{
can_enable_irq(dev); /* warm reset */
}
else
{
i527_write_reg(dev, I527_CTRL_REG, 0); /* cold reset */
}
}

/*---------------------------------------------------------------------------
* This is called from ioctl or from the bottom half handler.
* It must configure and possibly transmit an object
* Everything checkable has already been checked if we get here.
-------------------------------------------------------------------------- */
static void can_config_and_transmit(CAN_DEV *dev,
CAN_MSGOBJ *obj,
CAN_MSG *msg, int flag)
{
int i;

/* it looks like message 15 fires an interrupt when re-enabled */
if (msg->msgobj != 15)
i527_msgflag(dev, obj, I527_MSGVAL_R); /* being updated */

if (msg->id != obj->obj_id) {
i527_write_msgarb(dev, obj, msg->id);
obj->obj_id = msg->id;
PDEBUG("message has new ID 0x%08lx\n", (unsigned long)obj->obj_id);
}

/* write DLC and X flag */
i = (msg->dlc << I527_DLC_SHIFT) | (msg->config & I527_XTD)
| (msg->flags & CAN_MSGFLAG_WRITE ? I527_DIR_TX : I527_DIR_RX);
i527_write_msgcfg(dev, obj, i);

/* write data bytes */
if (msg->flags & CAN_MSGFLAG_WRITE)
i527_write_msgdata(dev, obj, msg->dlc, msg->data);

/* now set flags: *XIE, MSGVAL; then clear CPUUpd and set newdat */
i527_msgflag(dev, obj,
I527_MSGVAL_S & I527_TXIE_S & I527_RXIE_S);

if (!flag)
{ /* only setup, no tx */
if (msg->flags & CAN_MSGFLAG_WRITE)
i527_msgflag(dev, obj, I527_CPUUPD_R & I527_NEWDAT_S);
else
i527_msgflag(dev, obj, I527_RMTPND_R & I527_MSGLST_R
& I527_NEWDAT_R);
return;
}
/* else, tx too */
i527_msgflag(dev, obj, I527_CPUUPD_R & I527_NEWDAT_S & I527_TXRQST_S);
}


//IRQ////////////////////////////////////////////////////////////////////////
/* this bottom half does the work of message handling and buffer popping */

//---------------------------------------------------------------------------
static void can_write_interrupt(CAN_DEV *dev,
CAN_MSGOBJ *obj, int objnum)
{
PDEBUG("can_wi: interrupt on objnum %d\n", objnum);

/* write-irq flushes the queue and then awakes writers */

i527_msgflag(dev, obj, I527_INTPND_R);
/* head and tail access is atomic with HWBUSY access */
spin_lock(&obj->lock);
if (obj->head == obj->tail)
{
obj->obj_flags &= ~CAN_OBJFLAG_HWBUSY;
spin_unlock(&obj->lock);
wake_up_interruptible(&obj->write_q);
if (obj->async_write_q)
kill_fasync(&obj->async_write_q, SIGIO, POLLOUT);
return;
}
spin_unlock(&obj->lock);

/* else push out another packet */
can_config_and_transmit(dev, obj, obj->msg[obj->tail], 1 /* tx */);
kmem_cache_free(gpsCache, obj->msg[obj->tail]);
obj->msg[obj->tail] = NULL;
obj->tail = (obj->tail + 1) % CAN_BUFSIZE;
/* possibly awake writers */
if ( ((obj->head + CAN_BUFSIZE - obj->tail) % CAN_BUFSIZE)
== CAN_BUFSIZE/2)
{
wake_up_interruptible(&obj->write_q);
if (obj->async_write_q)
kill_fasync(&obj->async_write_q, SIGIO, POLLOUT);
}
}

//---------------------------------------------------------------------------
static void can_read_interrupt(CAN_DEV *dev,
CAN_MSGOBJ *obj, int objnum)
{
CAN_MSG *msg;
int newhead;

PDEBUG("can_ri: interrupt on objnum %d\n", objnum);

/* Check for transmission errors */
obj->error = 0;
if (i527_check_msgflag(dev, obj, I527_MSGLST_S))
{
obj->error = CAN_ERROR_MSGLST;
i527_msgflag(dev, obj, I527_MSGLST_R);
}

if (objnum != 15 )
{ /* Argh!!! it wasn't clear *not* to do that for 15 */
/* "The CPU should clear the bit before reading data and check it" */
i527_msgflag(dev, obj, I527_NEWDAT_R);
}

newhead = (obj->head + 1) % CAN_BUFSIZE;
if (newhead == obj->tail)
{
/* overflow, discard this message and mark overlow in the previous */
// printk(KERN_ERR CAN_TEXT "overflow for msgobj %i\n", objnum);
printk("ov\n");
obj->msg[(obj->head+CAN_BUFSIZE-1)%CAN_BUFSIZE]->error
|= CAN_ERROR_OVRFLW;
goto ack_return;
}

msg = kmem_cache_alloc(gpsCache, GFP_ATOMIC);
if (!msg)
{
printk(KERN_ERR CAN_TEXT "out of memory for packet to msgobj %i\n",
objnum);
goto ack_return;
}
obj->msg[obj->head] = msg;

msg->id = i527_read_msgarb(dev, obj);
obj->obj_id = 0; /* invalidate, so tx will set it */
msg->msgobj = objnum;
msg->config = i527_read_msgcfg(dev, obj);
msg->dlc = (msg->config & I527_DLC_MASK) >> I527_DLC_SHIFT;
msg->flags = CAN_MSGFLAG_READ;
msg->error = obj->error;
i527_read_msgdata(dev, obj, msg->dlc, msg->data);

obj->head = newhead;
i527_msgflag(dev, obj, I527_INTPND_R);

/* FIXME: should re-check NewDat according to data sheet */
if (objnum == 15)
{
i527_msgflag(dev, obj, I527_NEWDAT_R & I527_RMTPND_R);
}
PDEBUG("%i bytes from 0x%08lx\n", msg->dlc, (long)msg->id);

/* Wake any reading process */
wake_up_interruptible(&obj->read_q);

/* Signal any asynchronous reader */
if (obj->async_read_q != NULL)
kill_fasync(&obj->async_read_q, SIGIO, POLLIN);
return;

ack_return:
i527_msgflag(dev, obj, I527_INTPND_R);
if (objnum == 15)
{
i527_msgflag(dev, obj, I527_NEWDAT_R & I527_RMTPND_R);
}
}


/* map the interrupt register value to the message object */
static const int irqtab[17] = {
0, 0, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
};

//-------------------------------------------------------------------------
static void can_bh(unsigned long nNum)
{
CAN_DEV *dev = &gsDev;
CAN_MSGOBJ *obj = NULL;
int objnum;
int status, irqreg;
unsigned long flags;

spin_lock_irqsave(&can_lock, flags);

/* Get the interrupt register -- even if we'd done it at hw irq */
irqreg = i527_read_reg(dev, I527_INT_REG);
status = i527_read_reg(dev, I527_STAT_REG);
PDEBUG("can_bh: interrupt on irq %d\n", irqreg);

dev->irq_count++;

#ifdef CAN_DEBUG /* needed to avoid "unused variable lec" */
/* print some stupid message */
if (1) {
PDEBUG("{{{ irq for device\n");
if (status & 0x80) PDEBUG("status: BusOff\n");
if (status & 0x40) PDEBUG("status: Warning\n");
if (status & 0x20) PDEBUG("status: Wake\n");
if (status & 0x10) PDEBUG("status: RXOK\n");
if (status & 0x08) PDEBUG("status: TXOK\n");
if ((status & 0x07) != 7) {
static char *lec[]={"No","Stuff","Form","Ack","B1","B0","CRC"};
PDEBUG("status: LEC: %s Error\n", lec[status&7]);
}
}
#endif /* CAN_DEBUG */

/* Reset the status register */
i527_write_reg(dev, I527_STAT_REG, I527_STAT_REG_DEFAULT);

do {
objnum = irqtab[irqreg];

if (!objnum)
{
/* awake sleeping readers and send signals */
CAN_ERROR *info = dev->errorinfo;
PDEBUG("Status Register IRQ (0x%02x)\n", status);
dev->statusbyte = status;
wake_up_interruptible(&dev->error_q);

for (objnum = 0; objnum < CAN_NR_ERROR_FILES; objnum++, info++)
if (info->file)
kill_proc(info->pid, info->signal, 1);
printk("jcan: irq objnum = 0\n");
continue;
}

obj = dev->objs[objnum];
if (!obj)
{
printk("jcan: irq obj = 0\n");
/* object not allocated, clear the interrupt anyways */
i527_msgflag_noobj(dev, objnum, I527_INTPND_R);
PDEBUG("resetted irq for unallocated device %i\n", objnum);
continue;
}
else
PDEBUG("jcan: irq objnum %d\n", objnum);


if (obj->obj_flags & CAN_OBJFLAG_WRITE)
can_write_interrupt(dev, obj, objnum);
else
can_read_interrupt(dev, obj, objnum);
udelay(10); /* 14 MCLK max, be safe */
}
while ( (irqreg = i527_read_reg(dev, I527_INT_REG)) );

spin_unlock_irqrestore(&can_lock, flags);
PDEBUG("end of irq}}}\n");
}

static DECLARE_TASKLET(can_task, can_bh, (unsigned long)0);

/* actual interrupt handling --------------------------------------------*/
static void can_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
CAN_DEV *dev = (CAN_DEV *) dev_id;
int irqreg;

/* Get the interrupt register's status */
irqreg = i527_read_reg(dev, I527_INT_REG);

if (!irqreg)
{
return; /* Not us, probably a shared handler */
}
if (irqreg > 16)
{
printk(KERN_ERR CAN_TEXT "irq register too high: %i\n", irqreg);
return;
}

/* everything else is done at bottom-half time */
PDEBUG("can_int dev %p int_reg %d\n", dev, irqreg);
PDEBUG("** HW irq for device %i:\n", irqtab[irqreg]);

tasklet_schedule(&can_task);
}

/*========================================================================
* File operations definitions
* ------------------------------------------------------- ioctl-------- */
static int can_ioctl (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
#define IOC_BUFSIZE (CAN_READ_BUFS * sizeof(CAN_MSG))

static unsigned char localbuf[IOC_BUFSIZE];
CAN_DEV *dev = filp->private_data;
CAN_ERROR *info;
int size = _IOC_SIZE(cmd); /* the size bitfield in cmd */
int i, j, retval = 0; /* success by default */
/* I'm lazy, and I define "alias" names for the buffer */
void *karg = localbuf;
unsigned long *klong = karg;
CAN_REG *kreg = karg;
CAN_MSG *kmsg = karg;
CAN_MULTIREG *kmulti = karg;
CAN_MASKS *kmasks = karg;
CAN_MSGOBJ *obj;
unsigned char *area;

/*
* extract the type and number bitfields, and don't decode
* wrong cmds: return ENOTTY before verify_area()
*/
if (_IOC_TYPE(cmd) != CAN_IOC_MAGIC) return -ENOTTY;
if (_IOC_NR(cmd) > CAN_IOC_MAXNR) return -ENOTTY;

/*
* the direction is a bitmask, and VERIFY_WRITE catches R/W
* transfers. `Dir' is user-oriented, while
* verify_area is kernel-oriented, so the concept of "read" and
* "write" is reversed
*/
if (_IOC_DIR(cmd) & _IOC_READ)
{
if (!access_ok(VERIFY_WRITE, (void *)arg, size))
return -EFAULT;
}
else
if (_IOC_DIR(cmd) & _IOC_WRITE)
{
if (!access_ok(VERIFY_READ, (void *)arg, size))
return -EFAULT;
}

PDEBUG("ioctl: %08x %08lx: nr %i, size %i, dir %i\n",
cmd, arg, _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd));

/* first, retrieve data from userspace */
if ((_IOC_DIR(cmd) & _IOC_WRITE) && (size <= IOC_BUFSIZE))
copy_from_user(karg, (void *)arg, size);

/* and now the big switch... */
switch(cmd)
{
case CAN_IOCRESET:
case CAN_IOCSOFTRESET:
can_disable_irq(dev);
free_irq(IRQ_NUM, (void *)dev);
can_reset_i82527(dev);
i527_write_reg(dev, I527_STAT_REG, I527_STAT_REG_DEFAULT);
#ifdef __powerpc__
request_8xxirq(IRQ_NUM, can_interrupt, 0, CAN_NAME, (void *)dev);
#else
request_irq(IRQ_NUM, can_interrupt, 0, CAN_NAME, (void *)dev);
#endif
can_enable_irq(dev);
break;

case CAN_IOCGIRQCOUNT:
*klong = dev->irq_count;
break;

case CAN_IOCREADREG:
kreg->val = i527_read_reg(dev, kreg->reg & 0xff);
break;

case CAN_IOCWRITEREG:
printk("jcan write reg %02x %02x\n", kreg->reg, kreg->val);
i527_write_reg(dev, kreg->reg & 0xff, kreg->val);
break;

case CAN_IOCREADMULTI:
if (kmulti->last < kmulti->first)
return -EINVAL;
if (kmulti->last - kmulti->first + 1 > CAN_MULTIREG_MAX)
return -EINVAL;
for (i=0, j=kmulti->first; j<=kmulti->last; i++, j++)
kmulti->regs[i] = i527_read_reg(dev, j);
break;

case CAN_IOCWRITEMULTI:
if (kmulti->last < kmulti->first)
return -EINVAL;
if (kmulti->last - kmulti->first + 1 > CAN_MULTIREG_MAX)
return -EINVAL;
i=0;
for (i=0, j=kmulti->first; j <= kmulti->last; j++)
i527_write_reg(dev, j, kmulti->regs[i++]);
break;

case CAN_IOCREADALL:
area = kmalloc(256, GFP_USER);
if (!area) return -ENOMEM;
for (i=0; i<256; i++)
((u8 *)area)[i] = i527_read_reg(dev, i);
copy_to_user((void *)arg, area, 256);
kfree(area);
return 0;

case CAN_IOCGETMASKS:
kmasks->m_msg15 = i527_read_15_mask(dev);
kmasks->m_xtd = i527_read_x_mask(dev);
kmasks->m_std = i527_read_std_mask(dev);
break;

case CAN_IOCSETMASKS:
i527_write_15_mask(dev, kmasks->m_msg15);
i527_write_x_mask(dev, kmasks->m_xtd);
i527_write_std_mask(dev, kmasks->m_std);
break;

case CAN_IOCGETBPS:
*klong = dev->eBps;
break;

case CAN_IOCSETBPS:
can_setbps(dev, (BPS)arg );
break;

case CAN_IOCGETBUSCONF:
kreg->val = i527_read_reg(dev, I527_BUSCFG_REG);
break;

case CAN_IOCSETBUSCONF:
j = can_enable_cfg(dev);
i527_write_reg(dev, I527_BUSCFG_REG, kreg->val);
can_restore_cfg(dev, j);
break;

//-----------------------------------------------------------------
case CAN_IOCWRITEMSG:
case CAN_IOCSETUPMSG: /* copy the msgobj struct to device registers */
if (lib_checkmsgnum(kmsg->msgobj, kmsg->flags))
return -EINVAL;

obj = lib_findobj(dev, kmsg->msgobj, GFP_USER);
if (!obj) return -ENOMEM;
if (lib_setowner(obj, filp, kmsg->flags &
(CAN_MSGFLAG_WRITE | CAN_MSGFLAG_READ) ))
return -EBUSY;

/* before we touch the message, ensure it's not transmitting */
if (obj->obj_flags & CAN_OBJFLAG_HWBUSY) {
if (filp->f_flags & O_NONBLOCK) return -EAGAIN;
wait_event_interruptible(obj->write_q,
!(obj->obj_flags &CAN_OBJFLAG_HWBUSY));
if (signal_pending(current)) return -ERESTARTSYS;
}

if (cmd == CAN_IOCWRITEMSG)
obj->obj_flags |= CAN_OBJFLAG_HWBUSY;
can_config_and_transmit(dev, obj, kmsg,
cmd == CAN_IOCWRITEMSG ? 1 : 0);
break;

case CAN_IOCWRITEQ: /* place it in the queue */
#if 0
if (lib_checkmsgnum(kmsg->msgobj, kmsg->flags))
return -EINVAL;

obj = lib_findobj(dev, kmsg->msgobj, GFP_USER);
if (!obj) return -ENOMEM;
if (lib_setowner(obj, filp, kmsg->flags &
(CAN_MSGFLAG_WRITE | CAN_MSGFLAG_READ) ))
return -EBUSY;

/* place the message in the queue */
i = (obj->head + 1) % CAN_BUFSIZE;
if (i == obj->tail) {
/* queue full: sleep -- no problem with concurrent access */
if (filp->f_flags & O_NONBLOCK) return -EAGAIN;
wait_event_interruptible(obj->write_q, (i != obj->tail));
if (signal_pending(current)) return -ERESTARTSYS;
}
newmsg = kmem_cache_alloc(gpsCache, GFP_USER);
if (!newmsg) {
printk(KERN_ERR "can't allocate outgoing packet for msg %i\n",
kmsg->msgobj);
return -ENOMEM;
}
spin_lock_bh(obj->lock);
/* if already tranmitting, just add this to the queue */
if ( obj->obj_flags & CAN_OBJFLAG_HWBUSY ) {
*newmsg = *kmsg;
obj->msg[obj->head] = newmsg;
obj->head = i;
spin_unlock_bh(obj->lock);
break;
}
spin_unlock_bh(obj->lock);

/* not transmitting, can safely begin transmission */
obj->obj_flags |= CAN_OBJFLAG_HWBUSY;
kmem_cache_free(gpsCache, newmsg);
can_config_and_transmit(dev, obj, kmsg, 1);
#endif
break;

//-------------------------------------------------------------------
case CAN_IOCTXMSG: /* tx only, no need to call config_and_transmit() */
if (lib_checkmsgnum(*klong, CAN_MSGFLAG_WRITE))
return -EINVAL;
obj = lib_findobj(dev, *klong, GFP_USER);
if (!obj) return -ENOMEM;
if (obj->owner != filp) return -EPERM;
if (obj->obj_flags & CAN_OBJFLAG_HWBUSY) {
if (filp->f_flags & O_NONBLOCK) return -EAGAIN;
wait_event_interruptible(obj->write_q,
!(obj->obj_flags &CAN_OBJFLAG_HWBUSY));
if (signal_pending(current)) return -ERESTARTSYS;
}
obj->obj_flags |= CAN_OBJFLAG_HWBUSY;
i527_msgflag(dev, obj, I527_CPUUPD_R & I527_NEWDAT_S
& I527_TXRQST_S);
break;

//--------------------------------------------------------------------
case CAN_IOCRXMSG:
/* the message must be already configured and owned */
if (lib_checkmsgnum(kmsg->msgobj, CAN_MSGFLAG_READ))
return -EINVAL;
obj = lib_findobj(dev, kmsg->msgobj, GFP_USER);
if (!obj) return -ENOMEM;
if (obj->owner != filp) return -EPERM;

if (obj->head == obj->tail) {
if (filp->f_flags & O_NONBLOCK) {
return -EAGAIN;
}
wait_event_interruptible(obj->read_q, obj->head != obj->tail);
if (signal_pending(current))
return -ERESTARTSYS;
if (obj->head == obj->tail) {
PDEBUG("Argh: no message\n");
return -EFAULT; /* Hmmm.... */
}
}

PDEBUG("jcan: received msg\n");
i=0;
while((i < CAN_READ_BUFS) && (obj->head != obj->tail))
{
/* ok, we have a message to pull from the buffer */
*kmsg++ = *(obj->msg[obj->tail]);
kmem_cache_free(gpsCache, obj->msg[obj->tail]);
obj->msg[obj->tail] = NULL;
obj->tail = (obj->tail+1) % CAN_BUFSIZE;
i++;
}
retval = i;
size = retval * sizeof(CAN_MSG);
break;

case CAN_IOCPEEKMSG: /* similar, but never sleep and use an exact ID */
#if 0
if (lib_checkmsgnum(kmsg->msgobj, CAN_MSGFLAG_READ))
return -EINVAL;
obj = lib_findobj(dev, kmsg->msgobj, GFP_USER);
if (!obj) return -ENOMEM;
if (obj->owner != filp) return -EPERM;

for (i = obj->tail; i != obj->head; i = i+1 % CAN_BUFSIZE) {
PDEBUG("peeking item %i (%x %x -- %x %x)\n", i,
obj->msg[i]->id, kmsg->id,
obj->msg[i]->config&I527_XTD,
kmsg->config&I527_XTD);
if ((obj->msg[i]->id == kmsg->id) &&
((obj->msg[i]->config&I527_XTD) == (kmsg->config&I527_XTD)))
break;
}
if (i == obj->head) return -EAGAIN;

j = kmsg->flags;
*kmsg = *(obj->msg[i]);
PDEBUG("peekonly: %i\n", j&CAN_MSGFLAG_PEEKONLY);
if (j & CAN_MSGFLAG_PEEKONLY)
break; /* return the data but leave it there */
kmem_cache_free(gpsCache, obj->msg[i]);

/*
* remove the packet by shifting pointers: don't touch head
* as it is the active end, modified at interrupt time
*/
while (i != obj->tail) {
j = (i-1 + CAN_BUFSIZE) % CAN_BUFSIZE;
PDEBUG("copy %i to %i\n", j, i);
obj->msg[i] = obj->msg[j];
i = j;
}
obj->tail = (i+1) % CAN_BUFSIZE;
#endif
break;

case CAN_IOCRELEASEMSG:
if (lib_checkmsgnum(*klong, CAN_MSGFLAG_READ))
return -EINVAL;
obj = lib_findobj(dev, *klong, GFP_USER);
if (!obj) return -ENOMEM;
if (obj->owner != filp) return -EPERM;
lib_releaseobj(dev, *klong, obj);
break;

case CAN_IOCREQSIGNAL:
if (*klong >= SIGRTMIN) return -EINVAL;
/* change an entry, if already there */
info = lib_findfile(dev, filp);
if (info) {
if (!*klong) info->file = NULL;
else info->signal = *klong;
break;
}
/* look for a free slot */
info = dev->errorinfo;
for (i = 0; i<CAN_NR_ERROR_FILES; i++, info++)
if (!info->file)
break;
if (i == CAN_NR_ERROR_FILES) return -EBUSY;

info->file = filp;
info->pid = current->pid;
info->signal = *klong;
break;

/*
* I/O ports
*/
case CAN_IOCINPUT:
if (kreg->reg != 1 && kreg->reg != 2) return -EINVAL;
kreg->val = i527_read_reg(dev, kreg->reg == 1
? I527_P1IN : I527_P2IN);
break;

case CAN_IOCOUTPUT:
if (kreg->reg != 1 && kreg->reg != 2) return -EINVAL;
i527_write_reg(dev, kreg->reg == 1
? I527_P1OUT : I527_P2OUT, kreg->val);
break;

case CAN_IOCIOCFG:
if (kreg->reg != 1 && kreg->reg != 2) return -EINVAL;
i527_write_reg(dev, kreg->reg == 1
? I527_P1CONF : I527_P2CONF, kreg->val);
break;


default:
PDEBUG("ioctl: no such command\n");
return -ENOTTY;
}
/* finally, copy data to user space and return */
if (retval < 0) return retval;
if ((_IOC_DIR(cmd) & _IOC_READ) && (size <= IOC_BUFSIZE))
copy_to_user((void *)arg, karg, size);
return retval; /* sometimes, positive is what I want */
}


//-------------------------------------------------------------------------
static ssize_t can_read(struct file *file, char *buf,
size_t count, loff_t *ppos)
{
// CAN_DEV *dev = (CAN_DEV *) file->private_data;
// int minor = MINOR(file->f_dentry->d_inode->i_rdev);
// int num = CAN_DEV_TYPE(minor);
// unsigned char status;

return -ENOSYS; /* FIXME: reimplement write */
}

//-------------------------------------------------------------------------
static ssize_t can_write(struct file *file, const char *buf,
size_t count, loff_t *ppos)
{
// CAN_DEV *dev = (CAN_DEV *) file->private_data;
// int minor = MINOR(file->f_dentry->d_inode->i_rdev);
// int num = CAN_DEV_TYPE(minor);

return -ENOSYS; /* FIXME: reimplement write */

}


//-------------------------------------------------------------------------
static int can_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
int num = CAN_DEV_TYPE(minor);
int accmode = file->f_flags & O_ACCMODE;

/* We cannot open Message Objects 1-15 for both reading and writing */
if ((num >= 1) && (num < 15) && accmode == O_RDWR)
return -EACCES;

/* We cannot open Message Object 15 for writing */
if ((num == 15) && (accmode != O_RDONLY))
return -EACCES;

/* Set the device's private data */
file->private_data = &gsDev;

/* Check for first open for 82527 */
if (++(gsDev.usecount) == 1)
{
PDEBUG("first open, enable interrupts\n");
i527_write_reg(&gsDev, I527_STAT_REG, I527_STAT_REG_DEFAULT);
can_enable_irq(&gsDev);
}

MOD_INC_USE_COUNT;
return 0;
}

//-------------------------------------------------------------------------
static int can_release(struct inode *inode, struct file *file)
{
CAN_DEV *dev = (CAN_DEV *) file->private_data;
CAN_MSGOBJ *obj;
CAN_ERROR *info;
int i;

/* independently of the minor number, look for any owned objects */
for (i = I527_FIRST_OBJ; i < I527_MSG_OBJS; i++)
{
obj = dev->objs[i];
if (obj && obj->owner == file)
lib_releaseobj(dev, i, obj);
}
/* similarly, release signal notification */
info = lib_findfile(dev, file);
if (info)
info->file = 0;

/* Check for last close for 82527 */
if (--(dev->usecount) == 0)
{
PDEBUG("last close, disable interrupts\n");
can_disable_irq(dev);
}

MOD_DEC_USE_COUNT;
return 0;
}

/*-------------------------------------------------------------------------
* Setup file operations
*/

static struct file_operations can_fops = {
ioctl: can_ioctl,
read: can_read,
write: can_write,
open: can_open,
release: can_release,
};

//-------------------------------------------------------------------------
static void cleanup_device(CAN_DEV *dev)
{
int i;

if (dev->gotirq)
free_irq(IRQ_NUM, (void *)dev);

for (i = 0; i<I527_MSG_OBJS; i++)
if ( dev->objs[i])
{
if (dev->objs[i]->msg)
kfree(dev->objs[i]->msg);
kfree(dev->objs[i]);
dev->objs[i] = NULL;
}
}

//-------------------------------------------------------------------------
int __init init_device(void)
{
int i;
int nRet = 0;
CAN_DEV *dev = &gsDev;

printk(KERN_INFO CAN_TEXT "setting up device, base %x, irq %i\n",
IO_ADDR, IRQ_NUM);

gpsCache = kmem_cache_create("jcan-packet", sizeof(CAN_MSG),
0, SLAB_HWCACHE_ALIGN, NULL, NULL);
if (!gpsCache)
{
printk(KERN_ERR CAN_TEXT "cannot allocate cache for packets\n");
return -ENOMEM;
}

memset(dev, 0, sizeof(*dev));

// Allocate all message objects
for (i = 1; i<I527_MSG_OBJS; i++)
{
CAN_MSGOBJ *obj;
if (!(obj = kmalloc(sizeof(CAN_MSGOBJ), GFP_KERNEL)))
break;
memset(obj, 0, sizeof(*obj));
obj->regbase = i * I527_MSG_OFF;
spin_lock_init(&obj->lock);

dev->objs[i] = obj;
obj->msg = kmalloc(CAN_BUFSIZE * sizeof(CAN_MSG *),
GFP_KERNEL);
if (!obj->msg) break;
memset(obj->msg, 0, CAN_BUFSIZE * sizeof(CAN_MSG *));
}
if (i < I527_MSG_OBJS)
{
nRet = -ENOMEM; goto fail;
}

// map device
dev->base = (long) ioremap(IO_ADDR, IO_RANGE );
if (! dev->base)
{
printk(KERN_ERR CAN_TEXT "I/O map at 0x%x busy\n", IO_ADDR);
goto fail;
}
else
printk("jcan: remapped to: 0x%lx\n", (long)dev->base);

/* Wait queue initialization */
init_waitqueue_head(&dev->error_q);
for (i=0; i<I527_MSG_OBJS; i++)
{
if (dev->objs[i])
{
init_waitqueue_head(&dev->objs[i]->read_q);
init_waitqueue_head(&dev->objs[i]->write_q);
}
}
#ifdef __powerpc__
// Make IRQ3 edge sensitive.
((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |= 0x02000000;
nRet = request_8xxirq(IRQ_NUM, can_interrupt, 0, CAN_NAME, (void *)dev);
#else
nRet = request_irq(IRQ_NUM, can_interrupt, 0, CAN_NAME, (void *)dev);
#endif
if (nRet)
{
printk(KERN_ERR CAN_TEXT "dev: can't get irq %i\n", IRQ_NUM);
goto fail;
}

dev->gotirq = 1;
can_reset_i82527(dev); /* can't fail */

/* Register the char device */
nRet = register_chrdev(CAN_MAJOR, CAN_NAME, &can_fops);
if (nRet < 0)
{
printk(KERN_ERR CAN_TEXT "can't get major %d\n", CAN_MAJOR);
goto fail;
}
dev->registered = 1;
return 0; /* success */

fail:
cleanup_device(dev);
return nRet;
}

#ifdef MODULE
//MODULE_LICENSE("GPL");
MODULE_AUTHOR("George Cewe");
MODULE_DESCRIPTION("Driver for i82527 CAN controller");

//------------------------------------------------------------------------
static int can_init(void)
{
int nRet;

nRet = init_device();

if(!nRet)
printk(KERN_INFO CAN_TEXT "loaded (%sdebugging mode)\n",
debug ? "" : "non-");
return nRet;
}


//------------------------------------------------------------------------
static void can_cleanup(void)
{
cleanup_device(&gsDev);

if (gsDev.registered)
unregister_chrdev(CAN_MAJOR, CAN_NAME);

if (gpsCache)
kmem_cache_destroy(gpsCache);

printk(KERN_INFO CAN_TEXT "driver removed\n");
}

module_init(can_init);
module_exit(can_cleanup);

#endif
\
 
 \ /
  Last update: 2005-03-22 13:34    [W:0.069 / U:0.704 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site