pc300too.c
来自「linux 内核源代码」· C语言 代码 · 共 562 行 · 第 1/2 页
C
562 行
/* * Cyclades PC300 synchronous serial card driver for Linux * * Copyright (C) 2000-2007 Krzysztof Halasa <khc@pm.waw.pl> * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. * * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>. * * Sources of information: * Hitachi HD64572 SCA-II User's Manual * Cyclades PC300 Linux driver * * This driver currently supports only PC300/RSV (V.24/V.35) and * PC300/X21 cards. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/in.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/moduleparam.h>#include <linux/netdevice.h>#include <linux/hdlc.h>#include <linux/pci.h>#include <linux/delay.h>#include <asm/io.h>#include "hd64572.h"static const char* version = "Cyclades PC300 driver version: 1.17";static const char* devname = "PC300";#undef DEBUG_PKT#define DEBUG_RINGS#define PC300_PLX_SIZE 0x80 /* PLX control window size (128 B) */#define PC300_SCA_SIZE 0x400 /* SCA window size (1 KB) */#define ALL_PAGES_ALWAYS_MAPPED#define NEED_DETECT_RAM#define NEED_SCA_MSCI_INTR#define MAX_TX_BUFFERS 10static int pci_clock_freq = 33000000;static int use_crystal_clock = 0;static unsigned int CLOCK_BASE;/* Masks to access the init_ctrl PLX register */#define PC300_CLKSEL_MASK (0x00000004UL)#define PC300_CHMEDIA_MASK(port) (0x00000020UL << ((port) * 3))#define PC300_CTYPE_MASK (0x00000800UL)enum { PC300_RSV = 1, PC300_X21, PC300_TE }; /* card types *//* * PLX PCI9050-1 local configuration and shared runtime registers. * This structure can be used to access 9050 registers (memory mapped). */typedef struct { u32 loc_addr_range[4]; /* 00-0Ch : Local Address Ranges */ u32 loc_rom_range; /* 10h : Local ROM Range */ u32 loc_addr_base[4]; /* 14-20h : Local Address Base Addrs */ u32 loc_rom_base; /* 24h : Local ROM Base */ u32 loc_bus_descr[4]; /* 28-34h : Local Bus Descriptors */ u32 rom_bus_descr; /* 38h : ROM Bus Descriptor */ u32 cs_base[4]; /* 3C-48h : Chip Select Base Addrs */ u32 intr_ctrl_stat; /* 4Ch : Interrupt Control/Status */ u32 init_ctrl; /* 50h : EEPROM ctrl, Init Ctrl, etc */}plx9050;typedef struct port_s { struct net_device *dev; struct card_s *card; spinlock_t lock; /* TX lock */ sync_serial_settings settings; int rxpart; /* partial frame received, next frame invalid*/ unsigned short encoding; unsigned short parity; unsigned int iface; u16 rxin; /* rx ring buffer 'in' pointer */ u16 txin; /* tx ring buffer 'in' and 'last' pointers */ u16 txlast; u8 rxs, txs, tmc; /* SCA registers */ u8 phy_node; /* physical port # - 0 or 1 */}port_t;typedef struct card_s { int type; /* RSV, X21, etc. */ int n_ports; /* 1 or 2 ports */ u8 __iomem *rambase; /* buffer memory base (virtual) */ u8 __iomem *scabase; /* SCA memory base (virtual) */ plx9050 __iomem *plxbase; /* PLX registers memory base (virtual) */ u32 init_ctrl_value; /* Saved value - 9050 bug workaround */ u16 rx_ring_buffers; /* number of buffers in a ring */ u16 tx_ring_buffers; u16 buff_offset; /* offset of first buffer of first channel */ u8 irq; /* interrupt request level */ port_t ports[2];}card_t;#define sca_in(reg, card) readb(card->scabase + (reg))#define sca_out(value, reg, card) writeb(value, card->scabase + (reg))#define sca_inw(reg, card) readw(card->scabase + (reg))#define sca_outw(value, reg, card) writew(value, card->scabase + (reg))#define sca_inl(reg, card) readl(card->scabase + (reg))#define sca_outl(value, reg, card) writel(value, card->scabase + (reg))#define port_to_card(port) (port->card)#define log_node(port) (port->phy_node)#define phy_node(port) (port->phy_node)#define winbase(card) (card->rambase)#define get_port(card, port) ((port) < (card)->n_ports ? \ (&(card)->ports[port]) : (NULL))#include "hd6457x.c"static void pc300_set_iface(port_t *port){ card_t *card = port->card; u32 __iomem * init_ctrl = &card->plxbase->init_ctrl; u16 msci = get_msci(port); u8 rxs = port->rxs & CLK_BRG_MASK; u8 txs = port->txs & CLK_BRG_MASK; sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS, port_to_card(port)); switch(port->settings.clock_type) { case CLOCK_INT: rxs |= CLK_BRG; /* BRG output */ txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */ break; case CLOCK_TXINT: rxs |= CLK_LINE; /* RXC input */ txs |= CLK_PIN_OUT | CLK_BRG; /* BRG output */ break; case CLOCK_TXFROMRX: rxs |= CLK_LINE; /* RXC input */ txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */ break; default: /* EXTernal clock */ rxs |= CLK_LINE; /* RXC input */ txs |= CLK_PIN_OUT | CLK_LINE; /* TXC input */ break; } port->rxs = rxs; port->txs = txs; sca_out(rxs, msci + RXS, card); sca_out(txs, msci + TXS, card); sca_set_port(port); if (port->card->type == PC300_RSV) { if (port->iface == IF_IFACE_V35) writel(card->init_ctrl_value | PC300_CHMEDIA_MASK(port->phy_node), init_ctrl); else writel(card->init_ctrl_value & ~PC300_CHMEDIA_MASK(port->phy_node), init_ctrl); }}static int pc300_open(struct net_device *dev){ port_t *port = dev_to_port(dev); int result = hdlc_open(dev); if (result) return result; sca_open(dev); pc300_set_iface(port); return 0;}static int pc300_close(struct net_device *dev){ sca_close(dev); hdlc_close(dev); return 0;}static int pc300_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ const size_t size = sizeof(sync_serial_settings); sync_serial_settings new_line; sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; int new_type; port_t *port = dev_to_port(dev);#ifdef DEBUG_RINGS if (cmd == SIOCDEVPRIVATE) { sca_dump_rings(dev); return 0; }#endif if (cmd != SIOCWANDEV) return hdlc_ioctl(dev, ifr, cmd); if (ifr->ifr_settings.type == IF_GET_IFACE) { ifr->ifr_settings.type = port->iface; if (ifr->ifr_settings.size < size) { ifr->ifr_settings.size = size; /* data size wanted */ return -ENOBUFS; } if (copy_to_user(line, &port->settings, size)) return -EFAULT; return 0; } if (port->card->type == PC300_X21 && (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL || ifr->ifr_settings.type == IF_IFACE_X21)) new_type = IF_IFACE_X21; else if (port->card->type == PC300_RSV && (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL || ifr->ifr_settings.type == IF_IFACE_V35)) new_type = IF_IFACE_V35; else if (port->card->type == PC300_RSV && ifr->ifr_settings.type == IF_IFACE_V24) new_type = IF_IFACE_V24; else return hdlc_ioctl(dev, ifr, cmd); if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&new_line, line, size)) return -EFAULT; if (new_line.clock_type != CLOCK_EXT && new_line.clock_type != CLOCK_TXFROMRX && new_line.clock_type != CLOCK_INT && new_line.clock_type != CLOCK_TXINT) return -EINVAL; /* No such clock setting */ if (new_line.loopback != 0 && new_line.loopback != 1) return -EINVAL; memcpy(&port->settings, &new_line, size); /* Update settings */ port->iface = new_type; pc300_set_iface(port); return 0;}static void pc300_pci_remove_one(struct pci_dev *pdev){ int i; card_t *card = pci_get_drvdata(pdev);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?