📄 skfddi.c
字号:
/* * File Name: * skfddi.c * * Copyright Information: * Copyright SysKonnect 1998,1999. * * 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. * * The information in this file is provided "AS IS" without warranty. * * Abstract: * A Linux device driver supporting the SysKonnect FDDI PCI controller * familie. * * Maintainers: * CG Christoph Goos (cgoos@syskonnect.de) * * Contributors: * DM David S. Miller * * Address all question to: * linux@syskonnect.de * * The technical manual for the adapters is available from SysKonnect's * web pages: www.syskonnect.com * Goto "Support" and search Knowledge Base for "manual". * * Driver Architecture: * The driver architecture is based on the DEC FDDI driver by * Lawrence V. Stefani and several ethernet drivers. * I also used an existing Windows NT miniport driver. * All hardware dependant fuctions are handled by the SysKonnect * Hardware Module. * The only headerfiles that are directly related to this source * are skfddi.c, h/types.h, h/osdef1st.h, h/targetos.h. * The others belong to the SysKonnect FDDI Hardware Module and * should better not be changed. * NOTE: * Compiling this driver produces some warnings, but I did not fix * this, because the Hardware Module source is used for different * drivers, and fixing it for Linux might bring problems on other * projects. To keep the source common for all those drivers (and * thus simplify fixes to it), please do not clean it up! * * Modification History: * Date Name Description * 02-Mar-98 CG Created. * * 10-Mar-99 CG Support for 2.2.x added. * 25-Mar-99 CG Corrected IRQ routing for SMP (APIC) * 26-Oct-99 CG Fixed compilation error on 2.2.13 * 12-Nov-99 CG Source code release * 22-Nov-99 CG Included in kernel source. * 07-May-00 DM 64 bit fixes, new dma interface * * Compilation options (-Dxxx): * DRIVERDEBUG print lots of messages to log file * DUMPPACKETS print received/transmitted packets to logfile * * Tested cpu architectures: * - i386 * - sparc64 *//* Version information string - should be updated prior to *//* each new release!!! */#define VERSION "2.06"static const char *boot_msg = "SysKonnect FDDI PCI Adapter driver v" VERSION " for\n" " SK-55xx/SK-58xx adapters (SK-NET FDDI-FP/UP/LP)";/* Include files */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/delay.h>#include <asm/byteorder.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/ctype.h> // isdigit#include <linux/netdevice.h>#include <linux/fddidevice.h>#include <linux/skbuff.h>#include "h/types.h"#undef ADDR // undo Linux definition#include "h/skfbi.h"#include "h/fddi.h"#include "h/smc.h"#include "h/smtstate.h"// Define global routinesint skfp_probe(struct net_device *dev);// Define module-wide (static) routinesstatic struct net_device *alloc_device(struct net_device *dev, u_long iobase);static struct net_device *insert_device(struct net_device *dev, int (*init) (struct net_device *));static int fddi_dev_index(unsigned char *s);static void init_dev(struct net_device *dev, u_long iobase);static void link_modules(struct net_device *dev, struct net_device *tmp);static int skfp_driver_init(struct net_device *dev);static int skfp_open(struct net_device *dev);static int skfp_close(struct net_device *dev);static void skfp_interrupt(int irq, void *dev_id, struct pt_regs *regs);static struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev);static void skfp_ctl_set_multicast_list(struct net_device *dev);static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev);static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr);static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev);static void send_queued_packets(struct s_smc *smc);static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr);static void ResetAdapter(struct s_smc *smc);// Functions needed by the hardware modulevoid *mac_drv_get_space(struct s_smc *smc, u_int size);void *mac_drv_get_desc_mem(struct s_smc *smc, u_int size);unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt);unsigned long dma_master(struct s_smc *smc, void *virt, int len, int flag);void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr, int flag);void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd);void llc_restart_tx(struct s_smc *smc);void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, int frag_count, int len);void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, int frag_count);void mac_drv_fill_rxd(struct s_smc *smc);void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, int frag_count);int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead, int la_len);void smt_timer_poll(struct s_smc *smc);void ring_status_indication(struct s_smc *smc, u_long status);unsigned long smt_get_time(void);void smt_stat_counter(struct s_smc *smc, int stat);void cfm_state_change(struct s_smc *smc, int c_state);void ecm_state_change(struct s_smc *smc, int e_state);void pcm_state_change(struct s_smc *smc, int plc, int p_state);void rmt_state_change(struct s_smc *smc, int r_state);void drv_reset_indication(struct s_smc *smc);void dump_data(unsigned char *Data, int length);// External functions from the hardware moduleextern u_int mac_drv_check_space();extern void read_address(struct s_smc *smc, u_char * mac_addr);extern void card_stop(struct s_smc *smc);extern int mac_drv_init(struct s_smc *smc);extern void hwm_tx_frag(struct s_smc *smc, char far * virt, u_long phys, int len, int frame_status);extern int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len, int frame_status);extern int init_smt(struct s_smc *smc, u_char * mac_addr);extern void fddi_isr(struct s_smc *smc);extern void hwm_rx_frag(struct s_smc *smc, char far * virt, u_long phys, int len, int frame_status);extern void mac_drv_rx_mode(struct s_smc *smc, int mode);extern void mac_drv_clear_tx_queue(struct s_smc *smc);extern void mac_drv_clear_rx_queue(struct s_smc *smc);extern void mac_clear_multicast(struct s_smc *smc);extern void enable_tx_irq(struct s_smc *smc, u_short queue);extern void mac_drv_clear_txd(struct s_smc *smc);static struct pci_device_id skfddi_pci_tbl[] __initdata = { { PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, PCI_ANY_ID, PCI_ANY_ID, }, { } /* Terminating entry */};MODULE_DEVICE_TABLE(pci, skfddi_pci_tbl);MODULE_LICENSE("GPL");// Define module-wide (static) variablesstatic int num_boards; /* total number of adapters configured */static int num_fddi;static int autoprobed;#ifdef MODULEint init_module(void);void cleanup_module(void);static struct net_device *unlink_modules(struct net_device *p);static int loading_module = 1;#elsestatic int loading_module;#endif // MODULE#ifdef DRIVERDEBUG#define PRINTK(s, args...) printk(s, ## args)#else#define PRINTK(s, args...)#endif // DRIVERDEBUG#define PRIV(dev) (&(((struct s_smc *)dev->priv)->os))/* * ============== * = skfp_probe = * ============== * * Overview: * Probes for supported FDDI PCI controllers * * Returns: * Condition code * * Arguments: * dev - pointer to device information * * Functional Description: * This routine is called by the OS for each FDDI device name (fddi0, * fddi1,...,fddi6, fddi7) specified in drivers/net/Space.c. * If loaded as a module, it will detect and initialize all * adapters the first time it is called. * * Let's say that skfp_probe() is getting called to initialize fddi0. * Furthermore, let's say there are three supported controllers in the * system. Before skfp_probe() leaves, devices fddi0, fddi1, and fddi2 * will be initialized and a global flag will be set to indicate that * skfp_probe() has already been called. * * However...the OS doesn't know that we've already initialized * devices fddi1 and fddi2 so skfp_probe() gets called again and again * until it reaches the end of the device list for FDDI (presently, * fddi7). It's important that the driver "pretend" to probe for * devices fddi1 and fddi2 and return success. Devices fddi3 * through fddi7 will return failure since they weren't initialized. * * This algorithm seems to work for the time being. As other FDDI * drivers are written for Linux, a more generic approach (perhaps * similar to the Ethernet card approach) may need to be implemented. * * Return Codes: * 0 - This device (fddi0, fddi1, etc) configured successfully * -ENODEV - No devices present, or no SysKonnect FDDI PCI device * present for this device name * * * Side Effects: * Device structures for FDDI adapters (fddi0, fddi1, etc) are * initialized and the board resources are read and stored in * the device structure. */int skfp_probe(struct net_device *dev){ int i; /* used in for loops */ struct pci_dev *pdev = NULL; /* PCI device structure */#ifndef MEM_MAPPED_IO u16 port; /* temporary I/O (port) address */ int port_len; /* length of port address range (in bytes) */#else unsigned long port;#endif u16 command; /* PCI Configuration space Command register val */ struct s_smc *smc; /* board pointer */ struct net_device *tmp = dev; u8 first_dev_used = 0; u16 SubSysId; PRINTK(KERN_INFO "entering skfp_probe\n"); /* * Verify whether we're going through skfp_probe() again * * If so, see if we're going through for a subsequent fddi device that * we've already initialized. If we are, return success (0). If not, * return failure (-ENODEV). */ if (autoprobed) { PRINTK(KERN_INFO "Already entered skfp_probe\n"); if (dev != NULL) { if ((strncmp(dev->name, "fddi", 4) == 0) && (dev->base_addr != 0)) { return (0); } return (-ENODEV); } } autoprobed = 1; /* set global flag */ printk("%s\n", boot_msg); /* Scan for Syskonnect FDDI PCI controllers */ if (!pci_present()) { /* is PCI BIOS even present? */ printk("no PCI BIOS present\n"); return (-ENODEV); } for (i = 0; i < SKFP_MAX_NUM_BOARDS; i++) { // scan for PCI cards PRINTK(KERN_INFO "Check device %d\n", i); if ((pdev=pci_find_device(PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, pdev)) == 0) { break; } if (pci_enable_device(pdev)) continue;#ifndef MEM_MAPPED_IO /* Verify that I/O enable bit is set (PCI slot is enabled) */ pci_read_config_word(pdev, PCI_COMMAND, &command); if ((command & PCI_COMMAND_IO) == 0) { PRINTK("I/O enable bit not set!"); PRINTK(" Verify that slot is enabled\n"); continue; } /* Turn off memory mapped space and enable mastering */ PRINTK(KERN_INFO "Command Reg: %04x\n", command); command |= PCI_COMMAND_MASTER; command &= ~PCI_COMMAND_MEMORY; pci_write_config_word(pdev, PCI_COMMAND, command); /* Read I/O base address from PCI Configuration Space */ pci_read_config_word(pdev, PCI_BASE_ADDRESS_1, &port); port &= PCI_BASE_ADDRESS_IO_MASK; // clear I/O bit (bit 0) /* Verify port address range is not already being used */ port_len = FP_IO_LEN; if (check_region(port, port_len) != 0) { printk("I/O range allocated to adapter"); printk(" (0x%X-0x%X) is already being used!\n", port, (port + port_len - 1)); continue; }#else /* Verify that MEM enable bit is set (PCI slot is enabled) */ pci_read_config_word(pdev, PCI_COMMAND, &command); if ((command & PCI_COMMAND_MEMORY) == 0) { PRINTK("MEMORY-I/O enable bit not set!"); PRINTK(" Verify that slot is enabled\n"); continue; } /* Turn off IO mapped space and enable mastering */ PRINTK(KERN_INFO "Command Reg: %04x\n", command); command |= PCI_COMMAND_MASTER; command &= ~PCI_COMMAND_IO; pci_write_config_word(pdev, PCI_COMMAND, command); port = pci_resource_start(pdev, 0); port = (unsigned long)ioremap(port, 0x4000); if (!port){ printk("skfp: Unable to map MEMORY register, " "FDDI adapter will be disabled.\n"); break; }#endif if ((!loading_module) || first_dev_used) { /* Allocate a device structure for this adapter */ tmp = alloc_device(dev, port); } first_dev_used = 1; // only significant first time pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &SubSysId); if (tmp != NULL) { if (loading_module) link_modules(dev, tmp); dev = tmp; init_dev(dev, port); dev->irq = pdev->irq; /* Initialize board structure with bus-specific info */ smc = (struct s_smc *) dev->priv; smc->os.dev = dev; smc->os.bus_type = SK_BUS_TYPE_PCI; smc->os.pdev = *pdev; smc->os.QueueSkb = MAX_TX_QUEUE_LEN; smc->os.MaxFrameSize = MAX_FRAME_SIZE; smc->os.dev = dev; smc->hw.slot = -1; smc->os.ResetRequested = FALSE; skb_queue_head_init(&smc->os.SendSkbQueue); if (skfp_driver_init(dev) == 0) { // only increment global board // count on success num_boards++; request_region(dev->base_addr, FP_IO_LEN, dev->name); if ((SubSysId & 0xff00) == 0x5500 || (SubSysId & 0xff00) == 0x5800) { printk("%s: SysKonnect FDDI PCI adapter" " found (SK-%04X)\n", dev->name, SubSysId); } else { printk("%s: FDDI PCI adapter found\n", dev->name); } } else { kfree(dev); i = SKFP_MAX_NUM_BOARDS; // stop search } } // if (dev != NULL) } // for SKFP_MAX_NUM_BOARDS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -