1801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman/* 2801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * Loopback driver for rc-core, 3801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * 4801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * Copyright (c) 2010 David Härdeman <david@hardeman.nu> 5801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * 6801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * This driver receives TX data and passes it back as RX data, 7801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * which is useful for (scripted) debugging of rc-core without 8801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * having to use actual hardware. 9801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * 10801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * This program is free software; you can redistribute it and/or modify 11801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * it under the terms of the GNU General Public License as published by 12801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * the Free Software Foundation; either version 2 of the License, or 13801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * (at your option) any later version. 14801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * 15801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * This program is distributed in the hope that it will be useful, 16801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * but WITHOUT ANY WARRANTY; without even the implied warranty of 17801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * GNU General Public License for more details. 19801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * 20801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * You should have received a copy of the GNU General Public License 21801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * along with this program; if not, write to the Free Software 22801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman * 24801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman */ 25801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 26801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman#include <linux/device.h> 27801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman#include <linux/module.h> 28801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman#include <linux/sched.h> 29801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman#include <media/rc-core.h> 30801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 31801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman#define DRIVER_NAME "rc-loopback" 32801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman#define dprintk(x...) if (debug) printk(KERN_INFO DRIVER_NAME ": " x) 33801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman#define RXMASK_REGULAR 0x1 34801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman#define RXMASK_LEARNING 0x2 35801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 36801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanstatic bool debug; 37801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 38801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanstruct loopback_dev { 39801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman struct rc_dev *dev; 40801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman u32 txmask; 41801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman u32 txcarrier; 42801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman u32 txduty; 43801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman bool idle; 44801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman bool learning; 45801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman bool carrierreport; 46801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman u32 rxcarriermin; 47801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman u32 rxcarriermax; 48801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman}; 49801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 50801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanstatic struct loopback_dev loopdev; 51801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 52801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanstatic int loop_set_tx_mask(struct rc_dev *dev, u32 mask) 53801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman{ 54801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman struct loopback_dev *lodev = dev->priv; 55801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 56801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman if ((mask & (RXMASK_REGULAR | RXMASK_LEARNING)) != mask) { 57801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman dprintk("invalid tx mask: %u\n", mask); 58801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman return -EINVAL; 59801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman } 60801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 61801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman dprintk("setting tx mask: %u\n", mask); 62801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman lodev->txmask = mask; 63801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman return 0; 64801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman} 65801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 66801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanstatic int loop_set_tx_carrier(struct rc_dev *dev, u32 carrier) 67801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman{ 68801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman struct loopback_dev *lodev = dev->priv; 69801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 70801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman dprintk("setting tx carrier: %u\n", carrier); 71801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman lodev->txcarrier = carrier; 72801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman return 0; 73801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman} 74801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 75801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanstatic int loop_set_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle) 76801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman{ 77801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman struct loopback_dev *lodev = dev->priv; 78801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 79801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman if (duty_cycle < 1 || duty_cycle > 99) { 80801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman dprintk("invalid duty cycle: %u\n", duty_cycle); 81801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman return -EINVAL; 82801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman } 83801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 84801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman dprintk("setting duty cycle: %u\n", duty_cycle); 85801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman lodev->txduty = duty_cycle; 86801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman return 0; 87801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman} 88801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 89801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanstatic int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max) 90801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman{ 91801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman struct loopback_dev *lodev = dev->priv; 92801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 93801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman if (min < 1 || min > max) { 94801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman dprintk("invalid rx carrier range %u to %u\n", min, max); 95801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman return -EINVAL; 96801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman } 97801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 98801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman dprintk("setting rx carrier range %u to %u\n", min, max); 99801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman lodev->rxcarriermin = min; 100801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman lodev->rxcarriermax = max; 101801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman return 0; 102801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman} 103801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 1045588dc2b025fd8b2188142b8d59efe562bd57d80David Härdemanstatic int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) 105801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman{ 106801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman struct loopback_dev *lodev = dev->priv; 107801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman u32 rxmask; 108801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman unsigned total_duration = 0; 109801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman unsigned i; 110801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman DEFINE_IR_RAW_EVENT(rawir); 111801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 112801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman for (i = 0; i < count; i++) 113801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman total_duration += abs(txbuf[i]); 114801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 115801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman if (total_duration == 0) { 116801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman dprintk("invalid tx data, total duration zero\n"); 117801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman return -EINVAL; 118801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman } 119801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 120801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman if (lodev->txcarrier < lodev->rxcarriermin || 121801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman lodev->txcarrier > lodev->rxcarriermax) { 122801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman dprintk("ignoring tx, carrier out of range\n"); 123801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman goto out; 124801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman } 125801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 126801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman if (lodev->learning) 127801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rxmask = RXMASK_LEARNING; 128801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman else 129801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rxmask = RXMASK_REGULAR; 130801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 131801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman if (!(rxmask & lodev->txmask)) { 132801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman dprintk("ignoring tx, rx mask mismatch\n"); 133801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman goto out; 134801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman } 135801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 136801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman for (i = 0; i < count; i++) { 137801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rawir.pulse = i % 2 ? false : true; 1385588dc2b025fd8b2188142b8d59efe562bd57d80David Härdeman rawir.duration = txbuf[i] * 1000; 139801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman if (rawir.duration) 140801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman ir_raw_event_store_with_filter(dev, &rawir); 141801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman } 14208ffff9fa410916f1847aff831206465cefa924fDavid Härdeman 14308ffff9fa410916f1847aff831206465cefa924fDavid Härdeman /* Fake a silence long enough to cause us to go idle */ 14408ffff9fa410916f1847aff831206465cefa924fDavid Härdeman rawir.pulse = false; 14508ffff9fa410916f1847aff831206465cefa924fDavid Härdeman rawir.duration = dev->timeout; 14608ffff9fa410916f1847aff831206465cefa924fDavid Härdeman ir_raw_event_store_with_filter(dev, &rawir); 14708ffff9fa410916f1847aff831206465cefa924fDavid Härdeman 148801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman ir_raw_event_handle(dev); 149801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 150801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanout: 151801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman /* Lirc expects this function to take as long as the total duration */ 152801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman set_current_state(TASK_INTERRUPTIBLE); 153801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman schedule_timeout(usecs_to_jiffies(total_duration)); 1545588dc2b025fd8b2188142b8d59efe562bd57d80David Härdeman return count; 155801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman} 156801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 157801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanstatic void loop_set_idle(struct rc_dev *dev, bool enable) 158801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman{ 159801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman struct loopback_dev *lodev = dev->priv; 160801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 161801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman if (lodev->idle != enable) { 162801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman dprintk("%sing idle mode\n", enable ? "enter" : "exit"); 163801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman lodev->idle = enable; 164801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman } 165801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman} 166801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 167801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanstatic int loop_set_learning_mode(struct rc_dev *dev, int enable) 168801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman{ 169801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman struct loopback_dev *lodev = dev->priv; 170801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 171801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman if (lodev->learning != enable) { 172801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman dprintk("%sing learning mode\n", enable ? "enter" : "exit"); 173801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman lodev->learning = !!enable; 174801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman } 175801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 176801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman return 0; 177801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman} 178801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 179801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanstatic int loop_set_carrier_report(struct rc_dev *dev, int enable) 180801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman{ 181801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman struct loopback_dev *lodev = dev->priv; 182801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 183801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman if (lodev->carrierreport != enable) { 184801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman dprintk("%sabling carrier reports\n", enable ? "en" : "dis"); 185801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman lodev->carrierreport = !!enable; 186801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman } 187801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 188801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman return 0; 189801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman} 190801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 191801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanstatic int __init loop_init(void) 192801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman{ 193801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman struct rc_dev *rc; 194801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman int ret; 195801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 196801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc = rc_allocate_device(); 197801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman if (!rc) { 198801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman printk(KERN_ERR DRIVER_NAME ": rc_dev allocation failed\n"); 199801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman return -ENOMEM; 200801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman } 201801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 202801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->input_name = "rc-core loopback device"; 203801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->input_phys = "rc-core/virtual"; 204801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->input_id.bustype = BUS_VIRTUAL; 205801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->input_id.version = 1; 206801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->driver_name = DRIVER_NAME; 207801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->map_name = RC_MAP_EMPTY; 208801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->priv = &loopdev; 209801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->driver_type = RC_DRIVER_IR_RAW; 210801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->allowed_protos = RC_TYPE_ALL; 211801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->timeout = 100 * 1000 * 1000; /* 100 ms */ 212801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->min_timeout = 1; 213801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->max_timeout = UINT_MAX; 214801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->rx_resolution = 1000; 215801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->tx_resolution = 1000; 216801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->s_tx_mask = loop_set_tx_mask; 217801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->s_tx_carrier = loop_set_tx_carrier; 218801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->s_tx_duty_cycle = loop_set_tx_duty_cycle; 219801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->s_rx_carrier_range = loop_set_rx_carrier_range; 220801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->tx_ir = loop_tx_ir; 221801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->s_idle = loop_set_idle; 222801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->s_learning_mode = loop_set_learning_mode; 223801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->s_carrier_report = loop_set_carrier_report; 224801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc->priv = &loopdev; 225801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 226801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman loopdev.txmask = RXMASK_REGULAR; 227801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman loopdev.txcarrier = 36000; 228801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman loopdev.txduty = 50; 229801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman loopdev.rxcarriermin = 1; 230801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman loopdev.rxcarriermax = ~0; 231801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman loopdev.idle = true; 232801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman loopdev.learning = false; 233801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman loopdev.carrierreport = false; 234801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 235801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman ret = rc_register_device(rc); 236801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman if (ret < 0) { 237801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman printk(KERN_ERR DRIVER_NAME ": rc_dev registration failed\n"); 238801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc_free_device(rc); 239801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman return ret; 240801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman } 241801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 242801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman loopdev.dev = rc; 243801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman return 0; 244801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman} 245801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 246801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanstatic void __exit loop_exit(void) 247801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman{ 248801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman rc_unregister_device(loopdev.dev); 249801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman} 250801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 251801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanmodule_init(loop_init); 252801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanmodule_exit(loop_exit); 253801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 254801c73c04ad57689dc9b47baf62cbb23f954d987David Härdemanmodule_param(debug, bool, S_IRUGO | S_IWUSR); 255801c73c04ad57689dc9b47baf62cbb23f954d987David HärdemanMODULE_PARM_DESC(debug, "Enable debug messages"); 256801c73c04ad57689dc9b47baf62cbb23f954d987David Härdeman 257801c73c04ad57689dc9b47baf62cbb23f954d987David HärdemanMODULE_DESCRIPTION("Loopback device for rc-core debugging"); 258801c73c04ad57689dc9b47baf62cbb23f954d987David HärdemanMODULE_AUTHOR("David Härdeman <david@hardeman.nu>"); 259801c73c04ad57689dc9b47baf62cbb23f954d987David HärdemanMODULE_LICENSE("GPL"); 260