]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/pcan_dongle.c
The LinCAN driver license unified according to DCE FEE CTU head and superiors request.
[lincan.git] / lincan / src / pcan_dongle.c
1 /**************************************************************************/
2 /* File: pcan_dongle.h - PEAK's printer port dongle addapter              */
3 /*                                                                        */
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>       */
14 /*                                                                        */
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.                                              */
25 /*                                                                        */
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:                                                     */
29 /*                                                                        */
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 /**************************************************************************/
39
40
41 /****************************************************************************/
42 //
43 // all parts to handle the interface specific parts of pcan-dongle
44 //
45 // Revision 1.38  2004/07/28 22:03:29  jose pascual
46 // ported to LinCAN
47 //
48 // Revision 1.37  2004/04/11 22:03:29  klaus
49 // cosmetic changes
50 //
51 // Revision 1.36  2004/04/10 12:25:39  klaus
52 // merge polished between HEAD and kernel-2.6 branch
53 //
54 // Revision 1.35  2004/04/10 08:57:26  klaus
55 // merge finished between HEAD and kernel-2.6 branch
56 //
57 // Revision 1.32.2.1  2004/03/21 12:09:09  klaus
58 // first commit for branch to kernel 2.6 code
59 //
60 // Revision 1.34  2004/03/27 16:57:06  klaus
61 // modified for use with kernels <= 2.2.14
62 //
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
65 //
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
68 //
69 // Revision 1.31  2003/06/22 15:34:50  klaus
70 // added parts to support devfs provided by Philipp Baer (partially untested)
71 //
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
74 //
75 // Revision 1.28  2003/03/02 10:58:07  klaus
76 // merged USB thread into main path
77 //
78 // Revision 1.27  2003/03/02 10:58:07  klaus
79 // merged USB thread into main path
80 //
81 // Revision 1.26.2.5  2003/01/29 20:34:20  klaus
82 // release_20030129_a and release_20030129_u released
83 //
84 // Revision 1.26.2.4  2003/01/29 20:34:19  klaus
85 // release_20030129_a and release_20030129_u released
86 //
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
89 //
90 // Revision 1.26.2.2  2003/01/14 20:31:53  klaus
91 // read/write/minor assigment is working
92 //
93 /****************************************************************************/
94
95 /****************************************************************************/
96 // INCLUDES
97
98
99 #include "../include/can.h"
100 #include "../include/can_sysdep.h"
101 #include "../include/main.h"
102 #include "../include/sja1000p.h"
103
104 #include <linux/parport.h>
105
106 #include "../include/pcan_dongle.h"
107
108
109
110 /****************************************************************************/
111 // DEFINES
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
117
118 typedef void (*PARPORT_IRQ_HANLDER)(CAN_IRQ_HANDLER_ARGS(irq_number, dev_id));
119
120 /****************************************************************************/
121 // GLOBALS
122 CAN_DEFINE_SPINLOCK(pcan_lock);
123
124 /****************************************************************************/
125 // LOCALS
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
131
132 static unsigned char nibble_decode[32] =
133 {
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
138 };
139
140 struct DONGLE_PORT dongle_port;
141
142 char dongle_type[] = "epp_dongle";
143 //char dongle_type[] = "sp_dongle";
144
145 /****************************************************************************/
146 // CODE
147
148 //----------------------------------------------------------------------------
149 // enable and disable irqs
150 static void _parport_disable_irq(struct DONGLE_PORT *dng)
151 {
152   u16 _PC_ = (u16)dng->dwPort + 2;
153   can_outb(can_inb(_PC_) & ~0x10, _PC_);
154 }
155
156 static void _parport_enable_irq(struct DONGLE_PORT *dng)
157 {
158   u16 _PC_ = (u16)dng->dwPort + 2;
159   can_outb(can_inb(_PC_) | 0x10, _PC_);
160 }
161
162
163 // functions for SP port
164 static u8 pcan_dongle_sp_readreg(struct DONGLE_PORT *dng, u8 port) // read a register
165 {
166   u16 _PA_ = (u16)dng->dwPort;
167   u16 _PB_ = _PA_ + 1;
168   u16 _PC_ = _PB_ + 1;
169   u8  b0, b1 ;
170   u8  irqEnable = can_inb(_PC_) & 0x10; // don't influence irqEnable
171   can_spin_irqflags_t flags;
172
173   can_spin_lock_irqsave(&pcan_lock, flags);
174
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_);
182
183   can_spin_unlock_irqrestore(&pcan_lock, flags);
184
185   return  (b1 << 4) | b0 ;
186 }
187
188 static void pcan_dongle_writereg(struct DONGLE_PORT *dng, u8 port, u8 data) // write a register
189 {
190   u16 _PA_ = (u16)dng->dwPort;
191   u16 _PC_ = _PA_ + 2;
192   u8  irqEnable = can_inb(_PC_) & 0x10; // don't influence irqEnable
193   can_spin_irqflags_t flags;
194
195   can_spin_lock_irqsave(&pcan_lock, flags);
196
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_);
202
203   can_spin_unlock_irqrestore(&pcan_lock, flags);
204 }
205
206 // functions for EPP port
207 static u8 pcan_dongle_epp_readreg(struct DONGLE_PORT *dng, u8 port) // read a register
208 {
209   u16 _PA_ = (u16)dng->dwPort;
210   u16 _PC_ = _PA_ + 2;
211   u8  wert;
212   u8  irqEnable = can_inb(_PC_) & 0x10; // don't influence irqEnable
213   can_spin_irqflags_t flags;
214
215   can_spin_lock_irqsave(&pcan_lock, flags);
216
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_);
222
223   can_spin_unlock_irqrestore(&pcan_lock, flags);
224
225   return wert;
226 }
227
228 static int pcan_dongle_req_irq(struct DONGLE_PORT *dng)
229 {
230   if (dng->wInitStep == 3)
231   {
232     dng->wInitStep++;
233   }
234
235   return 0;
236 }
237
238 static void pcan_dongle_free_irq(struct DONGLE_PORT *dng)
239 {
240   if (dng->wInitStep == 4)
241   {
242     dng->wInitStep--;
243   }
244 }
245
246 // release and probe functions
247 static int pcan_dongle_cleanup(struct DONGLE_PORT *dng)
248 {
249   DEBUGMSG("%s: pcan_dongle_cleanup()\n", DEVICE_NAME);
250
251   switch(dng->wInitStep)
252   {
253     case 4: pcan_dongle_free_irq(dng);
254     case 3: if (dng->wType == HW_DONGLE_SJA)
255               sp_devices--;
256             else
257               epp_devices--;
258             dng_devices = sp_devices + epp_devices;
259     case 2:
260     case 1:
261             parport_unregister_device(dng->pardev);
262     case 0: dng->wInitStep = 0;
263   }
264
265   return 0;
266 }
267
268 // to switch epp on or restore register
269 static void setECR(struct DONGLE_PORT *dng)
270 {
271         u16 wEcr = dng->wEcr;
272
273         dng->ucOldECRContent = can_inb(wEcr);
274         can_outb((dng->ucOldECRContent & 0x1F) | 0x20, wEcr);
275
276         if (dng->ucOldECRContent == 0xff)
277                 DEBUGMSG("%s: realy ECP mode configured?\n", DEVICE_NAME);
278 }
279
280 static void restoreECR(struct DONGLE_PORT *dng)
281 {
282   u16 wEcr = dng->wEcr;
283
284   can_outb(dng->ucOldECRContent, wEcr);
285
286   DEBUGMSG("%s: restore ECR\n", DEVICE_NAME);
287 }
288
289 static int pcan_dongle_probe(struct DONGLE_PORT *dng) // probe for type
290 {
291   struct parport *p;
292
293   DEBUGMSG("%s: pcan_dongle_probe() - PARPORT_SUBSYSTEM\n", DEVICE_NAME);
294   
295   // probe does not probe for the sja1000 device here - this is done at sja1000_open()
296   p = parport_find_base(dng->dwPort);
297   if (!p)
298   {
299     DEBUGMSG("found no parport\n");
300     return -ENXIO;
301   }
302   else
303   {
304        dng->pardev = parport_register_device(p, "can", NULL, NULL, 
305                           (PARPORT_IRQ_HANLDER)dng->chip->chipspecops->irq_handler,
306                           0, (void *)dng->chip);
307         
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);
311                                       
312     if (!dng->pardev)
313     {
314       DEBUGMSG("found no parport device\n");
315       return -ENODEV;
316     }
317
318   }
319   
320   return 0;
321 }
322
323 // interface depended open and close
324 static int pcan_dongle_open(struct DONGLE_PORT *dng)
325 {
326   int result = 0;
327   u16 wPort;
328   
329   DEBUGMSG("%s: pcan_dongle_open()\n", DEVICE_NAME);
330   
331   result = parport_claim(dng->pardev);
332   
333   if (!result)
334   {
335     if (dng->pardev->port->irq == PARPORT_IRQ_NONE)
336     {
337       DEBUGMSG(KERN_ERR "%s: no irq associated to parport.\n", DEVICE_NAME);
338       result = -ENXIO;
339     }
340   }
341   else
342    DEBUGMSG(KERN_ERR "%s: can't claim parport.\n", DEVICE_NAME);        
343   
344   // save port state
345   if (!result)
346    {
347       wPort    = (u16)dng->dwPort;
348           
349      // save old port contents
350      dng->ucOldDataContent     = can_inb(wPort);
351      dng->ucOldControlContent  = can_inb(wPort + 2);
352           
353      // switch to epp mode if possible
354      if (dng->wType == HW_DONGLE_SJA_EPP)
355         setECR(dng); 
356   
357     // enable irqs
358     _parport_enable_irq(dng); // parport_enable_irq(dng->pardev->port); not working since 2.4.18
359   }     
360         
361   return result;
362 }
363
364 static int pcan_dongle_release(struct DONGLE_PORT *dng)
365 {
366   u16 wPort = (u16)dng->dwPort;
367
368   DEBUGMSG("%s: pcan_dongle_release()\n", DEVICE_NAME);
369   
370   // disable irqs
371   _parport_disable_irq(dng); // parport_disable_irq(dng->pardev->port); not working since 2.4.18
372
373   if (dng->wType == HW_DONGLE_SJA_EPP)
374     restoreECR(dng);
375     
376   // restore port state
377   can_outb(dng->ucOldDataContent, wPort);
378   can_outb(dng->ucOldControlContent, wPort + 2);
379       
380   parport_release(dng->pardev);
381   
382   return 0;
383 }
384
385 int  pcan_dongle_init(struct DONGLE_PORT *dng, u32 dwPort, u16 wIrq, char *type)
386 {
387   int err;
388   
389   DEBUGMSG("%s: pcan_dongle_init(), dng_devices = %d\n", DEVICE_NAME, dng_devices);
390   
391   dng->type = type;
392
393   dng->wType = (!strncmp(dongle_type, "sp", 4)) ? HW_DONGLE_SJA : HW_DONGLE_SJA_EPP;
394   
395   // set this before any instructions, fill struct pcandev, part 1 
396   dng->wInitStep   = 0;  
397         
398   // fill struct pcandev, 1st check if a default is set
399   if (!dwPort)
400   {
401     // there's no default available
402     if (dng_devices >= DNG_DEFAULT_COUNT)
403       return -ENODEV;
404     
405     dng->dwPort = dng_ports[dng_devices];
406   }
407   else
408     dng->dwPort = dwPort;
409   
410   if (!wIrq)
411   {
412     if (dng_devices >= DNG_DEFAULT_COUNT)
413       return -ENODEV;
414     
415     dng->wIrq   = dng_irqs[dng_devices];    
416   }
417   else
418     dng->wIrq   = wIrq;    
419   
420   if (dng->wType == HW_DONGLE_SJA)
421     {
422            dng->nMinor        = PCAN_DNG_SP_MINOR_BASE + sp_devices; 
423            dng->wEcr = 0; // set to anything
424     }
425   else
426     {
427             dng->nMinor        = PCAN_DNG_EPP_MINOR_BASE + epp_devices;  
428             dng->wEcr = (u16)dng->dwPort + 0x402;
429     }
430           
431         // is the device really available?              
432   if ((err = pcan_dongle_probe(dng)) < 0)
433     return err;
434   
435   if (dng->wType == HW_DONGLE_SJA)
436     sp_devices++;
437   else
438     epp_devices++;
439           
440   dng_devices = sp_devices + epp_devices;
441   
442   dng->wInitStep = 3;
443
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);
446         
447   return 0;
448 }
449
450
451
452
453 /**
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
457  *
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
466  */
467 int pcan_dongle_request_io(struct candevice_t *candev)
468 {
469         int res_init;
470
471         dongle_port.chip = candev->chip[0];
472
473         res_init = pcan_dongle_init(&dongle_port, 0, 0, dongle_type);
474
475         return res_init;
476 }
477
478 /**
479  * template_elease_io - free reserved io memory range
480  * @candev: pointer to candevice/board which releases io
481  *
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
489  */
490 int pcan_dongle_release_io(struct candevice_t *candev)
491 {
492         /* release I/O port */
493         pcan_dongle_release(&dongle_port);
494         
495         pcan_dongle_cleanup(&dongle_port);
496
497         return 0;
498 }
499
500 /**
501  * template_reset - hardware reset routine
502  * @candev: Pointer to candevice/board structure
503  *
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
509  */
510 int pcan_dongle_reset(struct candevice_t *candev)
511 {
512         int i=0;
513         struct canchip_t *chip;
514         int chipnr;
515         unsigned cdr;
516         
517         DEBUGMSG("Resetting pcan_dongle hardware ...\n");
518         for(chipnr=0;chipnr<candev->nr_sja1000_chips;chipnr++) {
519                 chip=candev->chip[chipnr];
520
521           pcan_dongle_write_register(sjaMOD_RM, chip->chip_base_addr+SJAMOD);
522           udelay(1000);
523         
524           cdr=pcan_dongle_read_register(chip->chip_base_addr+SJACDR);
525           pcan_dongle_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR);
526
527           pcan_dongle_write_register(0, chip->chip_base_addr+SJAIER);
528
529           i=20;
530           pcan_dongle_write_register(0, chip->chip_base_addr+SJAMOD);
531           while (pcan_dongle_read_register(chip->chip_base_addr+SJAMOD)&sjaMOD_RM) {
532                 if(!i--) {
533                         CANMSG("Reset status timeout!\n");
534                         CANMSG("Please check your hardware.\n");
535                         return -ENODEV;
536                 }
537                 udelay(1000);
538                 pcan_dongle_write_register(0, chip->chip_base_addr+SJAMOD);
539           }
540
541           cdr = pcan_dongle_read_register(chip->chip_base_addr+SJACDR);
542           pcan_dongle_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR);
543
544           pcan_dongle_write_register(0, chip->chip_base_addr+SJAIER);
545         }
546         return 0;
547 }
548
549 #define RESET_ADDR 0x0
550 #define NR_82527 0
551 #define NR_SJA1000 1
552
553 /**
554  * template_init_hw_data - Initialize hardware cards
555  * @candev: Pointer to candevice/board structure
556  *
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
566  */
567 int pcan_dongle_init_hw_data(struct candevice_t *candev) 
568 {
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;
575
576         return 0;
577 }
578
579 #define CHIP_TYPE "sja1000p"
580 /**
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
584  *
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
588  * "sja1000".
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
608  */
609 int pcan_dongle_init_chip_data(struct candevice_t *candev, int chipnr)
610 {
611 //    if (chipnr == 0)
612      {
613         /* initialize common routines for the SJA1000 chip */
614         sja1000p_fill_chipspecops(candev->chip[chipnr]);
615
616
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;
624
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 
627
628      }
629
630     return 0;
631 }
632
633 /**
634  * template_init_obj_data - Initialize message buffers
635  * @chip: Pointer to chip specific structure
636  * @objnr: Number of the message buffer
637  *
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
645  * base address.
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
649  */
650 int pcan_dongle_init_obj_data(struct canchip_t *chip, int objnr)
651 {
652         chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
653         chip->msgobj[objnr]->obj_flags=0;
654         
655         return 0;
656 }
657
658 /**
659  * template_program_irq - program interrupts
660  * @candev: Pointer to candevice/board structure
661  *
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
669  */
670 int pcan_dongle_program_irq(struct candevice_t *candev)
671 {
672         int ret_open;
673
674         pcan_dongle_req_irq(&dongle_port);
675         ret_open = pcan_dongle_open(&dongle_port);
676
677         return ret_open;
678 }
679
680
681 /**
682  * template_write_register - Low level write register routine
683  * @data: data to be written
684  * @address: memory address to write to
685  *
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
691  */
692 void pcan_dongle_write_register(unsigned data, can_ioptr_t address)
693 {
694    address -= dongle_port.chip->chip_base_addr;  // it's in mutiplexed mode
695
696    pcan_dongle_writereg(&dongle_port, (u8) address, (u8) data); // write a register
697
698 //   DEBUGMSG("Write Reg at: 0x%lx data 0x%x \n", address, (unsigned) data);
699 }
700
701 /**
702  * template_read_register - Low level read register routine
703  * @address: memory address to read from
704  *
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
710  */
711 unsigned pcan_dongle_read_register(can_ioptr_t address)
712 {
713    u8 val;
714
715   address -= dongle_port.chip->chip_base_addr;  // it's in mutiplexed mode
716         
717   if (dongle_port.wType == HW_DONGLE_SJA)
718      val = pcan_dongle_sp_readreg(&dongle_port, (u8) address); // functions for SP port
719   else 
720      val = pcan_dongle_epp_readreg(&dongle_port, (u8) address); // functions for EPP port
721
722 //  DEBUGMSG("Read Reg at: 0x%lx data 0x%x \n", address, val);
723
724   return ((unsigned)val);
725 }
726
727 /* !!! Don't change this function !!! */
728 int pcan_dongle_register(struct hwspecops_t *hwspecops)
729 {
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;
739         return 0;
740 }
741
742