Merge master into can-usb1 branch to include proc update for 3.12+ kernels.
authorPavel Pisa <pisa@cmp.felk.cvut.cz>
Wed, 14 May 2014 13:26:39 +0000 (15:26 +0200)
committerPavel Pisa <pisa@cmp.felk.cvut.cz>
Wed, 14 May 2014 13:26:39 +0000 (15:26 +0200)
Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
1  2 
lincan/src/Makefile.omk
lincan/src/proc.c

@@@ -1,6 -1,6 +1,6 @@@
  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 virtual template
 +              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
  
@@@ -62,12 -60,131 +62,132 @@@ static int cc=0; /* static counter for 
  
  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 <linux/seq_file.h>
+ #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)
@@@ -183,10 -291,7 +294,10 @@@ int can_init_procdir(void
  {
        int board;
        struct candevice_t *candev;
-       base->can_proc_entry = can_create_proc_entry("can", S_IFDIR | S_IRUGO |
 +
 +      mutex_init(&proc_mutex);
 +
+       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;
@@@ -214,42 -307,30 +325,39 @@@ int can_init_procentry(int board
  /* can_delete_procdir removes the entire CAN tree from the proc system */
  int can_delete_procdir(void)
  {
 -      if (remove_channel_from_procdir())
 +      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;
  }
  
- static int can_chip_procinfo(char *buf, char **start, off_t offset,
-                int count, int *eof, void *data)
 +/* can_delete_procentry removes device entries from CAN tree in the proc system */
 +int can_delete_procentry(struct candevice_t *candev)
 +{
 +      if (remove_channel_from_procdir(candev))
 +              return -ENODEV;
 +
 +      return 0;
 +}
 +
+ 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 */
@@@ -266,108 -347,57 +374,106 @@@ int add_channel_to_procdir(struct cande
  {
        int i=0;
  
 -      for (i=0; i < candev->nr_all_chips; i++) {
 +      mutex_lock(&proc_mutex);
 +      for (i=0; i < MAX_TOT_CHIPS; i++){
 +              if (!chips_p[i]) continue;
 +              if (chips_p[i]->hostdevice != candev) continue;
  
 -              base->channel[cc] = (struct channelproc_t *)
 +              base->channel[i] = (struct channelproc_t *)
                        can_checked_malloc(sizeof(struct channelproc_t));
 -              if (base->channel[cc] == NULL)
 +              if (base->channel[i] == NULL){
 +                      mutex_unlock(&proc_mutex);
                        return -ENOMEM;
 +              }
  
 -              sprintf(base->channel[cc]->ch_name, "channel%d",cc);
 +              sprintf(base->channel[i]->ch_name, "channel%d",i);
  
-               base->channel[i]->ch_entry = can_create_proc_entry(
 -              base->channel[cc]->ch_entry = can_proc_mkdir_mode(
 -                                              base->channel[cc]->ch_name,
++              base->channel[i]->ch_entry = can_proc_mkdir_mode(
 +                                              base->channel[i]->ch_name,
                                                S_IFDIR | S_IRUGO |S_IXUGO,
                                                base->can_proc_entry);
  
 -              if (base->channel[cc]->ch_entry == NULL)
 +              if (base->channel[i]->ch_entry == NULL){
 +                      mutex_unlock(&proc_mutex);
                        return -ENODEV;
 +              }
  
 -              add_object_to_procdir(cc);
 +              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[cc]->ch_entry,  /* parent dir, NULL->/proc */
 +                                     base->channel[i]->ch_entry,  /* parent dir, NULL->/proc */
-                                      can_chip_procinfo,
+                                      &can_chip_procinfo_ops,
 -                                     candev->chip[i]);
 -
 +                                     chips_p[i]);
                cc++;
        }
 +      mutex_unlock(&proc_mutex);
  
        return 0;
  }
  
 -int remove_channel_from_procdir(void)
 +int remove_channels_from_procdir(void)
  {
 +      int i=0;
 +
 +      mutex_lock(&proc_mutex);
 +      for (i=0; i < MAX_TOT_CHIPS; i++){
 +              if (!chips_p[i]) continue;
  
 -      while (cc != 0) {
                cc--;
  
 -              if(!base->channel[cc]) continue;
 +              if(!base->channel[i]) continue;
  
 -              remove_proc_entry("chip_info", base->channel[cc]->ch_entry);
 +              remove_proc_entry("chip_info", base->channel[i]->ch_entry);
  
 -              if (remove_object_from_procdir(cc))
 +              if (remove_object_from_procdir(i)){
 +                      mutex_unlock(&proc_mutex);
                        return -ENODEV;
 +              }
  
                /* 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[cc]->ch_entry))
++              if (can_proc_remove(base->channel[i]->ch_entry)){
 +                      mutex_unlock(&proc_mutex);
                        return -ENODEV;
 +              }
  
 -              can_checked_free(base->channel[cc]);
 -              base->channel[cc] = NULL;
 +              can_checked_free(base->channel[i]);
 +              base->channel[i] = NULL;
 +      }
 +      mutex_unlock(&proc_mutex);
 +
 +      return 0;
 +}
 +
 +int remove_channel_from_procdir(struct candevice_t *candev)
 +{
 +      int i=0,j=0;
 +
 +      mutex_lock(&proc_mutex);
 +      for (i=0; i < MAX_TOT_CHIPS; i++){
 +              if (!chips_p[i]) continue;
 +              if (chips_p[i]->hostdevice != candev) continue;
 +              if (!base->channel[i]) continue;
 +
 +              remove_proc_entry("chip_info", base->channel[i]->ch_entry);
 +
 +              if (remove_object_from_procdir(i)){
 +                      mutex_unlock(&proc_mutex);
 +                      return -ENODEV;
 +              }
 +
 +              /* 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;
 +              }
 +
 +              can_checked_free(base->channel[i]);
 +              base->channel[i] = NULL;
 +
 +              cc--;
        }
 +      mutex_unlock(&proc_mutex);
  
        return 0;
  }