X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/blobdiff_plain/33353b1cd90a21f7907e6d3151b2f1055396eba7..HEAD:/lincan/src/i82527.c diff --git a/lincan/src/i82527.c b/lincan/src/i82527.c index 58aa048..635dfc7 100644 --- a/lincan/src/i82527.c +++ b/lincan/src/i82527.c @@ -1,18 +1,43 @@ -/* i82527.c - * Linux CAN-bus device driver. - * Written by Arnaud Westenberg email:arnaud@wanadoo.nl - * Rewritten for new CAN queues by Pavel Pisa - OCERA team member - * email:pisa@cmp.felk.cvut.cz - * This software is released under the GPL-License. - * Version lincan-0.3 17 Jun 2004 - */ +/**************************************************************************/ +/* File: i82527.c - Intel i82527 CAN controller support */ +/* */ +/* LinCAN - (Not only) Linux CAN bus driver */ +/* Copyright (C) 2002-2009 DCE FEE CTU Prague */ +/* Copyright (C) 2002-2009 Pavel Pisa */ +/* Funded by OCERA and FRESCOR IST projects */ +/* Based on CAN driver code by Arnaud Westenberg */ +/* */ +/* 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. */ +/**************************************************************************/ #include "../include/can.h" #include "../include/can_sysdep.h" #include "../include/main.h" #include "../include/i82527.h" -void i82527_irq_rtr_handler(struct canchip_t *chip, struct msgobj_t *obj, +void i82527_irq_rtr_handler(struct canchip_t *chip, struct msgobj_t *obj, struct rtr_id *rtr_search, unsigned long message_id); @@ -45,7 +70,7 @@ int i82527_enable_configuration(struct canchip_t *chip) flags = can_read_reg(chip, iCTL) & (iCTL_IE|iCTL_SIE|iCTL_EIE); can_write_reg(chip, flags|iCTL_CCE, iCTL); - + return 0; } @@ -63,11 +88,11 @@ int i82527_chip_config(struct canchip_t *chip) { can_write_reg(chip,chip->int_cpu_reg,iCPU); // Configure cpu interface can_write_reg(chip,(iCTL_CCE|iCTL_INI),iCTL); // Enable configuration - i82527_seg_write_reg(chip,chip->int_clk_reg,iCLK); // Set clock out slew rates + i82527_seg_write_reg(chip,chip->int_clk_reg,iCLK); // Set clock out slew rates i82527_seg_write_reg(chip,chip->int_bus_reg,iBUS); /* Bus configuration */ can_write_reg(chip,0x00,iSTAT); /* Clear error status register */ - /* Check if we can at least read back some arbitrary data from the + /* Check if we can at least read back some arbitrary data from the * card. If we can not, the card is not properly configured! */ canobj_write_reg(chip,chip->msgobj[1],0x25,iMSGDAT1); @@ -127,7 +152,7 @@ int i82527_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, int best_error = 1000000000, error; int best_tseg=0, best_brp=0, best_rate=0, brp=0; int tseg=0, tseg1=0, tseg2=0; - + if (i82527_enable_configuration(chip)) return -ENODEV; @@ -161,7 +186,7 @@ int i82527_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, tseg2 = 0; if (tseg2 > MAX_TSEG2) tseg2 = MAX_TSEG2; - + tseg1 = best_tseg-tseg2-2; if (tseg1>MAX_TSEG1) { tseg1 = MAX_TSEG1; @@ -172,13 +197,13 @@ int i82527_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, DEBUGMSG("brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d, sampl_pt=%d\n", best_brp, best_tseg, tseg1, tseg2, (100*(best_tseg-tseg2)/(best_tseg+1))); - - + + i82527_seg_write_reg(chip, sjw<<6 | best_brp, iBT0); can_write_reg(chip, ((flags & BTR1_SAM) != 0)<<7 | tseg2<<4 | tseg1, iBT1); DEBUGMSG("Writing 0x%x to iBT0\n",(sjw<<6 | best_brp)); - DEBUGMSG("Writing 0x%x to iBT1\n",((flags & BTR1_SAM) != 0)<<7 | + DEBUGMSG("Writing 0x%x to iBT1\n",((flags & BTR1_SAM) != 0)<<7 | tseg2<<4 | tseg1); i82527_disable_configuration(chip); @@ -192,7 +217,7 @@ int i82527_standard_mask(struct canchip_t *chip, unsigned short code, unsigned s mask0 = (unsigned char) (mask >> 3); mask1 = (unsigned char) (mask << 5); - + can_write_reg(chip,mask0,iSGM0); can_write_reg(chip,mask1,iSGM1); @@ -268,7 +293,7 @@ int i82527_clear_objects(struct canchip_t *chip) DEBUGMSG("All message ID's set to standard\n"); else DEBUGMSG("All message ID's set to extended\n"); - + return 0; } @@ -312,7 +337,7 @@ int i82527_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, { int i=0,id0=0,id1=0,id2=0,id3=0; int len; - + len = msg->length; if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH; @@ -378,7 +403,7 @@ int i82527_remote_request(struct canchip_t *chip, struct msgobj_t *obj) { canobj_write_reg(chip,obj,(MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES),iMSGCTL0); canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_SET|MLST_RES|NEWD_RES),iMSGCTL1); - + return 0; } @@ -402,7 +427,7 @@ int i82527_start_chip(struct canchip_t *chip) flags = can_read_reg(chip, iCTL) & (iCTL_IE|iCTL_SIE|iCTL_EIE); can_write_reg(chip, flags, iCTL); - + return 0; } @@ -429,7 +454,7 @@ int i82527_release_chip(struct canchip_t *chip) return 0; } -static inline +static inline void i82527_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj) { int cmd; @@ -477,11 +502,11 @@ void i82527_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj, int o int i; unsigned long message_id; int msgcfg, msgctl1; - + msgctl1=canobj_read_reg(chip,obj,iMSGCTL1); if(msgctl1 & NEWD_RES) return; - + do { if(objnum != 14) { canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_RES|MLST_UNC|NEWD_RES),iMSGCTL1); @@ -514,7 +539,7 @@ void i82527_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj, int o for (i=0; i < obj->rx_msg.length; i++) obj->rx_msg.data[i] = canobj_read_reg(chip,obj,iMSGDAT0+i); - + if(objnum != 14) { /* if NEWD is set after data read, then read data are likely inconsistent */ msgctl1=canobj_read_reg(chip,obj,iMSGCTL1); @@ -529,21 +554,21 @@ void i82527_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj, int o canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_RES|MLST_UNC|NEWD_RES),iMSGCTL1); msgctl1=canobj_read_reg(chip,obj,iMSGCTL1); } - + /* fill CAN message timestamp */ can_filltimestamp(&obj->rx_msg.timestamp); canque_filter_msg2edges(obj->qends, &obj->rx_msg); - + if (msgctl1 & NEWD_SET) continue; - + if (msgctl1 & MLST_SET) { canobj_write_reg(chip,obj,(RMPD_UNC|TXRQ_UNC|MLST_RES|NEWD_UNC),iMSGCTL1); CANMSG("i82527_irq_read_handler: object %d message lost\n",objnum); } - + return; } while(1); @@ -574,11 +599,11 @@ void i82527_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj, int o if ((rtr_search!=NULL) && (rtr_search->id==message_id)) i82527_irq_rtr_handler(chip, obj, rtr_search, message_id); else - i82527_irq_read_handler(chip, obj, message_id); + i82527_irq_read_handler(chip, obj, message_id); */ -static inline +static inline void i82527_irq_update_filter(struct canchip_t *chip, struct msgobj_t *obj) { struct canfilt_t filt; @@ -596,7 +621,8 @@ void i82527_irq_update_filter(struct canchip_t *chip, struct msgobj_t *obj) i82527_pre_read_config(chip, obj); - CANMSG("i82527_irq_update_filter: obj at 0x%08lx\n",obj->obj_base_addr); + CANMSG("i82527_irq_update_filter: obj at 0x%08lx\n", + can_ioptr2ulong(obj->obj_base_addr)); } } @@ -661,16 +687,16 @@ int i82527_irq_handler(int irq, struct canchip_t *chip) CANMSG("i82527_irq_register 0x%x\n",irq_register); return CANCHIP_IRQ_STUCK; } - + DEBUGMSG("i82527: iIRQ 0x%02x\n",irq_register); - + if (irq_register == 0x01) { status_register=can_read_reg(chip, iSTAT); CANMSG("Status register: 0x%x\n",status_register); continue; /*return CANCHIP_IRQ_NONE;*/ } - + if (irq_register == 0x02) object = 14; else if(irq_register <= 13+3) @@ -679,17 +705,17 @@ int i82527_irq_handler(int irq, struct canchip_t *chip) return CANCHIP_IRQ_NONE; obj=chip->msgobj[object]; - + msgcfg = canobj_read_reg(chip,obj,iMSGCFG); if (msgcfg & MCFG_DIR) { can_msgobj_set_fl(obj,TX_REQUEST); - + /* calls i82527_irq_write_handler synchronized with other invocations */ if(i82527_irq_sync_activities(chip, obj)<=0){ /* The interrupt has to be cleared anyway */ canobj_write_reg(chip,obj,(MVAL_UNC|TXIE_UNC|RXIE_UNC|INTPD_RES),iMSGCTL0); - /* + /* * Rerun for case, that parallel activity on SMP or fully-preemptive * kernel result in preparation and finished sending of message * between above if and canobj_write_reg. @@ -697,11 +723,11 @@ int i82527_irq_handler(int irq, struct canchip_t *chip) i82527_irq_sync_activities(chip, obj); } } - else { + else { - i82527_irq_read_handler(chip, obj, object); + i82527_irq_read_handler(chip, obj, object); } - + } while((irq_register=i82527_seg_read_reg(chip, iIRQ)) != 0); return CANCHIP_IRQ_HANDLED; @@ -714,14 +740,14 @@ void i82527_irq_rtr_handler(struct canchip_t *chip, struct msgobj_t *obj, canobj_write_reg(chip,obj,(MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),iMSGCTL0); canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES),iMSGCTL1); - + can_spin_lock(&hardware_p->rtr_lock); rtr_search->rtr_message->id=message_id; rtr_search->rtr_message->length=(canobj_read_reg(chip,obj,iMSGCFG) & 0xf0)>>4; for (i=0; irtr_message->length; i++) rtr_search->rtr_message->data[i]=canobj_read_reg(chip,obj,iMSGDAT0+i); - + can_spin_unlock(&hardware_p->rtr_lock); if (waitqueue_active(&rtr_search->rtr_wq)) @@ -742,7 +768,7 @@ void i82527_irq_rtr_handler(struct canchip_t *chip, struct msgobj_t *obj, int i82527_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj) { can_preempt_disable(); - + can_msgobj_set_fl(obj,TX_REQUEST); /* calls i82527_irq_write_handler synchronized with other invocations @@ -756,7 +782,7 @@ int i82527_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj) int i82527_filtch_rq(struct canchip_t *chip, struct msgobj_t *obj) { can_preempt_disable(); - + can_msgobj_set_fl(obj,FILTCH_REQUEST); /* setups filter synchronized with other invocations from kernel and IRQ context */