* atheros driver (5/8)
@ 2005-08-05 2:59 Mateusz Berezecki
0 siblings, 0 replies; only message in thread
From: Mateusz Berezecki @ 2005-08-05 2:59 UTC (permalink / raw)
To: kernel-mentors; +Cc: netdev
[-- Attachment #1: Type: text/plain, Size: 1 bytes --]
[-- Attachment #2: atheros5212-5.patch --]
[-- Type: text/x-patch, Size: 26852 bytes --]
diff -uprN -X 'netdev-2.6.git#ieee80211/Documentation/dontdiff' netdev-2.6.git#ieee80211/drivers/net/wireless/atheros/atheros5212/init.c netdev-atheros/drivers/net/wireless/atheros/atheros5212/init.c
--- netdev-2.6.git#ieee80211/drivers/net/wireless/atheros/atheros5212/init.c 1970-01-01 01:00:00.000000000 +0100
+++ netdev-atheros/drivers/net/wireless/atheros/atheros5212/init.c 2005-08-05 03:48:36.000000000 +0200
@@ -0,0 +1,788 @@
+/*
+ * All the work was created by reverse engineering and porting
+ * for interoperability. The creator is Mateusz Berezecki,
+ * unless explicitly marked ( some parts are derived
+ * from GPL'ed parts of madwifi project located at http://madwifi.sf.net)
+ *
+ * derived or copied parts of code licensed under
+ * dual GPL/BSD license
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * rest of the code has been reversed by me are under copyright too... should they?:P
+ * Copyright (C) 2005 Mateusz Berezecki
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+
+#include <net/ieee80211.h>
+
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+#include "atheros_id.h"
+#include "atheros_dev.h"
+#include "atheros_defs.h"
+#include "atheros_registers.h"
+#include "atheros.h"
+#include "eeprom.h"
+#include "interrupts.h"
+#include "regops.h"
+#include "powermodes.h"
+#include "transmit_receive.h"
+#include "chans.h"
+
+struct net_device *atheros_card = NULL;
+
+unsigned int ath_radio(struct net_device *netdev)
+{
+ unsigned int ret = 0,val = 0;
+ unsigned int i;
+
+ ath_reg_write(netdev, 0x9800 + (0x34 << 2), 0x1c16);
+
+ for (i = 0; i < 8; i++)
+ ath_reg_write(netdev, 0x9800 + (0x20 << 2), 0x10000);
+
+ val = ath_reg_read(netdev, 0x9800 + (256 << 2));
+ val = (val >> 24) & 0xff;
+ val = (val & 0xf0) >> 4;
+ val |= ((val & 0x0f) << 4);
+
+ for (i = 0; i < 8; i++) {
+ ret = (ret << 1) | (val & 1);
+ val = val >> 1;
+ }
+
+ return ret;
+}
+
+unsigned int ath_selftest(struct net_device *netdev)
+{
+ unsigned int i, j;
+ unsigned int regs[2] = { 0x8000, 0x9800 + (8 << 2) };
+ unsigned int vals[2];
+ unsigned int values[4] = {
+ 0x55555555, 0xaaaaaaaa,
+ 0x66666666, 0x99999999
+ };
+
+ for (i = 0; i < 2; i++) {
+ unsigned int addr = regs[i];
+ unsigned int wdata, rdata;
+
+ vals[i] = ath_reg_read(netdev, addr);
+
+ for (j = 0; j < 256; j++) {
+ wdata = (j << 16) | j;
+ ath_reg_write(netdev, addr, wdata);
+ rdata = ath_reg_read(netdev, addr);
+ if (wdata != rdata) {
+ printk(KERN_DEBUG"atheros:(%d) read %x exp. %x\n",
+ j, rdata, wdata);
+ return 0;
+ }
+ }
+
+ for (j = 0; j < 4; j++) {
+ unsigned int tmp;
+ ath_reg_write(netdev, regs[i], values[j]);
+ tmp = ath_reg_read(netdev, regs[i]);
+ if (values[j] != tmp) {
+ printk(KERN_DEBUG"atheros: 2nd loop\n");
+ return 0;
+ }
+ }
+ ath_reg_write(netdev, regs[i], vals[i]);
+ }
+ udelay(100);
+ return 1;
+}
+
+unsigned int ath_set_reset_register(struct net_device *netdev,
+ unsigned int rmask)
+{
+ unsigned int mask = rmask ? rmask : ~0;
+ unsigned int t;
+
+
+ ath_reg_read(netdev, 0x000c);
+ ath_reg_write(netdev, 0x4000, rmask);
+ udelay(15);
+
+ mask &= (0x0001 | 0x0002);
+ rmask &= (0x0001 | 0x0002);
+ t = ath_timed_read(netdev, 0x4000, mask, rmask);
+
+ if ((rmask & 1) == 0) {
+ ath_reg_write(netdev, 0x14, 0);
+ if (!ath_set_power_mode(netdev, 2, 1, 0))
+ return t;
+ ath_reg_read(netdev, 0xc0);
+ }
+ return t;
+}
+
+unsigned int ath_prep_reset(struct net_device *netdev)
+{
+ return 1;
+}
+
+unsigned int ath_chip_reset(struct net_device *netdev, void *unused)
+{
+
+ if (!ath_set_reset_register(netdev, 0x13)) {
+ printk(KERN_DEBUG"atheros: if 1 (warm reset)\n");
+ return 0;
+ }
+
+ if (!ath_set_power_mode(netdev, 2, 1, 0)) {
+ printk(KERN_DEBUG"atheros: if #2 (power mode)\n");
+ return 0;
+ }
+
+ if (!ath_set_reset_register(netdev, 0)) {
+ printk(KERN_DEBUG"atheros: if 3 (cold reset)\n");
+ return 0;
+ }
+
+ if (unused == NULL)
+ return 1;
+
+ return 0;
+}
+
+unsigned int ath_reset(struct net_device *netdev)
+{
+ return 0;
+}
+
+struct chip_gain_desc athgaindesc = {
+ .entrycnt = 9,
+ .defentry = 4,
+ .deltas[0] = { {4, 1, 1, 1, 0, 0, 0}, 6, "FG8" },
+ .deltas[1] = { {4, 0, 1, 1, 0, 0, 0}, 4, "FG7" },
+ .deltas[2] = { {3, 1, 1, 1, 0, 0, 0}, 3, "FG6" },
+ .deltas[3] = { {4, 0, 0, 1, 0, 0, 0}, 1, "FG5" },
+ .deltas[4] = { {4, 1, 1, 0, 0, 0, 0}, 0, "FG4" },
+ .deltas[5] = { {4, 0, 1, 0, 0, 0, 0}, -2, "FG3" },
+ .deltas[6] = { {3, 1, 1, 0, 0, 0, 0}, -3, "FG2" },
+ .deltas[7] = { {4, 0, 0, 0, 0, 0, 0}, -4, "FG1" },
+ .deltas[8] = { {2, 1, 1, 0, 0, 0, 0}, -6, "FG0" },
+};
+
+struct chip_gain_desc ath5112gaindesc = {
+ .entrycnt = 8,
+ .defentry = 1,
+ .deltas[0] = { {3, 0, 0, 0, 0, 0, 0}, 6, "FG7" },
+ .deltas[1] = { {2, 0, 0, 0, 0, 0, 0}, 0, "FG6" },
+ .deltas[2] = { {1, 0, 0, 0, 0, 0, 0}, -3, "FG5" },
+ .deltas[3] = { {0, 0, 0, 0, 0, 0, 0}, 0, "FG4" },
+ .deltas[4] = { {0, 1, 1, 0, 0, 0, 0}, -8, "FG3" },
+ .deltas[5] = { {0, 1, 1, 0, 1, 1, 0},-10, "FG2" },
+ .deltas[6] = { {0, 1, 0, 1, 1, 1, 0},-13, "FG1" },
+ .deltas[7] = { {0, 1, 0, 1, 1, 0, 1},-16, "FG0" },
+};
+
+void ath_init_gain(struct net_device *netdev)
+{
+ struct atheros_priv *p = ieee80211_priv(netdev);
+
+ if ((p->rev_5ghz & 0xf0) >= (0x10|0x20)) {
+ p->gaindesc.number = ath5112gaindesc.defentry;
+ p->gaindesc.delta =
+ &ath5112gaindesc.deltas[ath5112gaindesc.defentry];
+ p->gaindesc.active = 1;
+ p->gaindesc.low = 20;
+ p->gaindesc.high = 85;
+ } else {
+ p->gaindesc.number = athgaindesc.defentry;
+ p->gaindesc.delta =
+ &athgaindesc.deltas[athgaindesc.defentry];
+ p->gaindesc.active = 1;
+ p->gaindesc.low = 20;
+ p->gaindesc.high = 35;
+ }
+}
+
+unsigned int ath_alloc_rf(struct net_device *netdev)
+{
+ /*
+ struct atheros_priv *p = ieee80211_priv(netdev);
+ */
+ return 1;
+}
+
+unsigned short chans11b[] = {
+ 2412, 2447, 2484
+};
+
+unsigned short chans11g[] = {
+ 2312, 2412, 2484
+};
+
+int ath_dev_attach(unsigned short devid, struct net_device *netdev)
+{
+ unsigned int val;
+ struct atheros_priv *pdata;
+ unsigned int i;
+
+ pdata = ieee80211_priv(netdev);
+
+ pdata->tpc = 16;
+ pdata->atim_win = 0;
+ pdata->cts = 4;
+ pdata->divctrl = 0;
+ pdata->iqcal = 0;
+ pdata->scaletpfactor = 0;
+ pdata->aifs = 2;
+ pdata->enableqos = 0;
+ pdata->swretry = 0;
+ pdata->hwtxtrycount = 10;
+ pdata->txlimit = 10;
+ pdata->beacon_interval = 100;
+ pdata->pwroverride = 0;
+ pdata->enable32clk = 0;
+
+ printk(KERN_DEBUG"atheros: devid is %x\n", devid);
+
+ /* first, power on the device... */
+ if (!ath_set_power_mode(netdev, PMODE_AWAKE, 1, 0)) {
+ printk(KERN_DEBUG"atheros: failed to wake up the device\n");
+ return 0;
+ }
+
+ /* ...reset the radio chip afterwards */
+ if (!ath_chip_reset(netdev, NULL)) {
+ printk(KERN_DEBUG"atheros: failed to reset the chip\n");
+ return -1;
+ }
+
+ pdata->mac_version = (ath_reg_read(netdev, 0x4020) & 0xff) >> 4;
+ pdata->mac_revision = ath_reg_read(netdev, 0x4020) & 0x0f;
+
+ printk(KERN_DEBUG"atheros: mac version %d\n", pdata->mac_version);
+ printk(KERN_DEBUG"atheros: mac revision %d\n", pdata->mac_revision);
+
+ if (pdata->mac_version != 5 || pdata->mac_revision < 2) {
+ printk(KERN_ERR"atheros: chip not supported\n");
+ return 0;
+ }
+
+ pdata->phy_revision = ath_reg_read(netdev, 0x9818);
+
+ if (ath_selftest(netdev) == 0) {
+ printk(KERN_ERR"atheros: POST test failed!\n");
+ return 0;
+ }
+
+ ath_reg_write(netdev, 0x9800, 0x00000007);
+
+ pdata->rev_5ghz = ath_radio(netdev);
+
+ /* XXX TODO: add some checks here fo chipset versioning */
+
+ printk(KERN_DEBUG"atheros: 2ghz radio revision %x\n",
+ pdata->rev_5ghz);
+
+ if (!eeprom_init(netdev)) {
+ printk(KERN_DEBUG"atheros: eeprom init failed!\n");
+ return 0;
+ }
+
+ /* ustawic kanaly i inne takie gadzety */
+ pdata->eeinfo.num_ch5 = 10;
+ pdata->eeinfo.num_ch2 = 3;
+
+ for (i = 0; i < 10; i++)
+ pdata->eeinfo.chans_11a[i].count = 11;
+
+ for (i = 0; i < 3; i++) {
+ pdata->eeinfo.ch_11b[i] = chans11b[i];
+ pdata->eeinfo.ch_11g[i] = chans11g[i];
+ pdata->eeinfo.chans_11b[i].count = 3;
+ pdata->eeinfo.chans_11g[i].count = 3;
+ }
+
+
+ if (!eeprom_read_caps(netdev))
+ return 0;
+
+ if (pdata->eeinfo.mode_b && (pdata->rev_5ghz & 0xf0) == 0x10) {
+ unsigned int tmpval;
+ ath_reg_write(netdev, 0x9800, 0x00004007);
+ udelay(2000);
+ pdata->rev_2ghz = ath_radio(netdev);
+ ath_reg_write(netdev, 0x9800, 0x00000007);
+ udelay(2000);
+
+ tmpval = pdata->rev_2ghz & 0xf0;
+
+ if (tmpval != 0x20) {
+ return 0;
+ }
+ }
+
+ printk(KERN_DEBUG"atheros: 5GHz radio revision %x\n",pdata->rev_2ghz);
+ eeprom_read(netdev, 0xbf, &val);
+ printk(KERN_DEBUG"atheros: regulatory domain -> %x(%d)\n",val, val);
+
+ pdata->domain = val;
+
+ ath_init_gain(netdev);
+
+ if (!ath_alloc_rf(netdev)) {
+ return 0;
+ }
+
+ if (!eeprom_read_mac(netdev, pdata->mac)) {
+ printk(KERN_DEBUG"atheros: MAC reading failed\n");
+ }
+ printk(KERN_DEBUG"atheros: MAC is %x.%x.%x.%x.%x.%x\n",
+ pdata->mac[0],pdata->mac[1],pdata->mac[2],
+ pdata->mac[3],pdata->mac[4],pdata->mac[5]);
+
+ return 1;
+}
+
+int ath_attach(unsigned short devid, struct net_device *netdev)
+{
+ unsigned t, i;
+ struct atheros_priv *p = ieee80211_priv(netdev);
+
+ if (!ath_dev_attach(devid, netdev))
+ return 0;
+
+
+ t = ath_setup_xtx_desc(netdev, NULL, 0, 0, 0, 0, 0, 0);
+ p->mretry = t;
+
+ if (ath_get_cap(netdev, CAP_PHYCOUNTERS, 0, NULL) == 0)
+ p->mib_enabled = 1;
+
+ p->keycache_size = ath_get_keycache_size(netdev);
+
+ printk(KERN_DEBUG"atheros: resetting key cache\n");
+ for (i = 0; i < p->keycache_size; i++) {
+ ath_reset_keycache(netdev, i);
+ }
+
+ for (i = 0; i < 4; i++) {
+ p->keymap[i/8] |= 1 << (i % 8);
+ /*
+ set_bit(p->keymap, i);
+ set_bit(p->keymap, i+32);
+ set_bit(p->keymap, i+64);
+ set_bit(p->keymap, i+32+64);
+ */
+ }
+
+ /* XXX this has to be finished yet. its quite complicated
+ * how it works, etc. */
+ if (!ath_get_channels(netdev, 0, -1, -1))
+ return 0;
+
+ /* XXX rate setup here */
+
+ ath_rate_setup(netdev, MODE_11A);
+ ath_rate_setup(netdev, MODE_11B);
+ ath_rate_setup(netdev, MODE_11G);
+
+
+ /* XXX allocate descriptors here */
+ /*
+ if (!ath_desc_alloc(netdev)) {
+ return 0;
+ }
+ */
+ p->beacon_q = ath_beacon_queue_setup(netdev);
+ if (p->beacon_q == (unsigned int) -1) {
+ printk(KERN_DEBUG"atheros: beacon queue setup failed\n");
+ return 0;
+ }
+
+ p->cabq = ath_txq_setup(netdev, TX_QUEUE_CAB, 0);
+ if (p->cabq == NULL) {
+ printk(KERN_DEBUG"atheros: unable to setup CAB xmit queue!\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+int ath_init(struct net_device *netdev)
+{
+ struct atheros_priv *p = ieee80211_priv(netdev);
+ int opmode = 0, status = 0;
+
+ ath_stop_locked(netdev);
+
+ /* XXX use the proper mode first. Where to get it from?*g* */
+ /*
+ ath_reset(netdev, opmode, chan, 0, &status);
+ */
+ ath_update_txpow(netdev);
+
+ if (ath_startrecv(netdev) != 0) {
+ printk(KERN_DEBUG"atheros: cant init receieve\n");
+ return -1;
+ }
+
+ p->intr_mask = INT_RX | INT_TX | INT_RXEOL |
+ INT_RXORN | INT_FATAL | INT_GLOBAL;
+
+ ath_set_interruptmask(netdev, p->intr_mask);
+
+ netdev->flags |= IFF_RUNNING;
+
+ return 1;
+}
+
+int ath_stop(struct net_device *netdev)
+{
+ struct atheros_priv *p = ieee80211_priv(netdev);
+ int error;
+
+ error = ath_stop_locked(netdev);
+
+ if (error == 0 && !p->invalid)
+ ath_set_power_mode(netdev, PMODE_FULL_SLEEP, 1, 0);
+
+ return error;
+}
+
+int ath_stop_locked(struct net_device *netdev)
+{
+ struct atheros_priv *p = ieee80211_priv(netdev);
+
+ if (netdev->flags & IFF_RUNNING) {
+ netif_stop_queue(netdev);
+ netdev->flags &= ~IFF_RUNNING;
+
+ if (!p->invalid) {
+ /*
+ if (p->softled) {
+ del_timer(&p->ledtimer);
+ ath_gpioset(netdev, p->ledpin,
+ !p->ledon);
+ p->blinking = 0;
+ }
+ */
+ ath_set_interruptmask(netdev, 0);
+ }
+
+ ath_draintxq(netdev);
+
+ if (!p->invalid) {
+ ath_stoprecv(netdev);
+ ath_phy_disable(netdev);
+ } else
+ p->rxlink = NULL;
+#ifdef NOT_YET
+ ath_beacon_free(netdev);
+#endif
+ }
+
+ return 0;
+}
+
+void ath_mode_init(struct net_device *netdev)
+{
+}
+
+int ath_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ return -1;
+}
+
+struct net_device_stats *ath_getstats(struct net_device *netdev)
+{
+ struct atheros_priv *p = ieee80211_priv(netdev);
+
+ /* same note as below applies here too */
+
+ return &p->devstats;
+}
+
+struct iw_statistics *ath_iw_getstats(struct net_device *netdev)
+{
+ /* returning stats from device.
+ * thats not so correct but will do for testing.
+ * in future versions use stats from associated
+ * node */
+ struct atheros_priv *p = ieee80211_priv(netdev);
+
+ /* TODO: update stat counters here and return */
+
+ return &p->stats;
+}
+
+int ath_set_mac_address(struct net_device *netdev, void *addr)
+{
+ int error;
+ struct atheros_priv *p;
+ struct sockaddr *mac = addr;
+
+ p = ieee80211_priv(netdev);
+
+ if (netif_running(netdev)) {
+ printk(KERN_DEBUG"atheros: cannot set address; device running\n");
+ return -EBUSY;
+ }
+
+ memcpy(netdev->dev_addr, mac->sa_data, 6);
+ error = -ath_reset(netdev);
+
+ return error;
+}
+
+int ath_change_mtu(struct net_device *netdev, int mtu)
+{
+ struct atheros_priv *p = ieee80211_priv(netdev);
+ int error;
+
+ if (!(ATH_MIN_MTU < mtu && mtu <= ATH_MAX_MTU))
+ return -EINVAL;
+
+ netdev->mtu = mtu;
+ tasklet_disable(&p->rxtq);
+ error = -ath_reset(netdev);
+ tasklet_enable(&p->rxtq);
+
+ return error;
+}
+
+void ath_netdev_init(struct net_device *netdev)
+{
+ unsigned int size;
+ struct net_device *ieee = netdev_priv(netdev);
+
+ printk(KERN_DEBUG"atheros pci: initializing netdevice\n");
+
+ netdev->open = ath_init;
+ netdev->stop = ath_stop;
+ //netdev->hard_start_xmit = ath_hardstart;
+// netdev->tx_timeout = ath_timeout;
+ netdev->watchdog_timeo = 5 * HZ;
+ netdev->set_multicast_list = ath_mode_init;
+ netdev->do_ioctl = ath_ioctl;
+ netdev->get_stats = ath_getstats;
+ netdev->set_mac_address = ath_set_mac_address;
+ netdev->change_mtu = ath_change_mtu;
+ netdev->tx_queue_len = ATHEROS_TXBUF-1;
+
+// ieee->hard_start_xmit = ath_hardstart;
+
+#ifdef CONFIG_NET_WIRELESS
+ netdev->get_wireless_stats = ath_iw_getstats;
+ netdev->wireless_handlers = &ath_iw_handler_def;
+
+#ifdef NOT_YET_BABE
+ /* just because it breaks stuff and its 2:13 am ;-P */
+ ath_iw_handler_def.private_args =
+ (struct iw_priv_args *) ieee80211_priv_args;
+
+ ath_iw_handler_def.num_private_args = get_priv_size();
+#endif
+#endif
+}
+
+int ath_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ unsigned char cache_sz;
+ unsigned char timer;
+ unsigned int val;
+ struct net_device *netdev;
+ struct atheros_priv *priv;
+ unsigned long phy_mem, virt_mem;
+
+ if (pci_enable_device(dev))
+ return (-EIO);
+
+ /* atheros chipsets support 32bit addressing mode */
+ if (pci_set_dma_mask(dev, 0xffffffff)) {
+ printk(KERN_ERR"atheros pci: couldn't set 32-bit DMA mode\n");
+ goto disable;
+ }
+
+ pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cache_sz);
+
+ /* as madwifi source says rx buffer DMA will work if and only if
+ * we have some alignment set up */
+
+ if (cache_sz == 0) {
+ cache_sz = L1_CACHE_BYTES / sizeof(unsigned int);
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, cache_sz);
+ }
+
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &timer);
+ if (timer == 0) {
+ /* XXX: Tune this ... */
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xff);
+ }
+
+ pci_set_master(dev);
+ pci_read_config_dword(dev, 0x40, &val);
+ pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
+
+ /* grab first memory region address */
+ phy_mem = pci_resource_start(dev, 0);
+
+ if (request_mem_region(phy_mem, pci_resource_len(dev, 0),
+ "atheros") == NULL) {
+ printk(KERN_ERR"atheros pci: couldn't get PCI memory\n");
+ goto disable;
+ }
+
+ virt_mem = (unsigned long)ioremap(phy_mem,pci_resource_len(dev,0));
+ if (virt_mem == 0x00000000) {
+ printk(KERN_ERR"atheros pci: couldn't remap PCI memory\n");
+ goto release;
+ }
+ printk(KERN_DEBUG"atheros pci: Using IRQ : %d\n", dev->irq);
+ atheros_card = alloc_ieee80211(sizeof(struct atheros_priv));
+
+ ath_netdev_init(atheros_card);
+ atheros_card->irq = dev->irq;
+ atheros_card->mem_start = virt_mem;
+ atheros_card->mem_end = virt_mem + pci_resource_len(dev, 0);
+ printk(KERN_DEBUG"atheros pci: memory spans : %08lx-%08lx\n",
+ atheros_card->mem_start, atheros_card->mem_end);
+
+
+ priv = ieee80211_priv(atheros_card);
+ priv->busdev = dev;
+
+ priv->invalid = 1;
+
+
+ SET_MODULE_OWNER(atheros_card);
+ SET_NETDEV_DEV(atheros_card, &dev->dev);
+
+ printk(KERN_DEBUG"atheros pci: allocated atheros netdevice\n");
+
+ pci_set_drvdata(dev, atheros_card);
+
+ if (request_irq(atheros_card->irq,
+ ath_intr, SA_SHIRQ,
+ atheros_card->name,
+ atheros_card)) {
+ printk(KERN_ERR"atheros pci: IRQ request failed.\n");
+ goto netdev_free;
+ }
+
+ if (!ath_attach(id->device, atheros_card))
+ goto freeirq;
+
+
+ eeprom_read_mac(atheros_card, atheros_card->dev_addr);
+
+ if (register_netdev(atheros_card))
+ goto detach;
+
+ priv->invalid = 0;
+
+ return 0;
+
+detach:
+ ath_detach(atheros_card);
+freeirq:
+ free_irq(atheros_card->irq, dev);
+
+netdev_free:
+ free_ieee80211(atheros_card);
+ atheros_card = NULL;
+
+mem_unmap:
+ iounmap((void *)virt_mem);
+release:
+ release_mem_region(phy_mem, pci_resource_len(dev, 0));
+disable:
+ pci_disable_device(dev);
+ return -ENODEV;
+}
+
+int ath_detach(struct net_device *netdev)
+{
+ struct atheros_priv *pdata = ieee80211_priv(netdev);
+
+ printk(KERN_DEBUG"atheros pci: detaching\n");
+
+ ath_stop(netdev);
+ pdata->invalid = 1;
+
+ unregister_netdev(netdev);
+
+ printk(KERN_DEBUG"atheros pci: detached.\n");
+ return 0;
+}
+
+
+void ath_remove(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ ath_detach(dev);
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+
+ iounmap((void *)dev->mem_start);
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ pci_disable_device(pdev);
+ free_ieee80211(atheros_card);
+ atheros_card = NULL;
+}
+
+struct pci_device_id atheros_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ATHEROS, ATHEROS_5212) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, atheros_ids);
+
+static struct pci_driver atheros5212_id = {
+ .name = "Atheros5212",
+ .id_table = atheros_ids,
+ .probe = ath_probe,
+ .remove = ath_remove,
+ .resume = NULL,
+ .suspend = NULL,
+};
+
+static int __init atheros_init()
+{
+ if (pci_register_driver(&atheros5212_id) != 0)
+ return -1;
+ return 0;
+}
+
+static void __exit atheros_exit()
+{
+ pci_unregister_driver(&atheros5212_id);
+ return;
+}
+
+module_init(atheros_init);
+module_exit(atheros_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Mateusz Berezecki");
diff -uprN -X 'netdev-2.6.git#ieee80211/Documentation/dontdiff' netdev-2.6.git#ieee80211/drivers/net/wireless/atheros/atheros5212/interrupts.c netdev-atheros/drivers/net/wireless/atheros/atheros5212/interrupts.c
--- netdev-2.6.git#ieee80211/drivers/net/wireless/atheros/atheros5212/interrupts.c 1970-01-01 01:00:00.000000000 +0100
+++ netdev-atheros/drivers/net/wireless/atheros/atheros5212/interrupts.c 2005-08-05 03:48:36.000000000 +0200
@@ -0,0 +1,171 @@
+/*
+ * All the work was created by reverse engineering and porting
+ * for interoperability. The creator is Mateusz Berezecki,
+ * unless explicitly marked ( some parts are derived
+ * from GPL'ed parts of madwifi project located at http://madwifi.sf.net)
+ *
+ * derived or copied parts of code licensed under
+ * dual GPL/BSD license
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * rest of the code has been reversed by me and is under copyright too
+ * Copyright (C) 2005 Mateusz Berezecki
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+
+#include <net/ieee80211.h>
+
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+#include "atheros_id.h"
+#include "atheros_dev.h"
+#include "atheros_defs.h"
+#include "atheros_registers.h"
+#include "atheros.h"
+#include "eeprom.h"
+
+/* check if we got some interrupt pending signal from a device */
+int ath_int_pending(struct net_device *netdev)
+{
+ int val;
+
+ val = ath_reg_read(netdev, AR5212_INTPEND);
+
+ if (val == 1)
+ return 1;
+
+ return 0;
+}
+
+/* get type of pending interrupts from the device */
+int ath_get_pending_ints(struct net_device *netdev, int *imask)
+{
+ unsigned int val;
+
+ val = ath_reg_read(netdev, AR5212_RAC_PISR);
+ if (val == 0xffffffff) {
+ *imask = 0;
+ return 0;
+ }
+
+ *imask = val & INT_COMMON;
+
+ if (val & AR5212_PISR_HIUERR) { /* we got some fatal hw error */
+ *imask |= INT_FATAL;
+ return 0;
+ }
+
+ if (val & (AR5212_PISR_RXOK|AR5212_PISR_RXERR)) {
+ *imask |= INT_RX;
+ }
+
+ if (val & (AR5212_PISR_TXOK|AR5212_PISR_TXERR)) {
+ *imask |= INT_TX;
+ }
+
+ if (val & AR5212_PISR_RXORN) {
+ printk(KERN_DEBUG"atheros: receive overrun!\n");
+ *imask |= INT_FATAL;
+ }
+
+ return 1;
+}
+
+/* get current interrupt mask */
+unsigned int ath_get_interrupts(struct net_device *netdev)
+{
+ struct atheros_priv *p = ieee80211_priv(netdev);
+ return p->intr_mask;
+}
+
+/* set new interrupt mask. this is a bit counter-intuitive.
+ * the masked interrupts will BE actually delivered. */
+unsigned int ath_set_interruptmask(struct net_device *netdev,
+ unsigned int mask)
+{
+ struct atheros_priv *p = ieee80211_priv(netdev);
+ unsigned int tmp = p->intr_mask;
+ unsigned int val;
+
+ if (tmp & INT_GLOBAL) {
+ ath_reg_write(netdev, AR5212_IER, AR5212_IER_DISABLE);
+ ath_reg_read(netdev, AR5212_IER);
+ }
+
+ val = mask & INT_COMMON;
+ if (mask & INT_TX)
+ val |= AR5212_PIMR_TXOK |
+ AR5212_PIMR_TXERR |
+ AR5212_PIMR_TXDESC;
+
+ if (mask & INT_RX)
+ val |= AR5212_PIMR_RXOK |
+ AR5212_PIMR_RXERR |
+ AR5212_PIMR_RXDESC;
+
+ if (mask & INT_FATAL)
+ val |= AR5212_PISR_HIUERR;
+
+ ath_reg_write(netdev, AR5212_PIMR, val);
+ p->intr_mask = mask;
+
+ if (mask & INT_GLOBAL) {
+ ath_reg_write(netdev, AR5212_IER, AR5212_IER_ENABLE);
+ ath_reg_read(netdev, AR5212_IER);
+ }
+
+ return tmp;
+}
+
+
+/* just standard interrupt handling stuff goes here */
+irqreturn_t ath_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *netdev = (struct net_device *)dev_id;
+ struct atheros_priv *pdata = ieee80211_priv(netdev);
+ //INT status;
+
+ if (pdata->invalid)
+ return IRQ_NONE;
+
+// if (ath_intr_pending(netdev) == 0)
+// return IRQ_NONE;
+
+// if ((netdev->flags & (IFF_RUNNING | IFF_UP))
+// != (IFF_RUNNING | IFF_UP)) {
+// ath_get_pendingIntr(netdev, &status);
+// ath_set_intr(netdev, 0);
+// return IRQ_HANDLED;
+// }
+
+// /* add support for different hardware interrupts */
+// ath_get_pendingIntr(netdev, &status);
+//
+ return IRQ_NONE;
+}
+
+
+
diff -uprN -X 'netdev-2.6.git#ieee80211/Documentation/dontdiff' netdev-2.6.git#ieee80211/drivers/net/wireless/atheros/atheros5212/interrupts.h netdev-atheros/drivers/net/wireless/atheros/atheros5212/interrupts.h
--- netdev-2.6.git#ieee80211/drivers/net/wireless/atheros/atheros5212/interrupts.h 1970-01-01 01:00:00.000000000 +0100
+++ netdev-atheros/drivers/net/wireless/atheros/atheros5212/interrupts.h 2005-08-05 03:48:36.000000000 +0200
@@ -0,0 +1,50 @@
+/*
+ * All the work was created by reverse engineering and porting
+ * for interoperability. The creator is Mateusz Berezecki,
+ * unless explicitly marked ( some parts are derived
+ * from GPL'ed parts of madwifi project located at http://madwifi.sf.net)
+ *
+ * derived or copied parts of code licensed under
+ * dual GPL/BSD license
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * rest of the code has been reversed by me and is under copyright too
+ * Copyright (C) 2005 Mateusz Berezecki
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _H_INT
+#define _H_INT
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+
+#include <net/ieee80211.h>
+
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+extern irqreturn_t ath_intr(int, void *, struct pt_regs *);
+
+#endif
+
[-- Attachment #3: Type: text/plain, Size: 154 bytes --]
_______________________________________________
Kernel-mentors mailing list
Kernel-mentors@selenic.com
http://selenic.com/mailman/listinfo/kernel-mentors
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2005-08-05 2:59 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-08-05 2:59 atheros driver (5/8) Mateusz Berezecki
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).