| 
									
										
										
										
											2005-05-12 22:54:16 -04:00
										 |  |  | static int prism2_enable_aux_port(struct net_device *dev, int enable) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u16 val, reg; | 
					
						
							|  |  |  | 	int i, tries; | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	struct hostap_interface *iface; | 
					
						
							|  |  |  | 	local_info_t *local; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	iface = netdev_priv(dev); | 
					
						
							|  |  |  | 	local = iface->local; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (local->no_pri) { | 
					
						
							|  |  |  | 		if (enable) { | 
					
						
							|  |  |  | 			PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux " | 
					
						
							|  |  |  | 			       "port is already enabled\n", dev->name); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&local->cmdlock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* wait until busy bit is clear */ | 
					
						
							|  |  |  | 	tries = HFA384X_CMD_BUSY_TIMEOUT; | 
					
						
							|  |  |  | 	while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { | 
					
						
							|  |  |  | 		tries--; | 
					
						
							|  |  |  | 		udelay(1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (tries == 0) { | 
					
						
							|  |  |  | 		reg = HFA384X_INW(HFA384X_CMD_OFF); | 
					
						
							|  |  |  | 		spin_unlock_irqrestore(&local->cmdlock, flags); | 
					
						
							|  |  |  | 		printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n", | 
					
						
							|  |  |  | 		       dev->name, reg); | 
					
						
							|  |  |  | 		return -ETIMEDOUT; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val = HFA384X_INW(HFA384X_CONTROL_OFF); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (enable) { | 
					
						
							|  |  |  | 		HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF); | 
					
						
							|  |  |  | 		HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF); | 
					
						
							|  |  |  | 		HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED) | 
					
						
							|  |  |  | 			printk("prism2_enable_aux_port: was not disabled!?\n"); | 
					
						
							|  |  |  | 		val &= ~HFA384X_AUX_PORT_MASK; | 
					
						
							|  |  |  | 		val |= HFA384X_AUX_PORT_ENABLE; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		HFA384X_OUTW(0, HFA384X_PARAM0_OFF); | 
					
						
							|  |  |  | 		HFA384X_OUTW(0, HFA384X_PARAM1_OFF); | 
					
						
							|  |  |  | 		HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED) | 
					
						
							|  |  |  | 			printk("prism2_enable_aux_port: was not enabled!?\n"); | 
					
						
							|  |  |  | 		val &= ~HFA384X_AUX_PORT_MASK; | 
					
						
							|  |  |  | 		val |= HFA384X_AUX_PORT_DISABLE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	HFA384X_OUTW(val, HFA384X_CONTROL_OFF); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	udelay(5); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i = 10000; | 
					
						
							|  |  |  | 	while (i > 0) { | 
					
						
							|  |  |  | 		val = HFA384X_INW(HFA384X_CONTROL_OFF); | 
					
						
							|  |  |  | 		val &= HFA384X_AUX_PORT_MASK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ((enable && val == HFA384X_AUX_PORT_ENABLED) || | 
					
						
							|  |  |  | 		    (!enable && val == HFA384X_AUX_PORT_DISABLED)) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		udelay(10); | 
					
						
							|  |  |  | 		i--; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&local->cmdlock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (i == 0) { | 
					
						
							|  |  |  | 		printk("prism2_enable_aux_port(%d) timed out\n", | 
					
						
							|  |  |  | 		       enable); | 
					
						
							|  |  |  | 		return -ETIMEDOUT; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len, | 
					
						
							|  |  |  | 			    void *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u16 page, offset; | 
					
						
							|  |  |  | 	if (addr & 1 || len & 1) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	page = addr >> 7; | 
					
						
							|  |  |  | 	offset = addr & 0x7f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); | 
					
						
							|  |  |  | 	HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	udelay(5); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef PRISM2_PCI
 | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2007-12-21 03:30:16 -05:00
										 |  |  | 		__le16 *pos = (__le16 *) buf; | 
					
						
							| 
									
										
										
										
											2005-05-12 22:54:16 -04:00
										 |  |  | 		while (len > 0) { | 
					
						
							|  |  |  | 			*pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF); | 
					
						
							|  |  |  | 			len -= 2; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #else /* PRISM2_PCI */
 | 
					
						
							|  |  |  | 	HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2); | 
					
						
							|  |  |  | #endif /* PRISM2_PCI */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len, | 
					
						
							|  |  |  | 			  void *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u16 page, offset; | 
					
						
							|  |  |  | 	if (addr & 1 || len & 1) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	page = addr >> 7; | 
					
						
							|  |  |  | 	offset = addr & 0x7f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); | 
					
						
							|  |  |  | 	HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	udelay(5); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef PRISM2_PCI
 | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2007-12-21 03:30:16 -05:00
										 |  |  | 		__le16 *pos = (__le16 *) buf; | 
					
						
							| 
									
										
										
										
											2005-05-12 22:54:16 -04:00
										 |  |  | 		while (len > 0) { | 
					
						
							|  |  |  | 			HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF); | 
					
						
							|  |  |  | 			len -= 2; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #else /* PRISM2_PCI */
 | 
					
						
							|  |  |  | 	HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2); | 
					
						
							|  |  |  | #endif /* PRISM2_PCI */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int prism2_pda_ok(u8 *buf) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-21 03:30:16 -05:00
										 |  |  | 	__le16 *pda = (__le16 *) buf; | 
					
						
							| 
									
										
										
										
											2005-05-12 22:54:16 -04:00
										 |  |  | 	int pos; | 
					
						
							|  |  |  | 	u16 len, pdr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff && | 
					
						
							|  |  |  | 	    buf[3] == 0x00) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pos = 0; | 
					
						
							|  |  |  | 	while (pos + 1 < PRISM2_PDA_SIZE / 2) { | 
					
						
							|  |  |  | 		len = le16_to_cpu(pda[pos]); | 
					
						
							|  |  |  | 		pdr = le16_to_cpu(pda[pos + 1]); | 
					
						
							|  |  |  | 		if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (pdr == 0x0000 && len == 2) { | 
					
						
							|  |  |  | 			/* PDA end found */ | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		pos += len + 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-10 21:13:23 +01:00
										 |  |  | #define prism2_download_aux_dump_npages 65536
 | 
					
						
							| 
									
										
										
										
											2005-05-12 22:54:16 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-10 21:13:23 +01:00
										 |  |  | struct prism2_download_aux_dump { | 
					
						
							|  |  |  | 	local_info_t *local; | 
					
						
							|  |  |  | 	u16 page[0x80]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int prism2_download_aux_dump_proc_show(struct seq_file *m, void *v) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct prism2_download_aux_dump *ctx = m->private; | 
					
						
							| 
									
										
										
										
											2005-05-12 22:54:16 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-10 21:13:23 +01:00
										 |  |  | 	hfa384x_from_aux(ctx->local->dev, (unsigned long)v - 1, 0x80, ctx->page); | 
					
						
							|  |  |  | 	seq_write(m, ctx->page, 0x80); | 
					
						
							| 
									
										
										
										
											2005-05-12 22:54:16 -04:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-10 21:13:23 +01:00
										 |  |  | static void *prism2_download_aux_dump_proc_start(struct seq_file *m, loff_t *_pos) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct prism2_download_aux_dump *ctx = m->private; | 
					
						
							|  |  |  | 	prism2_enable_aux_port(ctx->local->dev, 1); | 
					
						
							|  |  |  | 	if (*_pos >= prism2_download_aux_dump_npages) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	return (void *)((unsigned long)*_pos + 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void *prism2_download_aux_dump_proc_next(struct seq_file *m, void *v, loff_t *_pos) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	++*_pos; | 
					
						
							|  |  |  | 	if (*_pos >= prism2_download_aux_dump_npages) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	return (void *)((unsigned long)*_pos + 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void prism2_download_aux_dump_proc_stop(struct seq_file *m, void *v) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct prism2_download_aux_dump *ctx = m->private; | 
					
						
							|  |  |  | 	prism2_enable_aux_port(ctx->local->dev, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct seq_operations prism2_download_aux_dump_proc_seqops = { | 
					
						
							|  |  |  | 	.start	= prism2_download_aux_dump_proc_start, | 
					
						
							|  |  |  | 	.next	= prism2_download_aux_dump_proc_next, | 
					
						
							|  |  |  | 	.stop	= prism2_download_aux_dump_proc_stop, | 
					
						
							|  |  |  | 	.show	= prism2_download_aux_dump_proc_show, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int prism2_download_aux_dump_proc_open(struct inode *inode, struct file *file) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = seq_open_private(file, &prism2_download_aux_dump_proc_seqops, | 
					
						
							|  |  |  | 				   sizeof(struct prism2_download_aux_dump)); | 
					
						
							|  |  |  | 	if (ret == 0) { | 
					
						
							|  |  |  | 		struct seq_file *m = file->private_data; | 
					
						
							|  |  |  | 		m->private = PDE_DATA(inode); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct file_operations prism2_download_aux_dump_proc_fops = { | 
					
						
							|  |  |  | 	.open		= prism2_download_aux_dump_proc_open, | 
					
						
							|  |  |  | 	.read		= seq_read, | 
					
						
							|  |  |  | 	.llseek		= seq_lseek, | 
					
						
							|  |  |  | 	.release	= seq_release_private, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-05-12 22:54:16 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | static u8 * prism2_read_pda(struct net_device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u8 *buf; | 
					
						
							|  |  |  | 	int res, i, found = 0; | 
					
						
							|  |  |  | #define NUM_PDA_ADDRS 4
 | 
					
						
							|  |  |  | 	unsigned int pda_addr[NUM_PDA_ADDRS] = { | 
					
						
							|  |  |  | 		0x7f0000 /* others than HFA3841 */, | 
					
						
							|  |  |  | 		0x3f0000 /* HFA3841 */, | 
					
						
							|  |  |  | 		0x390000 /* apparently used in older cards */, | 
					
						
							|  |  |  | 		0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */, | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-13 00:35:56 -08:00
										 |  |  | 	buf = kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-05-12 22:54:16 -04:00
										 |  |  | 	if (buf == NULL) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Note: wlan card should be in initial state (just after init cmd)
 | 
					
						
							|  |  |  | 	 * and no other operations should be performed concurrently. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	prism2_enable_aux_port(dev, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < NUM_PDA_ADDRS; i++) { | 
					
						
							|  |  |  | 		PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x", | 
					
						
							|  |  |  | 		       dev->name, pda_addr[i]); | 
					
						
							|  |  |  | 		res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf); | 
					
						
							|  |  |  | 		if (res) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		if (res == 0 && prism2_pda_ok(buf)) { | 
					
						
							|  |  |  | 			PDEBUG2(DEBUG_EXTRA2, ": OK\n"); | 
					
						
							|  |  |  | 			found = 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			PDEBUG2(DEBUG_EXTRA2, ": failed\n"); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	prism2_enable_aux_port(dev, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!found) { | 
					
						
							|  |  |  | 		printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name); | 
					
						
							|  |  |  | 		kfree(buf); | 
					
						
							|  |  |  | 		buf = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return buf; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int prism2_download_volatile(local_info_t *local, | 
					
						
							|  |  |  | 				    struct prism2_download_data *param) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct net_device *dev = local->dev; | 
					
						
							|  |  |  | 	int ret = 0, i; | 
					
						
							|  |  |  | 	u16 param0, param1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (local->hw_downloading) { | 
					
						
							|  |  |  | 		printk(KERN_WARNING "%s: Already downloading - aborting new " | 
					
						
							|  |  |  | 		       "request\n", dev->name); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	local->hw_downloading = 1; | 
					
						
							|  |  |  | 	if (local->pri_only) { | 
					
						
							|  |  |  | 		hfa384x_disable_interrupts(dev); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		prism2_hw_shutdown(dev, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (prism2_hw_init(dev, 0)) { | 
					
						
							|  |  |  | 			printk(KERN_WARNING "%s: Could not initialize card for" | 
					
						
							|  |  |  | 			       " download\n", dev->name); | 
					
						
							|  |  |  | 			ret = -1; | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (prism2_enable_aux_port(dev, 1)) { | 
					
						
							|  |  |  | 		printk(KERN_WARNING "%s: Could not enable AUX port\n", | 
					
						
							|  |  |  | 		       dev->name); | 
					
						
							|  |  |  | 		ret = -1; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	param0 = param->start_addr & 0xffff; | 
					
						
							|  |  |  | 	param1 = param->start_addr >> 16; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | 
					
						
							|  |  |  | 	HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); | 
					
						
							|  |  |  | 	if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | 
					
						
							|  |  |  | 			     (HFA384X_PROGMODE_ENABLE_VOLATILE << 8), | 
					
						
							|  |  |  | 			     param0)) { | 
					
						
							|  |  |  | 		printk(KERN_WARNING "%s: Download command execution failed\n", | 
					
						
							|  |  |  | 		       dev->name); | 
					
						
							|  |  |  | 		ret = -1; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < param->num_areas; i++) { | 
					
						
							|  |  |  | 		PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n", | 
					
						
							|  |  |  | 		       dev->name, param->data[i].len, param->data[i].addr); | 
					
						
							|  |  |  | 		if (hfa384x_to_aux(dev, param->data[i].addr, | 
					
						
							|  |  |  | 				   param->data[i].len, param->data[i].data)) { | 
					
						
							|  |  |  | 			printk(KERN_WARNING "%s: RAM download at 0x%08x " | 
					
						
							|  |  |  | 			       "(len=%d) failed\n", dev->name, | 
					
						
							|  |  |  | 			       param->data[i].addr, param->data[i].len); | 
					
						
							|  |  |  | 			ret = -1; | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); | 
					
						
							|  |  |  | 	HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | 
					
						
							|  |  |  | 	if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | 
					
						
							|  |  |  | 				(HFA384X_PROGMODE_DISABLE << 8), param0)) { | 
					
						
							|  |  |  | 		printk(KERN_WARNING "%s: Download command execution failed\n", | 
					
						
							|  |  |  | 		       dev->name); | 
					
						
							|  |  |  | 		ret = -1; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/* ProgMode disable causes the hardware to restart itself from the
 | 
					
						
							|  |  |  | 	 * given starting address. Give hw some time and ACK command just in | 
					
						
							|  |  |  | 	 * case restart did not happen. */ | 
					
						
							|  |  |  | 	mdelay(5); | 
					
						
							|  |  |  | 	HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (prism2_enable_aux_port(dev, 0)) { | 
					
						
							|  |  |  | 		printk(KERN_DEBUG "%s: Disabling AUX port failed\n", | 
					
						
							|  |  |  | 		       dev->name); | 
					
						
							|  |  |  | 		/* continue anyway.. restart should have taken care of this */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mdelay(5); | 
					
						
							|  |  |  | 	local->hw_downloading = 0; | 
					
						
							|  |  |  | 	if (prism2_hw_config(dev, 2)) { | 
					
						
							|  |  |  | 		printk(KERN_WARNING "%s: Card configuration after RAM " | 
					
						
							|  |  |  | 		       "download failed\n", dev->name); | 
					
						
							|  |  |  | 		ret = -1; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  out: | 
					
						
							|  |  |  | 	local->hw_downloading = 0; | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int prism2_enable_genesis(local_info_t *local, int hcr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct net_device *dev = local->dev; | 
					
						
							|  |  |  | 	u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff }; | 
					
						
							|  |  |  | 	u8 readbuf[4]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n", | 
					
						
							|  |  |  | 	       dev->name, hcr); | 
					
						
							|  |  |  | 	local->func->cor_sreset(local); | 
					
						
							|  |  |  | 	hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); | 
					
						
							|  |  |  | 	local->func->genesis_reset(local, hcr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Readback test */ | 
					
						
							|  |  |  | 	hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); | 
					
						
							|  |  |  | 	hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); | 
					
						
							|  |  |  | 	hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) { | 
					
						
							|  |  |  | 		printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n", | 
					
						
							|  |  |  | 		       hcr); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		printk(KERN_DEBUG "Readback test failed, HCR 0x%02x " | 
					
						
							|  |  |  | 		       "write %02x %02x %02x %02x read %02x %02x %02x %02x\n", | 
					
						
							|  |  |  | 		       hcr, initseq[0], initseq[1], initseq[2], initseq[3], | 
					
						
							|  |  |  | 		       readbuf[0], readbuf[1], readbuf[2], readbuf[3]); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int prism2_get_ram_size(local_info_t *local) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */ | 
					
						
							|  |  |  | 	if (prism2_enable_genesis(local, 0x1f) == 0) | 
					
						
							|  |  |  | 		ret = 8; | 
					
						
							|  |  |  | 	else if (prism2_enable_genesis(local, 0x0f) == 0) | 
					
						
							|  |  |  | 		ret = 16; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		ret = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Disable genesis mode */ | 
					
						
							|  |  |  | 	local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int prism2_download_genesis(local_info_t *local, | 
					
						
							|  |  |  | 				   struct prism2_download_data *param) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct net_device *dev = local->dev; | 
					
						
							|  |  |  | 	int ram16 = 0, i; | 
					
						
							|  |  |  | 	int ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (local->hw_downloading) { | 
					
						
							|  |  |  | 		printk(KERN_WARNING "%s: Already downloading - aborting new " | 
					
						
							|  |  |  | 		       "request\n", dev->name); | 
					
						
							|  |  |  | 		return -EBUSY; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!local->func->genesis_reset || !local->func->cor_sreset) { | 
					
						
							|  |  |  | 		printk(KERN_INFO "%s: Genesis mode downloading not supported " | 
					
						
							|  |  |  | 		       "with this hwmodel\n", dev->name); | 
					
						
							|  |  |  | 		return -EOPNOTSUPP; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	local->hw_downloading = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (prism2_enable_aux_port(dev, 1)) { | 
					
						
							|  |  |  | 		printk(KERN_DEBUG "%s: failed to enable AUX port\n", | 
					
						
							|  |  |  | 		       dev->name); | 
					
						
							|  |  |  | 		ret = -EIO; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (local->sram_type == -1) { | 
					
						
							|  |  |  | 		/* 0x1F for x8 SRAM or 0x0F for x16 SRAM */ | 
					
						
							|  |  |  | 		if (prism2_enable_genesis(local, 0x1f) == 0) { | 
					
						
							|  |  |  | 			ram16 = 0; | 
					
						
							|  |  |  | 			PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 " | 
					
						
							|  |  |  | 			       "SRAM\n", dev->name); | 
					
						
							|  |  |  | 		} else if (prism2_enable_genesis(local, 0x0f) == 0) { | 
					
						
							|  |  |  | 			ram16 = 1; | 
					
						
							|  |  |  | 			PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 " | 
					
						
							|  |  |  | 			       "SRAM\n", dev->name); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			printk(KERN_DEBUG "%s: Could not initiate genesis " | 
					
						
							|  |  |  | 			       "mode\n", dev->name); | 
					
						
							|  |  |  | 			ret = -EIO; | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		if (prism2_enable_genesis(local, local->sram_type == 8 ? | 
					
						
							|  |  |  | 					  0x1f : 0x0f)) { | 
					
						
							|  |  |  | 			printk(KERN_DEBUG "%s: Failed to set Genesis " | 
					
						
							|  |  |  | 			       "mode (sram_type=%d)\n", dev->name, | 
					
						
							|  |  |  | 			       local->sram_type); | 
					
						
							|  |  |  | 			ret = -EIO; | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ram16 = local->sram_type != 8; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < param->num_areas; i++) { | 
					
						
							|  |  |  | 		PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n", | 
					
						
							|  |  |  | 		       dev->name, param->data[i].len, param->data[i].addr); | 
					
						
							|  |  |  | 		if (hfa384x_to_aux(dev, param->data[i].addr, | 
					
						
							|  |  |  | 				   param->data[i].len, param->data[i].data)) { | 
					
						
							|  |  |  | 			printk(KERN_WARNING "%s: RAM download at 0x%08x " | 
					
						
							|  |  |  | 			       "(len=%d) failed\n", dev->name, | 
					
						
							|  |  |  | 			       param->data[i].addr, param->data[i].len); | 
					
						
							|  |  |  | 			ret = -EIO; | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n"); | 
					
						
							|  |  |  | 	local->func->genesis_reset(local, ram16 ? 0x07 : 0x17); | 
					
						
							|  |  |  | 	if (prism2_enable_aux_port(dev, 0)) { | 
					
						
							|  |  |  | 		printk(KERN_DEBUG "%s: Failed to disable AUX port\n", | 
					
						
							|  |  |  | 		       dev->name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mdelay(5); | 
					
						
							|  |  |  | 	local->hw_downloading = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n"); | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Make sure the INIT command does not generate a command completion | 
					
						
							|  |  |  | 	 * event by disabling interrupts. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	hfa384x_disable_interrupts(dev); | 
					
						
							|  |  |  | 	if (prism2_hw_init(dev, 1)) { | 
					
						
							|  |  |  | 		printk(KERN_DEBUG "%s: Initialization after genesis mode " | 
					
						
							|  |  |  | 		       "download failed\n", dev->name); | 
					
						
							|  |  |  | 		ret = -EIO; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n"); | 
					
						
							|  |  |  | 	if (prism2_hw_init2(dev, 1)) { | 
					
						
							|  |  |  | 		printk(KERN_DEBUG "%s: Initialization(2) after genesis mode " | 
					
						
							|  |  |  | 		       "download failed\n", dev->name); | 
					
						
							|  |  |  | 		ret = -EIO; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  out: | 
					
						
							|  |  |  | 	local->hw_downloading = 0; | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef PRISM2_NON_VOLATILE_DOWNLOAD
 | 
					
						
							|  |  |  | /* Note! Non-volatile downloading functionality has not yet been tested
 | 
					
						
							|  |  |  |  * thoroughly and it may corrupt flash image and effectively kill the card that | 
					
						
							|  |  |  |  * is being updated. You have been warned. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int prism2_download_block(struct net_device *dev, | 
					
						
							|  |  |  | 					u32 addr, u8 *data, | 
					
						
							|  |  |  | 					u32 bufaddr, int rest_len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u16 param0, param1; | 
					
						
							|  |  |  | 	int block_len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	block_len = rest_len < 4096 ? rest_len : 4096; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	param0 = addr & 0xffff; | 
					
						
							|  |  |  | 	param1 = addr >> 16; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF); | 
					
						
							|  |  |  | 	HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | 
					
						
							|  |  |  | 			     (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8), | 
					
						
							|  |  |  | 			     param0)) { | 
					
						
							|  |  |  | 		printk(KERN_WARNING "%s: Flash download command execution " | 
					
						
							|  |  |  | 		       "failed\n", dev->name); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (hfa384x_to_aux(dev, bufaddr, block_len, data)) { | 
					
						
							|  |  |  | 		printk(KERN_WARNING "%s: flash download at 0x%08x " | 
					
						
							|  |  |  | 		       "(len=%d) failed\n", dev->name, addr, block_len); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | 
					
						
							|  |  |  | 	HFA384X_OUTW(0, HFA384X_PARAM1_OFF); | 
					
						
							|  |  |  | 	if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | 
					
						
							|  |  |  | 			     (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8), | 
					
						
							|  |  |  | 			     0)) { | 
					
						
							|  |  |  | 		printk(KERN_WARNING "%s: Flash write command execution " | 
					
						
							|  |  |  | 		       "failed\n", dev->name); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return block_len; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int prism2_download_nonvolatile(local_info_t *local, | 
					
						
							|  |  |  | 				       struct prism2_download_data *dl) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct net_device *dev = local->dev; | 
					
						
							|  |  |  | 	int ret = 0, i; | 
					
						
							|  |  |  | 	struct { | 
					
						
							| 
									
										
										
										
											2007-12-21 03:30:16 -05:00
										 |  |  | 		__le16 page; | 
					
						
							|  |  |  | 		__le16 offset; | 
					
						
							|  |  |  | 		__le16 len; | 
					
						
							| 
									
										
										
										
											2005-05-12 22:54:16 -04:00
										 |  |  | 	} dlbuffer; | 
					
						
							|  |  |  | 	u32 bufaddr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (local->hw_downloading) { | 
					
						
							|  |  |  | 		printk(KERN_WARNING "%s: Already downloading - aborting new " | 
					
						
							|  |  |  | 		       "request\n", dev->name); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER, | 
					
						
							|  |  |  | 				   &dlbuffer, 6, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ret < 0) { | 
					
						
							|  |  |  | 		printk(KERN_WARNING "%s: Could not read download buffer " | 
					
						
							|  |  |  | 		       "parameters\n", dev->name); | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n", | 
					
						
							| 
									
										
										
										
											2007-12-21 03:30:16 -05:00
										 |  |  | 	       le16_to_cpu(dlbuffer.len), | 
					
						
							|  |  |  | 	       le16_to_cpu(dlbuffer.page), | 
					
						
							|  |  |  | 	       le16_to_cpu(dlbuffer.offset)); | 
					
						
							| 
									
										
										
										
											2005-05-12 22:54:16 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-21 03:30:16 -05:00
										 |  |  | 	bufaddr = (le16_to_cpu(dlbuffer.page) << 7) + le16_to_cpu(dlbuffer.offset); | 
					
						
							| 
									
										
										
										
											2005-05-12 22:54:16 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	local->hw_downloading = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!local->pri_only) { | 
					
						
							|  |  |  | 		prism2_hw_shutdown(dev, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (prism2_hw_init(dev, 0)) { | 
					
						
							|  |  |  | 			printk(KERN_WARNING "%s: Could not initialize card for" | 
					
						
							|  |  |  | 			       " download\n", dev->name); | 
					
						
							|  |  |  | 			ret = -1; | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hfa384x_disable_interrupts(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (prism2_enable_aux_port(dev, 1)) { | 
					
						
							|  |  |  | 		printk(KERN_WARNING "%s: Could not enable AUX port\n", | 
					
						
							|  |  |  | 		       dev->name); | 
					
						
							|  |  |  | 		ret = -1; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	printk(KERN_DEBUG "%s: starting flash download\n", dev->name); | 
					
						
							|  |  |  | 	for (i = 0; i < dl->num_areas; i++) { | 
					
						
							|  |  |  | 		int rest_len = dl->data[i].len; | 
					
						
							|  |  |  | 		int data_off = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		while (rest_len > 0) { | 
					
						
							|  |  |  | 			int block_len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			block_len = prism2_download_block( | 
					
						
							|  |  |  | 				dev, dl->data[i].addr + data_off, | 
					
						
							|  |  |  | 				dl->data[i].data + data_off, bufaddr, | 
					
						
							|  |  |  | 				rest_len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (block_len < 0) { | 
					
						
							|  |  |  | 				ret = -1; | 
					
						
							|  |  |  | 				goto out; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			rest_len -= block_len; | 
					
						
							|  |  |  | 			data_off += block_len; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HFA384X_OUTW(0, HFA384X_PARAM1_OFF); | 
					
						
							|  |  |  | 	HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | 
					
						
							|  |  |  | 	if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | 
					
						
							|  |  |  | 				(HFA384X_PROGMODE_DISABLE << 8), 0)) { | 
					
						
							|  |  |  | 		printk(KERN_WARNING "%s: Download command execution failed\n", | 
					
						
							|  |  |  | 		       dev->name); | 
					
						
							|  |  |  | 		ret = -1; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (prism2_enable_aux_port(dev, 0)) { | 
					
						
							|  |  |  | 		printk(KERN_DEBUG "%s: Disabling AUX port failed\n", | 
					
						
							|  |  |  | 		       dev->name); | 
					
						
							|  |  |  | 		/* continue anyway.. restart should have taken care of this */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mdelay(5); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	local->func->hw_reset(dev); | 
					
						
							|  |  |  | 	local->hw_downloading = 0; | 
					
						
							|  |  |  | 	if (prism2_hw_config(dev, 2)) { | 
					
						
							|  |  |  | 		printk(KERN_WARNING "%s: Card configuration after flash " | 
					
						
							|  |  |  | 		       "download failed\n", dev->name); | 
					
						
							|  |  |  | 		ret = -1; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		printk(KERN_INFO "%s: Card initialized successfully after " | 
					
						
							|  |  |  | 		       "flash download\n", dev->name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  out: | 
					
						
							|  |  |  | 	local->hw_downloading = 0; | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void prism2_download_free_data(struct prism2_download_data *dl) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (dl == NULL) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < dl->num_areas; i++) | 
					
						
							|  |  |  | 		kfree(dl->data[i].data); | 
					
						
							|  |  |  | 	kfree(dl); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int prism2_download(local_info_t *local, | 
					
						
							|  |  |  | 			   struct prism2_download_param *param) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = 0; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	u32 total_len = 0; | 
					
						
							|  |  |  | 	struct prism2_download_data *dl = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x " | 
					
						
							|  |  |  | 	       "num_areas=%d\n", | 
					
						
							|  |  |  | 	       param->dl_cmd, param->start_addr, param->num_areas); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (param->num_areas > 100) { | 
					
						
							|  |  |  | 		ret = -EINVAL; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-02 13:33:40 +02:00
										 |  |  | 	dl = kzalloc(sizeof(*dl) + param->num_areas * | 
					
						
							| 
									
										
										
										
											2005-05-12 22:54:16 -04:00
										 |  |  | 		     sizeof(struct prism2_download_data_area), GFP_KERNEL); | 
					
						
							|  |  |  | 	if (dl == NULL) { | 
					
						
							|  |  |  | 		ret = -ENOMEM; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dl->dl_cmd = param->dl_cmd; | 
					
						
							|  |  |  | 	dl->start_addr = param->start_addr; | 
					
						
							|  |  |  | 	dl->num_areas = param->num_areas; | 
					
						
							|  |  |  | 	for (i = 0; i < param->num_areas; i++) { | 
					
						
							|  |  |  | 		PDEBUG(DEBUG_EXTRA2, | 
					
						
							|  |  |  | 		       "  area %d: addr=0x%08x len=%d ptr=0x%p\n", | 
					
						
							|  |  |  | 		       i, param->data[i].addr, param->data[i].len, | 
					
						
							|  |  |  | 		       param->data[i].ptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dl->data[i].addr = param->data[i].addr; | 
					
						
							|  |  |  | 		dl->data[i].len = param->data[i].len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		total_len += param->data[i].len; | 
					
						
							|  |  |  | 		if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN || | 
					
						
							|  |  |  | 		    total_len > PRISM2_MAX_DOWNLOAD_LEN) { | 
					
						
							|  |  |  | 			ret = -E2BIG; | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL); | 
					
						
							|  |  |  | 		if (dl->data[i].data == NULL) { | 
					
						
							|  |  |  | 			ret = -ENOMEM; | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_from_user(dl->data[i].data, param->data[i].ptr, | 
					
						
							|  |  |  | 				   param->data[i].len)) { | 
					
						
							|  |  |  | 			ret = -EFAULT; | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (param->dl_cmd) { | 
					
						
							|  |  |  | 	case PRISM2_DOWNLOAD_VOLATILE: | 
					
						
							|  |  |  | 	case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT: | 
					
						
							|  |  |  | 		ret = prism2_download_volatile(local, dl); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case PRISM2_DOWNLOAD_VOLATILE_GENESIS: | 
					
						
							|  |  |  | 	case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT: | 
					
						
							|  |  |  | 		ret = prism2_download_genesis(local, dl); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case PRISM2_DOWNLOAD_NON_VOLATILE: | 
					
						
							|  |  |  | #ifdef PRISM2_NON_VOLATILE_DOWNLOAD
 | 
					
						
							|  |  |  | 		ret = prism2_download_nonvolatile(local, dl); | 
					
						
							|  |  |  | #else /* PRISM2_NON_VOLATILE_DOWNLOAD */
 | 
					
						
							|  |  |  | 		printk(KERN_INFO "%s: non-volatile downloading not enabled\n", | 
					
						
							|  |  |  | 		       local->dev->name); | 
					
						
							|  |  |  | 		ret = -EOPNOTSUPP; | 
					
						
							|  |  |  | #endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
 | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		printk(KERN_DEBUG "%s: unsupported download command %d\n", | 
					
						
							|  |  |  | 		       local->dev->name, param->dl_cmd); | 
					
						
							|  |  |  | 		ret = -EINVAL; | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-05-17 22:47:34 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-05-12 22:54:16 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |  out: | 
					
						
							|  |  |  | 	if (ret == 0 && dl && | 
					
						
							|  |  |  | 	    param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) { | 
					
						
							|  |  |  | 		prism2_download_free_data(local->dl_pri); | 
					
						
							|  |  |  | 		local->dl_pri = dl; | 
					
						
							|  |  |  | 	} else if (ret == 0 && dl && | 
					
						
							|  |  |  | 		   param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) { | 
					
						
							|  |  |  | 		prism2_download_free_data(local->dl_sec); | 
					
						
							|  |  |  | 		local->dl_sec = dl; | 
					
						
							|  |  |  | 	} else | 
					
						
							|  |  |  | 		prism2_download_free_data(dl); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } |