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

📄 aic5800.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
    spin_lock_irqsave(&aic->async_queue_lock, flags);    if (aic->async_queue == NULL) {	aic->async_queue = packet;	send_next_async(aic);    } else {	p = aic->async_queue;	while (p->xnext != NULL) {	    p = p->xnext;	}		p->xnext = packet;    }        spin_unlock_irqrestore(&aic->async_queue_lock, flags);    return 1;}static int get_phy_reg(struct aic5800 *aic, int addr){        int retval;        int i = 0;	/* sanity check */        if (addr > 15) {                PRINT(KERN_ERR, aic->id, __FUNCTION__                      ": PHY register address %d out of range", addr);                return -1;        }	/* request data from PHY */        reg_write(aic, misc_PhyControl, LINK_PHY_READ | LINK_PHY_ADDR(addr));	/* read data from PhyControl register */	/* note that we have to wait until the register is updated */        do {                retval = reg_read(aic, misc_PhyControl);                if (i > 10000) {                        PRINT(KERN_ERR, aic->id, __FUNCTION__                               ": runaway loop, aborting");                        retval = -1;                        break;                }                i++;        } while ((retval & 0xf000000) != LINK_PHY_RADDR(addr));	/* we don't want a PhyInt interrupt */        reg_write(aic, misc_InterruptClear, INT_PhyInt);        if (retval != -1) {                return ((retval & 0xff0000)>>16);        } else {                return -1;        }}static quadlet_t generate_own_selfid(struct aic5800 *aic, int phyid){    quadlet_t lsid;    char phyreg[7];    int i;    for (i = 1; i < 7; i++) {	phyreg[i] = get_phy_reg(aic, i);    }    /* Standard PHY register map */    lsid = 0x80400000 | (phyid << 24);    lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */    lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */    lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dep) */    lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */    for (i = 0; i < (phyreg[2] & 0x1f); i++) { /* ports */	if (phyreg[3 + i] & 0x4) {	    lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3)						    << (6 - i*2);	} else {	    lsid |= 1 << (6 - i*2);	}    }    return lsid;};/* moved out to make interrupt routine more readable */inline static void handle_selfid(struct aic5800 *aic, struct hpsb_host *host,                          int phyid, int isroot, size_t size){    quadlet_t *q = aic->rcv_page;    quadlet_t lsid;    /* we need our own self-id packet */    lsid = generate_own_selfid(aic, phyid);    /* unconnected state? only begin and end marker in rcv_page */    if (size==8) {	hpsb_selfid_received(host, lsid);    }    /* process buffer... AIC's FIFO often contains some strangenesses */    while (size > 0) {	if (q[0] == 0xe0) {	    /* marker */	    q += 1;	    size -= 4;	    continue;	};	if (q[0] == 0x1) {	    /* marker */	    q += 1;	    size -= 4;	    break;	};	if (q[0] == ~q[1]) {	    /* correct self-id */	    if ((q[0] & 0x3f800000) == ((phyid + 1) << 24)) {		/* its our turn now! */		//PRINT(KERN_INFO, 		//      aic->id, "selfid packet 0x%x included", lsid);				hpsb_selfid_received(host, lsid);	    }	    //PRINT(KERN_INFO, aic->id, "selfid packet 0x%x rcvd", q[0]);	    hpsb_selfid_received(host, q[0]);	    q += 2;	    size -= 8;	    continue;	};    }    /* if we are root, our self-id packet is last */    if (isroot && phyid != 0) {	hpsb_selfid_received(host, lsid);    }    hpsb_selfid_complete(host, phyid, isroot);}static void aic_irq_handler(int irq, void *dev_id, struct pt_regs *regs){    struct aic5800 *aic = (struct aic5800 *)dev_id;    struct hpsb_host *host = aic->host;    quadlet_t *q = aic->rcv_page;     int phyid = -1, isroot = 0;    u32 interruptEvent = reg_read(aic, misc_InterruptEvents);    reg_write(aic, misc_InterruptClear, interruptEvent);    //printk("InterruptEvent 0x%x\n", interruptEvent);    if ( (interruptEvent & 0x3f) == 0x3f ) {	PRINT(KERN_INFO, aic->id, "Dma Engine Error");    };    if ( interruptEvent & INT_DmaAT ) {	if (aic->AT_program[0].status & 0xFFFF) 	    PRINT(KERN_INFO, aic->id, "AT: could not transfer %d bytes", 		  aic->AT_program[0].status & 0xFFFF);    };    if ( interruptEvent & INT_PhyInt) {	PRINT(KERN_INFO, aic->id, "PhyInt");    };    if ( interruptEvent & INT_DmaAR ) {	int rcv_bytes;	int i;	/* we calculate the number of received bytes from the	   residual count field */	rcv_bytes = AIC5800_ARFIFO_SIZE - (aic->AR_program->status & 0xFFFF);	//PRINT(KERN_INFO, aic->id, "AR_status 0x%x, %d bytes read", aic->AR_program->status, rcv_bytes);	if ((aic->AR_program->status & 0x84000000) 	    && (aic->AR_program->status & 0xFFFF) >= 8 ) {#ifndef __BIG_ENDIAN 	    /* we have to do byte-swapping on non-bigendian architectures */	    for (i=0; i< (rcv_bytes / sizeof(quadlet_t)); i++) {		*q = be32_to_cpu(*q);		q++;	    };	    q = aic->rcv_page;#endif	    if (*q == 0xe0) {		phyid = reg_read(aic, misc_NodeID);		isroot = phyid & 0x800000;		phyid = phyid & 0x3F;		handle_selfid(aic, host, phyid, isroot, rcv_bytes);	    } else {		hpsb_packet_received(host, aic->rcv_page, rcv_bytes, 0);	    };	} else {	    PRINT(KERN_ERR, aic->id, 		  "AR DMA program status value 0x%x is incorrect!",		  aic->AR_program->status);	};    }    if ( interruptEvent & INT_BusReset ) {	PRINT(KERN_INFO, aic->id, "bus reset occured");	if (!host->in_bus_reset) {	    hpsb_bus_reset(host);	}	reg_set_bits(aic, misc_Control, 0x1);	aic->NumBusResets++;    };    if (interruptEvent & INT_RcvData ) { 	aic->RxPackets++;    };    if (interruptEvent & INT_TxRdy) { 	/* async packet sent - transmitter ready */	u32 ack;	struct hpsb_packet *packet;	if (aic->async_queue) {	    spin_lock(&aic->async_queue_lock);	    	    ack = reg_read(aic, AT_ChannelStatus) & 0xF;	    	    packet = aic->async_queue;	    aic->async_queue = packet->xnext;	    	    if (aic->async_queue != NULL) {		send_next_async(aic);	    }	    spin_unlock(&aic->async_queue_lock);	    PRINT(KERN_INFO,aic->id,"packet sent with ack code %d",ack);	    hpsb_packet_sent(host, packet, ack);	    	} // else 	    //PRINT(KERN_INFO,aic->id,"packet sent without async_queue (self-id?)");	aic->TxRdy++;    };    if (interruptEvent & INT_ATError ) { 	PRINT(KERN_INFO,aic->id,"ATError");	aic->ATError++;    };    if (interruptEvent & INT_SendRej ) { 	aic->SendRej++;    };    if (interruptEvent & INT_HdrErr ) { 	aic->HdrErr++;    };    if (interruptEvent & INT_TCodeErr ) { 	PRINT(KERN_INFO,aic->id,"TCodeErr");	aic->TCodeErr++;    };    aic->NumInterrupts++;}inline static void * quadquadalign(void *buf){  if ((unsigned int) buf % 0x10 != 0) {	return (void *)(((unsigned int)buf + 0x10) & 0xFFFFFFF0);	} else {	return buf;  };}static int add_card(struct pci_dev *dev){#define FAIL(fmt, args...) do {\        PRINT_G(KERN_ERR, fmt , ## args); \        num_of_cards--; \        remove_card(aic); \        return 1; } while (0)        struct aic5800 *aic; /* shortcut to currently handled device */        unsigned long page;	if (pci_enable_device(dev))		return 1;        if (num_of_cards == MAX_AIC5800_CARDS) {                PRINT_G(KERN_WARNING, "cannot handle more than %d cards.  "                        "Adjust MAX_AIC5800_CARDS in aic5800.h.",                        MAX_AIC5800_CARDS);                return 1;        }        aic = &cards[num_of_cards++];        aic->id = num_of_cards-1;        aic->dev = dev;        if (!request_irq(dev->irq, aic_irq_handler, SA_SHIRQ,                         AIC5800_DRIVER_NAME, aic)) {                PRINT(KERN_INFO, aic->id, "allocated interrupt %d", dev->irq);        } else {                FAIL("failed to allocate shared interrupt %d", dev->irq);        }        page = get_free_page(GFP_KERNEL);        if (page != 0) {                aic->rcv_page = phys_to_virt(page);        } else {                FAIL("failed to allocate receive buffer");        }#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)        aic->registers = ioremap_nocache(dev->base_address[0],                                          AIC5800_REGSPACE_SIZE);#else        aic->registers = ioremap_nocache(dev->resource[0].start,                                          AIC5800_REGSPACE_SIZE);#endif        if (aic->registers == NULL) {                FAIL("failed to remap registers - card not accessible");        }        PRINT(KERN_INFO, aic->id, "remapped memory space reg 0x%p", 	      aic->registers);        aic->pbuf = kmalloc(AIC5800_PBUF_SIZE, GFP_KERNEL);        if (!aic->pbuf) {                FAIL("failed to allocate program buffer");        }	aic->AT_program = quadquadalign(aic->pbuf);	aic->AT_program[2].control = DMA_CMD_STOP;	aic->AR_program = aic->AT_program + MAX_AT_PROGRAM_SIZE * 	    sizeof(struct dma_cmd);        return 0;#undef FAIL}static void remove_card(struct aic5800 *aic){    /* Disable interrupts of this controller */    reg_write(aic, misc_InterruptMask, 0);    /* Free AR buffer */    free_page(virt_to_phys(aic->rcv_page));    /* Free channel program buffer */    kfree(aic->pbuf);    /* Free interrupt request */    free_irq(aic->dev->irq, aic);    /* Unmap register space */    iounmap(aic->registers);}static int init_driver(){        struct pci_dev *dev = NULL;        int success = 0;        if (num_of_cards) {                PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again");                return 0;        }        while ((dev = pci_find_device(PCI_VENDOR_ID_ADAPTEC,                                      PCI_DEVICE_ID_ADAPTEC_5800, dev))                != NULL) {                if (add_card(dev) == 0) {                        success = 1;                }        }        if (success == 0) {                PRINT_G(KERN_WARNING, "no operable AIC-5800 based cards found");                return -ENXIO;        }        return 0;}/** Prepare our local CSR ROM. This is done by using the software-stored    ROM and inserting the GUID read from the EEPROM */static size_t get_aic_rom(struct hpsb_host *host, const quadlet_t **ptr){    struct aic5800 *aic = host -> hostdata;    u64 guid;    /* Read the GUID from the card's EEPROM and put it into the right       place in the CONFIG ROM. */    guid = read_guid(aic);    aic5800_csr_rom[15] = (u32) (guid >> 32);    aic5800_csr_rom[16] = (u32) (guid & 0xFFFF);    *ptr = aic5800_csr_rom;    return sizeof(aic5800_csr_rom);}struct hpsb_host_template *get_aic_template(void){        static struct hpsb_host_template tmpl;        static int initialized = 0;        if (!initialized) {                /* Initialize by field names so that a template structure                 * reorganization does not influence this code. */                tmpl.name = "aic5800";                                tmpl.detect_hosts = aic_detect;                tmpl.initialize_host = aic_initialize;                tmpl.release_host = aic_release;                tmpl.get_rom = get_aic_rom;                tmpl.transmit_packet = aic_transmit;                tmpl.devctl = aic_devctl;                initialized = 1;        }        return &tmpl;}#ifdef MODULE/* EXPORT_NO_SYMBOLS; */MODULE_AUTHOR("Emanuel Pirker <epirker@edu.uni-klu.ac.at>");MODULE_DESCRIPTION("Adaptec AIC-5800 PCI-to-IEEE1394 controller driver");MODULE_SUPPORTED_DEVICE("aic5800");void cleanup_module(void){        hpsb_unregister_lowlevel(get_aic_template());        PRINT_G(KERN_INFO, "removed " AIC5800_DRIVER_NAME " module");}int init_module(void){        if (hpsb_register_lowlevel(get_aic_template())) {                PRINT_G(KERN_ERR, "registering failed");                return -ENXIO;        } else {                return 0;        }}#endif /* MODULE */

⌨️ 快捷键说明

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