From: Pavel Pisa Date: Wed, 14 May 2014 13:26:39 +0000 (+0200) Subject: Merge master into can-usb1 branch to include proc update for 3.12+ kernels. X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/commitdiff_plain/b29ebe97fb5acced24e8ce9bb30e5d4dcad58815?hp=074e90ee2a9a0a573bc987097650e9c1ec233337 Merge master into can-usb1 branch to include proc update for 3.12+ kernels. Signed-off-by: Pavel Pisa --- diff --git a/lincan/README b/lincan/README index 6d171ab..eee5842 100644 --- a/lincan/README +++ b/lincan/README @@ -161,14 +161,14 @@ whole OrtCAN tree. The latest version of stand-alone LinCAN sources can be obtained from GIT repository and build by next commands - git clone git://ortcan.git.sourceforge.net/gitroot/ortcan/lincan + git clone git://git.code.sf.net/p/ortcan/lincan cd lincan ./build-lincan.sh The other option is to build LinCAN driver as part of the whole OrtCAN tree - git clone git://ortcan.git.sourceforge.net/gitroot/ortcan/ortcan + git clone git://git.code.sf.net/p/ortcan/ortcan-top cd ortcan/ git submodule update --init make default-config @@ -199,24 +199,40 @@ INSTALLATION ============ Type 'make install' for standard make system compilation. The driver should be copied into actual kernel version -modules directory "/lib/modules/x.y.z/kernel/drivers/char". +modules directory "/lib/modules/x.y.z/extra". OMK system requires manual copy of files from "_compiled" tree -to its final destinations. +to its final destinations. Just compiled driver can be +tested directly from LinCAN build directory (i.e. example +for PC/104 PCM3680 board) -Create file "lincan.rules" with contents listed below in or linked -into "/etc/udev/rules.d" directory to enable automatic device nodes -creation for UDEV based system + insmod _compiled/modules/lincan.ko hw=pcm3680 io=0x200 irq=7,11 + +Driver can be copied into system final location after testing + + mkdir /lib/modules/$(uname -r)/extra + cp _compiled/modules/lincan.ko /lib/modules/$(uname -r)/extra + chown root:root /lib/modules/$(uname -r)/extra/lincan.ko + depmod -a + +Right to access the driver for non-root users can be granted by +generation of "10-lincan.rules" in the UDEV configuration directory +"/etc/udev/rules.d" # LinCAN driver SUBSYSTEM=="can",GROUP="users",MODE="0660" -The driver automatic loding can be requested by addition of "lincan" -line into "/etc/modules" od Debian based systems. +The driver automatic loading of the driver can be requested by addition +of "lincan" line into "/etc/modules" for Debian based systems. The module +parameters can be specified in the same file after "lincan" driver name +or in separate file in "/etc/modprobe.d" directory (i.e.) + + echo >/etc/modprobe.d/lincan.conf \ + options lincan processlocal=2 hw=pcm3680 io=0x200 irq=7,11 -The target hardware/board specific options should be added into -"/etc/modprobe.conf" file or file with similar functionality for your -distribution. The options are discusses in the next paragraph. +This files location can vary between distributions. +The LinCAN driver options are discusses in more details in +the next paragraph. LOADING ======= @@ -250,6 +266,7 @@ The hw argument can be one of: - gensja1000io for many sja1000 I/O mapped cards (PCAN-PC/104 for example). - gensja1000mm for ISA memory mapped sja1000 CAN cards (for pikronisa card used by PiKRON Ltd. the clockfreq=24000 has to be specified) +- pcisja1000mm for SJA1000 directly mapped into PCI mem region 0 - pimx1 for MX1_DIS1 extension board for PiMX1 ARM based BCC - msmcan for MICROSPACE IO space indexed i82527 - unican for Unicontrols PCAN card diff --git a/lincan/src/Makefile.omk b/lincan/src/Makefile.omk index 0d0c203..3756ffd 100644 --- a/lincan/src/Makefile.omk +++ b/lincan/src/Makefile.omk @@ -1,5 +1,5 @@ lincan_cards_NAMES = pip pccan smartcan nsi cc_can104 ems_cpcpci \ - pc_i03 pcm3680 aim104 m437 pcccan ssv bfadcan gensja1000io gensja1000mm eb8245 \ + pc_i03 pcm3680 aim104 m437 pcccan ssv bfadcan gensja1000io gensja1000mm pcisja1000mm eb8245 \ kv_pcican msmcan oscar adlink7841 pcan_pci esdpci200 unican usbcan virtual template lincan_morecards_NAMES = esdpci266 hms30c7202_can ns_dev_can ipci165 pimx1 tscan1 ts7kv nsi_canpci sh7760 mpc5200 diff --git a/lincan/src/Makefile.std b/lincan/src/Makefile.std index 49c4956..900cf91 100644 --- a/lincan/src/Makefile.std +++ b/lincan/src/Makefile.std @@ -63,7 +63,8 @@ endif SUPPORTED_CARDS = pip pccan smartcan nsi cc_can104 \ pc_i03 pcm3680 aim104 m437 pcccan ssv \ - bfadcan gensja1000mm gensja1000io kv_pcican msmcan virtual template \ + bfadcan gensja1000mm gensja1000io pcisja1000mm \ + kv_pcican msmcan virtual template \ unican unican_cl2 ems_cpcpci adlink7841 oscar \ pcan_pci esdpci200 # hms30c7202_can c_can c_can_irq tscan1 diff --git a/lincan/src/boardlist.c b/lincan/src/boardlist.c index 7623ea3..8cc67a0 100644 --- a/lincan/src/boardlist.c +++ b/lincan/src/boardlist.c @@ -57,6 +57,7 @@ extern int ssv_register(struct hwspecops_t *hwspecops); extern int bfadcan_register(struct hwspecops_t *hwspecops); extern int gensja1000mm_register(struct hwspecops_t *hwspecops); extern int gensja1000io_register(struct hwspecops_t *hwspecops); +extern int pcisja1000mm_register(struct hwspecops_t *hwspecops); extern int pimx1_register(struct hwspecops_t *hwspecops); extern int msmcan_register(struct hwspecops_t *hwspecops); extern int unican_register(struct hwspecops_t *hwspecops); @@ -146,6 +147,9 @@ const struct boardtype_t can_boardtypes[]={ #ifdef CONFIG_OC_LINCAN_CARD_gensja1000io {"gensja1000io", gensja1000io_register, 1}, #endif + #ifdef CONFIG_OC_LINCAN_CARD_pcisja1000mm + {"pcisja1000mm", pcisja1000mm_register, 0}, + #endif #ifdef CONFIG_OC_LINCAN_CARD_pimx1 {"pimx1", pimx1_register, 0}, #endif diff --git a/lincan/src/pcisja1000mm.c b/lincan/src/pcisja1000mm.c new file mode 100644 index 0000000..2f8a9ec --- /dev/null +++ b/lincan/src/pcisja1000mm.c @@ -0,0 +1,280 @@ +/**************************************************************************/ +/* File: pcisja1000mm.c - SJA1000 directly mapped into PCI mem region 0 */ +/* */ +/* 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/sja1000p.h" + +#ifdef CAN_ENABLE_PCI_SUPPORT + +#define DIRECT_PCISJA100_VENDOR 0x1b36 +#define DIRECT_PCISJA100_ID 0xbeef + +#define PCISJA1000MM_OCR_DEFAULT_STD 0xDA + +#define PCISJA1000MM_BYTES_PER_CIRCUIT 0x80 + +void pcisja1000mm_disconnect_irq(struct candevice_t *candev) +{ +} + +void pcisja1000mm_connect_irq(struct candevice_t *candev) +{ +} + +int pcisja1000mm_request_io(struct candevice_t *candev) +{ + unsigned long io_addr; + int i; + + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) + if(pci_request_region(candev->sysdevptr.pcidev, 0, "pcisja1000mm") != 0){ + CANMSG("Request of pcisja1000mm range failed\n"); + return -ENODEV; + } + #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ + if(pci_request_regions(candev->sysdevptr.pcidev, "pcisja1000mm") != 0){ + CANMSG("Request of pcisja1000mm regions failed\n"); + return -ENODEV; + } + #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ + + io_addr=pci_resource_start(candev->sysdevptr.pcidev,0);; + if (!(candev->dev_base_addr = ioremap(io_addr, + pci_resource_len(candev->sysdevptr.pcidev,0)))) { + CANMSG("Unable to access I/O memory at: 0x%lx\n", io_addr); + goto error_ioremap_io; + } + + candev->io_addr=io_addr; + + /* + * this is redundant with chip initialization, but remap address + * can change when resources are temporarily released + */ + for(i=0;inr_all_chips;i++) { + struct canchip_t *chip=candev->chip[i]; + if(!chip) continue; + chip->chip_base_addr = candev->dev_base_addr + + i * PCISJA1000MM_BYTES_PER_CIRCUIT; + if(!chip->msgobj[0]) continue; + chip->msgobj[0]->obj_base_addr=chip->chip_base_addr; + } + + pcisja1000mm_disconnect_irq(candev); + + return 0; + +error_ioremap_io: + #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 -ENODEV; +} + +int pcisja1000mm_release_io(struct candevice_t *candev) +{ + pcisja1000mm_disconnect_irq(candev); + + iounmap(candev->dev_base_addr); + + #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; +} + + +void pcisja1000mm_write_register(unsigned data, can_ioptr_t address) +{ + can_writeb(data,address); +} + +unsigned pcisja1000mm_read_register(can_ioptr_t address) +{ + return can_readb(address); +} + +int pcisja1000mm_reset(struct candevice_t *candev) +{ + int i=0,chip_nr; + struct canchip_t *chip; + unsigned cdr; + + DEBUGMSG("Resetting pcisja1000mm hardware ...\n"); + + pcisja1000mm_disconnect_irq(candev); + + for(chip_nr=0;chip_nrnr_all_chips;chip_nr++){ + if(!candev->chip[chip_nr]) continue; + chip=candev->chip[chip_nr]; + + pcisja1000mm_write_register(sjaMOD_RM, chip->chip_base_addr+SJAMOD); + udelay(1000); + + cdr=pcisja1000mm_read_register(chip->chip_base_addr+SJACDR); + pcisja1000mm_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR); + + pcisja1000mm_write_register(0, chip->chip_base_addr+SJAIER); + + i=20; + pcisja1000mm_write_register(0, chip->chip_base_addr+SJAMOD); + while (pcisja1000mm_read_register(chip->chip_base_addr+SJAMOD)&sjaMOD_RM){ + if(!i--) return -ENODEV; + udelay(1000); + pcisja1000mm_write_register(0, chip->chip_base_addr+SJAMOD); + } + + cdr=pcisja1000mm_read_register(chip->chip_base_addr+SJACDR); + pcisja1000mm_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR); + + pcisja1000mm_write_register(0, chip->chip_base_addr+SJAIER); + + pcisja1000mm_read_register(chip->chip_base_addr+SJAIR); + } + + + pcisja1000mm_connect_irq(candev); + + return 0; +} + +int pcisja1000mm_init_hw_data(struct candevice_t *candev) +{ + struct pci_dev *pcidev; + int i; + + pcidev = can_pci_get_next_untaken_device(DIRECT_PCISJA100_VENDOR, DIRECT_PCISJA100_ID); + if(pcidev == NULL) + return -ENODEV; + + if (pci_enable_device (pcidev)){ + printk(KERN_CRIT "Setup of PCISJA1000MM failed\n"); + can_pci_dev_put(pcidev); + return -EIO; + } + candev->sysdevptr.pcidev=pcidev; + + for(i=0;i<1;i++){ + + if(!(pci_resource_flags(pcidev,0)&IORESOURCE_MEM)){ + printk(KERN_ERR "PCISJA1000MM region %d is not memory\n",i); + goto error_ret; + } + } + candev->io_addr=pci_resource_start(pcidev,0); /*IO window for SJA1000 chips*/ + candev->dev_base_addr=can_ulong2ioptr(candev->io_addr); + candev->res_addr=0; + + /*candev->flags |= CANDEV_PROGRAMMABLE_IRQ;*/ + + candev->nr_82527_chips=0; + candev->nr_sja1000_chips=1; + candev->nr_all_chips=1; + + return 0; + +error_ret: + + printk(KERN_CRIT "Setup of PCISJA1000MM failed\n"); + pci_disable_device (pcidev); + can_pci_dev_put(pcidev); + return -EIO; +} + +void pcisja1000mm_done_hw_data(struct candevice_t *candev) +{ + struct pci_dev *pcidev = candev->sysdevptr.pcidev; + can_pci_dev_put(pcidev); +} + +int pcisja1000mm_init_chip_data(struct candevice_t *candev, int chipnr) +{ + + if(candev->sysdevptr.pcidev==NULL) + return -ENODEV; + + candev->chip[chipnr]->chip_irq=candev->sysdevptr.pcidev->irq; + + sja1000p_fill_chipspecops(candev->chip[chipnr]); + candev->chip[chipnr]->chip_base_addr= + can_ioport2ioptr(candev->io_addr+chipnr*PCISJA1000MM_BYTES_PER_CIRCUIT); + + candev->chip[chipnr]->flags = 0; + candev->chip[chipnr]->int_cpu_reg = 0; + candev->chip[chipnr]->int_clk_reg = 0; + candev->chip[chipnr]->int_bus_reg = 0; + candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF; + candev->chip[chipnr]->sja_ocr_reg = PCISJA1000MM_OCR_DEFAULT_STD; + candev->chip[chipnr]->clock = 16000000; + candev->chip[chipnr]->flags |= CHIP_IRQ_PCI; + + return 0; +} + +int pcisja1000mm_init_obj_data(struct canchip_t *chip, int objnr) +{ + chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr; + return 0; +} + +int pcisja1000mm_program_irq(struct candevice_t *candev) +{ + + return 0; +} + +int pcisja1000mm_register(struct hwspecops_t *hwspecops) +{ + hwspecops->request_io = pcisja1000mm_request_io; + hwspecops->release_io = pcisja1000mm_release_io; + hwspecops->reset = pcisja1000mm_reset; + hwspecops->init_hw_data = pcisja1000mm_init_hw_data; + hwspecops->done_hw_data = pcisja1000mm_done_hw_data; + hwspecops->init_chip_data = pcisja1000mm_init_chip_data; + hwspecops->init_obj_data = pcisja1000mm_init_obj_data; + hwspecops->write_register = pcisja1000mm_write_register; + hwspecops->read_register = pcisja1000mm_read_register; + hwspecops->program_irq = pcisja1000mm_program_irq; + return 0; +} + + +#endif /*CAN_ENABLE_PCI_SUPPORT*/ diff --git a/lincan/src/proc.c b/lincan/src/proc.c index aaab028..b9d3419 100644 --- a/lincan/src/proc.c +++ b/lincan/src/proc.c @@ -64,10 +64,130 @@ static struct canproc_t can_proc_base; static struct canproc_t *base=&can_proc_base; DEFINE_MUTEX(proc_mutex); /* synchronize access to canproc_t array */ -/* The following functions are needed only for kernel version 2.2. Kernel - * version 2.4 already defines them for us. - */ -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) + +#include + +#define CAN_PROC_SHOW_SINGLE_OPS_DECLARE(ops_name, show_function) \ +static int ops_name##_open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, show_function, PDE_DATA(inode)); \ +} \ +static const struct file_operations ops_name = { \ + .owner = THIS_MODULE, \ + .open = ops_name##_open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ +}; + +typedef struct file_operations can_proc_read_entry_ops_t; +typedef struct seq_file can_proc_seq_file_t; + +static inline void *can_seq_data(can_proc_seq_file_t *sqf) +{ + return sqf->private; +} + +#define can_seq_printf seq_printf + +struct proc_dir_entry *can_create_proc_read_entry(const char *name, + mode_t mode, struct proc_dir_entry *parent, + const can_proc_read_entry_ops_t *proc_read_entry_ops, void * data) +{ + return proc_create_data(name, mode, parent, proc_read_entry_ops, data); +} + +struct proc_dir_entry *can_proc_mkdir_mode(const char *name, umode_t mode, + struct proc_dir_entry *parent) +{ + return proc_mkdir_mode(name, mode, parent); +} + +static int can_proc_remove(struct proc_dir_entry *del) +{ + if(!del) return -ENODEV; + proc_remove(del); + return 0; +} + +static inline struct proc_dir_entry *can_proc_symlink(const char *name, + struct proc_dir_entry *parent, const char *dest) +{ + return proc_symlink(name, parent, dest); +} + +#else /* kernel older than 3.10 */ + +typedef read_proc_t *can_proc_read_entry_ops_t; +typedef struct { + int len; + int limit; + char *buf; + void *private; +} can_proc_seq_file_t; + +#define CAN_PROC_SHOW_SINGLE_OPS_DECLARE(ops_name, show_function) \ +static int ops_name##_show_wrapper(char *buf, char **start, off_t offset, \ + int count, int *eof, void *data) \ +{ \ + can_proc_seq_file_t seq_pos = { .len = 0, .buf = buf, .limit = PAGE_SIZE, \ + .private = data}; \ + *eof = 1; \ + show_function(&seq_pos, data); \ + return seq_pos.len; \ +} \ +const static can_proc_read_entry_ops_t ops_name = ops_name##_show_wrapper; + +static inline void *can_seq_data(can_proc_seq_file_t *sqf) +{ + return sqf->private; +} + +static inline int can_seq_printf(can_proc_seq_file_t *sqf, const char *f, ...) +{ + int ret; + va_list args; + va_start(args, f); + ret = vsnprintf(sqf->buf + sqf->len, sqf->limit - sqf->len, f, args); + sqf->len += ret; + if (sqf->len > sqf->limit) + sqf->len = sqf->limit; + va_end(args); + return ret; +} + +struct proc_dir_entry *can_create_proc_read_entry(const char *name, + mode_t mode, struct proc_dir_entry *parent, + const can_proc_read_entry_ops_t *proc_read_entry_ops, void * data) +{ + return create_proc_read_entry(name, mode, parent, *proc_read_entry_ops, data); +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)) + +struct proc_dir_entry *can_proc_mkdir_mode(const char *name, umode_t mode, + struct proc_dir_entry *parent) +{ + return create_proc_entry(name, S_IFDIR | mode, parent); +} + +/* This does not fully follow linux 2.4 and 2.6 prototype to simplify 2.2.x compatibility */ +/* The newer kernels use entry name instead of pointer to the entry */ +static int can_proc_remove(struct proc_dir_entry *del) +{ + if(!del) return -ENODEV; + remove_proc_entry(del->name, del->parent); + return 0; +} + +static inline struct proc_dir_entry *can_proc_symlink(const char *name, + struct proc_dir_entry *parent, const char *dest) +{ + return proc_symlink(name, parent, dest); +} + +#else /* ancient Linux kernel older than 2.3.0 */ static void can_fill_inode(struct inode *inode, int fill) { if (fill) @@ -114,10 +234,23 @@ static struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mo return new_entry; } -static int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent) +struct proc_dir_entry *can_create_proc_read_entry(const char *name, + mode_t mode, struct proc_dir_entry *parent, + read_proc_t *read_proc, void * data) +{ + return create_proc_read_entry(name, mode, parent, read_proc, data); +} + +struct proc_dir_entry *can_proc_mkdir_mode(const char *name, umode_t mode, + struct proc_dir_entry *parent) +{ + return can_create_proc_entry(name, S_IFDIR | mode, parent); +} + +static int can_proc_remove(struct proc_dir_entry *del) { if (del != NULL) { - proc_unregister(parent, del->low_ino); + proc_unregister(del->parent, del->low_ino); can_checked_free(del); return 0; } @@ -150,31 +283,9 @@ static inline struct proc_dir_entry *can_proc_symlink(const char *name, return entry; } -#else /* Functions forwarded for kernel 2.4 and above */ - -static inline struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mode, - struct proc_dir_entry *parent) -{ - return create_proc_entry(name, mode, parent); -} - +#endif /* Linux 2.2 - 2.3 kernels */ -/* This does not fully follow linux 2.4 and 2.6 prototype to simplify 2.2.x compatibility */ -/* The newer kernels use entry name instead of pointer to the entry */ -static int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent) -{ - if(!del) return -ENODEV; - remove_proc_entry(del->name,parent); - return 0; -} - -static inline struct proc_dir_entry *can_proc_symlink(const char *name, - struct proc_dir_entry *parent, const char *dest) -{ - return proc_symlink(name, parent, dest); -} - -#endif /* Functions required for kernel 2.2 */ +#endif /* Linux kernel 3.6 and 3.10+ */ /* can_init_procdir registers the entire CAN directory tree recursively at * the proc system. @@ -186,7 +297,7 @@ int can_init_procdir(void) mutex_init(&proc_mutex); - base->can_proc_entry = can_create_proc_entry("can", S_IFDIR | S_IRUGO | + base->can_proc_entry = can_proc_mkdir_mode("can", S_IFDIR | S_IRUGO | S_IXUGO, CAN_PROC_ROOT); if (base->can_proc_entry == NULL) return -ENODEV; @@ -217,7 +328,7 @@ int can_delete_procdir(void) if (remove_channels_from_procdir()) return -ENODEV; /* name: "can" */ - if (can_remove_proc_entry(base->can_proc_entry, CAN_PROC_ROOT)) + if (can_proc_remove(base->can_proc_entry)) return -ENODEV; return 0; @@ -232,24 +343,21 @@ int can_delete_procentry(struct candevice_t *candev) return 0; } -static int can_chip_procinfo(char *buf, char **start, off_t offset, - int count, int *eof, void *data) +static int can_chip_procinfo_show(can_proc_seq_file_t *sqf, void *data) { - struct canchip_t *chip=data; - int len=0; + struct canchip_t *chip=can_seq_data(sqf); /* Generic chip info */ - len += sprintf(buf+len,"type : %s\n",chip->chip_type); - len += sprintf(buf+len,"index : %d\n",chip->chip_idx); - len += sprintf(buf+len,"irq : %d\n",chip->chip_irq); - len += sprintf(buf+len,"addr : %lu\n", + can_seq_printf(sqf, "type : %s\n",chip->chip_type); + can_seq_printf(sqf, "index : %d\n",chip->chip_idx); + can_seq_printf(sqf, "irq : %d\n",chip->chip_irq); + can_seq_printf(sqf, "addr : %lu\n", can_ioptr2ulong(chip->chip_base_addr)); - len += sprintf(buf+len,"config : %s\n", + can_seq_printf(sqf, "config : %s\n", (chip->flags & CHIP_CONFIGURED) ? "yes":"no"); - len += sprintf(buf+len,"clock : %ld Hz\n",chip->clock); - len += sprintf(buf+len,"baud : %ld\n",chip->baudrate); - len += sprintf(buf+len,"num obj : %d\n",chip->max_objects); - + can_seq_printf(sqf, "clock : %ld Hz\n",chip->clock); + can_seq_printf(sqf, "baud : %ld\n",chip->baudrate); + can_seq_printf(sqf, "num obj : %d\n",chip->max_objects); #if 0 /* Chip specific info if available */ @@ -257,10 +365,10 @@ static int can_chip_procinfo(char *buf, char **start, off_t offset, len += (chip->chipspecops->get_info)(chip,buf+len); #endif - *eof = 1; - return len; + return 0; } +CAN_PROC_SHOW_SINGLE_OPS_DECLARE(can_chip_procinfo_ops, can_chip_procinfo_show); int add_channel_to_procdir(struct candevice_t *candev) { @@ -280,7 +388,7 @@ int add_channel_to_procdir(struct candevice_t *candev) sprintf(base->channel[i]->ch_name, "channel%d",i); - base->channel[i]->ch_entry = can_create_proc_entry( + base->channel[i]->ch_entry = can_proc_mkdir_mode( base->channel[i]->ch_name, S_IFDIR | S_IRUGO |S_IXUGO, base->can_proc_entry); @@ -292,10 +400,10 @@ int add_channel_to_procdir(struct candevice_t *candev) add_object_to_procdir(i); - create_proc_read_entry("chip_info", /* proc entry name */ + can_create_proc_read_entry("chip_info", /* proc entry name */ 0, /* protection mask, 0->default */ base->channel[i]->ch_entry, /* parent dir, NULL->/proc */ - can_chip_procinfo, + &can_chip_procinfo_ops, chips_p[i]); cc++; } @@ -324,8 +432,7 @@ int remove_channels_from_procdir(void) } /* name: base->channel[cc]->ch_name */ - if (can_remove_proc_entry(base->channel[i]->ch_entry, - base->can_proc_entry)){ + if (can_proc_remove(base->channel[i]->ch_entry)){ mutex_unlock(&proc_mutex); return -ENODEV; } @@ -356,8 +463,7 @@ int remove_channel_from_procdir(struct candevice_t *candev) } /* name: base->channel[cc]->ch_name */ - if (can_remove_proc_entry(base->channel[i]->ch_entry, - base->can_proc_entry)){ + if (can_proc_remove(base->channel[i]->ch_entry)){ mutex_unlock(&proc_mutex); return -ENODEV; } @@ -389,7 +495,7 @@ int add_object_to_procdir(int chip_nr) sprintf(base->channel[chip_nr]->object[i]->obj_name,"object%d",i); sprintf(base->channel[chip_nr]->object[i]->lnk_name,"dev"); - base->channel[chip_nr]->object[i]->obj_entry = can_create_proc_entry( + base->channel[chip_nr]->object[i]->obj_entry = can_proc_mkdir_mode( base->channel[chip_nr]->object[i]->obj_name, S_IFDIR | S_IRUGO | S_IXUGO, base->channel[chip_nr]->ch_entry); @@ -420,13 +526,10 @@ int remove_object_from_procdir(int chip_nr) if(!base->channel[chip_nr]->object[i]) continue; /* name: base->channel[chip_nr]->object[i]->lnk_name */ - if (can_remove_proc_entry( base->channel[chip_nr]->object[i]->lnk, - base->channel[chip_nr]->object[i]->obj_entry)) + if (can_proc_remove( base->channel[chip_nr]->object[i]->lnk)) return -ENODEV; /* name: base->channel[chip_nr]->object[i]->obj_name */ - if (can_remove_proc_entry( - base->channel[chip_nr]->object[i]->obj_entry, - base->channel[chip_nr]->ch_entry)) + if (can_proc_remove(base->channel[chip_nr]->object[i]->obj_entry)) return -ENODEV; can_checked_free(base->channel[chip_nr]->object[i]);