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

📄 ohci1394.c

📁 Armlinux ieee1394接口驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
	return 0;}static struct dma_trm_ctx *alloc_dma_trm_ctx(struct ti_ohci *ohci, int ctx, int num_desc,		  int ctrlSet, int ctrlClear, int cmdPtr){	struct dma_trm_ctx *d=NULL;	int i;	d = (struct dma_trm_ctx *)kmalloc(sizeof(struct dma_trm_ctx), 					  GFP_KERNEL);	if (d==NULL) {		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_trm_ctx");		return NULL;	}	memset (d, 0, sizeof (struct dma_trm_ctx));	d->ohci = (void *)ohci;	d->ctx = ctx;	d->num_desc = num_desc;	d->ctrlSet = ctrlSet;	d->ctrlClear = ctrlClear;	d->cmdPtr = cmdPtr;	d->prg_cpu = NULL;	d->prg_bus = NULL;	d->prg_cpu = kmalloc(d->num_desc * sizeof(struct at_dma_prg*), 			     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 at dma prg");		free_dma_trm_ctx(&d);		return NULL;	}	memset(d->prg_cpu, 0, d->num_desc * sizeof(struct at_dma_prg*));	memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t));	for (i=0; i<d->num_desc; i++) {                d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, 						     sizeof(struct at_dma_prg),						     d->prg_bus+i);		OHCI_DMA_ALLOC("consistent dma_trm prg[%d]", i);                if (d->prg_cpu[i] != NULL) {                        memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg));		} else {			PRINT(KERN_ERR, ohci->id, 			      "Failed to allocate at dma prg");			free_dma_trm_ctx(&d);			return NULL;		}	}        spin_lock_init(&d->lock);        /* initialize bottom handler */	tasklet_init (&d->task, dma_trm_tasklet, (unsigned long)d);	return d;}static u16 ohci_crc16 (u32 *ptr, int length){	int shift;	u32 crc, sum, data;	crc = 0;	for (; length > 0; length--) {		data = *ptr++;		for (shift = 28; shift >= 0; shift -= 4) {			sum = ((crc >> 12) ^ (data >> shift)) & 0x000f;			crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum;		}		crc &= 0xffff;	}	return crc;}/* Config ROM macro implementation influenced by NetBSD OHCI driver */struct config_rom_unit {	u32 *start;	u32 *refer;	int length;	int refunit;};struct config_rom_ptr {	u32 *data;	int unitnum;	struct config_rom_unit unitdir[10];};#define cf_put_1quad(cr, q) (((cr)->data++)[0] = cpu_to_be32(q))#define cf_put_4bytes(cr, b1, b2, b3, b4) \	(((cr)->data++)[0] = cpu_to_be32(((b1) << 24) | ((b2) << 16) | ((b3) << 8) | (b4)))#define cf_put_keyval(cr, key, val) (((cr)->data++)[0] = cpu_to_be32(((key) << 24) | (val)))static inline void cf_put_crc16(struct config_rom_ptr *cr, int unit){	*cr->unitdir[unit].start =		cpu_to_be32((cr->unitdir[unit].length << 16) |			    ohci_crc16(cr->unitdir[unit].start + 1,				       cr->unitdir[unit].length));}static inline void cf_unit_begin(struct config_rom_ptr *cr, int unit){	if (cr->unitdir[unit].refer != NULL) {		*cr->unitdir[unit].refer |=			cpu_to_be32 (cr->data - cr->unitdir[unit].refer);		cf_put_crc16(cr, cr->unitdir[unit].refunit);	}	cr->unitnum = unit;	cr->unitdir[unit].start = cr->data++;}static inline void cf_put_refer(struct config_rom_ptr *cr, char key, int unit){	cr->unitdir[unit].refer = cr->data;	cr->unitdir[unit].refunit = cr->unitnum;	(cr->data++)[0] = cpu_to_be32(key << 24);}static inline void cf_unit_end(struct config_rom_ptr *cr){	cr->unitdir[cr->unitnum].length = cr->data -		(cr->unitdir[cr->unitnum].start + 1);	cf_put_crc16(cr, cr->unitnum);}/* End of NetBSD derived code.  */static void ohci_init_config_rom(struct ti_ohci *ohci){	struct config_rom_ptr cr;	memset(&cr, 0, sizeof(cr));	memset(ohci->csr_config_rom_cpu, 0, sizeof (ohci->csr_config_rom_cpu));	cr.data = ohci->csr_config_rom_cpu;	/* Bus info block */	cf_unit_begin(&cr, 0);	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_BusID));	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_BusOptions));	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_GUIDHi));	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_GUIDLo));	cf_unit_end(&cr);	DBGMSG(ohci->id, "GUID: %08x:%08x", reg_read(ohci, OHCI1394_GUIDHi),		reg_read(ohci, OHCI1394_GUIDLo));	/* IEEE P1212 suggests the initial ROM header CRC should only	 * cover the header itself (and not the entire ROM). Since we do	 * this, then we can make our bus_info_len the same as the CRC	 * length.  */	ohci->csr_config_rom_cpu[0] |= cpu_to_be32(		(be32_to_cpu(ohci->csr_config_rom_cpu[0]) & 0x00ff0000) << 8);	reg_write(ohci, OHCI1394_ConfigROMhdr,		  be32_to_cpu(ohci->csr_config_rom_cpu[0]));	/* Root directory */	cf_unit_begin(&cr, 1);	cf_put_keyval(&cr, 0x03, 0x00005e);	/* Vendor ID */	cf_put_refer(&cr, 0x81, 2);		/* Textual description unit */	cf_put_keyval(&cr, 0x0c, 0x0083c0);	/* Node capabilities */	/* NOTE: Add other unit referers here, and append at bottom */	cf_unit_end(&cr);	/* Textual description - "Linux 1394" */	cf_unit_begin(&cr, 2);	cf_put_keyval(&cr, 0, 0);	cf_put_1quad(&cr, 0);	cf_put_4bytes(&cr, 'L', 'i', 'n', 'u');	cf_put_4bytes(&cr, 'x', ' ', '1', '3');	cf_put_4bytes(&cr, '9', '4', 0x0, 0x0);	cf_unit_end(&cr);	ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu;}static size_t ohci_get_rom(struct hpsb_host *host, const quadlet_t **ptr){	struct ti_ohci *ohci=host->hostdata;	DBGMSG(ohci->id, "request csr_rom address: %p",		ohci->csr_config_rom_cpu);	*ptr = ohci->csr_config_rom_cpu;	return ohci->csr_config_rom_length * 4;}int ohci_compare_swap(struct ti_ohci *ohci, quadlet_t *data,                      quadlet_t compare, int sel){	int i;	reg_write(ohci, OHCI1394_CSRData, *data);	reg_write(ohci, OHCI1394_CSRCompareData, compare);	reg_write(ohci, OHCI1394_CSRControl, sel & 0x3);	for (i = 0; i < OHCI_LOOP_COUNT; i++) {		if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)			break;		mdelay(1);	}	*data = reg_read(ohci, OHCI1394_CSRData);	return 0;}static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,                                 quadlet_t data, quadlet_t compare){	struct ti_ohci *ohci=host->hostdata;	ohci_compare_swap (ohci, &data, compare, reg);	return data;}static struct hpsb_host_template ohci_template = {	name:			OHCI1394_DRIVER_NAME,	initialize_host:	ohci_initialize,	release_host:		ohci_remove,	get_rom:		ohci_get_rom,	transmit_packet:	ohci_transmit,	devctl:			ohci_devctl,	hw_csr_reg:		ohci_hw_csr_reg,};#define FAIL(fmt, args...)			\do {						\	PRINT_G(KERN_ERR, fmt , ## args);	\	remove_card(ohci);			\	return 1;				\} while(0)static int __devinit ohci1394_add_one(struct pci_dev *dev, const struct pci_device_id *ent){	struct ti_ohci *ohci;	/* shortcut to currently handled device */	struct hpsb_host *host;	unsigned long ohci_base, ohci_len;	static int version_printed = 0;	if (version_printed++ == 0)		PRINT_G(KERN_INFO, "%s", version);        if (pci_enable_device(dev)) {		/* Skip ID's that fail */		PRINT_G(KERN_NOTICE, "Failed to enable OHCI hardware %d",			card_id_counter++);		return -ENXIO;        }        pci_set_master(dev);	host = hpsb_get_host(&ohci_template, sizeof (struct ti_ohci));	if (!host) {		PRINT_G(KERN_ERR, "Out of memory trying to allocate host structure");		return -ENOMEM;	}	ohci = host->hostdata;	ohci->host = host;	INIT_LIST_HEAD(&ohci->list);	ohci->id = card_id_counter++;	ohci->dev = dev;	host->pdev = dev;	ohci->host = host;	pci_set_drvdata(dev, ohci);	/* We don't want hardware swapping */	pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);	/* Some oddball Apple controllers do not order the selfid	 * properly, so we make up for it here.  */#ifndef __LITTLE_ENDIAN	/* XXX: Need a better way to check this. I'm wondering if we can	 * read the values of the OHCI1394_PCI_HCI_Control and the	 * noByteSwapData registers to see if they were not cleared to	 * zero. Should this work? Obviously it's not defined what these	 * registers will read when they aren't supported. Bleh! */	if (dev->vendor == PCI_VENDOR_ID_APPLE && 		dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) {			ohci->no_swap_incoming = 1;			ohci->selfid_swap = 0;	} else		ohci->selfid_swap = 1;#endif	/* csr_config rom allocation */	ohci->csr_config_rom_cpu = 		pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,				     &ohci->csr_config_rom_bus);	OHCI_DMA_ALLOC("consistent csr_config_rom");	if (ohci->csr_config_rom_cpu == NULL)		FAIL("Failed to allocate buffer config rom");	/* 	 * self-id dma buffer allocation	 */	ohci->selfid_buf_cpu = 		pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE,                      &ohci->selfid_buf_bus);	OHCI_DMA_ALLOC("consistent selfid_buf");	if (ohci->selfid_buf_cpu == NULL)		FAIL("Failed to allocate DMA buffer for self-id packets");	if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff)		PRINT(KERN_INFO, ohci->id, "SelfID buffer %p is not aligned on "		      "8Kb boundary... may cause problems on some CXD3222 chip", 		      ohci->selfid_buf_cpu);  	ohci->it_context =		alloc_dma_trm_ctx(ohci, 2, IT_NUM_DESC,				  OHCI1394_IsoXmitContextControlSet,				  OHCI1394_IsoXmitContextControlClear,				  OHCI1394_IsoXmitCommandPtr);	if (ohci->it_context == NULL)		FAIL("Failed to allocate IT context");	ohci_base = pci_resource_start(dev, 0);	ohci_len = pci_resource_len(dev, 0);	if (!request_mem_region (ohci_base, ohci_len, host->template->name))		FAIL("MMIO resource (0x%lx@0x%lx) unavailable, aborting.",		     ohci_base, ohci_len);	ohci->registers = ioremap(ohci_base, ohci_len);	if (ohci->registers == NULL)		FAIL("Failed to remap registers - card not accessible");	DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p",	      ohci->registers);	ohci->ar_req_context = 		alloc_dma_rcv_ctx(ohci, 0, AR_REQ_NUM_DESC,				  AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE,				  OHCI1394_AsReqRcvContextControlSet,				  OHCI1394_AsReqRcvContextControlClear,				  OHCI1394_AsReqRcvCommandPtr);	if (ohci->ar_req_context == NULL)		FAIL("Failed to allocate AR Req context");	ohci->ar_resp_context = 		alloc_dma_rcv_ctx(ohci, 1, AR_RESP_NUM_DESC,				  AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE,				  OHCI1394_AsRspRcvContextControlSet,				  OHCI1394_AsRspRcvContextControlClear,				  OHCI1394_AsRspRcvCommandPtr);		if (ohci->ar_resp_context == NULL)		FAIL("Failed to allocate AR Resp context");	ohci->at_req_context = 		alloc_dma_trm_ctx(ohci, 0, AT_REQ_NUM_DESC,				  OHCI1394_AsReqTrContextControlSet,				  OHCI1394_AsReqTrContextControlClear,				  OHCI1394_AsReqTrCommandPtr);		if (ohci->at_req_context == NULL)		FAIL("Failed to allocate AT Req context");	ohci->at_resp_context = 		alloc_dma_trm_ctx(ohci, 1, AT_RESP_NUM_DESC,				  OHCI1394_AsRspTrContextControlSet,				  OHCI1394_AsRspTrContextControlClear,				  OHCI1394_AsRspTrCommandPtr);		if (ohci->at_resp_context == NULL)		FAIL("Failed to allocate AT Resp context");	ohci->ir_context =		alloc_dma_rcv_ctx(ohci, 2, IR_NUM_DESC,				  IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,				  OHCI1394_IsoRcvContextControlSet,				  OHCI1394_IsoRcvContextControlClear,				  OHCI1394_IsoRcvCommandPtr);	if (ohci->ir_context == NULL)		FAIL("Failed to allocate IR context");	ohci->ISO_channel_usage = 0;        spin_lock_init(&ohci->IR_channel_lock);	if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,			 OHCI1394_DRIVER_NAME, ohci))		FAIL("Failed to allocate shared interrupt %d", dev->irq);	/* Tell the highlevel this host is ready */	highlevel_add_one_host (host);	return 0;#undef FAIL}static void remove_card(struct ti_ohci *ohci){	quadlet_t buf;	/* Soft reset before we start */	ohci_soft_reset(ohci);	/* Free AR dma */	free_dma_rcv_ctx(&ohci->ar_req_context);	free_dma_rcv_ctx(&ohci->ar_resp_context);	/* Free AT dma */	free_dma_trm_ctx(&ohci->at_req_context);	free_dma_trm_ctx(&ohci->at_resp_context);	/* Free IR dma */	free_dma_rcv_ctx(&ohci->ir_context);        /* Free IT dma */        free_dma_trm_ctx(&ohci->it_context);	/* Disable all interrupts */	reg_write(ohci, OHCI1394_IntMaskClear, 0x80000000);	free_irq(ohci->dev->irq, ohci);	/* Free self-id buffer */	if (ohci->selfid_buf_cpu) {		pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, 				    ohci->selfid_buf_cpu,				    ohci->selfid_buf_bus);		OHCI_DMA_FREE("consistent selfid_buf");	}		/* Free config rom */	if (ohci->csr_config_rom_cpu) {		pci_free_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,				    ohci->csr_config_rom_cpu, 				    ohci->csr_co

⌨️ 快捷键说明

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