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

📄 cosa.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	char idstring[COSA_MAX_ID_STRING];	if (cosa->usage > 1)		printk(KERN_INFO "cosa%d: WARNING: reset requested with cosa->usage > 1 (%d). Odd things may happen.\n",			cosa->num, cosa->usage);	cosa->firmware_status &= ~(COSA_FW_RESET|COSA_FW_START);	if (cosa_reset_and_read_id(cosa, idstring) < 0) {		printk(KERN_NOTICE "cosa%d: reset failed\n", cosa->num);		return -EIO;	}	printk(KERN_INFO "cosa%d: resetting device: %s\n", cosa->num,		idstring);	cosa->firmware_status |= COSA_FW_RESET;	return 0;}/* High-level function to download data into COSA memory. Calls download() */static inline int cosa_download(struct cosa_data *cosa, void __user *arg){	struct cosa_download d;	int i;	if (cosa->usage > 1)		printk(KERN_INFO "%s: WARNING: download of microcode requested with cosa->usage > 1 (%d). Odd things may happen.\n",			cosa->name, cosa->usage);	if (!(cosa->firmware_status & COSA_FW_RESET)) {		printk(KERN_NOTICE "%s: reset the card first (status %d).\n",			cosa->name, cosa->firmware_status);		return -EPERM;	}		if (copy_from_user(&d, arg, sizeof(d)))		return -EFAULT;	if (d.addr < 0 || d.addr > COSA_MAX_FIRMWARE_SIZE)		return -EINVAL;	if (d.len < 0 || d.len > COSA_MAX_FIRMWARE_SIZE)		return -EINVAL;	/* If something fails, force the user to reset the card */	cosa->firmware_status &= ~(COSA_FW_RESET|COSA_FW_DOWNLOAD);	i = download(cosa, d.code, d.len, d.addr);	if (i < 0) {		printk(KERN_NOTICE "cosa%d: microcode download failed: %d\n",			cosa->num, i);		return -EIO;	}	printk(KERN_INFO "cosa%d: downloading microcode - 0x%04x bytes at 0x%04x\n",		cosa->num, d.len, d.addr);	cosa->firmware_status |= COSA_FW_RESET|COSA_FW_DOWNLOAD;	return 0;}/* High-level function to read COSA memory. Calls readmem() */static inline int cosa_readmem(struct cosa_data *cosa, void __user *arg){	struct cosa_download d;	int i;	if (cosa->usage > 1)		printk(KERN_INFO "cosa%d: WARNING: readmem requested with "			"cosa->usage > 1 (%d). Odd things may happen.\n",			cosa->num, cosa->usage);	if (!(cosa->firmware_status & COSA_FW_RESET)) {		printk(KERN_NOTICE "%s: reset the card first (status %d).\n",			cosa->name, cosa->firmware_status);		return -EPERM;	}	if (copy_from_user(&d, arg, sizeof(d)))		return -EFAULT;	/* If something fails, force the user to reset the card */	cosa->firmware_status &= ~COSA_FW_RESET;	i = readmem(cosa, d.code, d.len, d.addr);	if (i < 0) {		printk(KERN_NOTICE "cosa%d: reading memory failed: %d\n",			cosa->num, i);		return -EIO;	}	printk(KERN_INFO "cosa%d: reading card memory - 0x%04x bytes at 0x%04x\n",		cosa->num, d.len, d.addr);	cosa->firmware_status |= COSA_FW_RESET;	return 0;}/* High-level function to start microcode. Calls startmicrocode(). */static inline int cosa_start(struct cosa_data *cosa, int address){	int i;	if (cosa->usage > 1)		printk(KERN_INFO "cosa%d: WARNING: start microcode requested with cosa->usage > 1 (%d). Odd things may happen.\n",			cosa->num, cosa->usage);	if ((cosa->firmware_status & (COSA_FW_RESET|COSA_FW_DOWNLOAD))		!= (COSA_FW_RESET|COSA_FW_DOWNLOAD)) {		printk(KERN_NOTICE "%s: download the microcode and/or reset the card first (status %d).\n",			cosa->name, cosa->firmware_status);		return -EPERM;	}	cosa->firmware_status &= ~COSA_FW_RESET;	if ((i=startmicrocode(cosa, address)) < 0) {		printk(KERN_NOTICE "cosa%d: start microcode at 0x%04x failed: %d\n",			cosa->num, address, i);		return -EIO;	}	printk(KERN_INFO "cosa%d: starting microcode at 0x%04x\n",		cosa->num, address);	cosa->startaddr = address;	cosa->firmware_status |= COSA_FW_START;	return 0;}		/* Buffer of size at least COSA_MAX_ID_STRING is expected */static inline int cosa_getidstr(struct cosa_data *cosa, char __user *string){	int l = strlen(cosa->id_string)+1;	if (copy_to_user(string, cosa->id_string, l))		return -EFAULT;	return l;}/* Buffer of size at least COSA_MAX_ID_STRING is expected */static inline int cosa_gettype(struct cosa_data *cosa, char __user *string){	int l = strlen(cosa->type)+1;	if (copy_to_user(string, cosa->type, l))		return -EFAULT;	return l;}static int cosa_ioctl_common(struct cosa_data *cosa,	struct channel_data *channel, unsigned int cmd, unsigned long arg){	void __user *argp = (void __user *)arg;	switch(cmd) {	case COSAIORSET:	/* Reset the device */		if (!capable(CAP_NET_ADMIN))			return -EACCES;		return cosa_reset(cosa);	case COSAIOSTRT:	/* Start the firmware */		if (!capable(CAP_SYS_RAWIO))			return -EACCES;		return cosa_start(cosa, arg);	case COSAIODOWNLD:	/* Download the firmware */		if (!capable(CAP_SYS_RAWIO))			return -EACCES;				return cosa_download(cosa, argp);	case COSAIORMEM:		if (!capable(CAP_SYS_RAWIO))			return -EACCES;		return cosa_readmem(cosa, argp);	case COSAIORTYPE:		return cosa_gettype(cosa, argp);	case COSAIORIDSTR:		return cosa_getidstr(cosa, argp);	case COSAIONRCARDS:		return nr_cards;	case COSAIONRCHANS:		return cosa->nchannels;	case COSAIOBMSET:		if (!capable(CAP_SYS_RAWIO))			return -EACCES;		if (is_8bit(cosa))			return -EINVAL;		if (arg != COSA_BM_OFF && arg != COSA_BM_ON)			return -EINVAL;		cosa->busmaster = arg;		return 0;	case COSAIOBMGET:		return cosa->busmaster;	}	return -ENOIOCTLCMD;}static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr,	int cmd){	int rv;	struct channel_data *chan = dev->priv;	rv = cosa_ioctl_common(chan->cosa, chan, cmd, (unsigned long)ifr->ifr_data);	if (rv == -ENOIOCTLCMD) {		return sppp_do_ioctl(dev, ifr, cmd);	}	return rv;}static int cosa_chardev_ioctl(struct inode *inode, struct file *file,	unsigned int cmd, unsigned long arg){	struct channel_data *channel = file->private_data;	struct cosa_data *cosa = channel->cosa;	return cosa_ioctl_common(cosa, channel, cmd, arg);}/*---------- HW layer interface ---------- *//* * The higher layer can bind itself to the HW layer by setting the callbacks * in the channel_data structure and by using these routines. */static void cosa_enable_rx(struct channel_data *chan){	struct cosa_data *cosa = chan->cosa;	if (!test_and_set_bit(chan->num, &cosa->rxbitmap))		put_driver_status(cosa);}static void cosa_disable_rx(struct channel_data *chan){	struct cosa_data *cosa = chan->cosa;	if (test_and_clear_bit(chan->num, &cosa->rxbitmap))		put_driver_status(cosa);}/* * FIXME: This routine probably should check for cosa_start_tx() called when * the previous transmit is still unfinished. In this case the non-zero * return value should indicate to the caller that the queuing(sp?) up * the transmit has failed. */static int cosa_start_tx(struct channel_data *chan, char *buf, int len){	struct cosa_data *cosa = chan->cosa;	unsigned long flags;#ifdef DEBUG_DATA	int i;	printk(KERN_INFO "cosa%dc%d: starting tx(0x%x)", chan->cosa->num,		chan->num, len);	for (i=0; i<len; i++)		printk(" %02x", buf[i]&0xff);	printk("\n");#endif	spin_lock_irqsave(&cosa->lock, flags);	chan->txbuf = buf;	chan->txsize = len;	if (len > COSA_MTU)		chan->txsize = COSA_MTU;	spin_unlock_irqrestore(&cosa->lock, flags);	/* Tell the firmware we are ready */	set_bit(chan->num, &cosa->txbitmap);	put_driver_status(cosa);	return 0;}static void put_driver_status(struct cosa_data *cosa){	unsigned long flags;	int status;	spin_lock_irqsave(&cosa->lock, flags);	status = (cosa->rxbitmap ? DRIVER_RX_READY : 0)		| (cosa->txbitmap ? DRIVER_TX_READY : 0)		| (cosa->txbitmap? ~(cosa->txbitmap<<DRIVER_TXMAP_SHIFT)			&DRIVER_TXMAP_MASK : 0);	if (!cosa->rxtx) {		if (cosa->rxbitmap|cosa->txbitmap) {			if (!cosa->enabled) {				cosa_putstatus(cosa, SR_RX_INT_ENA);#ifdef DEBUG_IO				debug_status_out(cosa, SR_RX_INT_ENA);#endif				cosa->enabled = 1;			}		} else if (cosa->enabled) {			cosa->enabled = 0;			cosa_putstatus(cosa, 0);#ifdef DEBUG_IO			debug_status_out(cosa, 0);#endif		}		cosa_putdata8(cosa, status);#ifdef DEBUG_IO		debug_data_cmd(cosa, status);#endif	}	spin_unlock_irqrestore(&cosa->lock, flags);}static void put_driver_status_nolock(struct cosa_data *cosa){	int status;	status = (cosa->rxbitmap ? DRIVER_RX_READY : 0)		| (cosa->txbitmap ? DRIVER_TX_READY : 0)		| (cosa->txbitmap? ~(cosa->txbitmap<<DRIVER_TXMAP_SHIFT)			&DRIVER_TXMAP_MASK : 0);	if (cosa->rxbitmap|cosa->txbitmap) {		cosa_putstatus(cosa, SR_RX_INT_ENA);#ifdef DEBUG_IO		debug_status_out(cosa, SR_RX_INT_ENA);#endif		cosa->enabled = 1;	} else {		cosa_putstatus(cosa, 0);#ifdef DEBUG_IO		debug_status_out(cosa, 0);#endif		cosa->enabled = 0;	}	cosa_putdata8(cosa, status);#ifdef DEBUG_IO	debug_data_cmd(cosa, status);#endif}/* * The "kickme" function: When the DMA times out, this is called to * clean up the driver status. * FIXME: Preliminary support, the interface is probably wrong. */static void cosa_kick(struct cosa_data *cosa){	unsigned long flags, flags1;	char *s = "(probably) IRQ";	if (test_bit(RXBIT, &cosa->rxtx))		s = "RX DMA";	if (test_bit(TXBIT, &cosa->rxtx))		s = "TX DMA";	printk(KERN_INFO "%s: %s timeout - restarting.\n", cosa->name, s); 	spin_lock_irqsave(&cosa->lock, flags);	cosa->rxtx = 0;	flags1 = claim_dma_lock();	disable_dma(cosa->dma);	clear_dma_ff(cosa->dma);	release_dma_lock(flags1);	/* FIXME: Anything else? */	udelay(100);	cosa_putstatus(cosa, 0);	udelay(100);	(void) cosa_getdata8(cosa);	udelay(100);	cosa_putdata8(cosa, 0);	udelay(100);	put_driver_status_nolock(cosa);	spin_unlock_irqrestore(&cosa->lock, flags);}/* * Check if the whole buffer is DMA-able. It means it is below the 16M of * physical memory and doesn't span the 64k boundary. For now it seems * SKB's never do this, but we'll check this anyway. */static int cosa_dma_able(struct channel_data *chan, char *buf, int len){	static int count;	unsigned long b = (unsigned long)buf;	if (b+len >= MAX_DMA_ADDRESS)		return 0;	if ((b^ (b+len)) & 0x10000) {		if (count++ < 5)			printk(KERN_INFO "%s: packet spanning a 64k boundary\n",				chan->name);		return 0;	}	return 1;}/* ---------- The SRP/COSA ROM monitor functions ---------- *//* * Downloading SRP microcode: say "w" to SRP monitor, it answers by "w=", * drivers need to say 4-digit hex number meaning start address of the microcode * separated by a single space. Monitor replies by saying " =". Now driver * has to write 4-digit hex number meaning the last byte address ended * by a single space. Monitor has to reply with a space. Now the download * begins. After the download monitor replies with "\r\n." (CR LF dot). */static int download(struct cosa_data *cosa, const char __user *microcode, int length, int address){	int i;	if (put_wait_data(cosa, 'w') == -1) return -1;	if ((i=get_wait_data(cosa)) != 'w') { printk("dnld: 0x%04x\n",i); return -2;}	if (get_wait_data(cosa) != '=') return -3;	if (puthexnumber(cosa, address) < 0) return -4;	if (put_wait_data(cosa, ' ') == -1) return -10;	if (get_wait_data(cosa) != ' ') return -11;	if (get_wait_data(cosa) != '=') return -12;	if (puthexnumber(cosa, address+length-1) < 0) return -13;	if (put_wait_data(cosa, ' ') == -1) return -18;	if (get_wait_data(cosa) != ' ') return -19;	while (length--) {		char c;#ifndef SRP_DOWNLOAD_AT_BOOT		if (get_user(c, microcode))			return -23; /* ??? */#else		c = *microcode;#endif		if (put_wait_data(cosa, c) == -1)			return -20;		microcode++;	}	if (get_wait_data(cosa) != '\r') return -21;	if (get_wait_data(cosa) != '\n') return -22;	if (get_wait_data(cosa) != '.') return -23;#if 0	printk(KERN_DEBUG "cosa%d: download completed.\n", cosa->num);#endif	return 0;}/* * Starting microcode is done via the "g" command of the SRP monitor. * The chat should be the following: "g" "g=" "<addr><CR>" * "<CR><CR><LF><CR><LF>". */static int startmicrocode(struct cosa_data *cosa, int address){	if (put_wait_data(cosa, 'g') == -1) return -1;	if (get_wait_data(cosa) != 'g') return -2;	if (get_wait_data(cosa) != '=') return -3;	if (puthexnumber(cosa, address) < 0) return -4;	if (put_wait_data(cosa, '\r') == -1) return -5;		if (get_wait_data(cosa) != '\r') return -6;	if (get_wait_data(cosa) != '\r') return -7;	if (get_wait_data(cosa) != '\n') return -8;	if (get_wait_data(cosa) != '\r') return -9;	if (get_wait_data(cosa) != '\n') return -10;#if 0	printk(KERN_DEBUG "cosa%d: microcode started\n", cosa->num);#endif	return 0;}/* * Reading memory is done via the "r" command of the SRP monitor. * The chat is the following "r" "r=" "<addr> " " =" "<last_byte> " " " * Then driver can read the data and the conversation is finished * by SRP monitor sending "<CR><LF>." (dot at the end). * * This routine is not needed during the normal operation and serves * for debugging purposes only. */static int readmem(struct cosa_data *cosa, char __user *microcode, int length, int address){	if (put_wait_data(cosa, 'r') == -1) return -1;	if ((get_wait_data(cosa)) != 'r') return -2;	if ((get_wait_data(cosa)) != '=') return -3;	if (puthexnumber(cosa, address) < 0) return -4;	if (put_wait_data(cosa, ' ') == -1) return -5;	if (get_wait_data(cosa) != ' ') return -6;	if (get_wait_data(cosa) != '=') return -7;	if (puthexnumber(cosa, address+length-1) < 0) return -8;	if (put_wait_data(cosa, ' ') == -1) return -9;	if (get_wait_data(cosa) != ' ') return -10;	while (length--) {		char c;		int i;		if ((i=get_wait_data(cosa)) == -1) {			printk (KERN_INFO "cosa: 0x%04x bytes remaining\n",				length);			return -11;		}		c=i;#if 1		if (put_user(c, microcode))			return -23; /* ??? */#else		*microcode = c;#endif		microcode++;	}	if (get_wait_data(cosa) != '\r') return -21;	if (get_wait_data(cosa) != '\n') return -22;	if (get_wait_data(cosa) != '.') return -23;#if 0	printk(KERN_DEBUG "cosa%d: readmem completed.\n", cosa->num);#endif	return 0;}/* * This function resets the device and reads the initial prompt * of the device's ROM monitor. */static int cosa_reset_and_read_id(struct cosa_data *cosa, char *idstring){	int i=0, id=0, prev=0, curr=0;	/* Reset the card ... */	cosa_putstatus(cosa, 0);	cosa_getdata8(cosa);	cosa_putstatus(cosa, SR_RST);#ifdef MODULE	current->state = TASK_INTERRUPTIBLE;	schedule_timeout(HZ/2);#else	udelay(5*100000);#endif	/* Disable all IRQs from the card */	cosa_putstatus(cosa, 0);	/*	 * Try to read the ID string. The card then prints out the	 * identification string ended by the "\n\x2e".	 *

⌨️ 快捷键说明

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