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

📄 wavelan_cs.c

📁 pcmcia source code
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *	Wavelan Pcmcia driver * *		Jean II - HPLB '96 * * Reorganisation and extension of the driver. * Original copyright follow. See wavelan_cs.h for details. * * This code is derived from Anthony D. Joseph's code and all the changes here * are also under the original copyright below. * * This code supports version 2.00 of WaveLAN/PCMCIA cards (2.4GHz), and * can work on Linux 2.0.36 with support of David Hinds' PCMCIA Card Services * * Joe Finney (joe@comp.lancs.ac.uk) at Lancaster University in UK added * critical code in the routine to initialize the Modem Management Controller. * * Thanks to Alan Cox and Bruce Janson for their advice. * *	-- Yunzhou Li (scip4166@nus.sg) *#ifdef WAVELAN_ROAMING	 * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu) * based on patch by Joe Finney from Lancaster University.#endif * * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor. * *   A non-shared memory PCMCIA ethernet driver for linux * * ISA version modified to support PCMCIA by Anthony Joseph (adj@lcs.mit.edu) * * * Joseph O'Sullivan & John Langford (josullvn@cs.cmu.edu & jcl@cs.cmu.edu) * * Apr 2 '98  made changes to bring the i82593 control/int handling in line *             with offical specs... * **************************************************************************** *   Copyright 1995 *   Anthony D. Joseph *   Massachusetts Institute of Technology * *   Permission to use, copy, modify, and distribute this program *   for any purpose and without fee is hereby granted, provided *   that this copyright and permission notice appear on all copies *   and supporting documentation, the name of M.I.T. not be used *   in advertising or publicity pertaining to distribution of the *   program without specific prior permission, and notice be given *   in supporting documentation that copying and distribution is *   by permission of M.I.T.  M.I.T. makes no representations about *   the suitability of this software for any purpose.  It is pro- *   vided "as is" without express or implied warranty.          **************************************************************************** * */#include "wavelan_cs.h"		/* Private header *//************************* MISC SUBROUTINES **************************//* * Subroutines which won't fit in one of the following category * (wavelan modem or i82593) *//*------------------------------------------------------------------*//* * Wrapper for disabling interrupts. * (note : inline, so optimised away) */static inline voidwv_splhi(net_local *		lp,	 unsigned long *	pflags){  spin_lock_irqsave(&lp->spinlock, *pflags);  /* Note : above does the cli(); itself */}/*------------------------------------------------------------------*//* * Wrapper for re-enabling interrupts. */static inline voidwv_splx(net_local *		lp,	unsigned long *		pflags){  spin_unlock_irqrestore(&lp->spinlock, *pflags);  /* Note : enabling interrupts on the hardware is done in wv_ru_start()   * via : outb(OP1_INT_ENABLE, LCCR(base));   */}/*------------------------------------------------------------------*//* * Wrapper for reporting error to cardservices */static void cs_error(client_handle_t handle, int func, int ret){    error_info_t err = { func, ret };    CardServices(ReportError, handle, &err);}#ifdef STRUCT_CHECK/*------------------------------------------------------------------*//* * Sanity routine to verify the sizes of the various WaveLAN interface * structures. */static char *wv_structuct_check(void){#define	SC(t,s,n)	if (sizeof(t) != s) return(n);  SC(psa_t, PSA_SIZE, "psa_t");  SC(mmw_t, MMW_SIZE, "mmw_t");  SC(mmr_t, MMR_SIZE, "mmr_t");#undef	SC  return((char *) NULL);} /* wv_structuct_check */#endif	/* STRUCT_CHECK *//******************* MODEM MANAGEMENT SUBROUTINES *******************//* * Useful subroutines to manage the modem of the wavelan *//*------------------------------------------------------------------*//* * Read from card's Host Adaptor Status Register. */static inline u_charhasr_read(u_long	base){  return(inb(HASR(base)));} /* hasr_read *//*------------------------------------------------------------------*//* * Write to card's Host Adapter Command Register. */static inline voidhacr_write(u_long	base,	   u_char	hacr){  outb(hacr, HACR(base));} /* hacr_write *//*------------------------------------------------------------------*//* * Write to card's Host Adapter Command Register. Include a delay for * those times when it is needed. */static inline voidhacr_write_slow(u_long	base,		u_char	hacr){  hacr_write(base, hacr);  /* delay might only be needed sometimes */  mdelay(1);} /* hacr_write_slow *//*------------------------------------------------------------------*//* * Read the Parameter Storage Area from the WaveLAN card's memory */static voidpsa_read(device *	dev,	 int		o,	/* offset in PSA */	 u_char *	b,	/* buffer to fill */	 int		n)	/* size to read */{  u_char *	ptr = ((u_char *)dev->mem_start) + PSA_ADDR + (o << 1);  while(n-- > 0)    {      *b++ = readb(ptr);      /* Due to a lack of address decode pins, the WaveLAN PCMCIA card       * only supports reading even memory addresses. That means the       * increment here MUST be two.       * Because of that, we can't use memcpy_fromio()...       */      ptr += 2;    }} /* psa_read *//*------------------------------------------------------------------*//* * Write the Paramter Storage Area to the WaveLAN card's memory */static voidpsa_write(device *	dev,	  int		o,	/* Offset in psa */	  u_char *	b,	/* Buffer in memory */	  int		n)	/* Length of buffer */{  u_char *	ptr = ((u_char *) dev->mem_start) + PSA_ADDR + (o << 1);  int		count = 0;  ioaddr_t	base = dev->base_addr;  /* As there seem to have no flag PSA_BUSY as in the ISA model, we are   * oblige to verify this address to know when the PSA is ready... */  volatile u_char *	verify = ((u_char *) dev->mem_start) + PSA_ADDR +    (psaoff(0, psa_comp_number) << 1);  /* Authorize writting to PSA */  hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN);  while(n-- > 0)    {      /* write to PSA */      writeb(*b++, ptr);      ptr += 2;      /* I don't have the spec, so I don't know what the correct       * sequence to write is. This hack seem to work for me... */      count = 0;      while((readb(verify) != PSA_COMP_PCMCIA_915) && (count++ < 100))	mdelay(1);    }  /* Put the host interface back in standard state */  hacr_write(base, HACR_DEFAULT);} /* psa_write */#ifdef SET_PSA_CRC/*------------------------------------------------------------------*//* * Calculate the PSA CRC * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code * NOTE: By specifying a length including the CRC position the * returned value should be zero. (i.e. a correct checksum in the PSA) * * The Windows drivers don't use the CRC, but the AP and the PtP tool * depend on it. */static u_shortpsa_crc(unsigned char *	psa,	/* The PSA */	int		size)	/* Number of short for CRC */{  int		byte_cnt;	/* Loop on the PSA */  u_short	crc_bytes = 0;	/* Data in the PSA */  int		bit_cnt;	/* Loop on the bits of the short */  for(byte_cnt = 0; byte_cnt < size; byte_cnt++ )    {      crc_bytes ^= psa[byte_cnt];	/* Its an xor */      for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ )	{	  if(crc_bytes & 0x0001)	    crc_bytes = (crc_bytes >> 1) ^ 0xA001;	  else	    crc_bytes >>= 1 ;        }    }  return crc_bytes;} /* psa_crc */#endif	/* SET_PSA_CRC *//*------------------------------------------------------------------*//* * update the checksum field in the Wavelan's PSA */static voidupdate_psa_checksum(device *	dev){#ifdef SET_PSA_CRC  psa_t		psa;  u_short	crc;  /* read the parameter storage area */  psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));  /* update the checksum */  crc = psa_crc((unsigned char *) &psa,		sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1])		- sizeof(psa.psa_crc_status));  psa.psa_crc[0] = crc & 0xFF;  psa.psa_crc[1] = (crc & 0xFF00) >> 8;  /* Write it ! */  psa_write(dev, (char *)&psa.psa_crc - (char *)&psa,	    (unsigned char *)&psa.psa_crc, 2);#ifdef DEBUG_IOCTL_INFO  printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n",          dev->name, psa.psa_crc[0], psa.psa_crc[1]);  /* Check again (luxury !) */  crc = psa_crc((unsigned char *) &psa,		 sizeof(psa) - sizeof(psa.psa_crc_status));  if(crc != 0)    printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name);#endif /* DEBUG_IOCTL_INFO */#endif	/* SET_PSA_CRC */} /* update_psa_checksum *//*------------------------------------------------------------------*//* * Write 1 byte to the MMC. */static inline voidmmc_out(u_long		base,	u_short		o,	u_char		d){  /* Wait for MMC to go idle */  while(inb(HASR(base)) & HASR_MMI_BUSY)    ;  outb((u_char)((o << 1) | MMR_MMI_WR), MMR(base));  outb(d, MMD(base));}/*------------------------------------------------------------------*//* * Routine to write bytes to the Modem Management Controller. * We start by the end because it is the way it should be ! */static inline voidmmc_write(u_long	base,	  u_char	o,	  u_char *	b,	  int		n){  o += n;  b += n;  while(n-- > 0 )    mmc_out(base, --o, *(--b));} /* mmc_write *//*------------------------------------------------------------------*//* * Read 1 byte from the MMC. * Optimised version for 1 byte, avoid using memory... */static inline u_charmmc_in(u_long	base,       u_short	o){  while(inb(HASR(base)) & HASR_MMI_BUSY)    ;  outb(o << 1, MMR(base));		/* Set the read address */  outb(0, MMD(base));			/* Required dummy write */  while(inb(HASR(base)) & HASR_MMI_BUSY)    ;  return (u_char) (inb(MMD(base)));	/* Now do the actual read */}/*------------------------------------------------------------------*//* * Routine to read bytes from the Modem Management Controller. * The implementation is complicated by a lack of address lines, * which prevents decoding of the low-order bit. * (code has just been moved in the above function) * We start by the end because it is the way it should be ! */static inline voidmmc_read(u_long		base,	 u_char		o,	 u_char *	b,	 int		n){  o += n;  b += n;  while(n-- > 0)    *(--b) = mmc_in(base, --o);} /* mmc_read *//*------------------------------------------------------------------*//* * Get the type of encryption available... */static inline intmmc_encr(u_long		base)	/* i/o port of the card */{  int	temp;  temp = mmc_in(base, mmroff(0, mmr_des_avail));  if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES))    return 0;  else    return temp;}/*------------------------------------------------------------------*//* * Wait for the frequency EEprom to complete a command... * I hope this one will be optimally inlined... */static inline voidfee_wait(u_long		base,	/* i/o port of the card */	 int		delay,	/* Base delay to wait for */	 int		number)	/* Number of time to wait */{  int		count = 0;	/* Wait only a limited time */  while((count++ < number) &&	(mmc_in(base, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY))    udelay(delay);}/*------------------------------------------------------------------*//* * Read bytes from the Frequency EEprom (frequency select cards). */static voidfee_read(u_long		base,	/* i/o port of the card */	 u_short	o,	/* destination offset */	 u_short *	b,	/* data buffer */	 int		n)	/* number of registers */{  b += n;		/* Position at the end of the area */  /* Write the address */  mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1);  /* Loop on all buffer */  while(n-- > 0)    {      /* Write the read command */      mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ);      /* Wait until EEprom is ready (should be quick !) */      fee_wait(base, 10, 100);      /* Read the value */      *--b = ((mmc_in(base, mmroff(0, mmr_fee_data_h)) << 8) |	      mmc_in(base, mmroff(0, mmr_fee_data_l)));    }}#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel *//*------------------------------------------------------------------*//* * Write bytes from the Frequency EEprom (frequency select cards). * This is a bit complicated, because the frequency eeprom has to * be unprotected and the write enabled. * Jean II */static voidfee_write(u_long	base,	/* i/o port of the card */	  u_short	o,	/* destination offset */	  u_short *	b,	/* data buffer */	  int		n)	/* number of registers */

⌨️ 快捷键说明

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