/* rt2x00core.c * * Copyright (C) 2004 - 2005 rt2x00-2.0.0-b3 SourceForge Project * * 2006 rtnet adaption by Daniel Gregorek * * * 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., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * Module: rt2x00core * Abstract: rt2x00 core routines. */ #include #include #include #include #include #include #include #include #include #include #include "rt2x00.h" #ifdef DRV_NAME #undef DRV_NAME #define DRV_NAME "rt_rt2x00core" #endif /* DRV_NAME */ static int rt2x00_radio_on(struct _rt2x00_core *core); static int rt2x00_radio_off(struct _rt2x00_core *core); static int cards[MAX_UNITS] = { [0 ...(MAX_UNITS - 1)] = 1 }; module_param_array(cards, int, NULL, 0444); MODULE_PARM_DESC(cards, "array of cards to be supported (e.g. 1,0,1)"); /* * Writes the pending configuration to the device */ static void rt2x00_update_config(struct _rt2x00_core *core) { u16 update_flags = 0x0000; if (!test_bit(DEVICE_ENABLED, &core->flags) && !test_bit(DEVICE_RADIO_ON, &core->flags)) return; if (test_and_set_bit(DEVICE_CONFIG_UPDATE, &core->flags)) return; update_flags = core->config.update_flags; core->config.update_flags = 0; if (likely(update_flags)) core->handler->dev_update_config(core, update_flags); clear_bit(DEVICE_CONFIG_UPDATE, &core->flags); } /* * Radio control. */ static int rt2x00_radio_on(struct _rt2x00_core *core) { int status = 0x00000000; if (test_bit(DEVICE_RADIO_ON, &core->flags)) { WARNING("Radio already on.\n"); return -ENOTCONN; } status = core->handler->dev_radio_on(core); if (status) return status; set_bit(DEVICE_RADIO_ON, &core->flags); return 0; } static int rt2x00_radio_off(struct _rt2x00_core *core) { if (!test_and_clear_bit(DEVICE_RADIO_ON, &core->flags)) { WARNING("Radio already off.\n"); return -ENOTCONN; } core->handler->dev_radio_off(core); return 0; } /* * user space io handler */ static int rt2x00_ioctl(struct rtnet_device *rtnet_dev, struct ifreq *ifr, int request) { struct rtwlan_device *rtwlan_dev = rtnetdev_priv(rtnet_dev); struct _rt2x00_core *core = rtwlan_priv(rtwlan_dev); struct rtwlan_cmd *cmd; u8 rate, dsss_rate, ofdm_rate; u32 address, value; cmd = (struct rtwlan_cmd *)ifr->ifr_data; switch (request) { case IOC_RTWLAN_IFINFO: cmd->args.info.bitrate = core->config.bitrate; cmd->args.info.channel = core->config.channel; cmd->args.info.retry = core->config.short_retry; cmd->args.info.txpower = core->config.txpower; cmd->args.info.bbpsens = core->config.bbpsens; cmd->args.info.mode = core->rtwlan_dev->mode; cmd->args.info.rx_packets = core->rtwlan_dev->stats.rx_packets; cmd->args.info.tx_packets = core->rtwlan_dev->stats.tx_packets; cmd->args.info.tx_retry = core->rtwlan_dev->stats.tx_retry; cmd->args.info.autoresponder = core->config.config_flags & CONFIG_AUTORESP ? 1 : 0; cmd->args.info.dropbcast = core->config.config_flags & CONFIG_DROP_BCAST ? 1 : 0; cmd->args.info.dropmcast = core->config.config_flags & CONFIG_DROP_MCAST ? 1 : 0; DEBUG("rtwlan_dev->mode=%d\n", rtwlan_dev->mode); break; case IOC_RTWLAN_BITRATE: rate = cmd->args.set.bitrate; ofdm_rate = ieee80211_is_ofdm_rate(rate); dsss_rate = ieee80211_is_dsss_rate(rate); DEBUG("bitrate=%d\n", rate); if (!(dsss_rate ^ ofdm_rate)) NOTICE("Rate %d is not DSSS and not OFDM.\n", rate); core->config.bitrate = rate; core->config.update_flags |= UPDATE_BITRATE; break; case IOC_RTWLAN_CHANNEL: DEBUG("channel=%d\n", cmd->args.set.channel); core->config.channel = cmd->args.set.channel; core->config.update_flags |= UPDATE_CHANNEL; break; case IOC_RTWLAN_RETRY: core->config.short_retry = cmd->args.set.retry; core->config.update_flags |= UPDATE_RETRY; break; case IOC_RTWLAN_TXPOWER: core->config.txpower = cmd->args.set.txpower; core->config.update_flags |= UPDATE_TXPOWER; break; case IOC_RTWLAN_AUTORESP: if (cmd->args.set.autoresponder) core->config.config_flags |= CONFIG_AUTORESP; else core->config.config_flags &= ~CONFIG_AUTORESP; core->config.update_flags |= UPDATE_AUTORESP; break; case IOC_RTWLAN_DROPBCAST: if (cmd->args.set.dropbcast) core->config.config_flags |= CONFIG_DROP_BCAST; else core->config.config_flags &= ~CONFIG_DROP_BCAST; core->config.update_flags |= UPDATE_PACKET_FILTER; break; case IOC_RTWLAN_DROPMCAST: if (cmd->args.set.dropmcast) core->config.config_flags |= CONFIG_DROP_MCAST; else core->config.config_flags &= ~CONFIG_DROP_MCAST; core->config.update_flags |= UPDATE_PACKET_FILTER; break; case IOC_RTWLAN_TXMODE: core->rtwlan_dev->mode = cmd->args.set.mode; break; case IOC_RTWLAN_BBPSENS: value = cmd->args.set.bbpsens; if (value < 0) value = 0; if (value > 127) value = 127; core->config.bbpsens = value; core->config.update_flags |= UPDATE_BBPSENS; break; case IOC_RTWLAN_REGREAD: case IOC_RTWLAN_BBPREAD: address = cmd->args.reg.address; core->handler->dev_register_access(core, request, address, &value); cmd->args.reg.value = value; break; case IOC_RTWLAN_REGWRITE: case IOC_RTWLAN_BBPWRITE: address = cmd->args.reg.address; value = cmd->args.reg.value; core->handler->dev_register_access(core, request, address, &value); break; default: ERROR("Unknown request!\n"); return -1; } if (request != IOC_RTWLAN_IFINFO) rt2x00_update_config(core); return 0; } /* * TX/RX related routines. */ static int rt2x00_start_xmit(struct rtskb *rtskb, struct rtnet_device *rtnet_dev) { struct rtwlan_device *rtwlan_dev = rtnetdev_priv(rtnet_dev); struct _rt2x00_core *core = rtwlan_priv(rtwlan_dev); u16 xmit_flags = 0x0000; u8 rate = 0x00; if (unlikely(rtskb)) { rate = core->config.bitrate; if (ieee80211_is_ofdm_rate(rate)) xmit_flags |= XMIT_OFDM; /* Check if the packet should be acknowledged */ if (core->rtwlan_dev->mode == RTWLAN_TXMODE_ACK) xmit_flags |= XMIT_ACK; if (core->handler->dev_xmit_packet(core, rtskb, rate, xmit_flags)) ERROR("Packet dropped !"); dev_kfree_rtskb(rtskb); } return 0; } /*** * rt2x00_open * @rtdev */ static int rt2x00_open(struct rtnet_device *rtnet_dev) { struct rtwlan_device *rtwlan_dev = rtnetdev_priv(rtnet_dev); struct _rt2x00_core *core = rtwlan_priv(rtwlan_dev); int status = 0x00000000; DEBUG("Start.\n"); if (test_and_set_bit(DEVICE_ENABLED, &core->flags)) { ERROR("device already enabled.\n"); return -EBUSY; } /* * Start rtnet interface. */ rt_stack_connect(rtnet_dev, &STACK_manager); status = rt2x00_radio_on(core); if (status) { clear_bit(DEVICE_ENABLED, &core->flags); ERROR("Couldn't activate radio.\n"); return status; } core->config.led_status = 1; core->config.update_flags |= UPDATE_LED_STATUS; rt2x00_update_config(core); rtnetif_start_queue(rtnet_dev); DEBUG("Exit success.\n"); return 0; } /*** * rt2x00_close * @rtdev */ static int rt2x00_close(struct rtnet_device *rtnet_dev) { struct rtwlan_device *rtwlan_dev = rtnetdev_priv(rtnet_dev); struct _rt2x00_core *core = rtwlan_priv(rtwlan_dev); DEBUG("Start.\n"); if (!test_and_clear_bit(DEVICE_ENABLED, &core->flags)) { ERROR("device already disabled.\n"); return -EBUSY; } rt2x00_radio_off(core); rtnetif_stop_queue(rtnet_dev); rt_stack_disconnect(rtnet_dev); return 0; } /* * Initialization handlers. */ static void rt2x00_init_config(struct _rt2x00_core *core) { DEBUG("Start.\n"); memset(&core->config.bssid, '\0', sizeof(core->config.bssid)); core->config.channel = 1; core->config.bitrate = capabilities.bitrate[0]; core->config.bbpsens = 50; core->config.config_flags = 0; core->config.config_flags |= CONFIG_DROP_BCAST | CONFIG_DROP_MCAST | CONFIG_AUTORESP; core->config.short_retry = 4; core->config.long_retry = 7; core->config.txpower = 100; core->config.plcp = 48; core->config.sifs = 10; core->config.slot_time = 20; core->rtwlan_dev->mode = RTWLAN_TXMODE_RAW; core->config.update_flags = UPDATE_ALL_CONFIG; } struct rtnet_device *rt2x00_core_probe(struct _rt2x00_dev_handler *handler, void *priv, u32 sizeof_dev) { struct rtnet_device *rtnet_dev = NULL; struct _rt2x00_core *core = NULL; struct rtwlan_device *rtwlan_dev = NULL; static int cards_found = -1; int err; DEBUG("Start.\n"); cards_found++; if (cards[cards_found] == 0) goto exit; rtnet_dev = rtwlan_alloc_dev(sizeof_dev + sizeof(*core), RX_ENTRIES * 2); if (!rtnet_dev) goto exit; rt_rtdev_connect(rtnet_dev, &RTDEV_manager); rtnet_dev->vers = RTDEV_VERS_2_0; rtwlan_dev = rtnetdev_priv(rtnet_dev); memset(rtwlan_dev, 0x00, sizeof(*rtwlan_dev)); core = rtwlan_priv(rtwlan_dev); memset(core, 0x00, sizeof(*core)); core->rtwlan_dev = rtwlan_dev; core->handler = handler; core->priv = (void *)core + sizeof(*core); core->rtnet_dev = rtnet_dev; /* Set configuration default values. */ rt2x00_init_config(core); if (core->handler->dev_probe && core->handler->dev_probe(core, priv)) { ERROR("device probe failed.\n"); goto exit; } INFO("Device " MAC_FMT " detected.\n", MAC_ARG(rtnet_dev->dev_addr)); rtwlan_dev->hard_start_xmit = rt2x00_start_xmit; rtnet_dev->open = &rt2x00_open; rtnet_dev->stop = &rt2x00_close; rtnet_dev->do_ioctl = &rt2x00_ioctl; rtnet_dev->hard_header = &rt_eth_header; if ((err = rt_register_rtnetdev(rtnet_dev)) != 0) { rtdev_free(rtnet_dev); ERROR("rtnet_device registration failed.\n"); printk("err=%d\n", err); goto exit_dev_remove; } set_bit(DEVICE_AWAKE, &core->flags); return rtnet_dev; exit_dev_remove: if (core->handler->dev_remove) core->handler->dev_remove(core); exit: return NULL; } EXPORT_SYMBOL_GPL(rt2x00_core_probe); void rt2x00_core_remove(struct rtnet_device *rtnet_dev) { rt_unregister_rtnetdev(rtnet_dev); rt_rtdev_disconnect(rtnet_dev); rtdev_free(rtnet_dev); } EXPORT_SYMBOL_GPL(rt2x00_core_remove); /* * RT2x00 core module information. */ static char version[] = DRV_NAME " - " DRV_VERSION; MODULE_AUTHOR(DRV_AUTHOR); MODULE_DESCRIPTION("RTnet rt2500 PCI WLAN driver (Core Module)"); MODULE_LICENSE("GPL"); static int __init rt2x00_core_init(void) { printk(KERN_INFO "Loading module: %s\n", version); return 0; } static void __exit rt2x00_core_exit(void) { printk(KERN_INFO "Unloading module: %s\n", version); } module_init(rt2x00_core_init); module_exit(rt2x00_core_exit);