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 + -
显示快捷键?