⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dscc4.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	for (i = 0; i < 16; i++)		pci_write_config_dword(pdev, i << 2, dscc4_pci_config_store[i]);	up(&dscc4_sem);}#else#define dscc4_pci_reset(pdev,ioaddr)	do {} while (0)#endif /* CONFIG_DSCC4_PCI_RST */static int dscc4_open(struct net_device *dev){	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);	struct dscc4_pci_priv *ppriv;	int ret = -EAGAIN;	if ((dscc4_loopback_check(dpriv) < 0) || !dev->hard_start_xmit)		goto err;	if ((ret = hdlc_open(dev)))		goto err;	ppriv = dpriv->pci_priv;	/*	 * Due to various bugs, there is no way to reliably reset a	 * specific port (manufacturer's dependant special PCI #RST wiring	 * apart: it affects all ports). Thus the device goes in the best	 * silent mode possible at dscc4_close() time and simply claims to	 * be up if it's opened again. It still isn't possible to change	 * the HDLC configuration without rebooting but at least the ports	 * can be up/down ifconfig'ed without killing the host.	 */	if (dpriv->flags & FakeReset) {		dpriv->flags &= ~FakeReset;		scc_patchl(0, PowerUp, dpriv, dev, CCR0);		scc_patchl(0, 0x00050000, dpriv, dev, CCR2);		scc_writel(EventsMask, dpriv, dev, IMR);		printk(KERN_INFO "%s: up again.\n", dev->name);		goto done;	}	/* IDT+IDR during XPR */	dpriv->flags = NeedIDR | NeedIDT;	scc_patchl(0, PowerUp | Vis, dpriv, dev, CCR0);	/*	 * The following is a bit paranoid...	 *	 * NB: the datasheet "...CEC will stay active if the SCC is in	 * power-down mode or..." and CCR2.RAC = 1 are two different	 * situations.	 */	if (scc_readl_star(dpriv, dev) & SccBusy) {		printk(KERN_ERR "%s busy. Try later\n", dev->name);		ret = -EAGAIN;		goto err_out;	} else		printk(KERN_INFO "%s: available. Good\n", dev->name);	scc_writel(EventsMask, dpriv, dev, IMR);	/* Posted write is flushed in the wait_ack loop */	scc_writel(TxSccRes | RxSccRes, dpriv, dev, CMDR);	if ((ret = dscc4_wait_ack_cec(dpriv, dev, "Cec")) < 0)		goto err_disable_scc_events;	/*	 * I would expect XPR near CE completion (before ? after ?).	 * At worst, this code won't see a late XPR and people	 * will have to re-issue an ifconfig (this is harmless).	 * WARNING, a really missing XPR usually means a hardware	 * reset is needed. Suggestions anyone ?	 */	if ((ret = dscc4_xpr_ack(dpriv)) < 0) {		printk(KERN_ERR "%s: %s timeout\n", DRV_NAME, "XPR");		goto err_disable_scc_events;	}		if (debug > 2)		dscc4_tx_print(dev, dpriv, "Open");done:	netif_start_queue(dev);        init_timer(&dpriv->timer);        dpriv->timer.expires = jiffies + 10*HZ;        dpriv->timer.data = (unsigned long)dev;        dpriv->timer.function = &dscc4_timer;        add_timer(&dpriv->timer);	netif_carrier_on(dev);	return 0;err_disable_scc_events:	scc_writel(0xffffffff, dpriv, dev, IMR);	scc_patchl(PowerUp | Vis, 0, dpriv, dev, CCR0);err_out:	hdlc_close(dev);err:	return ret;}#ifdef DSCC4_POLLINGstatic int dscc4_tx_poll(struct dscc4_dev_priv *dpriv, struct net_device *dev){	/* FIXME: it's gonna be easy (TM), for sure */}#endif /* DSCC4_POLLING */static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);	struct dscc4_pci_priv *ppriv = dpriv->pci_priv;	struct TxFD *tx_fd;	int next;	next = dpriv->tx_current%TX_RING_SIZE;	dpriv->tx_skbuff[next] = skb;	tx_fd = dpriv->tx_fd + next;	tx_fd->state = FrameEnd | TO_STATE_TX(skb->len);	tx_fd->data = pci_map_single(ppriv->pdev, skb->data, skb->len,				     PCI_DMA_TODEVICE);	tx_fd->complete = 0x00000000;	tx_fd->jiffies = jiffies;	mb();#ifdef DSCC4_POLLING	spin_lock(&dpriv->lock);	while (dscc4_tx_poll(dpriv, dev));	spin_unlock(&dpriv->lock);#endif	dev->trans_start = jiffies;	if (debug > 2)		dscc4_tx_print(dev, dpriv, "Xmit");	/* To be cleaned(unsigned int)/optimized. Later, ok ? */	if (!((++dpriv->tx_current - dpriv->tx_dirty)%TX_RING_SIZE))		netif_stop_queue(dev);	if (dscc4_tx_quiescent(dpriv, dev))		dscc4_do_tx(dpriv, dev);	return 0;}static int dscc4_close(struct net_device *dev){	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);	del_timer_sync(&dpriv->timer);	netif_stop_queue(dev);	scc_patchl(PowerUp | Vis, 0, dpriv, dev, CCR0);	scc_patchl(0x00050000, 0, dpriv, dev, CCR2);	scc_writel(0xffffffff, dpriv, dev, IMR);	dpriv->flags |= FakeReset;	hdlc_close(dev);	return 0;}static inline int dscc4_check_clock_ability(int port){	int ret = 0;#ifdef CONFIG_DSCC4_PCISYNC	if (port >= 2)		ret = -1;#endif	return ret;}/* * DS1 p.137: "There are a total of 13 different clocking modes..." *                                  ^^ * Design choices: * - by default, assume a clock is provided on pin RxClk/TxClk (clock mode 0a). *   Clock mode 3b _should_ work but the testing seems to make this point *   dubious (DIY testing requires setting CCR0 at 0x00000033). *   This is supposed to provide least surprise "DTE like" behavior. * - if line rate is specified, clocks are assumed to be locally generated. *   A quartz must be available (on pin XTAL1). Modes 6b/7b are used. Choosing *   between these it automagically done according on the required frequency *   scaling. Of course some rounding may take place. * - no high speed mode (40Mb/s). May be trivial to do but I don't have an *   appropriate external clocking device for testing. * - no time-slot/clock mode 5: shameless lazyness. * * The clock signals wiring can be (is ?) manufacturer dependant. Good luck. * * BIG FAT WARNING: if the device isn't provided enough clocking signal, it * won't pass the init sequence. For example, straight back-to-back DTE without * external clock will fail when dscc4_open() (<- 'ifconfig hdlcx xxx') is * called. * * Typos lurk in datasheet (missing divier in clock mode 7a figure 51 p.153 * DS0 for example) * * Clock mode related bits of CCR0: *     +------------ TOE: output TxClk (0b/2b/3a/3b/6b/7a/7b only) *     | +---------- SSEL: sub-mode select 0 -> a, 1 -> b *     | | +-------- High Speed: say 0 *     | | | +-+-+-- Clock Mode: 0..7 *     | | | | | | * -+-+-+-+-+-+-+-+ * x|x|5|4|3|2|1|0| lower bits * * Division factor of BRR: k = (N+1)x2^M (total divider = 16xk in mode 6b) *            +-+-+-+------------------ M (0..15) *            | | | |     +-+-+-+-+-+-- N (0..63) *    0 0 0 0 | | | | 0 0 | | | | | | * ...-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *    f|e|d|c|b|a|9|8|7|6|5|4|3|2|1|0| lower bits * */static int dscc4_set_clock(struct net_device *dev, u32 *bps, u32 *state){	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);	int ret = -1;	u32 brr;	*state &= ~Ccr0ClockMask;	if (*bps) { /* Clock generated - required for DCE */		u32 n = 0, m = 0, divider;		int xtal;		xtal = dpriv->pci_priv->xtal_hz;		if (!xtal)			goto done;		if (dscc4_check_clock_ability(dpriv->dev_id) < 0)			goto done;		divider = xtal / *bps;		if (divider > BRR_DIVIDER_MAX) {			divider >>= 4;			*state |= 0x00000036; /* Clock mode 6b (BRG/16) */		} else			*state |= 0x00000037; /* Clock mode 7b (BRG) */		if (divider >> 22) {			n = 63;			m = 15;		} else if (divider) {			/* Extraction of the 6 highest weighted bits */			m = 0;			while (0xffffffc0 & divider) {				m++;				divider >>= 1;			}			n = divider;		}		brr = (m << 8) | n;		divider = n << m;		if (!(*state & 0x00000001)) /* ?b mode mask => clock mode 6b */			divider <<= 4;		*bps = xtal / divider;	} else {		/*		 * External clock - DTE		 * "state" already reflects Clock mode 0a (CCR0 = 0xzzzzzz00).		 * Nothing more to be done		 */		brr = 0;	}	scc_writel(brr, dpriv, dev, BRR);	ret = 0;done:	return ret;}static int dscc4_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){	sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync;	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);	const size_t size = sizeof(dpriv->settings);	int ret = 0;        if (dev->flags & IFF_UP)                return -EBUSY;	if (cmd != SIOCWANDEV)		return -EOPNOTSUPP;	switch(ifr->ifr_settings.type) {	case IF_GET_IFACE:		ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL;		if (ifr->ifr_settings.size < size) {			ifr->ifr_settings.size = size; /* data size wanted */			return -ENOBUFS;		}		if (copy_to_user(line, &dpriv->settings, size))			return -EFAULT;		break;	case IF_IFACE_SYNC_SERIAL:		if (!capable(CAP_NET_ADMIN))			return -EPERM;		if (dpriv->flags & FakeReset) {			printk(KERN_INFO "%s: please reset the device"			       " before this command\n", dev->name);			return -EPERM;		}		if (copy_from_user(&dpriv->settings, line, size))			return -EFAULT;		ret = dscc4_set_iface(dpriv, dev);		break;	default:		ret = hdlc_ioctl(dev, ifr, cmd);		break;	}	return ret;}static int dscc4_match(struct thingie *p, int value){	int i;	for (i = 0; p[i].define != -1; i++) {		if (value == p[i].define)			break;	}	if (p[i].define == -1)		return -1;	else		return i;}static int dscc4_clock_setting(struct dscc4_dev_priv *dpriv,			       struct net_device *dev){	sync_serial_settings *settings = &dpriv->settings;	int ret = -EOPNOTSUPP;	u32 bps, state;	bps = settings->clock_rate;	state = scc_readl(dpriv, CCR0);	if (dscc4_set_clock(dev, &bps, &state) < 0)		goto done;	if (bps) { /* DCE */		printk(KERN_DEBUG "%s: generated RxClk (DCE)\n", dev->name);		if (settings->clock_rate != bps) {			printk(KERN_DEBUG "%s: clock adjusted (%08d -> %08d)\n",				dev->name, settings->clock_rate, bps);			settings->clock_rate = bps;		}	} else { /* DTE */		state |= PowerUp | Vis;		printk(KERN_DEBUG "%s: external RxClk (DTE)\n", dev->name);	}	scc_writel(state, dpriv, dev, CCR0);	ret = 0;done:	return ret;}static int dscc4_encoding_setting(struct dscc4_dev_priv *dpriv,				  struct net_device *dev){	struct thingie encoding[] = {		{ ENCODING_NRZ,		0x00000000 },		{ ENCODING_NRZI,	0x00200000 },		{ ENCODING_FM_MARK,	0x00400000 },		{ ENCODING_FM_SPACE,	0x00500000 },		{ ENCODING_MANCHESTER,	0x00600000 },		{ -1,			0}	};	int i, ret = 0;	i = dscc4_match(encoding, dpriv->encoding);	if (i >= 0)		scc_patchl(EncodingMask, encoding[i].bits, dpriv, dev, CCR0);	else		ret = -EOPNOTSUPP;	return ret;}static int dscc4_loopback_setting(struct dscc4_dev_priv *dpriv,				  struct net_device *dev){	sync_serial_settings *settings = &dpriv->settings;	u32 state;	state = scc_readl(dpriv, CCR1);	if (settings->loopback) {		printk(KERN_DEBUG "%s: loopback\n", dev->name);		state |= 0x00000100;	} else {		printk(KERN_DEBUG "%s: normal\n", dev->name);		state &= ~0x00000100;	}	scc_writel(state, dpriv, dev, CCR1);	return 0;}static int dscc4_crc_setting(struct dscc4_dev_priv *dpriv,			     struct net_device *dev){	struct thingie crc[] = {		{ PARITY_CRC16_PR0_CCITT,	0x00000010 },		{ PARITY_CRC16_PR1_CCITT,	0x00000000 },		{ PARITY_CRC32_PR0_CCITT,	0x00000011 },		{ PARITY_CRC32_PR1_CCITT,	0x00000001 }	};	int i, ret = 0;	i = dscc4_match(crc, dpriv->parity);	if (i >= 0)		scc_patchl(CrcMask, crc[i].bits, dpriv, dev, CCR1);	else		ret = -EOPNOTSUPP;	return ret;}static int dscc4_set_iface(struct dscc4_dev_priv *dpriv, struct net_device *dev){	struct {		int (*action)(struct dscc4_dev_priv *, struct net_device *);	} *p, do_setting[] = {		{ dscc4_encoding_setting },		{ dscc4_clock_setting },		{ dscc4_loopback_setting },		{ dscc4_crc_setting },		{ NULL }	};	int ret = 0;	for (p = do_setting; p->action; p++) {		if ((ret = p->action(dpriv, dev)) < 0)			break;	}	return ret;}static irqreturn_t dscc4_irq(int irq, void *token, struct pt_regs *ptregs){	struct dscc4_dev_priv *root = token;	struct dscc4_pci_priv *priv;	struct net_device *dev;	void __iomem *ioaddr;	u32 state;	unsigned long flags;	int i, handled = 1;	priv = root->pci_priv;	dev = dscc4_to_dev(root);	spin_lock_irqsave(&priv->lock, flags);	ioaddr = root->base_addr;	state = readl(ioaddr + GSTAR);	if (!state) {		handled = 0;		goto out;	}	if (debug > 3)		printk(KERN_DEBUG "%s: GSTAR = 0x%08x\n", DRV_NAME, state);	writel(state, ioaddr + GSTAR);	if (state & Arf) {		printk(KERN_ERR "%s: failure (Arf). Harass the maintener\n",		       dev->name);		goto out;	}	state &= ~ArAck;	if (state & Cfg) {		if (debug > 0)			printk(KERN_DEBUG "%s: CfgIV\n", DRV_NAME);		if (priv->iqcfg[priv->cfg_cur++%IRQ_RING_SIZE] & Arf)			printk(KERN_ERR "%s: %s failed\n", dev->name, "CFG");		if (!(state &= ~Cfg))			goto out;	}	if (state & RxEvt) {		i = dev_per_card - 1;		do {			dscc4_rx_irq(priv, root + i);		} while (--i >= 0);		state &= ~RxEvt;	}	if (state & TxEvt) {		i = dev_per_card - 1;		do {			dscc4_tx_irq(priv, root + i);		} while (--i >= 0);		state &= ~TxEvt;	}out:	spin_unlock_irqrestore(&priv->lock, flags);	return IRQ_RETVAL(handled);}static void dscc4_tx_irq(struct dscc4_pci_priv *ppriv,				struct dscc4_dev_priv *dpriv){	struct net_device *dev = dscc4_to_dev(dpriv);	u32 state;	int cur, loop = 0;try:	cur = dpriv->iqtx_current%IRQ_RING_SIZE;	state = dpriv->iqtx[cur];	if (!state) {		if (debug > 4)			printk(KERN_DEBUG "%s: Tx ISR = 0x%08x\n", dev->name,			       state);		if ((debug > 1) && (loop > 1))			printk(KERN_DEBUG "%s: Tx irq loop=%d\n", dev->name, loop);		if (loop && netif_queue_stopped(dev))			if ((dpriv->tx_current - dpriv->tx_dirty)%TX_RING_SIZE)				netif_wake_queue(dev);		if (netif_running(dev) && dscc4_tx_quiescent(dpriv, dev) &&

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -