-/****************************************************************************/
-// Ingenieria Almudi (www.almudi.com)
-// Ported to LinCAN by Jose Pascual Ramírez (josepascual@almudi.com)
-//
-//
-// Copyright (C) 2001,2002,2003,2004 PEAK System-Technik GmbH
-//
-// linux@peak-system.com
-// www.peak-system.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-//
-// Maintainer(s): Klaus Hitschler (klaus.hitschler@gmx.de)
-//
-// Contributions: Marcel Offermans (marcel.offermans@luminis.nl)
-// Philipp Baer (philipp.baer@informatik.uni-ulm.de)
-/****************************************************************************/
+/**************************************************************************/
+/* File: pcan_dongle.h - PEAK's printer port dongle addapter */
+/* */
+/* LinCAN - (Not only) Linux CAN bus driver */
+/* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz> */
+/* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz> */
+/* Copyright (C) 2005 Klaus Hitschler <klaus.hitschler@gmx.de> */
+/* Copyright (C) 2005-2006 Jose Pascual Ramírez <josepascual@almudi.com> */
+/* Copyright (C) 2001,2002,2003,2004 PEAK System-Technik GmbH */
+/* Funded by OCERA and FRESCOR IST projects */
+/* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl> */
+/* Contributions: Marcel Offermans <marcel.offermans@luminis.nl> */
+/* Philipp Baer <philipp.baer@informatik.uni-ulm.de> */
+/* */
+/* LinCAN is free software; you can redistribute it and/or modify it */
+/* under terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2, or (at your option) any */
+/* later version. LinCAN 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 LinCAN; see file */
+/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
+/* Cambridge, MA 02139, USA. */
+/* */
+/* To allow use of LinCAN in the compact embedded systems firmware */
+/* and RT-executives (RTEMS for example), main authors agree with next */
+/* special exception: */
+/* */
+/* Including LinCAN header files in a file, instantiating LinCAN generics */
+/* or templates, or linking other files with LinCAN objects to produce */
+/* an application image/executable, does not by itself cause the */
+/* resulting application image/executable to be covered by */
+/* the GNU General Public License. */
+/* This exception does not however invalidate any other reasons */
+/* why the executable file might be covered by the GNU Public License. */
+/* Publication of enhanced or derived LinCAN files is required although. */
+/**************************************************************************/
+
/****************************************************************************/
//
#define ECR_PORT_SIZE 1 // size of the associated ECR register
#define DNG_DEFAULT_COUNT 4 // count of defaults for init
-typedef void (*PARPORT_IRQ_HANLDER)(int, void *, struct pt_regs *);
+typedef void (*PARPORT_IRQ_HANLDER)(CAN_IRQ_HANDLER_ARGS(irq_number, dev_id));
/****************************************************************************/
// GLOBALS
static void _parport_disable_irq(struct DONGLE_PORT *dng)
{
u16 _PC_ = (u16)dng->dwPort + 2;
- outb(inb(_PC_) & ~0x10, _PC_);
+ can_outb(can_inb(_PC_) & ~0x10, _PC_);
}
static void _parport_enable_irq(struct DONGLE_PORT *dng)
{
u16 _PC_ = (u16)dng->dwPort + 2;
- outb(inb(_PC_) | 0x10, _PC_);
+ can_outb(can_inb(_PC_) | 0x10, _PC_);
}
u16 _PB_ = _PA_ + 1;
u16 _PC_ = _PB_ + 1;
u8 b0, b1 ;
- u8 irqEnable = inb(_PC_) & 0x10; // don't influence irqEnable
+ u8 irqEnable = can_inb(_PC_) & 0x10; // don't influence irqEnable
can_spin_irqflags_t flags;
can_spin_lock_irqsave(&pcan_lock, flags);
- outb((0x0B ^ 0x0D) | irqEnable, _PC_);
- outb((port & 0x1F) | 0x80, _PA_);
- outb((0x0B ^ 0x0C) | irqEnable, _PC_);
- b1=nibble_decode[inb(_PB_)>>3];
- outb(0x40, _PA_);
- b0=nibble_decode[inb(_PB_)>>3];
- outb((0x0B ^ 0x0D) | irqEnable, _PC_);
+ can_outb((0x0B ^ 0x0D) | irqEnable, _PC_);
+ can_outb((port & 0x1F) | 0x80, _PA_);
+ can_outb((0x0B ^ 0x0C) | irqEnable, _PC_);
+ b1=nibble_decode[can_inb(_PB_)>>3];
+ can_outb(0x40, _PA_);
+ b0=nibble_decode[can_inb(_PB_)>>3];
+ can_outb((0x0B ^ 0x0D) | irqEnable, _PC_);
can_spin_unlock_irqrestore(&pcan_lock, flags);
{
u16 _PA_ = (u16)dng->dwPort;
u16 _PC_ = _PA_ + 2;
- u8 irqEnable = inb(_PC_) & 0x10; // don't influence irqEnable
+ u8 irqEnable = can_inb(_PC_) & 0x10; // don't influence irqEnable
can_spin_irqflags_t flags;
can_spin_lock_irqsave(&pcan_lock, flags);
- outb((0x0B ^ 0x0D) | irqEnable, _PC_);
- outb(port & 0x1F, _PA_);
- outb((0x0B ^ 0x0C) | irqEnable, _PC_);
- outb(data, _PA_);
- outb((0x0B ^ 0x0D) | irqEnable, _PC_);
+ can_outb((0x0B ^ 0x0D) | irqEnable, _PC_);
+ can_outb(port & 0x1F, _PA_);
+ can_outb((0x0B ^ 0x0C) | irqEnable, _PC_);
+ can_outb(data, _PA_);
+ can_outb((0x0B ^ 0x0D) | irqEnable, _PC_);
can_spin_unlock_irqrestore(&pcan_lock, flags);
}
u16 _PA_ = (u16)dng->dwPort;
u16 _PC_ = _PA_ + 2;
u8 wert;
- u8 irqEnable = inb(_PC_) & 0x10; // don't influence irqEnable
+ u8 irqEnable = can_inb(_PC_) & 0x10; // don't influence irqEnable
can_spin_irqflags_t flags;
can_spin_lock_irqsave(&pcan_lock, flags);
- outb((0x0B ^ 0x0F) | irqEnable, _PC_);
- outb((port & 0x1F) | 0x80, _PA_);
- outb((0x0B ^ 0x2E) | irqEnable, _PC_);
- wert = inb(_PA_);
- outb((0x0B ^ 0x0F) | irqEnable, _PC_);
+ can_outb((0x0B ^ 0x0F) | irqEnable, _PC_);
+ can_outb((port & 0x1F) | 0x80, _PA_);
+ can_outb((0x0B ^ 0x2E) | irqEnable, _PC_);
+ wert = can_inb(_PA_);
+ can_outb((0x0B ^ 0x0F) | irqEnable, _PC_);
can_spin_unlock_irqrestore(&pcan_lock, flags);
{
u16 wEcr = dng->wEcr;
- dng->ucOldECRContent = inb(wEcr);
- outb((dng->ucOldECRContent & 0x1F) | 0x20, wEcr);
+ dng->ucOldECRContent = can_inb(wEcr);
+ can_outb((dng->ucOldECRContent & 0x1F) | 0x20, wEcr);
if (dng->ucOldECRContent == 0xff)
DEBUGMSG("%s: realy ECP mode configured?\n", DEVICE_NAME);
{
u16 wEcr = dng->wEcr;
- outb(dng->ucOldECRContent, wEcr);
+ can_outb(dng->ucOldECRContent, wEcr);
DEBUGMSG("%s: restore ECR\n", DEVICE_NAME);
}
struct parport *p;
DEBUGMSG("%s: pcan_dongle_probe() - PARPORT_SUBSYSTEM\n", DEVICE_NAME);
-
+
// probe does not probe for the sja1000 device here - this is done at sja1000_open()
p = parport_find_base(dng->dwPort);
if (!p)
}
else
{
- dng->pardev = parport_register_device(p, "can", NULL, NULL,
+ dng->pardev = parport_register_device(p, "can", NULL, NULL,
(PARPORT_IRQ_HANLDER)dng->chip->chipspecops->irq_handler,
0, (void *)dng->chip);
-
+
// DEBUGMSG("datos IRQ: irq_handler=0x%x p=0x%x dng->chip=0x%x dng->pardev->port->irq=0x%x irq_handler2=0x%x\n",
// dng->chip->chipspecops->irq_handler,
// p,dng->chip,dng->pardev->port->irq, &sja1000p_irq_handler);
-
+
if (!dng->pardev)
{
DEBUGMSG("found no parport device\n");
}
}
-
+
return 0;
}
{
int result = 0;
u16 wPort;
-
+
DEBUGMSG("%s: pcan_dongle_open()\n", DEVICE_NAME);
-
+
result = parport_claim(dng->pardev);
-
+
if (!result)
{
if (dng->pardev->port->irq == PARPORT_IRQ_NONE)
}
}
else
- DEBUGMSG(KERN_ERR "%s: can't claim parport.\n", DEVICE_NAME);
-
+ DEBUGMSG(KERN_ERR "%s: can't claim parport.\n", DEVICE_NAME);
+
// save port state
if (!result)
{
wPort = (u16)dng->dwPort;
-
+
// save old port contents
- dng->ucOldDataContent = inb(wPort);
- dng->ucOldControlContent = inb(wPort + 2);
-
+ dng->ucOldDataContent = can_inb(wPort);
+ dng->ucOldControlContent = can_inb(wPort + 2);
+
// switch to epp mode if possible
if (dng->wType == HW_DONGLE_SJA_EPP)
- setECR(dng);
-
+ setECR(dng);
+
// enable irqs
_parport_enable_irq(dng); // parport_enable_irq(dng->pardev->port); not working since 2.4.18
- }
-
+ }
+
return result;
}
u16 wPort = (u16)dng->dwPort;
DEBUGMSG("%s: pcan_dongle_release()\n", DEVICE_NAME);
-
+
// disable irqs
_parport_disable_irq(dng); // parport_disable_irq(dng->pardev->port); not working since 2.4.18
if (dng->wType == HW_DONGLE_SJA_EPP)
restoreECR(dng);
-
+
// restore port state
- outb(dng->ucOldDataContent, wPort);
- outb(dng->ucOldControlContent, wPort + 2);
-
+ can_outb(dng->ucOldDataContent, wPort);
+ can_outb(dng->ucOldControlContent, wPort + 2);
+
parport_release(dng->pardev);
-
+
return 0;
}
int pcan_dongle_init(struct DONGLE_PORT *dng, u32 dwPort, u16 wIrq, char *type)
{
int err;
-
+
DEBUGMSG("%s: pcan_dongle_init(), dng_devices = %d\n", DEVICE_NAME, dng_devices);
-
+
dng->type = type;
dng->wType = (!strncmp(dongle_type, "sp", 4)) ? HW_DONGLE_SJA : HW_DONGLE_SJA_EPP;
-
- // set this before any instructions, fill struct pcandev, part 1
- dng->wInitStep = 0;
-
+
+ // set this before any instructions, fill struct pcandev, part 1
+ dng->wInitStep = 0;
+
// fill struct pcandev, 1st check if a default is set
if (!dwPort)
{
// there's no default available
if (dng_devices >= DNG_DEFAULT_COUNT)
return -ENODEV;
-
+
dng->dwPort = dng_ports[dng_devices];
}
else
dng->dwPort = dwPort;
-
+
if (!wIrq)
{
if (dng_devices >= DNG_DEFAULT_COUNT)
return -ENODEV;
-
- dng->wIrq = dng_irqs[dng_devices];
+
+ dng->wIrq = dng_irqs[dng_devices];
}
else
- dng->wIrq = wIrq;
-
+ dng->wIrq = wIrq;
+
if (dng->wType == HW_DONGLE_SJA)
{
- dng->nMinor = PCAN_DNG_SP_MINOR_BASE + sp_devices;
+ dng->nMinor = PCAN_DNG_SP_MINOR_BASE + sp_devices;
dng->wEcr = 0; // set to anything
}
else
{
- dng->nMinor = PCAN_DNG_EPP_MINOR_BASE + epp_devices;
+ dng->nMinor = PCAN_DNG_EPP_MINOR_BASE + epp_devices;
dng->wEcr = (u16)dng->dwPort + 0x402;
}
-
- // is the device really available?
+
+ // is the device really available?
if ((err = pcan_dongle_probe(dng)) < 0)
return err;
-
+
if (dng->wType == HW_DONGLE_SJA)
sp_devices++;
else
epp_devices++;
-
+
dng_devices = sp_devices + epp_devices;
-
+
dng->wInitStep = 3;
- DEBUGMSG(KERN_INFO "%s: %s device minor %d prepared (io=0x%04x,irq=%d)\n", DEVICE_NAME,
+ DEBUGMSG(KERN_INFO "%s: %s device minor %d prepared (io=0x%04x,irq=%d)\n", DEVICE_NAME,
dng->type, dng->nMinor, dng->dwPort, dng->wIrq);
-
+
return 0;
}
*
* The function template_request_io() is used to reserve the io-memory. If your
* hardware uses a dedicated memory range as hardware control registers you
- * will have to add the code to reserve this memory as well.
+ * will have to add the code to reserve this memory as well.
* %IO_RANGE is the io-memory range that gets reserved, please adjust according
* your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
* #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
{
/* release I/O port */
pcan_dongle_release(&dongle_port);
-
+
pcan_dongle_cleanup(&dongle_port);
return 0;
* template_reset - hardware reset routine
* @candev: Pointer to candevice/board structure
*
- * The function template_reset() is used to give a hardware reset. This is
- * rather hardware specific so I haven't included example code. Don't forget to
+ * The function template_reset() is used to give a hardware reset. This is
+ * rather hardware specific so I haven't included example code. Don't forget to
* check the reset status of the chip before returning.
* Return Value: The function returns zero on success or %-ENODEV on failure
* File: src/template.c
struct canchip_t *chip;
int chipnr;
unsigned cdr;
-
+
DEBUGMSG("Resetting pcan_dongle hardware ...\n");
for(chipnr=0;chipnr<candev->nr_sja1000_chips;chipnr++) {
chip=candev->chip[chipnr];
pcan_dongle_write_register(sjaMOD_RM, chip->chip_base_addr+SJAMOD);
udelay(1000);
-
+
cdr=pcan_dongle_read_register(chip->chip_base_addr+SJACDR);
pcan_dongle_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR);
* Return Value: The function always returns zero
* File: src/template.c
*/
-int pcan_dongle_init_hw_data(struct candevice_t *candev)
+int pcan_dongle_init_hw_data(struct candevice_t *candev)
{
candev->res_addr=RESET_ADDR;
candev->nr_82527_chips=NR_82527;
* The entry @int_clk_reg holds hardware specific options for the Clock Out
* register. Options defined in the %i82527.h file:
* %iCLK_CD0, %iCLK_CD1, %iCLK_CD2, %iCLK_CD3, %iCLK_SL0, %iCLK_SL1.
- * The entry @int_bus_reg holds hardware specific options for the Bus
+ * The entry @int_bus_reg holds hardware specific options for the Bus
* Configuration register. Options defined in the %i82527.h file:
* %iBUS_DR0, %iBUS_DR1, %iBUS_DT1, %iBUS_POL, %iBUS_CBY.
* Return Value: The function always returns zero
candev->chip[chipnr]->chip_type=CHIP_TYPE;
- candev->chip[chipnr]->chip_base_addr=candev->io_addr;
+ candev->chip[chipnr]->chip_base_addr=can_ioport2ioptr(candev->io_addr);
candev->chip[chipnr]->clock = 16000000;
candev->chip[chipnr]->int_clk_reg = 0x0;
candev->chip[chipnr]->int_bus_reg = 0x0;
candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF;
candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL | sjaOCR_TX0_LH;
- candev->chip[chipnr]->flags |= CHIP_IRQ_CUSTOM; // I don't want setup call request_irq
- // I'm going to do it through parport_register_device
+ candev->chip[chipnr]->flags |= CHIP_IRQ_CUSTOM; // I don't want setup call request_irq
+ // I'm going to do it through parport_register_device
}
* CAN chip. In case of the sja1000 there's only one message object but on the
* i82527 chip there are 15.
* The code below is for a i82527 chip and initializes the object base addresses
- * The entry @obj_base_addr represents the first memory address of the message
+ * The entry @obj_base_addr represents the first memory address of the message
* object. In case of the sja1000 @obj_base_addr is taken the same as the chips
* base address.
* Unless the hardware uses a segmented memory map, flags can be set zero.
{
chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
chip->msgobj[objnr]->obj_flags=0;
-
+
return 0;
}
* template_program_irq - program interrupts
* @candev: Pointer to candevice/board structure
*
- * The function template_program_irq() is used for hardware that uses
+ * The function template_program_irq() is used for hardware that uses
* programmable interrupts. If your hardware doesn't use programmable interrupts
- * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
- * leave this function unedited. Again this function is hardware specific so
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
+ * leave this function unedited. Again this function is hardware specific so
* there's no example code.
* Return value: The function returns zero on success or %-ENODEV on failure
* File: src/template.c
* Return Value: The function does not return a value
* File: src/template.c
*/
-void pcan_dongle_write_register(unsigned data, unsigned long address)
+void pcan_dongle_write_register(unsigned data, can_ioptr_t address)
{
address -= dongle_port.chip->chip_base_addr; // it's in mutiplexed mode
* Return Value: The function returns the value stored in @address
* File: src/template.c
*/
-unsigned pcan_dongle_read_register(unsigned long address)
+unsigned pcan_dongle_read_register(can_ioptr_t address)
{
u8 val;
address -= dongle_port.chip->chip_base_addr; // it's in mutiplexed mode
-
+
if (dongle_port.wType == HW_DONGLE_SJA)
val = pcan_dongle_sp_readreg(&dongle_port, (u8) address); // functions for SP port
- else
+ else
val = pcan_dongle_epp_readreg(&dongle_port, (u8) address); // functions for EPP port
// DEBUGMSG("Read Reg at: 0x%lx data 0x%x \n", address, val);