1 /**************************************************************************/
2 /* File: pcan_dongle.h - PEAK's printer port dongle addapter */
4 /* LinCAN - (Not only) Linux CAN bus driver */
5 /* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz> */
6 /* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz> */
7 /* Copyright (C) 2005 Klaus Hitschler <klaus.hitschler@gmx.de> */
8 /* Copyright (C) 2005-2006 Jose Pascual RamÃrez <josepascual@almudi.com> */
9 /* Copyright (C) 2001,2002,2003,2004 PEAK System-Technik GmbH */
10 /* Funded by OCERA and FRESCOR IST projects */
11 /* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl> */
12 /* Contributions: Marcel Offermans <marcel.offermans@luminis.nl> */
13 /* Philipp Baer <philipp.baer@informatik.uni-ulm.de> */
15 /* LinCAN is free software; you can redistribute it and/or modify it */
16 /* under terms of the GNU General Public License as published by the */
17 /* Free Software Foundation; either version 2, or (at your option) any */
18 /* later version. LinCAN is distributed in the hope that it will be */
19 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */
20 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
21 /* General Public License for more details. You should have received a */
22 /* copy of the GNU General Public License along with LinCAN; see file */
23 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
24 /* Cambridge, MA 02139, USA. */
26 /* To allow use of LinCAN in the compact embedded systems firmware */
27 /* and RT-executives (RTEMS for example), main authors agree with next */
28 /* special exception: */
30 /* Including LinCAN header files in a file, instantiating LinCAN generics */
31 /* or templates, or linking other files with LinCAN objects to produce */
32 /* an application image/executable, does not by itself cause the */
33 /* resulting application image/executable to be covered by */
34 /* the GNU General Public License. */
35 /* This exception does not however invalidate any other reasons */
36 /* why the executable file might be covered by the GNU Public License. */
37 /* Publication of enhanced or derived LinCAN files is required although. */
38 /**************************************************************************/
41 /****************************************************************************/
43 // all parts to handle the interface specific parts of pcan-dongle
45 // Revision 1.38 2004/07/28 22:03:29 jose pascual
48 // Revision 1.37 2004/04/11 22:03:29 klaus
51 // Revision 1.36 2004/04/10 12:25:39 klaus
52 // merge polished between HEAD and kernel-2.6 branch
54 // Revision 1.35 2004/04/10 08:57:26 klaus
55 // merge finished between HEAD and kernel-2.6 branch
57 // Revision 1.32.2.1 2004/03/21 12:09:09 klaus
58 // first commit for branch to kernel 2.6 code
60 // Revision 1.34 2004/03/27 16:57:06 klaus
61 // modified for use with kernels <= 2.2.14
63 // Revision 1.33 2004/03/27 15:10:54 klaus
64 // prepared for use with gcc 3.x, modified for use with kernels < 2.2.4
66 // Revision 1.32 2004/03/04 18:50:08 klaus
67 // renamed PA,PB,PC to _PA_, ... to support (partially) cross-compiling for MIPS
69 // Revision 1.31 2003/06/22 15:34:50 klaus
70 // added parts to support devfs provided by Philipp Baer (partially untested)
72 // Revision 1.30 2003/06/04 19:26:15 klaus
73 // adapted to kernel 2.5.69 using GCC 3.2.3 (marcel), released release_20030604_x
75 // Revision 1.28 2003/03/02 10:58:07 klaus
76 // merged USB thread into main path
78 // Revision 1.27 2003/03/02 10:58:07 klaus
79 // merged USB thread into main path
81 // Revision 1.26.2.5 2003/01/29 20:34:20 klaus
82 // release_20030129_a and release_20030129_u released
84 // Revision 1.26.2.4 2003/01/29 20:34:19 klaus
85 // release_20030129_a and release_20030129_u released
87 // Revision 1.26.2.3 2003/01/28 23:28:26 klaus
88 // reorderd pcan_usb.c and pcan_usb_kernel.c, tidied up
90 // Revision 1.26.2.2 2003/01/14 20:31:53 klaus
91 // read/write/minor assigment is working
93 /****************************************************************************/
95 /****************************************************************************/
99 #include "../include/can.h"
100 #include "../include/can_sysdep.h"
101 #include "../include/main.h"
102 #include "../include/sja1000p.h"
104 #include <linux/parport.h>
106 #include "../include/pcan_dongle.h"
110 /****************************************************************************/
112 #define PCAN_DNG_SP_MINOR_BASE 16 // starting point of minors for SP devices
113 #define PCAN_DNG_EPP_MINOR_BASE 24 // starting point of minors for EPP devices
114 #define DNG_PORT_SIZE 4 // the address range of the dongle-port
115 #define ECR_PORT_SIZE 1 // size of the associated ECR register
116 #define DNG_DEFAULT_COUNT 4 // count of defaults for init
118 typedef void (*PARPORT_IRQ_HANLDER)(CAN_IRQ_HANDLER_ARGS(irq_number, dev_id));
120 /****************************************************************************/
122 CAN_DEFINE_SPINLOCK(pcan_lock);
124 /****************************************************************************/
126 static u16 dng_ports[] = {0x378, 0x278, 0x3bc, 0x2bc};
127 static u8 dng_irqs[] = {7, 5, 7, 5};
128 static u16 dng_devices = 0; // the number of accepted dng_devices
129 static u16 epp_devices = 0; // ... epp_devices
130 static u16 sp_devices = 0; // ... sp_devices
132 static unsigned char nibble_decode[32] =
134 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
135 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
136 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
137 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7
140 struct DONGLE_PORT dongle_port;
142 char dongle_type[] = "epp_dongle";
143 //char dongle_type[] = "sp_dongle";
145 /****************************************************************************/
148 //----------------------------------------------------------------------------
149 // enable and disable irqs
150 static void _parport_disable_irq(struct DONGLE_PORT *dng)
152 u16 _PC_ = (u16)dng->dwPort + 2;
153 can_outb(can_inb(_PC_) & ~0x10, _PC_);
156 static void _parport_enable_irq(struct DONGLE_PORT *dng)
158 u16 _PC_ = (u16)dng->dwPort + 2;
159 can_outb(can_inb(_PC_) | 0x10, _PC_);
163 // functions for SP port
164 static u8 pcan_dongle_sp_readreg(struct DONGLE_PORT *dng, u8 port) // read a register
166 u16 _PA_ = (u16)dng->dwPort;
170 u8 irqEnable = can_inb(_PC_) & 0x10; // don't influence irqEnable
171 can_spin_irqflags_t flags;
173 can_spin_lock_irqsave(&pcan_lock, flags);
175 can_outb((0x0B ^ 0x0D) | irqEnable, _PC_);
176 can_outb((port & 0x1F) | 0x80, _PA_);
177 can_outb((0x0B ^ 0x0C) | irqEnable, _PC_);
178 b1=nibble_decode[can_inb(_PB_)>>3];
179 can_outb(0x40, _PA_);
180 b0=nibble_decode[can_inb(_PB_)>>3];
181 can_outb((0x0B ^ 0x0D) | irqEnable, _PC_);
183 can_spin_unlock_irqrestore(&pcan_lock, flags);
185 return (b1 << 4) | b0 ;
188 static void pcan_dongle_writereg(struct DONGLE_PORT *dng, u8 port, u8 data) // write a register
190 u16 _PA_ = (u16)dng->dwPort;
192 u8 irqEnable = can_inb(_PC_) & 0x10; // don't influence irqEnable
193 can_spin_irqflags_t flags;
195 can_spin_lock_irqsave(&pcan_lock, flags);
197 can_outb((0x0B ^ 0x0D) | irqEnable, _PC_);
198 can_outb(port & 0x1F, _PA_);
199 can_outb((0x0B ^ 0x0C) | irqEnable, _PC_);
200 can_outb(data, _PA_);
201 can_outb((0x0B ^ 0x0D) | irqEnable, _PC_);
203 can_spin_unlock_irqrestore(&pcan_lock, flags);
206 // functions for EPP port
207 static u8 pcan_dongle_epp_readreg(struct DONGLE_PORT *dng, u8 port) // read a register
209 u16 _PA_ = (u16)dng->dwPort;
212 u8 irqEnable = can_inb(_PC_) & 0x10; // don't influence irqEnable
213 can_spin_irqflags_t flags;
215 can_spin_lock_irqsave(&pcan_lock, flags);
217 can_outb((0x0B ^ 0x0F) | irqEnable, _PC_);
218 can_outb((port & 0x1F) | 0x80, _PA_);
219 can_outb((0x0B ^ 0x2E) | irqEnable, _PC_);
220 wert = can_inb(_PA_);
221 can_outb((0x0B ^ 0x0F) | irqEnable, _PC_);
223 can_spin_unlock_irqrestore(&pcan_lock, flags);
228 static int pcan_dongle_req_irq(struct DONGLE_PORT *dng)
230 if (dng->wInitStep == 3)
238 static void pcan_dongle_free_irq(struct DONGLE_PORT *dng)
240 if (dng->wInitStep == 4)
246 // release and probe functions
247 static int pcan_dongle_cleanup(struct DONGLE_PORT *dng)
249 DEBUGMSG("%s: pcan_dongle_cleanup()\n", DEVICE_NAME);
251 switch(dng->wInitStep)
253 case 4: pcan_dongle_free_irq(dng);
254 case 3: if (dng->wType == HW_DONGLE_SJA)
258 dng_devices = sp_devices + epp_devices;
261 parport_unregister_device(dng->pardev);
262 case 0: dng->wInitStep = 0;
268 // to switch epp on or restore register
269 static void setECR(struct DONGLE_PORT *dng)
271 u16 wEcr = dng->wEcr;
273 dng->ucOldECRContent = can_inb(wEcr);
274 can_outb((dng->ucOldECRContent & 0x1F) | 0x20, wEcr);
276 if (dng->ucOldECRContent == 0xff)
277 DEBUGMSG("%s: realy ECP mode configured?\n", DEVICE_NAME);
280 static void restoreECR(struct DONGLE_PORT *dng)
282 u16 wEcr = dng->wEcr;
284 can_outb(dng->ucOldECRContent, wEcr);
286 DEBUGMSG("%s: restore ECR\n", DEVICE_NAME);
289 static int pcan_dongle_probe(struct DONGLE_PORT *dng) // probe for type
293 DEBUGMSG("%s: pcan_dongle_probe() - PARPORT_SUBSYSTEM\n", DEVICE_NAME);
295 // probe does not probe for the sja1000 device here - this is done at sja1000_open()
296 p = parport_find_base(dng->dwPort);
299 DEBUGMSG("found no parport\n");
304 dng->pardev = parport_register_device(p, "can", NULL, NULL,
305 (PARPORT_IRQ_HANLDER)dng->chip->chipspecops->irq_handler,
306 0, (void *)dng->chip);
308 // 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",
309 // dng->chip->chipspecops->irq_handler,
310 // p,dng->chip,dng->pardev->port->irq, &sja1000p_irq_handler);
314 DEBUGMSG("found no parport device\n");
323 // interface depended open and close
324 static int pcan_dongle_open(struct DONGLE_PORT *dng)
329 DEBUGMSG("%s: pcan_dongle_open()\n", DEVICE_NAME);
331 result = parport_claim(dng->pardev);
335 if (dng->pardev->port->irq == PARPORT_IRQ_NONE)
337 DEBUGMSG(KERN_ERR "%s: no irq associated to parport.\n", DEVICE_NAME);
342 DEBUGMSG(KERN_ERR "%s: can't claim parport.\n", DEVICE_NAME);
347 wPort = (u16)dng->dwPort;
349 // save old port contents
350 dng->ucOldDataContent = can_inb(wPort);
351 dng->ucOldControlContent = can_inb(wPort + 2);
353 // switch to epp mode if possible
354 if (dng->wType == HW_DONGLE_SJA_EPP)
358 _parport_enable_irq(dng); // parport_enable_irq(dng->pardev->port); not working since 2.4.18
364 static int pcan_dongle_release(struct DONGLE_PORT *dng)
366 u16 wPort = (u16)dng->dwPort;
368 DEBUGMSG("%s: pcan_dongle_release()\n", DEVICE_NAME);
371 _parport_disable_irq(dng); // parport_disable_irq(dng->pardev->port); not working since 2.4.18
373 if (dng->wType == HW_DONGLE_SJA_EPP)
376 // restore port state
377 can_outb(dng->ucOldDataContent, wPort);
378 can_outb(dng->ucOldControlContent, wPort + 2);
380 parport_release(dng->pardev);
385 int pcan_dongle_init(struct DONGLE_PORT *dng, u32 dwPort, u16 wIrq, char *type)
389 DEBUGMSG("%s: pcan_dongle_init(), dng_devices = %d\n", DEVICE_NAME, dng_devices);
393 dng->wType = (!strncmp(dongle_type, "sp", 4)) ? HW_DONGLE_SJA : HW_DONGLE_SJA_EPP;
395 // set this before any instructions, fill struct pcandev, part 1
398 // fill struct pcandev, 1st check if a default is set
401 // there's no default available
402 if (dng_devices >= DNG_DEFAULT_COUNT)
405 dng->dwPort = dng_ports[dng_devices];
408 dng->dwPort = dwPort;
412 if (dng_devices >= DNG_DEFAULT_COUNT)
415 dng->wIrq = dng_irqs[dng_devices];
420 if (dng->wType == HW_DONGLE_SJA)
422 dng->nMinor = PCAN_DNG_SP_MINOR_BASE + sp_devices;
423 dng->wEcr = 0; // set to anything
427 dng->nMinor = PCAN_DNG_EPP_MINOR_BASE + epp_devices;
428 dng->wEcr = (u16)dng->dwPort + 0x402;
431 // is the device really available?
432 if ((err = pcan_dongle_probe(dng)) < 0)
435 if (dng->wType == HW_DONGLE_SJA)
440 dng_devices = sp_devices + epp_devices;
444 DEBUGMSG(KERN_INFO "%s: %s device minor %d prepared (io=0x%04x,irq=%d)\n", DEVICE_NAME,
445 dng->type, dng->nMinor, dng->dwPort, dng->wIrq);
454 * template_request_io: - reserve io or memory range for can board
455 * @candev: pointer to candevice/board which asks for io. Field @io_addr
456 * of @candev is used in most cases to define start of the range
458 * The function template_request_io() is used to reserve the io-memory. If your
459 * hardware uses a dedicated memory range as hardware control registers you
460 * will have to add the code to reserve this memory as well.
461 * %IO_RANGE is the io-memory range that gets reserved, please adjust according
462 * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
463 * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
464 * Return Value: The function returns zero on success or %-ENODEV on failure
465 * File: src/template.c
467 int pcan_dongle_request_io(struct candevice_t *candev)
471 dongle_port.chip = candev->chip[0];
473 res_init = pcan_dongle_init(&dongle_port, 0, 0, dongle_type);
479 * template_elease_io - free reserved io memory range
480 * @candev: pointer to candevice/board which releases io
482 * The function template_release_io() is used to free reserved io-memory.
483 * In case you have reserved more io memory, don't forget to free it here.
484 * IO_RANGE is the io-memory range that gets released, please adjust according
485 * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
486 * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
487 * Return Value: The function always returns zero
488 * File: src/template.c
490 int pcan_dongle_release_io(struct candevice_t *candev)
492 /* release I/O port */
493 pcan_dongle_release(&dongle_port);
495 pcan_dongle_cleanup(&dongle_port);
501 * template_reset - hardware reset routine
502 * @candev: Pointer to candevice/board structure
504 * The function template_reset() is used to give a hardware reset. This is
505 * rather hardware specific so I haven't included example code. Don't forget to
506 * check the reset status of the chip before returning.
507 * Return Value: The function returns zero on success or %-ENODEV on failure
508 * File: src/template.c
510 int pcan_dongle_reset(struct candevice_t *candev)
513 struct canchip_t *chip;
517 DEBUGMSG("Resetting pcan_dongle hardware ...\n");
518 for(chipnr=0;chipnr<candev->nr_sja1000_chips;chipnr++) {
519 chip=candev->chip[chipnr];
521 pcan_dongle_write_register(sjaMOD_RM, chip->chip_base_addr+SJAMOD);
524 cdr=pcan_dongle_read_register(chip->chip_base_addr+SJACDR);
525 pcan_dongle_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR);
527 pcan_dongle_write_register(0, chip->chip_base_addr+SJAIER);
530 pcan_dongle_write_register(0, chip->chip_base_addr+SJAMOD);
531 while (pcan_dongle_read_register(chip->chip_base_addr+SJAMOD)&sjaMOD_RM) {
533 CANMSG("Reset status timeout!\n");
534 CANMSG("Please check your hardware.\n");
538 pcan_dongle_write_register(0, chip->chip_base_addr+SJAMOD);
541 cdr = pcan_dongle_read_register(chip->chip_base_addr+SJACDR);
542 pcan_dongle_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR);
544 pcan_dongle_write_register(0, chip->chip_base_addr+SJAIER);
549 #define RESET_ADDR 0x0
554 * template_init_hw_data - Initialize hardware cards
555 * @candev: Pointer to candevice/board structure
557 * The function template_init_hw_data() is used to initialize the hardware
558 * structure containing information about the installed CAN-board.
559 * %RESET_ADDR represents the io-address of the hardware reset register.
560 * %NR_82527 represents the number of intel 82527 chips on the board.
561 * %NR_SJA1000 represents the number of philips sja1000 chips on the board.
562 * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
563 * the hardware uses programmable interrupts.
564 * Return Value: The function always returns zero
565 * File: src/template.c
567 int pcan_dongle_init_hw_data(struct candevice_t *candev)
569 candev->res_addr=RESET_ADDR;
570 candev->nr_82527_chips=NR_82527;
571 candev->nr_sja1000_chips=NR_SJA1000;
572 candev->nr_all_chips=NR_82527+NR_SJA1000;
573 // candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
574 candev->flags |= CANDEV_PROGRAMMABLE_IRQ;
579 #define CHIP_TYPE "sja1000p"
581 * template_init_chip_data - Initialize chips
582 * @candev: Pointer to candevice/board structure
583 * @chipnr: Number of the CAN chip on the hardware card
585 * The function template_init_chip_data() is used to initialize the hardware
586 * structure containing information about the CAN chips.
587 * %CHIP_TYPE represents the type of CAN chip. %CHIP_TYPE can be "i82527" or
589 * The @chip_base_addr entry represents the start of the 'official' memory map
590 * of the installed chip. It's likely that this is the same as the @io_addr
591 * argument supplied at module loading time.
592 * The @clock entry holds the chip clock value in Hz.
593 * The entry @sja_cdr_reg holds hardware specific options for the Clock Divider
594 * register. Options defined in the %sja1000.h file:
595 * %CDR_CLKOUT_MASK, %CDR_CLK_OFF, %CDR_RXINPEN, %CDR_CBP, %CDR_PELICAN
596 * The entry @sja_ocr_reg holds hardware specific options for the Output Control
597 * register. Options defined in the %sja1000.h file:
598 * %OCR_MODE_BIPHASE, %OCR_MODE_TEST, %OCR_MODE_NORMAL, %OCR_MODE_CLOCK,
599 * %OCR_TX0_LH, %OCR_TX1_ZZ.
600 * The entry @int_clk_reg holds hardware specific options for the Clock Out
601 * register. Options defined in the %i82527.h file:
602 * %iCLK_CD0, %iCLK_CD1, %iCLK_CD2, %iCLK_CD3, %iCLK_SL0, %iCLK_SL1.
603 * The entry @int_bus_reg holds hardware specific options for the Bus
604 * Configuration register. Options defined in the %i82527.h file:
605 * %iBUS_DR0, %iBUS_DR1, %iBUS_DT1, %iBUS_POL, %iBUS_CBY.
606 * Return Value: The function always returns zero
607 * File: src/template.c
609 int pcan_dongle_init_chip_data(struct candevice_t *candev, int chipnr)
613 /* initialize common routines for the SJA1000 chip */
614 sja1000p_fill_chipspecops(candev->chip[chipnr]);
617 candev->chip[chipnr]->chip_type=CHIP_TYPE;
618 candev->chip[chipnr]->chip_base_addr=can_ioport2ioptr(candev->io_addr);
619 candev->chip[chipnr]->clock = 16000000;
620 candev->chip[chipnr]->int_clk_reg = 0x0;
621 candev->chip[chipnr]->int_bus_reg = 0x0;
622 candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF;
623 candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL | sjaOCR_TX0_LH;
625 candev->chip[chipnr]->flags |= CHIP_IRQ_CUSTOM; // I don't want setup call request_irq
626 // I'm going to do it through parport_register_device
634 * template_init_obj_data - Initialize message buffers
635 * @chip: Pointer to chip specific structure
636 * @objnr: Number of the message buffer
638 * The function template_init_obj_data() is used to initialize the hardware
639 * structure containing information about the different message objects on the
640 * CAN chip. In case of the sja1000 there's only one message object but on the
641 * i82527 chip there are 15.
642 * The code below is for a i82527 chip and initializes the object base addresses
643 * The entry @obj_base_addr represents the first memory address of the message
644 * object. In case of the sja1000 @obj_base_addr is taken the same as the chips
646 * Unless the hardware uses a segmented memory map, flags can be set zero.
647 * Return Value: The function always returns zero
648 * File: src/template.c
650 int pcan_dongle_init_obj_data(struct canchip_t *chip, int objnr)
652 chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
653 chip->msgobj[objnr]->obj_flags=0;
659 * template_program_irq - program interrupts
660 * @candev: Pointer to candevice/board structure
662 * The function template_program_irq() is used for hardware that uses
663 * programmable interrupts. If your hardware doesn't use programmable interrupts
664 * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
665 * leave this function unedited. Again this function is hardware specific so
666 * there's no example code.
667 * Return value: The function returns zero on success or %-ENODEV on failure
668 * File: src/template.c
670 int pcan_dongle_program_irq(struct candevice_t *candev)
674 pcan_dongle_req_irq(&dongle_port);
675 ret_open = pcan_dongle_open(&dongle_port);
682 * template_write_register - Low level write register routine
683 * @data: data to be written
684 * @address: memory address to write to
686 * The function template_write_register() is used to write to hardware registers
687 * on the CAN chip. You should only have to edit this function if your hardware
688 * uses some specific write process.
689 * Return Value: The function does not return a value
690 * File: src/template.c
692 void pcan_dongle_write_register(unsigned data, can_ioptr_t address)
694 address -= dongle_port.chip->chip_base_addr; // it's in mutiplexed mode
696 pcan_dongle_writereg(&dongle_port, (u8) address, (u8) data); // write a register
698 // DEBUGMSG("Write Reg at: 0x%lx data 0x%x \n", address, (unsigned) data);
702 * template_read_register - Low level read register routine
703 * @address: memory address to read from
705 * The function template_read_register() is used to read from hardware registers
706 * on the CAN chip. You should only have to edit this function if your hardware
707 * uses some specific read process.
708 * Return Value: The function returns the value stored in @address
709 * File: src/template.c
711 unsigned pcan_dongle_read_register(can_ioptr_t address)
715 address -= dongle_port.chip->chip_base_addr; // it's in mutiplexed mode
717 if (dongle_port.wType == HW_DONGLE_SJA)
718 val = pcan_dongle_sp_readreg(&dongle_port, (u8) address); // functions for SP port
720 val = pcan_dongle_epp_readreg(&dongle_port, (u8) address); // functions for EPP port
722 // DEBUGMSG("Read Reg at: 0x%lx data 0x%x \n", address, val);
724 return ((unsigned)val);
727 /* !!! Don't change this function !!! */
728 int pcan_dongle_register(struct hwspecops_t *hwspecops)
730 hwspecops->request_io = pcan_dongle_request_io;
731 hwspecops->release_io = pcan_dongle_release_io;
732 hwspecops->reset = pcan_dongle_reset;
733 hwspecops->init_hw_data = pcan_dongle_init_hw_data;
734 hwspecops->init_chip_data = pcan_dongle_init_chip_data;
735 hwspecops->init_obj_data = pcan_dongle_init_obj_data;
736 hwspecops->write_register = pcan_dongle_write_register;
737 hwspecops->read_register = pcan_dongle_read_register;
738 hwspecops->program_irq = pcan_dongle_program_irq;