📄 tdma_module.c
字号:
/*** * * rtmac/tdma/tdma_module.c * * RTmac - real-time networking media access control subsystem * Copyright (C) 2002 Marc Kleine-Budde <kleine-budde@gmx.de>, * 2003-2005 Jan Kiszka <Jan.Kiszka@web.de> * * 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 <asm/div64.h>#include <asm/semaphore.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <rtnet_sys.h>#include <rtmac/rtmac_vnic.h>#include <rtmac/tdma/tdma.h>#include <rtmac/tdma/tdma_dev.h>#include <rtmac/tdma/tdma_ioctl.h>#include <rtmac/tdma/tdma_proto.h>#include <rtmac/tdma/tdma_worker.h>/* RTAI-specific: start scheduling timer */#ifdef CONFIG_RTOS_STARTSTOP_TIMERstatic int start_timer = 0;module_param(start_timer, int, 0444);MODULE_PARM_DESC(start_timer, "set to non-zero to start RTAI timer");#endif#ifdef CONFIG_PROC_FSLIST_HEAD(tdma_devices);DECLARE_MUTEX(tdma_nrt_lock);int tdma_proc_read(char *buf, char **start, off_t offset, int count, int *eof, void *data){ struct tdma_priv *entry; const char *state;#ifdef CONFIG_RTNET_TDMA_MASTER u64 cycle;#endif RTNET_PROC_PRINT_VARS(80); down(&tdma_nrt_lock); if (!RTNET_PROC_PRINT("Interface API Device Operation Mode " "Cycle State\n")) goto done; list_for_each_entry(entry, &tdma_devices, list_entry) { if (!RTNET_PROC_PRINT("%-15s %-15s ", entry->rtdev->name, entry->api_device.device_name)) break; if (test_bit(TDMA_FLAG_CALIBRATED, &entry->flags)) {#ifdef CONFIG_RTNET_TDMA_MASTER if (test_bit(TDMA_FLAG_BACKUP_MASTER, &entry->flags) && !test_bit(TDMA_FLAG_BACKUP_ACTIVE, &entry->flags)) state = "stand-by"; else#endif /* CONFIG_RTNET_TDMA_MASTER */ state = "active"; } else state = "init";#ifdef CONFIG_RTNET_TDMA_MASTER if (test_bit(TDMA_FLAG_MASTER, &entry->flags)) { cycle = entry->cycle_period + 500; do_div(cycle, 1000); if (test_bit(TDMA_FLAG_BACKUP_MASTER, &entry->flags)) { if (!RTNET_PROC_PRINT("Backup Master %-7ld %s\n", (unsigned long)cycle, state)) break; } else { if (!RTNET_PROC_PRINT("Master %-7ld %s\n", (unsigned long)cycle, state)) break; } } else#endif /* CONFIG_RTNET_TDMA_MASTER */ if (!RTNET_PROC_PRINT("Slave - %s\n", state)) break; } done: up(&tdma_nrt_lock); RTNET_PROC_PRINT_DONE;}int tdma_slots_proc_read(char *buf, char **start, off_t offset, int count, int *eof, void *data){ struct tdma_priv *entry; struct tdma_slot *slot; int i; int jnt_id; u64 slot_offset; RTNET_PROC_PRINT_VARS(80); down(&tdma_nrt_lock); if (!RTNET_PROC_PRINT("Interface " "Slots (id[->joint]:offset:phasing/period:size)\n")) goto done; list_for_each_entry(entry, &tdma_devices, list_entry) { if (!RTNET_PROC_PRINT("%-15s ", entry->rtdev->name)) break;#ifdef CONFIG_RTNET_TDMA_MASTER if (test_bit(TDMA_FLAG_BACKUP_MASTER, &entry->flags)) { slot_offset = entry->backup_sync_inc - entry->cycle_period + 500; do_div(slot_offset, 1000); if (!RTNET_PROC_PRINT("bak:%ld ", (unsigned long)slot_offset)) break; }#endif /* CONFIG_RTNET_TDMA_MASTER */ if (entry->slot_table) { if (down_interruptible(&entry->rtdev->nrt_lock)) break; for (i = 0; i <= entry->max_slot_id; i++) { slot = entry->slot_table[i]; if (!slot || ((i == DEFAULT_NRT_SLOT) && (entry->slot_table[DEFAULT_SLOT] == slot))) continue; if (slot->queue == &slot->local_queue) { if (!RTNET_PROC_PRINT("%d", i)) { up(&entry->rtdev->nrt_lock); goto done; } } else for (jnt_id = 0; jnt_id <= entry->max_slot_id; jnt_id++) if (&entry->slot_table[jnt_id]->local_queue == slot->queue) { if (!RTNET_PROC_PRINT("%d->%d", i, jnt_id)) { up(&entry->rtdev->nrt_lock); goto done; } break; } slot_offset = slot->offset + 500; do_div(slot_offset, 1000); if (!RTNET_PROC_PRINT(":%ld:%d/%d:%d ", (unsigned long)slot_offset, slot->phasing + 1, slot->period, slot->mtu)) { up(&entry->rtdev->nrt_lock); goto done; } } up(&entry->rtdev->nrt_lock); } if (!RTNET_PROC_PRINT("\n")) break; } done: up(&tdma_nrt_lock); RTNET_PROC_PRINT_DONE;}#endif /* CONFIG_PROC_FS */int tdma_attach(struct rtnet_device *rtdev, void *priv){ struct tdma_priv *tdma = (struct tdma_priv *)priv; int ret; memset(tdma, 0, sizeof(struct tdma_priv)); tdma->magic = TDMA_MAGIC; tdma->rtdev = rtdev; rtdm_lock_init(&tdma->lock); rtdm_event_init(&tdma->worker_wakeup, 0); rtdm_event_init(&tdma->xmit_event, 0); rtdm_event_init(&tdma->sync_event, 0); ret = tdma_dev_init(rtdev, tdma); if (ret < 0) goto err_out1; ret = rtdm_task_init(&tdma->worker_task, "rtnet-tdma", tdma_worker, tdma, DEF_WORKER_PRIO, 0); if (ret != 0) goto err_out2; RTNET_MOD_INC_USE_COUNT;#ifdef CONFIG_PROC_FS down(&tdma_nrt_lock); list_add(&tdma->list_entry, &tdma_devices); up(&tdma_nrt_lock);#endif /* CONFIG_PROC_FS */ return 0; err_out2: tdma_dev_release(tdma); err_out1: rtdm_event_destroy(&tdma->sync_event); rtdm_event_destroy(&tdma->xmit_event); rtdm_event_destroy(&tdma->worker_wakeup); return ret;}int tdma_detach(struct rtnet_device *rtdev, void *priv){ struct tdma_priv *tdma = (struct tdma_priv *)priv; struct tdma_job *job, *tmp; int err; set_bit(TDMA_FLAG_SHUTDOWN, &tdma->flags); rtdm_event_destroy(&tdma->sync_event); rtdm_event_destroy(&tdma->xmit_event); rtdm_event_destroy(&tdma->worker_wakeup); err = tdma_dev_release(tdma); if (err < 0) return err; rtdm_task_join_nrt(&tdma->worker_task, 100); list_for_each_entry_safe(job, tmp, &tdma->first_job->entry, entry) { if (job->id >= 0) tdma_cleanup_slot(tdma, SLOT_JOB(job)); else if (job->id == XMIT_RPL_CAL) { __list_del(job->entry.prev, job->entry.next); kfree_rtskb(REPLY_CAL_JOB(job)->reply_rtskb); } } if (tdma->slot_table) kfree(tdma->slot_table);#ifdef CONFIG_RTNET_TDMA_MASTER if (test_bit(TDMA_FLAG_MASTER, &tdma->flags)) rtskb_pool_release(&tdma->cal_rtskb_pool);#endif RTNET_MOD_DEC_USE_COUNT;#ifdef CONFIG_PROC_FS down(&tdma_nrt_lock); list_del(&tdma->list_entry); up(&tdma_nrt_lock);#endif /* CONFIG_PROC_FS */ return 0;}#ifdef CONFIG_PROC_FSstruct rtmac_proc_entry tdma_proc_entries[] = { { name: "tdma", handler: tdma_proc_read }, { name: "tdma_slots", handler: tdma_slots_proc_read }, { name: NULL, handler: NULL }};#endif /* CONFIG_PROC_FS */struct rtmac_disc tdma_disc = { name: "TDMA", priv_size: sizeof(struct tdma_priv), disc_type: __constant_htons(RTMAC_TYPE_TDMA), packet_rx: tdma_packet_rx, rt_packet_tx: tdma_rt_packet_tx, nrt_packet_tx: tdma_nrt_packet_tx, get_mtu: tdma_get_mtu, vnic_xmit: RTMAC_DEFAULT_VNIC, attach: tdma_attach, detach: tdma_detach, ioctls: { service_name: "RTmac/TDMA", ioctl_type: RTNET_IOC_TYPE_RTMAC_TDMA, handler: tdma_ioctl },#ifdef CONFIG_PROC_FS proc_entries: tdma_proc_entries#endif /* CONFIG_PROC_FS */};int __init tdma_init(void){ int ret; printk("RTmac/TDMA: init time division multiple access control " "mechanism\n"); ret = rtmac_disc_register(&tdma_disc); if (ret < 0) return ret;#ifdef CONFIG_RTOS_STARTSTOP_TIMER if (start_timer) rtos_timer_start();#endif return 0;}void tdma_release(void){ rtmac_disc_deregister(&tdma_disc);#ifdef CONFIG_RTOS_STARTSTOP_TIMER if (start_timer) rtos_timer_stop();#endif printk("RTmac/TDMA: unloaded\n");}module_init(tdma_init);module_exit(tdma_release);MODULE_AUTHOR("Jan Kiszka");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -