Will be tested, when I get to the hardware at school.
/*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 <linux/malloc.h>
struct canhardware_t *hosthardware_p;
union {
+ void *anydev;
#ifdef CAN_ENABLE_PCI_SUPPORT
struct pci_dev *pcidev;
#endif /*CAN_ENABLE_PCI_SUPPORT*/
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*/
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
#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}
};
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");
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;
}
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
#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)
{
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*/
/* 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.
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;
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.
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;