From d659fb1c5ce646e10820cfd349d8a4220d1ee67d Mon Sep 17 00:00:00 2001 From: ppisa Date: Tue, 6 Apr 2004 10:15:26 +0000 Subject: [PATCH] Added support for Unicontrols PCI CAN card. Will be tested, when I get to the hardware at school. --- lincan/include/can_sysdep.h | 5 ++ lincan/include/main.h | 3 + lincan/src/boardlist.c | 8 +++ lincan/src/kv_pcican.c | 8 ++- lincan/src/setup.c | 23 +++++++ lincan/src/unican.c | 124 ++++++++++++++++++++++++++++++++++-- lincan/src/write.c | 13 ++-- lincan/src/write_rtl.c | 13 ++-- 8 files changed, 182 insertions(+), 15 deletions(-) diff --git a/lincan/include/can_sysdep.h b/lincan/include/can_sysdep.h index 0dd0e55..f8499d1 100644 --- a/lincan/include/can_sysdep.h +++ b/lincan/include/can_sysdep.h @@ -30,8 +30,13 @@ /*optional features*/ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) #define CAN_ENABLE_KERN_FASYNC +#ifdef CONFIG_PCI #define CAN_ENABLE_PCI_SUPPORT #endif +#ifdef CONFIG_VME_some_option_there +#define CAN_ENABLE_VME_SUPPORT +#endif +#endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) #include diff --git a/lincan/include/main.h b/lincan/include/main.h index 78eace8..506e262 100644 --- a/lincan/include/main.h +++ b/lincan/include/main.h @@ -88,6 +88,7 @@ struct candevice_t { struct canhardware_t *hosthardware_p; union { + void *anydev; #ifdef CAN_ENABLE_PCI_SUPPORT struct pci_dev *pcidev; #endif /*CAN_ENABLE_PCI_SUPPORT*/ @@ -474,6 +475,8 @@ struct boardtype_t { const struct boardtype_t* boardtype_find(const char *str); +int can_check_dev_taken(void *anydev); + #ifdef CAN_WITH_RTL extern int can_rtl_priority; #endif /*CAN_WITH_RTL*/ diff --git a/lincan/src/boardlist.c b/lincan/src/boardlist.c index f0b7dff..b04636c 100644 --- a/lincan/src/boardlist.c +++ b/lincan/src/boardlist.c @@ -33,6 +33,8 @@ extern int bfadcan_register(struct hwspecops_t *hwspecops); extern int pikronisa_register(struct hwspecops_t *hwspecops); extern int msmcan_register(struct hwspecops_t *hwspecops); extern int unican_register(struct hwspecops_t *hwspecops); +extern int unican_pci_register(struct hwspecops_t *hwspecops); +extern int unican_vme_register(struct hwspecops_t *hwspecops); const struct boardtype_t can_boardtypes[]={ #ifdef CONFIG_OC_LINCAN_CARD_template @@ -94,6 +96,12 @@ const struct boardtype_t can_boardtypes[]={ #endif #ifdef CONFIG_OC_LINCAN_CARD_unican {"unican", unican_register, 1}, + #endif + #if defined(CONFIG_OC_LINCAN_CARD_unican)&&defined(CAN_ENABLE_PCI_SUPPORT) + {"unican-pci", unican_pci_register, 0}, + #endif + #if defined(CONFIG_OC_LINCAN_CARD_unican)&&defined(CAN_ENABLE_VME_SUPPORT) + {"unican-vme", unican_vme_register, 1}, #endif {NULL} }; diff --git a/lincan/src/kv_pcican.c b/lincan/src/kv_pcican.c index c49a3de..e7f36e3 100644 --- a/lincan/src/kv_pcican.c +++ b/lincan/src/kv_pcican.c @@ -183,8 +183,10 @@ int kv_pcican_init_hw_data(struct candevice_t *candev) struct pci_dev *pcidev = NULL; int i; - pcidev = pci_find_device(KV_PCICAN_PCICAN_VENDOR, KV_PCICAN_PCICAN_ID, pcidev); - if(pcidev == NULL) return -ENODEV; + do { + pcidev = pci_find_device(KV_PCICAN_PCICAN_VENDOR, KV_PCICAN_PCICAN_ID, pcidev); + if(pcidev == NULL) return -ENODEV; + } while(can_check_dev_taken(pcidev)); if (pci_enable_device (pcidev)){ printk(KERN_CRIT "Setup of PCICAN failed\n"); @@ -193,7 +195,7 @@ int kv_pcican_init_hw_data(struct candevice_t *candev) candev->sysdevptr.pcidev=pcidev; for(i=0;i<3;i++){ - if(!(pci_resource_flags(pcidev,0)&IORESOURCE_IO)){ + if(!(pci_resource_flags(pcidev,i)&IORESOURCE_IO)){ printk(KERN_CRIT "PCICAN region %d is not IO\n",i); return -EIO; } diff --git a/lincan/src/setup.c b/lincan/src/setup.c index 6a59e2f..83eef72 100644 --- a/lincan/src/setup.c +++ b/lincan/src/setup.c @@ -215,6 +215,29 @@ int can_base_addr_fixup(struct candevice_t *candev, unsigned long new_base) return 0; } +/** + * can_check_dev_taken - checks if bus device description is already taken by driver + * @anydev: pointer to bus specific Linux device description + * + * Returns: Returns 1 if device is already used by LinCAN driver, 0 otherwise. + */ +int can_check_dev_taken(void *anydev) +{ + int board_nr; + struct candevice_t *candev; + void *boarddev; + + for (board_nr=hardware_p->nr_boards; board_nr--; ) { + if((candev=hardware_p->candevice[board_nr])==NULL) + continue; + boarddev=candev->sysdevptr.anydev; + if(boarddev == anydev) + return 1; + } + + return 0; +} + /** * register_obj_struct - registers message object into global array diff --git a/lincan/src/unican.c b/lincan/src/unican.c index efc5ac2..5cab054 100644 --- a/lincan/src/unican.c +++ b/lincan/src/unican.c @@ -12,10 +12,8 @@ #include "../include/unican_cl2.h" #include "../include/setup.h" -#ifdef CAN_WITH_RTL - -#endif /*CAN_WITH_RTL*/ - +#define UNICAN_PCI_VENDOR 0xFA3C +#define UNICAN_PCI_ID 0x0101 static void unican_delay(long msdelay) { @@ -848,3 +846,121 @@ int unican_register(struct hwspecops_t *hwspecops) hwspecops->program_irq = unican_program_irq; return 0; } + + +/* Unicontrols PCI board specific functions */ + +#ifdef CAN_ENABLE_PCI_SUPPORT + +int unican_pci_request_io(struct candevice_t *candev) +{ + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) + if(pci_request_region(candev->sysdevptr.pcidev, 0, "unican_pci") != 0){ + CANMSG("Request of Unican PCI range failed\n"); + return -ENODEV; + } + #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ + if(pci_request_regions(candev->sysdevptr.pcidev, "kv_pcican") != 0){ + CANMSG("Request of Unican PCI range failed\n"); + return -ENODEV; + } + #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ + + return 0; +} + + +int unican_pci_release_io(struct candevice_t *candev) +{ + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) + pci_release_region(candev->sysdevptr.pcidev, 0); + #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ + pci_release_regions(candev->sysdevptr.pcidev); + #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ + return 0; +} + + +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)); + + if (pci_enable_device (pcidev)){ + printk(KERN_CRIT "Setup of Unican PCI failed\n"); + 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"); + return -EIO; + } + candev->dev_base_addr=pci_resource_start(pcidev,0); /*S5920*/ + candev->io_addr=candev->dev_base_addr; + candev->res_addr=candev->dev_base_addr; + + /*candev->flags |= CANDEV_PROGRAMMABLE_IRQ;*/ + + candev->nr_82527_chips=0; + candev->nr_sja1000_chips=0; + candev->nr_all_chips=1; + + return 0; +} + + +int unican_pci_init_chip_data(struct candevice_t *candev, int chipnr) +{ + int ret; + candev->chip[chipnr]->chip_irq=candev->sysdevptr.pcidev->irq; + ret = unican_pci_init_chip_data(candev, chipnr); + candev->chip[chipnr]->flags |= CHIP_IRQ_PCI; + return ret; +} + +int unican_pci_register(struct hwspecops_t *hwspecops) +{ + hwspecops->request_io = unican_pci_request_io; + hwspecops->release_io = unican_pci_release_io; + hwspecops->reset = unican_reset; + hwspecops->init_hw_data = unican_pci_init_hw_data; + hwspecops->init_chip_data = unican_pci_init_chip_data; + hwspecops->init_obj_data = unican_init_obj_data; + hwspecops->write_register = NULL; + hwspecops->read_register = NULL; + hwspecops->program_irq = unican_program_irq; + return 0; +} + +#endif /*CAN_ENABLE_PCI_SUPPORT*/ + +#ifdef CAN_ENABLE_VME_SUPPORT + +int unican_vme_reset(struct candevice_t *candev) +{ + struct chip_t *chip = candev->chip[0]; + writew(chip->chip_irq,chip->chip_base_addr+CL2_VME_INT_VECTOR); + return unican_reset(candev); +} + + +int unican_vme_register(struct hwspecops_t *hwspecops) +{ + hwspecops->request_io = unican_request_io; + hwspecops->release_io = unican_release_io; + hwspecops->reset = unican_vme_reset; + hwspecops->init_hw_data = unican_init_hw_data; + hwspecops->init_chip_data = unican_init_chip_data; + hwspecops->init_obj_data = unican_init_obj_data; + hwspecops->write_register = NULL; + hwspecops->read_register = NULL; + hwspecops->program_irq = unican_program_irq; + return 0; +} + +#endif /*CAN_ENABLE_VME_SUPPORT*/ diff --git a/lincan/src/write.c b/lincan/src/write.c index 1760bc2..e3809b0 100644 --- a/lincan/src/write.c +++ b/lincan/src/write.c @@ -53,8 +53,10 @@ ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t * /* Prepare first message */ copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t)); - /* Automatic selection of extended format if "extended" set and ID>2047 */ - if (extended) if (msg_buff.id & ~0x7ffl ) msg_buff.flags |= MSG_EXT; + + /* Automatic selection of extended format if ID>2047 */ + if (msg_buff.id & ~0x7ffl & MSG_ID_MASK ) msg_buff.flags |= MSG_EXT; + /* has been dependent on "extended" option */ /* If the output buffer is full, return immediately in case O_NONBLOCK * has been specified or loop until space becomes available. @@ -89,8 +91,11 @@ ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t * bytes_to_copy -= sizeof(struct canmsg_t); /* Prepare first message */ copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t)); - /* Automatic selection of extended format if "extended" set and ID>2047 */ - if (extended) if (msg_buff.id & ~0x7ffl ) msg_buff.flags |= MSG_EXT; + + /* Automatic selection of extended format if ID>2047 */ + if (msg_buff.id & ~0x7ffl & MSG_ID_MASK ) msg_buff.flags |= MSG_EXT; + /* has been dependent on "extended" option */ + /* Get slot */ if(canque_get_inslot4id(qends, &qedge, &slot, 0, msg_buff.id, 0) < 0) break; diff --git a/lincan/src/write_rtl.c b/lincan/src/write_rtl.c index a1d4647..70af511 100644 --- a/lincan/src/write_rtl.c +++ b/lincan/src/write_rtl.c @@ -47,8 +47,10 @@ ssize_t can_write_rtl_posix(struct rtl_file *fptr, const char *buffer, qends = canuser->qends; msg_flags=msg_buff->flags; - /* Automatic selection of extended format if "extended" set and ID>2047 */ - if (extended) if (msg_buff->id & ~0x7ffl ) msg_flags |= MSG_EXT; + + /* Automatic selection of extended format if ID>2047 */ + if (msg_buff->id & ~0x7ffl & MSG_ID_MASK ) msg_flags |= MSG_EXT; + /* has been dependent on "extended" option */ /* If the output buffer is full, return immediately in case O_NONBLOCK * has been specified or loop until space becomes available. @@ -82,8 +84,11 @@ ssize_t can_write_rtl_posix(struct rtl_file *fptr, const char *buffer, while (bytes_to_copy >= sizeof(struct canmsg_t)) { bytes_to_copy -= sizeof(struct canmsg_t); msg_flags=msg_buff->flags; - /* Automatic selection of extended format if "extended" set and ID>2047 */ - if (extended) if (msg_buff->id & ~0x7ffl ) msg_flags |= MSG_EXT; + + /* Automatic selection of extended format if ID>2047 */ + if (msg_buff->id & ~0x7ffl & MSG_ID_MASK ) msg_flags |= MSG_EXT; + /* has been dependent on "extended" option */ + /* Get slot */ if(canque_get_inslot4id(qends, &qedge, &slot, 0, msg_buff->id, 0) < 0) break; -- 2.39.2