X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/blobdiff_plain/bb942b0bf58dd15491aee5acb3b4ec76559104a1..04ac67cc3cac14cd601daacd0592121ec0b84012:/lincan/src/unican.c diff --git a/lincan/src/unican.c b/lincan/src/unican.c index 7b27ade..ae2934a 100644 --- a/lincan/src/unican.c +++ b/lincan/src/unican.c @@ -1,10 +1,36 @@ -/* unican.c - * Linux CAN-bus device driver. - * Written for new CAN driver version 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: unican.c - Unicontrols PCAN,PCAN-PCI, VCAN boards 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" @@ -54,7 +80,7 @@ int unican_chip_config(struct canchip_t *chip) sCAN_CARD *chipext = (sCAN_CARD *)chip->chip_data; unican_delay(10); - + /* disable all card interrupts */ ret = cl2_int_mode(chipext, INT_MODE_ALL*0); if(ret != CL2_OK) { @@ -65,13 +91,13 @@ int unican_chip_config(struct canchip_t *chip) if (chip->baudrate == 0) chip->baudrate=1000000; - + ret = chip->chipspecops->baud_rate(chip,chip->baudrate,chip->clock,0,75,0); if(ret < 0){ CANMSG("can not set baudrate\n"); return ret; } - + unican_delay(2); /* set interrupt inhibit time to 1 ms */ ret = cl2_set_iit(chipext, 10); @@ -88,7 +114,7 @@ int unican_chip_config(struct canchip_t *chip) return -ENODEV; } unican_delay(1); - + /* enable all card interrupts */ ret = cl2_int_mode(chipext, INT_MODE_ALL); if(ret != CL2_OK) { @@ -151,12 +177,12 @@ int unican_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, case 1000000:bt_val = CL2_BITRATE_1M; break; default: return -EINVAL; } - + ret=cl2_set_bitrate(chipext,bt_val); if(ret == CL2_COMMAND_BUSY) return -EBUSY; if(ret != CL2_OK) return -EINVAL; unican_delay(2); - + return 0; } @@ -202,7 +228,7 @@ void unican_read(struct canchip_t *chip, struct msgobj_t *obj) { obj->rx_msg.flags = 0; } - /*if ( !(u & (CL2_REMOTE_FRAME<<8)) ) + /*if ( !(u & (CL2_REMOTE_FRAME<<8)) ) obj->rx_msg.flags |= MSG_RTR;*/ obj->rx_msg.length = ( (u >> 4) & 0x000F ); @@ -227,7 +253,7 @@ void unican_read(struct canchip_t *chip, struct msgobj_t *obj) { #else /* CAN_MSG_VERSION_2 */ obj->rx_msg.timestamp = timestamp; #endif /* CAN_MSG_VERSION_2 */ - + /* increment rx-buffer pointer */ if ( (chipext->rxBufBase + chipext->rxBufSize*16 ) <= (chipext->rxBufPtr += 16) ) { chipext->rxBufPtr = chipext->rxBufBase; @@ -262,7 +288,7 @@ int unican_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj) * Return Value: negative value reports error. * File: src/unican.c */ -int unican_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, +int unican_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg) { return 0; @@ -279,7 +305,7 @@ int unican_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, * Return Value: negative value reports error. * File: src/unican.c */ -int unican_send_msg(struct canchip_t *chip, struct msgobj_t *obj, +int unican_send_msg(struct canchip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg) { return 0; @@ -308,7 +334,7 @@ int unican_check_tx_stat(struct canchip_t *chip) * Return Value: negative value reports error. * File: src/unican.c */ -int unican_set_btregs(struct canchip_t *chip, unsigned short btr0, +int unican_set_btregs(struct canchip_t *chip, unsigned short btr0, unsigned short btr1) { int ret; @@ -482,10 +508,10 @@ void unican_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj) cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot); if(cmd<0) return; /* No more messages to send */ - + cobid = obj->tx_slot->msg.id; - + if ( (obj->tx_slot->msg.flags & MSG_EXT) ) { /* 2.0B frame */ cobid <<= 3; } else { /* 2.0A frame */ @@ -499,10 +525,10 @@ void unican_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj) if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH; u = (len << 12) | (cobid & 0x00FF); - - if ( !(obj->tx_slot->msg.flags & MSG_RTR) ) + + if ( !(obj->tx_slot->msg.flags & MSG_RTR) ) u |= CL2_REMOTE_FRAME<<8; - if ( obj->tx_slot->msg.flags & MSG_EXT ) + if ( obj->tx_slot->msg.flags & MSG_EXT ) u |= CL2_EXT_FRAME<<8; unican_writew(u,ptr16++); @@ -524,7 +550,7 @@ void unican_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj) u = ((cobid>>16) & 0xFF00) | CL2_MESSAGE_VALID; unican_writew(u,(__u16*)chipext->asyncTxBufPtr); - if ( (chipext->asyncTxBufBase + chipext->asyncTxBufSize*16) <= + if ( (chipext->asyncTxBufBase + chipext->asyncTxBufSize*16) <= (chipext->asyncTxBufPtr += 16) ) { chipext->asyncTxBufPtr = chipext->asyncTxBufBase; } @@ -540,9 +566,9 @@ void unican_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj) /* Free transmitted slot */ canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); obj->tx_slot=NULL; - + }while(1); - + return; } @@ -575,7 +601,7 @@ void unican_irq_sync_activities(struct canchip_t *chip, struct msgobj_t *obj) * unican_irq_handler: - interrupt service routine * @irq: interrupt vector number, this value is system specific * @chip: pointer to chip state structure - * + * * Interrupt handler is activated when state of CAN controller chip changes, * there is message to be read or there is more space for new messages or * error occurs. The receive events results in reading of the message from @@ -596,7 +622,7 @@ int unican_irq_handler(int irq, struct canchip_t *chip) } if (cl2_get_status(chipext, &status) == CL2_NO_REQUEST) { - /* Reenable interrupts generation, this has to be even there, + /* Reenable interrupts generation, this has to be even there, * because irq_accept disables interrupts */ cl2_gen_interrupt(chipext); @@ -635,7 +661,7 @@ int unican_irq_handler(int irq, struct canchip_t *chip) * unican_irq_accept: - fast irq accept routine, blocks further interrupts * @irq: interrupt vector number, this value is system specific * @chip: pointer to chip state structure - * + * * This routine only accepts interrupt reception and stops further * incoming interrupts, but does not handle situation causing interrupt. * File: src/unican.c @@ -652,7 +678,7 @@ int unican_irq_accept(int irq, struct canchip_t *chip) /*void unican_do_tx_timeout(unsigned long data) { struct msgobj_t *obj=(struct msgobj_t *)data; - + }*/ /** @@ -702,7 +728,7 @@ int unican_request_io(struct candevice_t *candev) CANMSG("Unable to access I/O memory at: 0x%lx\n", candev->io_addr); can_release_mem_region(candev->io_addr,IO_RANGE); return -ENODEV; - + } can_base_addr_fixup(candev, remap_addr); DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + IO_RANGE - 1); @@ -736,7 +762,7 @@ int unican_reset(struct candevice_t *candev) int i; struct canchip_t *chip = candev->chip[0]; sCAN_CARD *chipext; - + if(chip->chip_data == NULL) { chip->chip_data = can_checked_malloc(sizeof(sCAN_CARD)); @@ -748,9 +774,9 @@ int unican_reset(struct candevice_t *candev) return -ENODEV; } } - + chipext = (sCAN_CARD *)chip->chip_data; - + i = 0; /* reset and test whether the card is present */ do { @@ -764,14 +790,14 @@ int unican_reset(struct candevice_t *candev) CANMSG("card check failed %d\n",ret); return -ENODEV; } - + /* start card firmware */ ret = cl2_start_firmware(chipext); if(ret != CL2_OK){ CANMSG("cl2_start_firmware returned %d\n",ret); return -ENODEV; } - + unican_delay(100); return 0; @@ -784,7 +810,7 @@ int unican_reset(struct candevice_t *candev) * Return Value: The function always returns zero * File: src/unican.c */ -int unican_init_hw_data(struct candevice_t *candev) +int unican_init_hw_data(struct candevice_t *candev) { candev->res_addr=0; candev->nr_82527_chips=0; @@ -813,7 +839,7 @@ int unican_init_chip_data(struct candevice_t *candev, int chipnr) chip->int_bus_reg = 0x0; chip->max_objects = 1; chip->chip_base_addr=candev->dev_base_addr; - + CANMSG("initializing unican chip operations\n"); chip->chipspecops->chip_config=unican_chip_config; chip->chipspecops->baud_rate=unican_baud_rate; @@ -916,11 +942,11 @@ int unican_pci_request_io(struct candevice_t *candev) pci_release_regions(candev->sysdevptr.pcidev); #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ return -ENODEV; - + } can_base_addr_fixup(candev, remap_addr); DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + IO_RANGE - 1); - DEBUGMSG("VMA: dev_base_addr: 0x%lx chip_base_addr: 0x%lx\n", + DEBUGMSG("VMA: dev_base_addr: 0x%lx chip_base_addr: 0x%lx\n", can_ioptr2ulong(candev->dev_base_addr), can_ioptr2ulong(candev->chip[0]->chip_base_addr)); @@ -944,25 +970,26 @@ int unican_pci_init_hw_data(struct candevice_t *candev) { struct pci_dev *pcidev = NULL; - do { - pcidev = pci_find_device(UNICAN_PCI_VENDOR, UNICAN_PCI_ID, pcidev); - if(pcidev == NULL) return -ENODEV; - } while(can_check_dev_taken(pcidev)); - + pcidev = can_pci_get_next_untaken_device(UNICAN_PCI_VENDOR, UNICAN_PCI_ID); + if(pcidev == NULL) + return -ENODEV; + if (pci_enable_device (pcidev)){ printk(KERN_CRIT "Setup of Unican PCI failed\n"); + can_pci_dev_put(pcidev); return -EIO; } candev->sysdevptr.pcidev=pcidev; - + if(!(pci_resource_flags(pcidev,0)&IORESOURCE_MEM)){ printk(KERN_CRIT "Unican PCI region 0 is not MEM\n"); + can_pci_dev_put(pcidev); return -EIO; } candev->io_addr=pci_resource_start(pcidev,0); candev->res_addr=candev->io_addr; candev->dev_base_addr=NULL; - + /*candev->flags |= CANDEV_PROGRAMMABLE_IRQ;*/ candev->nr_82527_chips=0; @@ -972,6 +999,11 @@ int unican_pci_init_hw_data(struct candevice_t *candev) return 0; } +void unican_pci_done_hw_data(struct candevice_t *candev) +{ + struct pci_dev *pcidev = candev->sysdevptr.pcidev; + can_pci_dev_put(pcidev); +} int unican_pci_init_chip_data(struct candevice_t *candev, int chipnr) { @@ -988,6 +1020,7 @@ int unican_pci_register(struct hwspecops_t *hwspecops) hwspecops->release_io = unican_pci_release_io; hwspecops->reset = unican_reset; hwspecops->init_hw_data = unican_pci_init_hw_data; + hwspecops->done_hw_data = unican_pci_done_hw_data; hwspecops->init_chip_data = unican_pci_init_chip_data; hwspecops->init_obj_data = unican_init_obj_data; hwspecops->write_register = NULL;