/*** * * rtmac/tdma/tdma_module.c * * RTmac - real-time networking media access control subsystem * Copyright (C) 2002 Marc Kleine-Budde , * 2003-2005 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 #include #include #include #ifdef CONFIG_XENO_OPT_VFILE int tdma_proc_read(struct xnvfile_regular_iterator *it, void *data) { int d, err = 0; struct rtnet_device *rtdev; struct tdma_priv *tdma; const char *state; #ifdef CONFIG_XENO_DRIVERS_NET_TDMA_MASTER u64 cycle; #endif xnvfile_printf(it, "Interface API Device Operation Mode " "Cycle State\n"); for (d = 1; d <= MAX_RT_DEVICES; d++) { rtdev = rtdev_get_by_index(d); if (!rtdev) continue; err = mutex_lock_interruptible(&rtdev->nrt_lock); if (err < 0) { rtdev_dereference(rtdev); break; } if (!rtdev->mac_priv) goto unlock_dev; tdma = (struct tdma_priv *)rtdev->mac_priv->disc_priv; xnvfile_printf(it, "%-15s %-15s ", rtdev->name, tdma->api_device.name); if (test_bit(TDMA_FLAG_CALIBRATED, &tdma->flags)) { #ifdef CONFIG_XENO_DRIVERS_NET_TDMA_MASTER if (test_bit(TDMA_FLAG_BACKUP_MASTER, &tdma->flags) && !test_bit(TDMA_FLAG_BACKUP_ACTIVE, &tdma->flags)) state = "stand-by"; else #endif /* CONFIG_XENO_DRIVERS_NET_TDMA_MASTER */ state = "active"; } else state = "init"; #ifdef CONFIG_XENO_DRIVERS_NET_TDMA_MASTER if (test_bit(TDMA_FLAG_MASTER, &tdma->flags)) { cycle = tdma->cycle_period + 500; do_div(cycle, 1000); if (test_bit(TDMA_FLAG_BACKUP_MASTER, &tdma->flags)) xnvfile_printf(it, "Backup Master %-7ld %s\n", (unsigned long)cycle, state); else xnvfile_printf(it, "Master %-7ld %s\n", (unsigned long)cycle, state); } else #endif /* CONFIG_XENO_DRIVERS_NET_TDMA_MASTER */ xnvfile_printf(it, "Slave - %s\n", state); unlock_dev: mutex_unlock(&rtdev->nrt_lock); rtdev_dereference(rtdev); } return err; } int tdma_slots_proc_read(struct xnvfile_regular_iterator *it, void *data) { int d, i, err = 0; struct rtnet_device *rtdev; struct tdma_priv *tdma; struct tdma_slot *slot; int jnt_id; u64 slot_offset; xnvfile_printf(it, "Interface " "Slots (id[->joint]:offset:phasing/period:size)\n"); for (d = 1; d <= MAX_RT_DEVICES; d++) { rtdev = rtdev_get_by_index(d); if (!rtdev) continue; err = mutex_lock_interruptible(&rtdev->nrt_lock); if (err < 0) { rtdev_dereference(rtdev); break; } if (!rtdev->mac_priv) goto unlock_dev; tdma = (struct tdma_priv *)rtdev->mac_priv->disc_priv; xnvfile_printf(it, "%-15s ", rtdev->name); #ifdef CONFIG_XENO_DRIVERS_NET_TDMA_MASTER if (test_bit(TDMA_FLAG_BACKUP_MASTER, &tdma->flags)) { slot_offset = tdma->backup_sync_inc - tdma->cycle_period + 500; do_div(slot_offset, 1000); xnvfile_printf(it, "bak:%ld ", (unsigned long)slot_offset); } #endif /* CONFIG_XENO_DRIVERS_NET_TDMA_MASTER */ if (tdma->slot_table) for (i = 0; i <= tdma->max_slot_id; i++) { slot = tdma->slot_table[i]; if (!slot || ((i == DEFAULT_NRT_SLOT) && (tdma->slot_table[DEFAULT_SLOT] == slot))) continue; if (slot->queue == &slot->local_queue) { xnvfile_printf(it, "%d", i); } else for (jnt_id = 0; jnt_id <= tdma->max_slot_id; jnt_id++) if (&tdma->slot_table[jnt_id] ->local_queue == slot->queue) { xnvfile_printf(it, "%d->%d", i, jnt_id); break; } slot_offset = slot->offset + 500; do_div(slot_offset, 1000); xnvfile_printf(it, ":%ld:%d/%d:%d ", (unsigned long)slot_offset, slot->phasing + 1, slot->period, slot->mtu); } xnvfile_printf(it, "\n"); unlock_dev: mutex_unlock(&rtdev->nrt_lock); rtdev_dereference(rtdev); } return err; } #endif /* CONFIG_XENO_OPT_VFILE */ 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; 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; rtdm_event_destroy(&tdma->sync_event); rtdm_event_destroy(&tdma->xmit_event); rtdm_event_destroy(&tdma->worker_wakeup); tdma_dev_release(tdma); rtdm_task_destroy(&tdma->worker_task); 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_XENO_DRIVERS_NET_TDMA_MASTER if (test_bit(TDMA_FLAG_MASTER, &tdma->flags)) rtskb_pool_release(&tdma->cal_rtskb_pool); #endif return 0; } #ifdef CONFIG_XENO_OPT_VFILE struct rtmac_proc_entry tdma_proc_entries[] = { { name: "tdma", handler: tdma_proc_read }, { name: "tdma_slots", handler: tdma_slots_proc_read }, }; #endif /* CONFIG_XENO_OPT_VFILE */ 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_XENO_OPT_VFILE proc_entries: tdma_proc_entries, nr_proc_entries: ARRAY_SIZE(tdma_proc_entries), #endif /* CONFIG_XENO_OPT_VFILE */ }; 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; return 0; } void tdma_release(void) { rtmac_disc_deregister(&tdma_disc); printk("RTmac/TDMA: unloaded\n"); } module_init(tdma_init); module_exit(tdma_release); MODULE_AUTHOR("Jan Kiszka"); MODULE_LICENSE("GPL");