📄 aic5800.c
字号:
/* * +++ THIS DRIVER IS ORPHANED AND UNSUPPORTED +++ * * aic5800.c - Adaptec AIC-5800 PCI-IEEE1394 chip driver * Copyright (C)1999 Emanuel Pirker <epirker@edu.uni-klu.ac.at> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <linux/kernel.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/wait.h>#include <linux/errno.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/fs.h>#include <linux/poll.h>#include <linux/delay.h>#include <asm/byteorder.h>#include <asm/atomic.h>#include <asm/io.h>#include <asm/uaccess.h>#include "ieee1394_types.h"#include "hosts.h"#include "ieee1394_core.h"#include "ieee1394.h"#include "aic5800.h"/// print general (card independent) information #define PRINT_G(level, fmt, args...) printk(level "aic5800: " fmt "\n" , ## args)/// print card specific information #define PRINT(level, card, fmt, args...) printk(level "aic5800-%d: " fmt "\n" , card , ## args)/// card array static struct aic5800 cards[MAX_AIC5800_CARDS];/// holds the number of installed aic5800 cardsstatic int num_of_cards = 0;static int add_card(struct pci_dev *dev);static void remove_card(struct aic5800 *aic);static int init_driver(void);/***************************************************************** * Auxiliary functions needed to read the EEPROM * Daniel Minitti *****************************************************************/#define SEEPDOUT 0x1#define SEEPDIN 0x02#define SEEPSK 0x04#define SEEPCS 0x08#define SEEPCYC 0x10#define SEEPBUSY 0x20#define CLOCK_PULSE() {\ int cnt=200;\ while(cnt-->0 && reg_read(aic, misc_SEEPCTL) & SEEPBUSY);\ if (reg_read(aic, misc_SEEPCTL) & SEEPBUSY) printk("BUSY ");\ }static inline unsigned short read_seeprom_word(struct aic5800 *aic, int offset) { int i; unsigned char temp; unsigned char read_cmd[3] = {1,1,0}; unsigned short rd; // send chip select for one clock cycle. reg_write(aic, misc_SEEPCTL, SEEPSK|SEEPCS); CLOCK_PULSE(); // write start bit (1) & READ op-code (10b) for (i=0; i<sizeof(read_cmd); i++) { temp = SEEPCS | SEEPCYC | read_cmd[i]; reg_write(aic, misc_SEEPCTL, temp); CLOCK_PULSE(); temp = temp ^ SEEPSK; reg_write(aic, misc_SEEPCTL, temp); CLOCK_PULSE(); } // write 8 bit address (MSB --> LSB) for (i=7; i>=0; i--) { temp = offset; temp = (temp >> i) & 1; temp = SEEPCS | SEEPCYC | temp; reg_write(aic, misc_SEEPCTL, temp); CLOCK_PULSE(); temp = temp ^ SEEPSK; reg_write(aic, misc_SEEPCTL, temp); CLOCK_PULSE(); } // read 16 bit (MSB --> LSB) rd = 0; for (i=0; i<=16; i++) { temp = SEEPCS | SEEPCYC; reg_write(aic, misc_SEEPCTL, temp); CLOCK_PULSE(); temp = temp ^ SEEPSK; rd = (rd << 1) | (unsigned short)((reg_read(aic, misc_SEEPCTL)& SEEPDIN)>>1); reg_write(aic, misc_SEEPCTL, temp); CLOCK_PULSE(); } // reset chip select for the next command cycle reg_write(aic, misc_SEEPCTL, SEEPCYC); CLOCK_PULSE(); reg_write(aic, misc_SEEPCTL, SEEPCYC | SEEPSK); CLOCK_PULSE(); reg_write(aic, misc_SEEPCTL, SEEPCYC); CLOCK_PULSE(); reg_write(aic, misc_SEEPCTL, 0); CLOCK_PULSE(); return rd;}#undef DEBUG_SEEPROM/** Read 64-bit GUID (Global Unique ID) from SEEPROM * * It works well on AHA-8945. * On AHA-8920 it works well only on first time, It returns ffff... on * the other times. *****************************************************************/static unsigned long long read_guid(struct aic5800 *aic) { int i; unsigned long long guid;#ifdef DEBUG_SEEPROM printk("\n"); printk("SEEPCTL value = 0x%x\n", reg_read(aic, misc_SEEPCTL));#endif /* read GUID */ guid = 0; for (i=0x10; i<0x14; i++) guid = (guid << 16) | read_seeprom_word(aic,i);#ifdef DEBUG_SEEPROM for (i=0; i<3; i++) printk("%x ", (unsigned int) read_seeprom_word(aic,i)); printk("\nGUID = "); for (i=3; i>=0; i--) printk("%x ", (unsigned int)(guid>>(16*i))&0xffff); printk("\nSEEPCTL value = 0x%x\n", reg_read(aic, misc_SEEPCTL));#endif return guid;}#undef CLOCK_PULSE()static int aic_detect(struct hpsb_host_template *tmpl){ struct hpsb_host *host; int i; init_driver(); for (i = 0; i < num_of_cards; i++) { host = hpsb_get_host(tmpl, 0); if (host == NULL) { /* simply don't init more after out of mem */ return i; } host->hostdata = &cards[i]; cards[i].host = host; } return num_of_cards;}static int aic_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg){ struct aic5800 *aic = host->hostdata; int retval = 0; unsigned long flags; struct hpsb_packet *packet, *lastpacket; switch (cmd) { case RESET_BUS: reg_write(aic, misc_PhyControl, 0x00004140 ); break; case GET_CYCLE_COUNTER: arg = reg_read(aic, misc_CycleTimer); break; case SET_CYCLE_COUNTER: reg_write(aic, misc_CycleTimer, arg); break; case SET_BUS_ID: reg_clear_bits(aic, misc_NodeID, 0xFFC0); reg_set_bits(aic, misc_NodeID, (arg<<6)); break; case ACT_CYCLE_MASTER: if (arg) { /* enable cycleMaster */ reg_set_bits(aic, misc_Control, 0x20000); } else { /* disable cycleMaster */ reg_clear_bits(aic, misc_Control, 0x20000); }; break; case CANCEL_REQUESTS: spin_lock_irqsave(&aic->async_queue_lock, flags); /* stop any chip activity */ reg_write( aic, AT_ChannelControl, 0x80000000); packet = aic->async_queue; aic->async_queue = NULL; spin_unlock_irqrestore(&aic->async_queue_lock, flags); while (packet != NULL) { lastpacket = packet; packet = packet->xnext; hpsb_packet_sent(host, lastpacket, ACKX_ABORTED); } break; case MODIFY_USAGE: if (arg) { MOD_INC_USE_COUNT; } else { MOD_DEC_USE_COUNT; } break;#if 0 case DEBUG_DUMPINFO: PRINT(KERN_INFO, aic->id, AIC5800_DRIVER_NAME); PRINT(KERN_INFO, aic->id, " Register MMIO base: 0x%p\n", aic->registers); PRINT(KERN_INFO, aic->id, " NodeID: 0x%x\n", reg_read(aic, misc_NodeID) ); PRINT(KERN_INFO,aic->id, " #Intr: %lu BusResets: %lu\n", aic->NumInterrupts, aic->NumBusResets); PRINT(KERN_INFO, aic->id, " TxPackets: %lu RxPackets: %lu\n", aic->TxPackets, aic->RxPackets); PRINT(KERN_INFO,aic->id, " TxRdy: %lu ATErr: %lu HdrErr: %lu TcodeErr: %lu SendRej: %lu\n", aic->TxRdy, aic->ATError, aic->HdrErr, aic->TCodeErr, aic->SendRej); break;#endif default: PRINT(KERN_ERR, aic->id, "unknown devctl command %d", cmd); retval = -1; } return retval; }/** Initialize the host adapter chip and corresponding data structures. We reset the chip, enable transmitter, receiver, the physical DMA units, cycle timer, cycle source, reception of selfid packets and initialize several other registers. */static int aic_initialize(struct hpsb_host *host){ int i; struct aic5800 *aic = host->hostdata; /* Reset data structures */ aic->async_queue = NULL; spin_lock_init(&aic->async_queue_lock); /* Reset the chip */ reg_write( aic, misc_Reset, 0x37); udelay(10); // FIXME reg_write( aic, misc_Reset, 0); /* Enable Transmitter/Receiver, enable physDMA, * enable CycleTimer, cycleSource */ reg_write( aic, misc_Control, 0x82050003); /* Enable reception of SelfID packets */ reg_set_bits(aic, misc_PacketControl, 0x20); reg_write(aic, AT_InterruptSelect, 0x00F0001); reg_write(aic, AT_BranchSelect, 0x0100010); reg_write(aic, AT_WaitSelect, 0x00F0001); reg_write(aic, misc_ATRetries, reg_read(aic, misc_ATRetries) | 0x7); /* initialize AR DMA */ /* unset run bit */ reg_write( aic, AR_ChannelControl, 0x80000000); /* here we should have 0 iterations because of the code in the DmaAR handler. However, to be sure we do it */ i = 0; while (reg_read(aic, AR_ChannelStatus) & 0x400) { i++; if (i>100000) { PRINT(KERN_ERR, aic->id, "Huh! Can't set AR_ChannelControl... card can not receive!"); break; } } (aic->AR_program)->control = ( DMA_CMD_INPUTLAST | DMA_KEY_STREAM0 | DMA_INTR_ALWAYS | DMA_BRANCH_ALWAYS) + AIC5800_ARFIFO_SIZE; (aic->AR_program)->address = virt_to_bus(aic->rcv_page); (aic->AR_program)->branchAddress = virt_to_bus(aic->AR_program); (aic->AR_program)->status = AIC5800_ARFIFO_SIZE; (aic->AR_program+1)->control = DMA_CMD_STOP; (aic->AR_program+1)->address = 0; (aic->AR_program+1)->branchAddress = 0; (aic->AR_program+1)->status = 0; reg_write( aic, AR_CommandPtr, (u32) virt_to_bus(aic->AR_program)); reg_write( aic, AR_ChannelControl, 0x80008000); /* Enable Interrupts */ reg_write(aic, misc_InterruptClear, 0xFFFFFFFF); reg_write(aic, misc_InterruptMask, 0xFFFFFFFF); /*reg_write(aic, misc_InterruptMask, 0x00F1F03F);*/ return 1;}static void aic_release(struct hpsb_host *host){ struct aic5800 *aic; if (host != NULL) { aic = host->hostdata; remove_card(aic); } }/* This must be called with the async_queue_lock held. */static void send_next_async(struct aic5800 *aic){ int i; struct hpsb_packet *packet = aic->async_queue; /* stop the channel program if it's still running */ reg_write( aic, AT_ChannelControl, 0x80000000); /* re-format packet header for AIC-5800 chip */ packet->header[1] = (packet->header[1] & 0xFFFF) | (packet->header[0] & 0xFFFF0000); packet->header[0] = (packet->header[0] & 0xFFFF);#ifndef __BIG_ENDIAN /* Packet must be byte-swapped in non-big-endian environments, * see AIC-5800 specification... */ { u32 i; for ( i = 0 ; i < packet->header_size/sizeof(u32) ; i++ ) packet->header[i] = cpu_to_be32( packet->header[i] ); for ( i = 0 ; i < packet->data_size/sizeof(u32) ; i++ ) packet->data[i] = cpu_to_be32( packet->data[i] ); } #endif /* typically we use only a few iterations here */ i = 0; while (reg_read(aic, AT_ChannelStatus) & 0x400) { i++; if (i>5000) { PRINT(KERN_ERR, aic->id, "runaway loop 1 in send_next_async() - bailing out..."); break; }; }; /* set data buffer address and packet length */ memset(aic->AT_program, 0, MAX_AT_PROGRAM_SIZE * sizeof(struct dma_cmd)); if (packet->data_size) { aic->AT_program[0].control = ( DMA_CMD_OUTPUTMORE | DMA_KEY_STREAM0 ) + packet -> header_size; aic->AT_program[0].address = virt_to_bus( packet->header ); aic->AT_program[1].control = ( DMA_CMD_OUTPUTLAST | DMA_KEY_STREAM0 | DMA_INTR_ALWAYS ) + packet -> data_size; aic->AT_program[1].address = virt_to_bus( packet->data ); aic->AT_program[2].control = DMA_CMD_STOP; } else { aic->AT_program[0].control = ( DMA_CMD_OUTPUTLAST | DMA_INTR_ALWAYS | DMA_KEY_STREAM0 ) + packet -> header_size; aic->AT_program[0].address = virt_to_bus( packet->header ); aic->AT_program[1].control = DMA_CMD_STOP; }; /* set program start address */ reg_write(aic, AT_CommandPtr, (unsigned int) virt_to_bus(aic->AT_program)); /* typically we use only a few iterations here */ i = 0; while (reg_read(aic, AT_CommandPtr) != (unsigned int) virt_to_bus(aic->AT_program)) { i++; if (i>5000) { PRINT(KERN_ERR, aic->id, "runaway loop 2 in send_next_async() - bailing out..."); break; }; }; /* run program */ reg_write( aic, AT_ChannelControl, 0x80008000);}static int aic_transmit(struct hpsb_host *host, struct hpsb_packet *packet){ struct aic5800 *aic = host->hostdata; struct hpsb_packet *p; unsigned long flags; if (packet->data_size >= 4096) { PRINT(KERN_ERR, aic->id, "transmit packet data too big (%d)", packet->data_size); return 0; } packet->xnext = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -