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

📄 ib-pcmcia.c

📁 linux下的无线宽带驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* iBurst (TM) compatible driver for 2.6 Linux kernel. * based on the original ArrayComm (TM) iBurst (TM) driver. * Nicholas Jefferson <nicholas@pythontraining.com.au> * 11 May 2005 * * Ported to 2.6 Linux kernel by Nik Trevallyn-Jones. * Patches for 2.6.13 Linux kernel by Greg Cockburn and Scott McKenzie. * Patch for 2.6.16 Linux kernel by Daniel Burr. * Patch for 2.6.17 Linux kernel by Damian Ivereigh * Patch for sysfs by Scott McKenzie. * Fixes to support new hardware by Shane MacPhillamy. * * 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. */#include "ib-net.h"#include <asm/io.h>#include <linux/version.h>#include <pcmcia/cs_types.h>#include <pcmcia/cs.h>#include <pcmcia/cisreg.h>#include <pcmcia/cistpl.h>#include <pcmcia/ds.h>static int debug = 0;module_param(debug, int, 0);#define DEBUG(n, args...) if (debug < (n)) ; else printk(KERN_INFO args)/** * interval - poll interval (in milliseconds). */static int interval = 4;module_param(interval, int, 0);/** * io16 - PCMCIA 16 bit mode. */static int io16 = 0;module_param(io16, int, 0);/** * enum ib_pcmcia_ifstate - hardware interface state. */enum ib_pcmcia_ifstate{	IFSTATE_RESET = 0,	IFSTATE_WAIT = 1,	IFSTATE_NORMAL = 2,};/** * ib_pcmcia_offset - i/o mapped memory offsets. */enum ib_pcmcia_offset{	OFFSET_UT_MAGIC1 = 0x00,	OFFSET_UT_MAGIC2 = 0x01,	OFFSET_UT_SEQUENCE = 0x02,	OFFSET_UT_FEEDBACK = 0x03,	OFFSET_UT_JRX = 0x04,	OFFSET_UT_ITX = 0x05,	OFFSET_UT_PACKET = 0x06,	OFFSET_UT_STATUS = 0x07,	OFFSET_PC_MAGIC1 = 0x08,	OFFSET_PC_MAGIC2 = 0x09,	OFFSET_PC_SEQUENCE = 0x0a,	OFFSET_PC_FEEDBACK = 0x0b,	OFFSET_PC_JTX = 0x0c,	OFFSET_PC_IRX = 0x0d,	OFFSET_PC_PACKET = 0x0e,	OFFSET_PC_STATUS = 0x0f,	OFFSET_UT_ICHUNK = 0x10,	OFFSET_UT_NCHUNK = 0x11,	OFFSET_PC_JCHUNK = 0x12,	OFFSET_PC_NCHUNK = 0x13,	OFFSET_UT_ETHERNET = 0x1a,};/** * ib_pcmcia_local_t - PCMCIA device private state. * @dev: PCMCIA device state. * @node: network node. * @mem: i/o mapped memory. * @modem: corresponding modem state. * @timer: poll hardware. * @release: release configuration timer. * @ifstate: hardware state. * @sequence: hardware sync protocol. * @feedback: hardware sync protocol. * @rx_echunk: expected chunks (32 bytes) to receive. * @rx_ibuf: next index into rx_buf to use. * @rx_nbuf: packet length. * @tx_echunk: expected chunks (32 bytes) to transmit. * @tx_jbuf: next index into tx_buf to use. * @irx: most recent index into i/o mapped receive buffer. * @jtx: most recent index into i/o mapped transmit buffer. * @nreset: number of hardware resets. */struct ib_pcmcia_local_t {	struct pcmcia_device *dev;	struct dev_node_t node;	unsigned char *mem;	struct ib_net_modem_t *modem;	struct timer_list timer;	struct timer_list release;	enum ib_pcmcia_ifstate ifstate;	unsigned int sequence, feedback;	int rx_echunk, rx_ibuf, rx_nbuf;	int tx_echunk, tx_jbuf;	int irx, jtx;	int nreset;};/** * ib_pcmcia_dev_info - identifier for this driver. */static dev_info_t ib_pcmcia_dev_info = "iburst_cs";/** * ib_pcmcia_blit - the selected blit function. */static void (*ib_pcmcia_blit)(unsigned char*, unsigned char*, int);/** * ib_pcmcia_timer - poll hardware. * @_local: device private state. */static void ib_pcmcia_timer(unsigned long _local){	struct ib_pcmcia_local_t *local = (struct ib_pcmcia_local_t*) _local;	ib_net_schedule(local->modem);	local->timer.expires = jiffies + msecs_to_jiffies(interval);	local->timer.function = ib_pcmcia_timer;	local->timer.data = _local;	add_timer(&local->timer);}/** * ib_pcmcia_blit16 - blit chunks (32 bytes) 16 bits at a time. * @_dst: destination buffer. * @_src: source buffer. * @nchunk: chunk count. */static void ib_pcmcia_blit16(unsigned char *_dst, unsigned char *_src,		int nchunk){	uint16_t *dst = (uint16_t*) _dst;	uint16_t *src = (uint16_t*) _src;	while (nchunk--) {		dst[0] = src[0];		dst[1] = src[1];		dst[2] = src[2];		dst[3] = src[3];		dst[4] = src[4];		dst[5] = src[5];		dst[6] = src[6];		dst[7] = src[7];		dst[8] = src[8];		dst[9] = src[9];		dst[10] = src[10];		dst[11] = src[11];		dst[12] = src[12];		dst[13] = src[13];		dst[14] = src[14];		dst[15] = src[15];		dst += 16;		src += 16;	}}/** * ib_pcmcia_blit32 - blit chunks (32 bytes) 32 bits at a time. * @_dst: destination buffer. * @_src: source buffer. * @nchunk: chunk count. */static void ib_pcmcia_blit32(unsigned char *_dst, unsigned char *_src,		int nchunk){	uint32_t *dst = (uint32_t*) _dst;	uint32_t *src = (uint32_t*) _src;	while (1 < nchunk) {		dst[0] = src[0];		dst[1] = src[1];		dst[2] = src[2];		dst[3] = src[3];		dst[4] = src[4];		dst[5] = src[5];		dst[6] = src[6];		dst[7] = src[7];		dst[8] = src[8];		dst[9] = src[9];		dst[10] = src[10];		dst[11] = src[11];		dst[12] = src[12];		dst[13] = src[13];		dst[14] = src[14];		dst[15] = src[15];		dst += 16;		src += 16;		nchunk -= 2;	}	if (nchunk) {		dst[0] = src[0];		dst[1] = src[1];		dst[2] = src[2];		dst[3] = src[3];		dst[4] = src[4];		dst[5] = src[5];		dst[6] = src[6];		dst[7] = src[7];	}}/** * ib_pcmcia_release - release configuration. * @_local: device private state. */static void ib_pcmcia_release(unsigned long _local){	struct ib_pcmcia_local_t *local = (struct ib_pcmcia_local_t *) _local;	struct pcmcia_device *link = local->dev;	del_timer_sync(&local->timer);	ib_net_flush(local->modem);	iounmap(local->mem);	pcmcia_disable_device(link);}/** * ib_pcmcia_detach - detach device. * @link: device state. */static void ib_pcmcia_detach(struct pcmcia_device *link){	struct ib_pcmcia_local_t *local = link->priv;	del_timer_sync(&local->release);	ib_pcmcia_release((unsigned long) local);	if (local->modem)		ib_net_deregister(local->modem);	kfree(local);}/** * ib_pcmcia_reset - reset hardware protocol. *     called under ib_lock * @local: device private state. */static void ib_pcmcia_reset(struct ib_pcmcia_local_t *local){	struct ib_net_modem_t *modem = local->modem;	unsigned char *mem = local->mem;	unsigned int sequence, feedback;	mem[OFFSET_PC_MAGIC2] = 0x00;	mem[OFFSET_PC_MAGIC1] = 0x00;	sequence = mem[OFFSET_UT_SEQUENCE];	feedback = mem[OFFSET_UT_FEEDBACK];	if (local->nreset)		local->sequence = (feedback + 1) & 0xff;	else		local->sequence = (feedback + 7) & 0xff;	local->feedback = sequence;	mem[OFFSET_PC_SEQUENCE] = local->sequence;	mem[OFFSET_PC_FEEDBACK] = local->feedback;	mem[OFFSET_PC_IRX] = local->irx = 0;	mem[OFFSET_PC_JTX] = local->jtx = 0;	mem[OFFSET_PC_PACKET] = modem->stats.tx_packets & 0xff;	mem[OFFSET_PC_STATUS] = modem->pc_status;	mem[OFFSET_PC_MAGIC1] = 0xac;	mem[OFFSET_PC_MAGIC2] = 0x02;	local->ifstate = IFSTATE_WAIT;	local->nreset += 1;}/** * ib_pcmcia_check - check hardware consistent. *     called under ib_lock * @local: device private state. */static int ib_pcmcia_check(struct ib_pcmcia_local_t *local){	unsigned char *mem = local->mem;	if (mem[OFFSET_PC_MAGIC1] != 0xac || mem[OFFSET_PC_MAGIC2] != 0x02			|| mem[OFFSET_PC_SEQUENCE] != local->sequence			|| mem[OFFSET_PC_FEEDBACK] != local->feedback			|| mem[OFFSET_PC_IRX] != local->irx			|| mem[OFFSET_PC_JTX] != local->jtx) {		DEBUG(8, "ib-pcmcia: check %02X %02X %02X %02X "				"%02X %02X %02X %02X %02X %02X %02X %02X\n",				mem[OFFSET_PC_MAGIC1], mem[OFFSET_PC_MAGIC2],				mem[OFFSET_PC_PACKET], mem[OFFSET_PC_STATUS],				mem[OFFSET_PC_SEQUENCE], local->sequence,				mem[OFFSET_PC_FEEDBACK], local->feedback,				mem[OFFSET_PC_IRX], local->irx,				mem[OFFSET_PC_JTX], local->jtx);		ib_pcmcia_reset(local);		return 1;	}	return 0;}/** * ib_pcmcia_normal - normal operation; transfer chunks. *     called under ib_lock * @local: device private state. */static void ib_pcmcia_normal(struct ib_pcmcia_local_t *local){	struct ib_net_modem_t *modem = local->modem;	struct ib_net_radio_t *radio = (struct ib_net_radio_t*) modem->rx_buf;	unsigned char *mem = local->mem;	int irx, jrx, rx_ichunk, rx_nchunk;	int itx, jtx, tx_jchunk, tx_nchunk;	int nchunk, nbuf;	int packet;	if (ib_pcmcia_check(local))		return;	if (mem[OFFSET_UT_MAGIC1] != 0xac || mem[OFFSET_UT_MAGIC2] != 0x02			|| mem[OFFSET_UT_SEQUENCE] != local->feedback			|| mem[OFFSET_UT_FEEDBACK] != local->sequence) {		DEBUG(8, "ib-pcmcia: normal %02X %02X "				"%02X %02X %02X %02X\n",				mem[OFFSET_UT_MAGIC1], mem[OFFSET_UT_MAGIC2],				mem[OFFSET_UT_SEQUENCE], local->feedback,				mem[OFFSET_UT_FEEDBACK], local->sequence);		mem[OFFSET_PC_IRX] = local->irx = 0;		mem[OFFSET_PC_JTX] = local->jtx = 0;		local->ifstate = IFSTATE_WAIT;		return;	}	packet = modem->stats.tx_packets & 0xff;	ib_net_ut_status(modem, mem[OFFSET_UT_STATUS]);	if (mem[OFFSET_PC_PACKET] != packet)		mem[OFFSET_PC_PACKET] = packet;	if (mem[OFFSET_PC_STATUS] != modem->pc_status)		mem[OFFSET_PC_STATUS] = modem->pc_status;	rx_ichunk = mem[OFFSET_UT_ICHUNK];	rx_nchunk = mem[OFFSET_UT_NCHUNK];	tx_jchunk = mem[OFFSET_PC_JCHUNK];	tx_nchunk = mem[OFFSET_PC_NCHUNK];	if (rx_ichunk == 0 || rx_nchunk == 0)		goto failed;	if (tx_jchunk == 0 || tx_nchunk == 0)		goto failed;	if (tx_jchunk <= rx_ichunk && rx_ichunk < tx_jchunk + tx_nchunk)		goto failed;	if (rx_ichunk <= tx_jchunk && tx_jchunk < rx_ichunk + rx_nchunk)		goto failed;	if (0x80 < rx_ichunk + rx_nchunk || 0x80 < tx_jchunk + tx_nchunk)		goto failed;	while (1) {		irx = local->irx;		if (mem[OFFSET_PC_IRX] != irx)			goto failed;		jrx = mem[OFFSET_UT_JRX];		if (2 * rx_nchunk <= jrx)			goto failed;		if (irx == jrx)			break;		if (jrx < irx)			nchunk = jrx - irx + 2 * rx_nchunk;		else			nchunk = jrx - irx;		if (rx_nchunk < nchunk)			goto failed;		if (rx_nchunk <= irx)			irx -= rx_nchunk;		if (rx_nchunk - irx < nchunk)			nchunk = rx_nchunk - irx;		if (local->rx_echunk == 0) {			ib_pcmcia_blit(modem->rx_buf,					mem + ((rx_ichunk + irx) << 5), 1);			if (radio->word[0] & FLAG_EXTENSION)				goto failed;			nbuf = IB_NET_NBUF(radio->word[0], radio->word[1]);			if (nbuf < IB_NET_RADIO_HEAD)				goto failed;			if (IB_NET_RADIO_HEAD + ETH_DATA_LEN < nbuf)				goto failed;			local->irx += 1;			if (local->irx == 2 * rx_nchunk)				local->irx = 0;			mem[OFFSET_PC_IRX] = local->irx;			if (nbuf <= 32) {				ib_net_rx_parse(modem, nbuf);				continue;			}			local->rx_echunk = ((nbuf + 31) >> 5) - 1;			local->rx_ibuf = 32;

⌨️ 快捷键说明

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