X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/blobdiff_plain/dd8f47bb1f3be71c28588fdbcf69ef3b9656d9f4..HEAD:/lincan/src/pcan_dongle.c diff --git a/lincan/src/pcan_dongle.c b/lincan/src/pcan_dongle.c index ca7ef79..7757efb 100644 --- a/lincan/src/pcan_dongle.c +++ b/lincan/src/pcan_dongle.c @@ -1,32 +1,42 @@ -/****************************************************************************/ -// 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 */ +/* Copyright (C) 2002-2009 Pavel Pisa */ +/* Copyright (C) 2005 Klaus Hitschler */ +/* Copyright (C) 2005-2006 Jose Pascual Ramírez */ +/* 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 */ +/* Contributions: Marcel Offermans */ +/* Philipp Baer */ +/* */ +/* 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. */ +/**************************************************************************/ + /****************************************************************************/ // @@ -140,13 +150,13 @@ char dongle_type[] = "epp_dongle"; 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_); } @@ -157,18 +167,18 @@ static u8 pcan_dongle_sp_readreg(struct DONGLE_PORT *dng, u8 port) // read a reg 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); @@ -179,16 +189,16 @@ static void pcan_dongle_writereg(struct DONGLE_PORT *dng, u8 port, u8 data) // w { 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); } @@ -199,16 +209,16 @@ static u8 pcan_dongle_epp_readreg(struct DONGLE_PORT *dng, u8 port) // read a re 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); @@ -260,8 +270,8 @@ static void setECR(struct DONGLE_PORT *dng) { 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); @@ -271,7 +281,7 @@ static void restoreECR(struct DONGLE_PORT *dng) { u16 wEcr = dng->wEcr; - outb(dng->ucOldECRContent, wEcr); + can_outb(dng->ucOldECRContent, wEcr); DEBUGMSG("%s: restore ECR\n", DEVICE_NAME); } @@ -281,7 +291,7 @@ static int pcan_dongle_probe(struct DONGLE_PORT *dng) // probe for type 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) @@ -291,14 +301,14 @@ static int pcan_dongle_probe(struct DONGLE_PORT *dng) // probe for type } 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"); @@ -306,7 +316,7 @@ static int pcan_dongle_probe(struct DONGLE_PORT *dng) // probe for type } } - + return 0; } @@ -315,11 +325,11 @@ static int pcan_dongle_open(struct DONGLE_PORT *dng) { 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) @@ -329,25 +339,25 @@ static int pcan_dongle_open(struct DONGLE_PORT *dng) } } 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; } @@ -356,84 +366,84 @@ static int pcan_dongle_release(struct DONGLE_PORT *dng) 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; } @@ -447,7 +457,7 @@ int pcan_dongle_init(struct DONGLE_PORT *dng, u32 dwPort, u16 wIrq, char *type) * * 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. @@ -481,7 +491,7 @@ int pcan_dongle_release_io(struct candevice_t *candev) { /* release I/O port */ pcan_dongle_release(&dongle_port); - + pcan_dongle_cleanup(&dongle_port); return 0; @@ -491,8 +501,8 @@ int pcan_dongle_release_io(struct candevice_t *candev) * 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 @@ -503,14 +513,14 @@ int pcan_dongle_reset(struct candevice_t *candev) struct canchip_t *chip; int chipnr; unsigned cdr; - + DEBUGMSG("Resetting pcan_dongle hardware ...\n"); for(chipnr=0;chipnrnr_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); @@ -554,7 +564,7 @@ int pcan_dongle_reset(struct candevice_t *candev) * 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; @@ -590,7 +600,7 @@ int pcan_dongle_init_hw_data(struct candevice_t *candev) * 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 @@ -605,15 +615,15 @@ int pcan_dongle_init_chip_data(struct candevice_t *candev, int chipnr) 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 } @@ -630,7 +640,7 @@ int pcan_dongle_init_chip_data(struct candevice_t *candev, int chipnr) * 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. @@ -641,7 +651,7 @@ int pcan_dongle_init_obj_data(struct canchip_t *chip, int objnr) { chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr; chip->msgobj[objnr]->obj_flags=0; - + return 0; } @@ -649,10 +659,10 @@ int pcan_dongle_init_obj_data(struct canchip_t *chip, int objnr) * 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 @@ -679,7 +689,7 @@ int pcan_dongle_program_irq(struct candevice_t *candev) * 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 @@ -698,15 +708,15 @@ void pcan_dongle_write_register(unsigned data, unsigned long address) * 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);