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

📄 ohci1394.c

📁 Armlinux ieee1394接口驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
	(noswap ? data : le32_to_cpu(data))static const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0, 			    -1, 0, -1, 0, -1, -1, 16, -1};/*  * Determine the length of a packet in the buffer * Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca> */static __inline__ int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *buf_ptr,			 int offset, unsigned char tcode, int noswap){	int length = -1;	if (d->ctx < 2) { /* Async Receive Response/Request */		length = TCODE_SIZE[tcode];		if (length == 0) {			if (offset + 12 >= d->buf_size) {				length = (cond_le32_to_cpu(d->buf_cpu[(idx + 1) % d->num_desc]						[3 - ((d->buf_size - offset) >> 2)], noswap) >> 16);			} else {				length = (cond_le32_to_cpu(buf_ptr[3], noswap) >> 16);			}			length += 20;		}	} else if (d->ctx == 2) { /* Iso receive */		/* Assumption: buffer fill mode with header/trailer */		length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8;	}	if (length > 0 && length % 4)		length += 4 - (length % 4);	return length;}/* Tasklet that processes dma receive buffers */static void dma_rcv_tasklet (unsigned long data){	struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data;	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);	unsigned int split_left, idx, offset, rescount;	unsigned char tcode;	int length, bytes_left, ack;	unsigned long flags;	quadlet_t *buf_ptr;	char *split_ptr;	char msg[256];	spin_lock_irqsave(&d->lock, flags);	idx = d->buf_ind;	offset = d->buf_offset;	buf_ptr = d->buf_cpu[idx] + offset/4;	dma_cache_wback_inv(&(d->prg_cpu[idx]->status), sizeof(d->prg_cpu[idx]->status));	rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;	bytes_left = d->buf_size - rescount - offset;	dma_cache_wback_inv(buf_ptr, bytes_left);	while (bytes_left > 0) {		tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf;		/* packet_length() will return < 4 for an error */		length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->no_swap_incoming);		if (length < 4) { /* something is wrong */			sprintf(msg,"Unexpected tcode 0x%x(0x%08x) in AR ctx=%d, length=%d",				tcode, cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming),				d->ctx, length);			ohci1394_stop_context(ohci, d->ctrlClear, msg);			spin_unlock_irqrestore(&d->lock, flags);			return;		}		/* The first case is where we have a packet that crosses		 * over more than one descriptor. The next case is where		 * it's all in the first descriptor.  */		if ((offset + length) > d->buf_size) {			DBGMSG(ohci->id,"Split packet rcv'd");			if (length > d->split_buf_size) {				ohci1394_stop_context(ohci, d->ctrlClear,					     "Split packet size exceeded");				d->buf_ind = idx;				d->buf_offset = offset;				spin_unlock_irqrestore(&d->lock, flags);				return;			}			if (le32_to_cpu(d->prg_cpu[(idx+1)%d->num_desc]->status)			    == d->buf_size) {				/* Other part of packet not written yet.				 * this should never happen I think				 * anyway we'll get it on the next call.  */				PRINT(KERN_INFO, ohci->id,				      "Got only half a packet!");				d->buf_ind = idx;				d->buf_offset = offset;				spin_unlock_irqrestore(&d->lock, flags);				return;			}			split_left = length;			split_ptr = (char *)d->spb;			memcpy(split_ptr,buf_ptr,d->buf_size-offset);			split_left -= d->buf_size-offset;			split_ptr += d->buf_size-offset;			insert_dma_buffer(d, idx);			idx = (idx+1) % d->num_desc;			buf_ptr = d->buf_cpu[idx];			dma_cache_wback_inv(buf_ptr, d->buf_size);			offset=0;			while (split_left >= d->buf_size) {				memcpy(split_ptr,buf_ptr,d->buf_size);				split_ptr += d->buf_size;				split_left -= d->buf_size;				insert_dma_buffer(d, idx);				idx = (idx+1) % d->num_desc;				buf_ptr = d->buf_cpu[idx];                                dma_cache_wback_inv(buf_ptr, d->buf_size);			}			if (split_left > 0) {				memcpy(split_ptr, buf_ptr, split_left);				offset = split_left;				buf_ptr += offset/4;			}		} else {			DBGMSG(ohci->id,"Single packet rcv'd");			memcpy(d->spb, buf_ptr, length);			offset += length;			buf_ptr += length/4;			if (offset==d->buf_size) {				insert_dma_buffer(d, idx);				idx = (idx+1) % d->num_desc;				buf_ptr = d->buf_cpu[idx];				offset=0;			}		}				/* We get one phy packet to the async descriptor for each		 * bus reset. We always ignore it.  */		if (tcode != OHCI1394_TCODE_PHY) {			if (!ohci->no_swap_incoming)				packet_swab(d->spb, tcode, (length - 4) >> 2);			DBGMSG(ohci->id, "Packet received from node"				" %d ack=0x%02X spd=%d tcode=0x%X"				" length=%d ctx=%d tlabel=%d",				(d->spb[1]>>16)&0x3f,				(cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f,				(cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3,				tcode, length, d->ctx,				(cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>10)&0x3f);			ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f)				== 0x11) ? 1 : 0;			hpsb_packet_received(ohci->host, d->spb, 					     length-4, ack);		}#ifdef OHCI1394_DEBUG		else			PRINT (KERN_DEBUG, ohci->id, "Got phy packet ctx=%d ... discarded",			       d->ctx);#endif                dma_cache_wback_inv(&(d->prg_cpu[idx]->status),                        sizeof(d->prg_cpu[idx]->status));	       	rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;		bytes_left = d->buf_size - rescount - offset;	}	d->buf_ind = idx;	d->buf_offset = offset;	spin_unlock_irqrestore(&d->lock, flags);}/* Bottom half that processes sent packets */static void dma_trm_tasklet (unsigned long data){	struct dma_trm_ctx *d = (struct dma_trm_ctx*)data;	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);	struct hpsb_packet *packet, *nextpacket;	unsigned long flags;	u32 ack;        size_t datasize;	spin_lock_irqsave(&d->lock, flags);	if (d->fifo_first == NULL) {#if 0		ohci1394_stop_context(ohci, d->ctrlClear, 			     "Packet sent ack received but queue is empty");#endif		spin_unlock_irqrestore(&d->lock, flags);		return;	}	while (d->fifo_first) {		packet = d->fifo_first;                datasize = d->fifo_first->data_size;		if (datasize && packet->type != hpsb_raw)			ack = le32_to_cpu(				d->prg_cpu[d->sent_ind]->end.status) >> 16;		else 			ack = le32_to_cpu(				d->prg_cpu[d->sent_ind]->begin.status) >> 16;		if (ack == 0) 			/* this packet hasn't been sent yet*/			break;#ifdef OHCI1394_DEBUG		if (datasize)			DBGMSG(ohci->id,			       "Packet sent to node %d tcode=0x%X tLabel="			       "0x%02X ack=0x%X spd=%d dataLength=%d ctx=%d",                                 (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])                                        >>16)&0x3f,                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])                                        >>4)&0xf,                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])                                        >>10)&0x3f,                                ack&0x1f, (ack>>5)&0x3,                                 le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3])                                        >>16,                                d->ctx);		else 			DBGMSG(ohci->id,			       "Packet sent to node %d tcode=0x%X tLabel="			       "0x%02X ack=0x%X spd=%d data=0x%08X ctx=%d",                                 (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])                                        >>16)&0x3f,                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])                                        >>4)&0xf,                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])                                        >>10)&0x3f,                                ack&0x1f, (ack>>5)&0x3,                                 le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]),                                d->ctx);#endif		                nextpacket = packet->xnext;		hpsb_packet_sent(ohci->host, packet, ack & 0xf);		if (datasize) {			pci_unmap_single(ohci->dev, 					 cpu_to_le32(d->prg_cpu[d->sent_ind]->end.address),					 datasize, PCI_DMA_TODEVICE);			OHCI_DMA_FREE("single Xmit data packet");		}		d->sent_ind = (d->sent_ind+1)%d->num_desc;		d->free_prgs++;		d->fifo_first = nextpacket;	}	if (d->fifo_first == NULL)		d->fifo_last = NULL;	dma_trm_flush(ohci, d);	spin_unlock_irqrestore(&d->lock, flags);}static int free_dma_rcv_ctx(struct dma_rcv_ctx **d){	int i;	struct ti_ohci *ohci;	if (*d==NULL) return -1;	ohci = (struct ti_ohci *)(*d)->ohci;	DBGMSG(ohci->id, "Freeing dma_rcv_ctx %d",(*d)->ctx);		ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL);	tasklet_kill(&(*d)->task);	if ((*d)->buf_cpu) {		for (i=0; i<(*d)->num_desc; i++)			if ((*d)->buf_cpu[i] && (*d)->buf_bus[i]) {				pci_free_consistent(					ohci->dev, (*d)->buf_size, 					(*d)->buf_cpu[i], (*d)->buf_bus[i]);				OHCI_DMA_FREE("consistent dma_rcv buf[%d]", i);			}		kfree((*d)->buf_cpu);		kfree((*d)->buf_bus);	}	if ((*d)->prg_cpu) {		for (i=0; i<(*d)->num_desc; i++) 			if ((*d)->prg_cpu[i] && (*d)->prg_bus[i]) {				pci_free_consistent(					ohci->dev, sizeof(struct dma_cmd), 					(*d)->prg_cpu[i], (*d)->prg_bus[i]);				OHCI_DMA_FREE("consistent dma_rcv prg[%d]", i);			}		kfree((*d)->prg_cpu);		kfree((*d)->prg_bus);	}	if ((*d)->spb) kfree((*d)->spb);	kfree(*d);	*d = NULL;	return 0;}static struct dma_rcv_ctx *alloc_dma_rcv_ctx(struct ti_ohci *ohci, int ctx, int num_desc,		  int buf_size, int split_buf_size, 		  int ctrlSet, int ctrlClear, int cmdPtr){	struct dma_rcv_ctx *d=NULL;	int i;	d = (struct dma_rcv_ctx *)kmalloc(sizeof(struct dma_rcv_ctx), 					  GFP_KERNEL);	if (d == NULL) {		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_rcv_ctx");		return NULL;	}	memset (d, 0, sizeof (struct dma_rcv_ctx));	d->ohci = (void *)ohci;	d->ctx = ctx;	d->num_desc = num_desc;	d->buf_size = buf_size;	d->split_buf_size = split_buf_size;	d->ctrlSet = ctrlSet;	d->ctrlClear = ctrlClear;	d->cmdPtr = cmdPtr;	d->buf_cpu = NULL;	d->buf_bus = NULL;	d->prg_cpu = NULL;	d->prg_bus = NULL;	d->spb = NULL;	d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL);	d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);	if (d->buf_cpu == NULL || d->buf_bus == NULL) {		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer");		free_dma_rcv_ctx(&d);		return NULL;	}	memset(d->buf_cpu, 0, d->num_desc * sizeof(quadlet_t*));	memset(d->buf_bus, 0, d->num_desc * sizeof(dma_addr_t));	d->prg_cpu = kmalloc(d->num_desc * sizeof(struct dma_cmd*), 			     GFP_KERNEL);	d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);	if (d->prg_cpu == NULL || d->prg_bus == NULL) {		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma prg");		free_dma_rcv_ctx(&d);		return NULL;	}	memset(d->prg_cpu, 0, d->num_desc * sizeof(struct dma_cmd*));	memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t));	d->spb = kmalloc(d->split_buf_size, GFP_KERNEL);	if (d->spb == NULL) {		PRINT(KERN_ERR, ohci->id, "Failed to allocate split buffer");		free_dma_rcv_ctx(&d);		return NULL;	}	for (i=0; i<d->num_desc; i++) {		d->buf_cpu[i] = pci_alloc_consistent(ohci->dev, 						     d->buf_size,						     d->buf_bus+i);		OHCI_DMA_ALLOC("consistent dma_rcv buf[%d]", i);				if (d->buf_cpu[i] != NULL) {			memset(d->buf_cpu[i], 0, d->buf_size);		} else {			PRINT(KERN_ERR, ohci->id, 			      "Failed to allocate dma buffer");			free_dma_rcv_ctx(&d);			return NULL;		}		                d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, 						     sizeof(struct dma_cmd),						     d->prg_bus+i);		OHCI_DMA_ALLOC("consistent dma_rcv prg[%d]", i);                if (d->prg_cpu[i] != NULL) {                        memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd));		} else {			PRINT(KERN_ERR, ohci->id, 			      "Failed to allocate dma prg");			free_dma_rcv_ctx(&d);			return NULL;		}	}        spin_lock_init(&d->lock);	/* initialize tasklet */	tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long)d);	return d;}static int free_dma_trm_ctx(struct dma_trm_ctx **d){	struct ti_ohci *ohci;	int i;	if (*d==NULL) return -1;	ohci = (struct ti_ohci *)(*d)->ohci;	DBGMSG(ohci->id, "Freeing dma_trm_ctx %d",(*d)->ctx);	ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL);	tasklet_kill(&(*d)->task);	if ((*d)->prg_cpu) {		for (i=0; i<(*d)->num_desc; i++) 			if ((*d)->prg_cpu[i] && (*d)->prg_bus[i]) {				pci_free_consistent(					ohci->dev, sizeof(struct at_dma_prg), 					(*d)->prg_cpu[i], (*d)->prg_bus[i]);				OHCI_DMA_FREE("consistent dma_trm prg[%d]", i);			}		kfree((*d)->prg_cpu);		kfree((*d)->prg_bus);	}	kfree(*d);	*d = NULL;

⌨️ 快捷键说明

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