📄 ohci1394.c
字号:
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 + -