/* * Copyright (C) 2006 Wolfgang Grandegger * * Derived from RTnet project file stack/rtcan_module.c: * * Copyright (C) 2002 Ulrich Marx * 2003-2006 Jan Kiszka * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include #include MODULE_LICENSE("GPL"); const char rtcan_rtdm_provider_name[] = "(C) 2006 RT-Socket-CAN Development Team"; #ifdef CONFIG_PROC_FS struct proc_dir_entry *rtcan_proc_root; static void rtcan_dev_get_ctrlmode_name(can_ctrlmode_t ctrlmode, char* name, int max_len) { snprintf(name, max_len, "%s%s", ctrlmode & CAN_CTRLMODE_LISTENONLY ? "listen-only " : "", ctrlmode & CAN_CTRLMODE_LOOPBACK ? "loopback " : ""); } static char *rtcan_state_names[] = { "active", "warning", "passive" , "bus-off", "scanning", "stopped", "sleeping" }; static void rtcan_dev_get_state_name(can_state_t state, char* name, int max_len) { if (state >= CAN_STATE_ACTIVE && state <= CAN_STATE_SLEEPING) strncpy(name, rtcan_state_names[state], max_len); else strncpy(name, "unknown", max_len); } static void rtcan_dev_get_baudrate_name(can_baudrate_t baudrate, char* name, int max_len) { switch (baudrate) { case CAN_BAUDRATE_UNCONFIGURED: strncpy(name, "undefined", max_len); break; case CAN_BAUDRATE_UNKNOWN: strncpy(name, "unknown", max_len); break; default: ksformat(name, max_len, "%d", baudrate); break; } } static void rtcan_dev_get_bittime_name(struct can_bittime *bit_time, char* name, int max_len) { switch (bit_time->type) { case CAN_BITTIME_STD: ksformat(name, max_len, "brp=%d prop_seg=%d phase_seg1=%d " "phase_seg2=%d sjw=%d sam=%d", bit_time->std.brp, bit_time->std.prop_seg, bit_time->std.phase_seg1, bit_time->std.phase_seg2, bit_time->std.sjw, bit_time->std.sam); break; case CAN_BITTIME_BTR: ksformat(name, max_len, "btr0=0x%02x btr1=0x%02x", bit_time->btr.btr0, bit_time->btr.btr1); break; default: strncpy(name, "unknown", max_len); break; } } static void rtcan_get_timeout_name(nanosecs_rel_t timeout, char* name, int max_len) { if (timeout == RTDM_TIMEOUT_INFINITE) strncpy(name, "infinite", max_len); else ksformat(name, max_len, "%lld", (long long)timeout); } static int rtcan_read_proc_devices(struct seq_file *p, void *data) { int i; struct rtcan_device *dev; char state_name[20], baudrate_name[20]; if (down_interruptible(&rtcan_devices_nrt_lock)) return -ERESTARTSYS; /* Name___________ _Baudrate State___ _TX_Counts _TX_Counts ____Errors * rtcan0 125000 stopped 1234567890 1234567890 1234567890 * rtcan1 undefined warning 1234567890 1234567890 1234567890 * rtcan2 undefined scanning 1234567890 1234567890 1234567890 */ seq_printf(p, "Name___________ _Baudrate State___ TX_Counter RX_Counter " "____Errors\n"); for (i = 1; i <= RTCAN_MAX_DEVICES; i++) { if ((dev = rtcan_dev_get_by_index(i)) != NULL) { rtcan_dev_get_state_name(dev->state, state_name, sizeof(state_name)); rtcan_dev_get_baudrate_name(dev->baudrate, baudrate_name, sizeof(baudrate_name)); seq_printf(p, "%-15s %9s %-8s %10d %10d %10d\n", dev->name, baudrate_name, state_name, dev->tx_count, dev->rx_count, dev->err_count); rtcan_dev_dereference(dev); } } up(&rtcan_devices_nrt_lock); return 0; } static int rtcan_proc_devices_open(struct inode *inode, struct file *file) { return single_open(file, rtcan_read_proc_devices, NULL); } static const DEFINE_PROC_OPS(rtcan_proc_devices_ops, rtcan_proc_devices_open, single_release, seq_read, NULL); static int rtcan_read_proc_sockets(struct seq_file *p, void *data) { struct rtcan_socket *sock; struct rtdm_fd *fd; struct rtcan_device *dev; char name[IFNAMSIZ] = "not-bound"; char rx_timeout[20], tx_timeout[20]; rtdm_lockctx_t lock_ctx; int ifindex; if (down_interruptible(&rtcan_devices_nrt_lock)) return -ERESTARTSYS; /* Name___________ Filter ErrMask RX_Timeout TX_Timeout RX_BufFull TX_Lo * rtcan0 1 0x00010 1234567890 1234567890 1234567890 12345 */ seq_printf(p, "Name___________ Filter ErrMask RX_Timeout_ns " "TX_Timeout_ns RX_BufFull TX_Lo\n"); rtdm_lock_get_irqsave(&rtcan_recv_list_lock, lock_ctx); list_for_each_entry(sock, &rtcan_socket_list, socket_list) { fd = rtcan_socket_to_fd(sock); if (rtcan_sock_is_bound(sock)) { ifindex = atomic_read(&sock->ifindex); if (ifindex) { dev = rtcan_dev_get_by_index(ifindex); if (dev) { strncpy(name, dev->name, IFNAMSIZ); rtcan_dev_dereference(dev); } } else ksformat(name, sizeof(name), "%d", ifindex); } rtcan_get_timeout_name(sock->tx_timeout, tx_timeout, sizeof(tx_timeout)); rtcan_get_timeout_name(sock->rx_timeout, rx_timeout, sizeof(rx_timeout)); seq_printf(p, "%-15s %6d 0x%05x %13s %13s %10d %5d\n", name, sock->flistlen, sock->err_mask, rx_timeout, tx_timeout, sock->rx_buf_full, rtcan_loopback_enabled(sock)); } rtdm_lock_put_irqrestore(&rtcan_recv_list_lock, lock_ctx); up(&rtcan_devices_nrt_lock); return 0; } static int rtcan_proc_sockets_open(struct inode *inode, struct file *file) { return single_open(file, rtcan_read_proc_sockets, NULL); } static const DEFINE_PROC_OPS(rtcan_proc_sockets_ops, rtcan_proc_sockets_open, single_release, seq_read, NULL); static int rtcan_read_proc_info(struct seq_file *p, void *data) { struct rtcan_device *dev = p->private; char state_name[20], baudrate_name[20]; char ctrlmode_name[80], bittime_name[80]; if (down_interruptible(&rtcan_devices_nrt_lock)) return -ERESTARTSYS; rtcan_dev_get_state_name(dev->state, state_name, sizeof(state_name)); rtcan_dev_get_ctrlmode_name(dev->ctrl_mode, ctrlmode_name, sizeof(ctrlmode_name)); rtcan_dev_get_baudrate_name(dev->baudrate, baudrate_name, sizeof(baudrate_name)); rtcan_dev_get_bittime_name(&dev->bit_time, bittime_name, sizeof(bittime_name)); seq_printf(p, "Device %s\n", dev->name); seq_printf(p, "Controller %s\n", dev->ctrl_name); seq_printf(p, "Board %s\n", dev->board_name); seq_printf(p, "Clock-Hz %d\n", dev->can_sys_clock); seq_printf(p, "Baudrate %s\n", baudrate_name); seq_printf(p, "Bit-time %s\n", bittime_name); seq_printf(p, "Ctrl-Mode %s\n", ctrlmode_name); seq_printf(p, "State %s\n", state_name); seq_printf(p, "TX-Counter %d\n", dev->tx_count); seq_printf(p, "RX-Counter %d\n", dev->rx_count); seq_printf(p, "Errors %d\n", dev->err_count); #ifdef RTCAN_USE_REFCOUNT seq_printf(p, "Refcount %d\n", atomic_read(&dev->refcount)); #endif up(&rtcan_devices_nrt_lock); return 0; } static int rtcan_proc_info_open(struct inode *inode, struct file *file) { return single_open(file, rtcan_read_proc_info, pde_data(inode)); } static const DEFINE_PROC_OPS(rtcan_proc_info_ops, rtcan_proc_info_open, single_release, seq_read, NULL); static int rtcan_read_proc_filter(struct seq_file *p, void *data) { struct rtcan_device *dev = p->private; struct rtcan_recv *recv_listener = dev->recv_list; struct rtdm_fd *fd; rtdm_lockctx_t lock_ctx; /* __CAN_ID__ _CAN_Mask_ Inv MatchCount * 0x12345678 0x12345678 no 1234567890 */ seq_printf(p, "__CAN_ID__ _CAN_Mask_ Inv MatchCount\n"); rtdm_lock_get_irqsave(&rtcan_recv_list_lock, lock_ctx); /* Loop over the reception list of the device */ while (recv_listener != NULL) { fd = rtcan_socket_to_fd(recv_listener->sock); seq_printf(p, "0x%08x 0x%08x %s %10d\n", recv_listener->can_filter.can_id, recv_listener->can_filter.can_mask & ~CAN_INV_FILTER, (recv_listener->can_filter.can_mask & CAN_INV_FILTER) ? "yes" : " no", recv_listener->match_count); recv_listener = recv_listener->next; } rtdm_lock_put_irqrestore(&rtcan_recv_list_lock, lock_ctx); return 0; } static int rtcan_proc_filter_open(struct inode *inode, struct file *file) { return single_open(file, rtcan_read_proc_filter, pde_data(inode)); } static const DEFINE_PROC_OPS(rtcan_proc_filter_ops, rtcan_proc_filter_open, single_release, seq_read, NULL); static int rtcan_read_proc_version(struct seq_file *p, void *data) { seq_printf(p, "RT-Socket-CAN %d.%d.%d\n", RTCAN_MAJOR_VER, RTCAN_MINOR_VER, RTCAN_BUGFIX_VER); return 0; } static int rtcan_proc_version_open(struct inode *inode, struct file *file) { return single_open(file, rtcan_read_proc_version, NULL); } static const DEFINE_PROC_OPS(rtcan_proc_version_ops, rtcan_proc_version_open, single_release, seq_read, NULL); void rtcan_dev_remove_proc(struct rtcan_device* dev) { if (!dev->proc_root) return; remove_proc_entry("info", dev->proc_root); remove_proc_entry("filters", dev->proc_root); remove_proc_entry(dev->name, rtcan_proc_root); dev->proc_root = NULL; } int rtcan_dev_create_proc(struct rtcan_device* dev) { if (!rtcan_proc_root) return -EINVAL; dev->proc_root = proc_mkdir(dev->name, rtcan_proc_root); if (!dev->proc_root) { printk("%s: unable to create /proc device entries\n", dev->name); return -1; } proc_create_data("info", S_IFREG | S_IRUGO | S_IWUSR, dev->proc_root, &rtcan_proc_info_ops, dev); proc_create_data("filters", S_IFREG | S_IRUGO | S_IWUSR, dev->proc_root, &rtcan_proc_filter_ops, dev); return 0; } static int rtcan_proc_register(void) { rtcan_proc_root = proc_mkdir("rtcan", NULL); if (!rtcan_proc_root) { printk("rtcan: unable to initialize /proc entries\n"); return -1; } proc_create("devices", S_IFREG | S_IRUGO | S_IWUSR, rtcan_proc_root, &rtcan_proc_devices_ops); proc_create("version", S_IFREG | S_IRUGO | S_IWUSR, rtcan_proc_root, &rtcan_proc_version_ops); proc_create("sockets", S_IFREG | S_IRUGO | S_IWUSR, rtcan_proc_root, &rtcan_proc_sockets_ops); return 0; } static void rtcan_proc_unregister(void) { remove_proc_entry("devices", rtcan_proc_root); remove_proc_entry("version", rtcan_proc_root); remove_proc_entry("sockets", rtcan_proc_root); remove_proc_entry("rtcan", 0); } #endif /* CONFIG_PROC_FS */ int __init rtcan_init(void) { int err = 0; if (!rtdm_available()) return -ENOSYS; printk("RT-Socket-CAN %d.%d.%d - %s\n", RTCAN_MAJOR_VER, RTCAN_MINOR_VER, RTCAN_BUGFIX_VER, rtcan_rtdm_provider_name); if ((err = rtcan_raw_proto_register()) != 0) goto out; #ifdef CONFIG_PROC_FS if ((err = rtcan_proc_register()) != 0) goto out; #endif out: return err; } void __exit rtcan_exit(void) { rtcan_raw_proto_unregister(); #ifdef CONFIG_PROC_FS rtcan_proc_unregister(); #endif printk("rtcan: unloaded\n"); } module_init(rtcan_init); module_exit(rtcan_exit);