diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-03-02 02:36:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-03-02 02:36:47 +0000 |
commit | 8624512aa908741ba2795200133eae0d7f4557ea (patch) | |
tree | d5d3036fccf2604f4c98dedc11e8adb929d6b52e /drivers | |
parent | 7b8f5d6f1d45d9f9de1d26e7d3c32aa5af11b488 (diff) |
Merge with 2.3.48.
Diffstat (limited to 'drivers')
273 files changed, 27617 insertions, 14066 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 1c99a05a7..1d4653233 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -57,6 +57,11 @@ SUB_DIRS += macintosh MOD_SUB_DIRS += macintosh endif +ifdef CONFIG_PPC +SUB_DIRS += macintosh +MOD_SUB_DIRS += macintosh +endif + ifeq ($(CONFIG_USB),y) SUB_DIRS += usb MOD_SUB_DIRS += usb diff --git a/drivers/atm/Config.in b/drivers/atm/Config.in index 07e712751..8fb55632a 100644 --- a/drivers/atm/Config.in +++ b/drivers/atm/Config.in @@ -51,4 +51,29 @@ if [ "$CONFIG_PCI" = "y" ]; then bool ' Enable debugging messages' CONFIG_ATM_IA_DEBUG fi fi +if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SBUS" = "y" ]; then + tristate 'FORE Systems 200E-series' CONFIG_ATM_FORE200E + if [ "$CONFIG_ATM_FORE200E" != "n" ]; then + if [ "$CONFIG_PCI" = "y" ]; then + bool ' PCA-200E support' CONFIG_ATM_FORE200E_PCA y + if [ "$CONFIG_ATM_FORE200E_PCA" = "y" ]; then + bool ' Use default PCA-200E firmware (normally enabled)' CONFIG_ATM_FORE200E_PCA_DEFAULT_FW + if [ "$CONFIG_ATM_FORE200E_PCA_DEFAULT_FW" = "n" ]; then + string ' Pathname of user-supplied binary firmware' CONFIG_ATM_FORE200E_PCA_FW + fi + fi + fi + if [ "$CONFIG_SBUS" = "y" ]; then + bool ' SBA-200E support' CONFIG_ATM_FORE200E_SBA y + if [ "$CONFIG_ATM_FORE200E_SBA" = "y" ]; then + bool ' Use default SBA-200E firmware (normally enabled)' CONFIG_ATM_FORE200E_SBA_DEFAULT_FW + if [ "$CONFIG_ATM_FORE200E_SBA_DEFAULT_FW" = "n" ]; then + string ' Pathname of user-supplied binary firmware' CONFIG_ATM_FORE200E_SBA_FW "" + fi + fi + fi + int ' Maximum number of tx retries' CONFIG_ATM_FORE200E_TX_RETRY 16 + int ' Debugging level (0-3)' CONFIG_ATM_FORE200E_DEBUG 0 + fi +fi endmenu diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile index 25b57fdd4..f126bd232 100644 --- a/drivers/atm/Makefile +++ b/drivers/atm/Makefile @@ -100,6 +100,58 @@ else LX_OBJS += $(NEED_IDT77105_LX) endif +ifeq ($(CONFIG_ATM_FORE200E_PCA),y) +FORE200E_FW_OBJS += fore200e_pca_fw.o + ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y) +# guess the target endianess to choose the right PCA-200E firmware image + CONFIG_ATM_FORE200E_PCA_FW := $(shell if test -n "`$(CC) -E -dM ../../include/asm/byteorder.h | grep ' __LITTLE_ENDIAN '`"; then echo pca200e.bin; else echo pca200e_ecd.bin2; fi) + endif +endif +ifeq ($(CONFIG_ATM_FORE200E_SBA),y) +FORE200E_FW_OBJS += fore200e_sba_fw.o + ifeq ($(CONFIG_ATM_FORE200E_SBA_DEFAULT_FW),y) + CONFIG_ATM_FORE200E_SBA_FW := sba200e_ecd.bin2 + endif +endif +ifeq ($(CONFIG_ATM_FORE200E),y) +L_OBJS += fore200e.o $(FORE200E_FW_OBJS) +else + ifeq ($(CONFIG_ATM_FORE200E),m) + M_OBJS += fore_200e.o + endif +endif + EXTRA_CFLAGS=-g include $(TOPDIR)/Rules.make + +# FORE Systems 200E-series firmware magic +fore200e_pca_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_PCA_FW)) \ + fore200e_mkfirm + ./fore200e_mkfirm -k -b _fore200e_pca_fw \ + -i $(CONFIG_ATM_FORE200E_PCA_FW) -o $@ + +fore200e_sba_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_SBA_FW)) \ + fore200e_mkfirm + ./fore200e_mkfirm -k -b _fore200e_sba_fw \ + -i $(CONFIG_ATM_FORE200E_SBA_FW) -o $@ + +fore200e_mkfirm: fore200e_mkfirm.c + $(HOSTCC) $(HOSTCFLAGS) $< -o $@ + +# deal with the various suffixes of the firmware images +%.bin: %.data + objcopy -Iihex $< -Obinary $@.gz + gzip -df $@.gz + +%.bin1: %.data + objcopy -Iihex $< -Obinary $@.gz + gzip -df $@.gz + +%.bin2: %.data + objcopy -Iihex $< -Obinary $@.gz + gzip -df $@.gz + +# module build +fore_200e.o: fore200e.o $(FORE200E_FW_OBJS) + $(LD) -r -o $@ $< $(FORE200E_FW_OBJS) diff --git a/drivers/atm/atmdev_init.c b/drivers/atm/atmdev_init.c index 20fcaee4a..357cbdbe0 100644 --- a/drivers/atm/atmdev_init.c +++ b/drivers/atm/atmdev_init.c @@ -28,6 +28,9 @@ extern int hrz_detect(void); #ifdef CONFIG_ATM_IA extern int ia_detect(void); #endif +#ifdef CONFIG_ATM_FORE200E +extern int fore200e_detect(void); +#endif int __init atmdev_init(void) @@ -56,5 +59,8 @@ int __init atmdev_init(void) #ifdef CONFIG_ATM_IA devs += ia_detect(); #endif +#ifdef CONFIG_ATM_FORE200E + devs += fore200e_detect(); +#endif return devs; } diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 1904b7e71..081fcdfed 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -156,7 +156,8 @@ static int tx_complete = 0,dma_complete = 0,queued = 0,requeued = 0, static struct atm_dev *eni_boards = NULL; -static u32 *zeroes = NULL; /* aligned "magic" zeroes */ +static u32 *cpu_zeroes = NULL; /* aligned "magic" zeroes */ +static dma_addr_t zeroes; /* Read/write registers on card */ #define eni_in(r) readl(eni_dev->reg+(r)*4) @@ -349,18 +350,21 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, struct eni_vcc *eni_vcc; u32 dma_rd,dma_wr; u32 dma[RX_DMA_BUF*2]; - unsigned long paddr,here; + dma_addr_t paddr; + unsigned long here; int i,j; eni_dev = ENI_DEV(vcc->dev); eni_vcc = ENI_VCC(vcc); paddr = 0; /* GCC, shut up */ if (skb) { - paddr = (unsigned long) skb->data; + paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len, + PCI_DMA_FROMDEVICE); + ENI_PRV_PADDR(skb) = paddr; if (paddr & 3) printk(KERN_CRIT DEV_LABEL "(itf %d): VCI %d has " "mis-aligned RX data (0x%lx)\n",vcc->dev->number, - vcc->vci,paddr); + vcc->vci,(unsigned long) paddr); ENI_PRV_SIZE(skb) = size+skip; /* PDU plus descriptor */ ATM_SKB(skb)->vcc = vcc; @@ -390,7 +394,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, if (init > words) init = words; dma[j++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; paddr += init << 2; words -= init; } @@ -399,7 +403,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, dma[j++] = MID_DT_16W | ((words >> 4) << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; paddr += (words & ~15) << 2; words &= 15; } @@ -409,7 +413,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, dma[j++] = MID_DT_8W | ((words >> 3) << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; paddr += (words & ~7) << 2; words &= 7; } @@ -419,7 +423,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, dma[j++] = MID_DT_4W | ((words >> 2) << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; paddr += (words & ~3) << 2; words &= 3; } @@ -429,7 +433,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, dma[j++] = MID_DT_2W | ((words >> 1) << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; paddr += (words & ~1) << 2; words &= 1; } @@ -437,7 +441,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, if (words) { dma[j++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; } } if (size != eff) { @@ -447,8 +451,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, } if (!j || j > 2*RX_DMA_BUF) { printk(KERN_CRIT DEV_LABEL "!j or j too big!!!\n"); - if (skb) kfree_skb(skb); - return -1; + goto trouble; } dma[j-2] |= MID_DMA_END; j = j >> 1; @@ -461,8 +464,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, if (!NEPMOK(dma_wr,j+j+1,dma_rd,NR_DMA_RX)) { /* @@@ +1 is ugly */ printk(KERN_WARNING DEV_LABEL "(itf %d): RX DMA full\n", vcc->dev->number); - if (skb) kfree_skb(skb); - return -1; + goto trouble; } for (i = 0; i < j; i++) { writel(dma[i*2],eni_dev->rx_dma+dma_wr*8); @@ -472,12 +474,19 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, if (skb) { ENI_PRV_POS(skb) = eni_vcc->descr+size+1; skb_queue_tail(&eni_dev->rx_queue,skb); -eni_vcc->last = skb; + eni_vcc->last = skb; rx_enqueued++; } eni_vcc->descr = here; eni_out(dma_wr,MID_DMA_WR_RX); return 0; + +trouble: + if (paddr) + pci_unmap_single(eni_dev->pci_dev,paddr,skb->len, + PCI_DMA_FROMDEVICE); + if (skb) dev_kfree_skb_irq(skb); + return -1; } @@ -747,7 +756,9 @@ rx_dequeued++; } eni_vcc->rxing--; eni_vcc->rx_pos = ENI_PRV_POS(skb) & (eni_vcc->words-1); - if (!skb->len) kfree_skb(skb); + pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len, + PCI_DMA_TODEVICE); + if (!skb->len) dev_kfree_skb_irq(skb); else { EVENT("pushing (len=%ld)\n",skb->len,0); if (vcc->qos.aal == ATM_AAL0) @@ -902,13 +913,13 @@ static int start_rx(struct atm_dev *dev) enum enq_res { enq_ok,enq_next,enq_jam }; -static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr, +static inline void put_dma(int chan,u32 *dma,int *j,dma_addr_t paddr, u32 size) { u32 init,words; - DPRINTK("put_dma: 0x%lx+0x%x\n",paddr,size); - EVENT("put_dma: 0x%lx+0x%lx\n",paddr,size); + DPRINTK("put_dma: 0x%lx+0x%x\n",(unsigned long) paddr,size); + EVENT("put_dma: 0x%lx+0x%lx\n",(unsigned long) paddr,size); #if 0 /* don't complain anymore */ if (paddr & 3) printk(KERN_ERR "put_dma: unaligned addr (0x%lx)\n",paddr); @@ -918,10 +929,11 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr, if (paddr & 3) { init = 4-(paddr & 3); if (init > size || size < 7) init = size; - DPRINTK("put_dma: %lx DMA: %d/%d bytes\n",paddr,init,size); + DPRINTK("put_dma: %lx DMA: %d/%d bytes\n", + (unsigned long) paddr,init,size); dma[(*j)++] = MID_DT_BYTE | (init << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += init; size -= init; } @@ -930,10 +942,11 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr, if (words && (paddr & 31)) { init = 8-((paddr & 31) >> 2); if (init > words) init = words; - DPRINTK("put_dma: %lx DMA: %d/%d words\n",paddr,init,words); + DPRINTK("put_dma: %lx DMA: %d/%d words\n", + (unsigned long) paddr,init,words); dma[(*j)++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += init << 2; words -= init; } @@ -943,18 +956,18 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr, words); dma[(*j)++] = MID_DT_16W | ((words >> 4) << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += (words & ~15) << 2; words &= 15; } #endif #ifdef CONFIG_ATM_ENI_BURST_TX_8W /* recommended */ if (words & ~7) { - DPRINTK("put_dma: %lx DMA: %d*8/%d words\n",paddr,words >> 3, - words); + DPRINTK("put_dma: %lx DMA: %d*8/%d words\n", + (unsigned long) paddr,words >> 3,words); dma[(*j)++] = MID_DT_8W | ((words >> 3) << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += (words & ~7) << 2; words &= 7; } @@ -965,7 +978,7 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr, words); dma[(*j)++] = MID_DT_4W | ((words >> 2) << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += (words & ~3) << 2; words &= 3; } @@ -976,23 +989,25 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr, words); dma[(*j)++] = MID_DT_2W | ((words >> 1) << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += (words & ~1) << 2; words &= 1; } #endif if (words) { - DPRINTK("put_dma: %lx DMA: %d words\n",paddr,words); + DPRINTK("put_dma: %lx DMA: %d words\n",(unsigned long) paddr, + words); dma[(*j)++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += words << 2; } if (size) { - DPRINTK("put_dma: %lx DMA: %d bytes\n",paddr,size); + DPRINTK("put_dma: %lx DMA: %d bytes\n",(unsigned long) paddr, + size); dma[(*j)++] = MID_DT_BYTE | (size << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; } } @@ -1003,6 +1018,7 @@ static enum enq_res do_tx(struct sk_buff *skb) struct eni_dev *eni_dev; struct eni_vcc *eni_vcc; struct eni_tx *tx; + dma_addr_t paddr; u32 dma_rd,dma_wr; u32 size; /* in words */ int aal5,dma_size,i,j; @@ -1079,6 +1095,9 @@ DPRINTK("iovcnt = %d\n",ATM_SKB(skb)->iovcnt); vcc->dev->number); return enq_jam; } + paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len, + PCI_DMA_TODEVICE); + ENI_PRV_PADDR(skb) = paddr; /* prepare DMA queue entries */ j = 0; eni_dev->dma[j++] = (((tx->tx_pos+TX_DESCR_SIZE) & (tx->words-1)) << @@ -1086,21 +1105,17 @@ DPRINTK("iovcnt = %d\n",ATM_SKB(skb)->iovcnt); MID_DT_JK; j++; if (!ATM_SKB(skb)->iovcnt) - if (aal5) - put_dma(tx->index,eni_dev->dma,&j, - (unsigned long) skb->data,skb->len); - else put_dma(tx->index,eni_dev->dma,&j, - (unsigned long) skb->data+4,skb->len-4); + if (aal5) put_dma(tx->index,eni_dev->dma,&j,paddr,skb->len); + else put_dma(tx->index,eni_dev->dma,&j,paddr+4,skb->len-4); else { -DPRINTK("doing direct send\n"); +DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */ for (i = 0; i < ATM_SKB(skb)->iovcnt; i++) put_dma(tx->index,eni_dev->dma,&j,(unsigned long) ((struct iovec *) skb->data)[i].iov_base, ((struct iovec *) skb->data)[i].iov_len); } if (skb->len & 3) - put_dma(tx->index,eni_dev->dma,&j, - (unsigned long) zeroes,4-(skb->len & 3)); + put_dma(tx->index,eni_dev->dma,&j,zeroes,4-(skb->len & 3)); /* JK for AAL5 trailer - AAL0 doesn't need it, but who cares ... */ eni_dev->dma[j++] = (((tx->tx_pos+size) & (tx->words-1)) << MID_DMA_COUNT_SHIFT) | (tx->index << MID_DMA_CHAN_SHIFT) | @@ -1188,8 +1203,10 @@ static void dequeue_tx(struct atm_dev *dev) break; } ENI_VCC(vcc)->txing -= ENI_PRV_SIZE(skb); + pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len, + PCI_DMA_TODEVICE); if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); + else dev_kfree_skb_irq(skb); vcc->stats->tx++; wake_up(&eni_dev->tx_wait); dma_complete++; @@ -1670,7 +1687,7 @@ static int __init eni_init(struct atm_dev *dev) (eni_dev->asic ? PCI_COMMAND_PARITY | PCI_COMMAND_SERR : 0)))) { printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory " "(0x%02x)\n",dev->number,error); - return error; + return -EIO; } printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%lx,irq=%d,", dev->number,revision,real_base,eni_dev->irq); @@ -2020,7 +2037,6 @@ static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb) if (!skb) { printk(KERN_CRIT "!skb in eni_send ?\n"); if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); return -EINVAL; } if (vcc->qos.aal == ATM_AAL0) { @@ -2195,7 +2211,14 @@ int __init eni_detect(void) struct atm_dev *dev; struct eni_dev *eni_dev; int devs,type; + struct sk_buff *skb; + DPRINTK("eni_detect\n"); + if (sizeof(skb->cb) < sizeof(struct eni_skb_prv)) { + printk(KERN_ERR "eni_detect: skb->cb is too small (%d < %d)\n", + sizeof(skb->cb),sizeof(struct eni_skb_prv)); + return 0; + } eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev), GFP_KERNEL); if (!eni_dev) return -ENOMEM; @@ -2208,8 +2231,9 @@ int __init eni_detect(void) PCI_DEVICE_ID_EF_ATM_ASIC : PCI_DEVICE_ID_EF_ATM_FPGA, pci_dev))) { if (!devs) { - zeroes = kmalloc(4,GFP_KERNEL); - if (!zeroes) { + cpu_zeroes = pci_alloc_consistent(pci_dev, + ENI_ZEROES_SIZE,&zeroes); + if (!cpu_zeroes) { kfree(eni_dev); return -ENOMEM; } @@ -2231,11 +2255,12 @@ int __init eni_detect(void) if (!eni_dev) break; } } - kfree(eni_dev); - if (!devs && zeroes) { - kfree(zeroes); - zeroes = NULL; + if (!devs && cpu_zeroes) { + pci_free_consistent(eni_dev->pci_dev,ENI_ZEROES_SIZE, + cpu_zeroes,zeroes); + cpu_zeroes = NULL; } + kfree(eni_dev); return devs; } diff --git a/drivers/atm/eni.h b/drivers/atm/eni.h index ca1749f59..76d0dd482 100644 --- a/drivers/atm/eni.h +++ b/drivers/atm/eni.h @@ -27,6 +27,8 @@ #define DEFAULT_RX_MULT 300 /* max_sdu*3 */ #define DEFAULT_TX_MULT 300 /* max_sdu*3 */ +#define ENI_ZEROES_SIZE 4 /* need that many DMA-able zero bytes */ + struct eni_free { unsigned long start; /* counting in bytes */ @@ -113,9 +115,11 @@ struct eni_skb_prv { struct atm_skb_data _; /* reserved */ unsigned long pos; /* position of next descriptor */ int size; /* PDU size in reassembly buffer */ + dma_addr_t paddr; /* DMA handle */ }; #define ENI_PRV_SIZE(skb) (((struct eni_skb_prv *) (skb)->cb)->size) #define ENI_PRV_POS(skb) (((struct eni_skb_prv *) (skb)->cb)->pos) +#define ENI_PRV_PADDR(skb) (((struct eni_skb_prv *) (skb)->cb)->paddr) #endif diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c new file mode 100644 index 000000000..4c07f2e7f --- /dev/null +++ b/drivers/atm/fore200e.c @@ -0,0 +1,2973 @@ +/* + $Id: fore200e.c,v 1.1 2000/02/21 16:04:31 davem Exp $ + + A FORE Systems 200E-series driver for ATM on Linux. + Christophe Lizzi (lizzi@cnam.fr), October 1999-February 2000. + + Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de). + + This driver simultaneously supports PCA-200E and SBA-200E adapters + on i386, alpha (untested), powerpc, sparc and sparc64 architectures. + + 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/version.h> +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/malloc.h> +#include <linux/init.h> +#include <linux/capability.h> +#include <linux/sched.h> +#include <linux/atmdev.h> +#include <linux/sonet.h> +#include <linux/atm_suni.h> +#include <asm/io.h> +#include <asm/string.h> +#include <asm/segment.h> +#include <asm/page.h> +#include <asm/irq.h> +#include <asm/dma.h> +#include <asm/byteorder.h> +#include <asm/uaccess.h> + +#ifdef CONFIG_ATM_FORE200E_PCA +#include <linux/pci.h> +#endif + +#ifdef CONFIG_ATM_FORE200E_SBA +#include <asm/idprom.h> +#include <asm/sbus.h> +#include <asm/openprom.h> +#include <asm/oplib.h> +#include <asm/pgtable.h> +#endif + +#ifdef MODULE +#include <linux/module.h> +#endif + +#include "fore200e.h" +#include "suni.h" + +#if 1 /* ensure correct handling of 52-byte AAL0 SDUs used by atmdump-like apps */ +#define FORE200E_52BYTE_AAL0_SDU +#endif + +#define FORE200E_VERSION "0.2a" + + +#define FORE200E "fore200e: " + +#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0) +#define DPRINTK(level, format, args...) do { if (CONFIG_ATM_FORE200E_DEBUG >= (level)) \ + printk(FORE200E format, ##args); } while(0) +#else +#define DPRINTK(level, format, args...) while(0) +#endif + + +#define FORE200E_ALIGN(addr, alignment) \ + ((((unsigned long)(addr) + (alignment - 1)) & ~(alignment - 1)) - (unsigned long)(addr)) + +#define FORE200E_DMA_INDEX(dma_addr, type, index) ((dma_addr) + (index) * sizeof(type)) + +#define FORE200E_INDEX(virt_addr, type, index) (&((type *)(virt_addr))[ index ]) + +#define FORE200E_NEXT_ENTRY(index, modulo) (index = ++(index) % (modulo)) + + +#define MSECS(ms) (((ms)*HZ/1000)+1) + + +extern const struct atmdev_ops fore200e_ops; +extern const struct fore200e_bus fore200e_bus[]; + +static struct fore200e* fore200e_boards = NULL; + + +#ifdef MODULE +MODULE_AUTHOR("Christophe Lizzi - credits to Uwe Dannowski and Heikki Vatiainen"); +MODULE_DESCRIPTION("FORE Systems 200E-series ATM driver - version " FORE200E_VERSION); +MODULE_SUPPORTED_DEVICE("PCA-200E, SBA-200E"); +#endif + + +static const int fore200e_rx_buf_nbr[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = { + { BUFFER_S1_NBR, BUFFER_L1_NBR }, + { BUFFER_S2_NBR, BUFFER_L2_NBR } +}; + +static const int fore200e_rx_buf_size[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = { + { BUFFER_S1_SIZE, BUFFER_L1_SIZE }, + { BUFFER_S2_SIZE, BUFFER_L2_SIZE } +}; + + +#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0) +static const char* fore200e_traffic_class[] = { "NONE", "UBR", "CBR", "VBR", "ABR", "ANY" }; +#endif + + +#if 0 /* currently unused */ +static int +fore200e_fore2atm_aal(enum fore200e_aal aal) +{ + switch(aal) { + case FORE200E_AAL0: return ATM_AAL0; + case FORE200E_AAL34: return ATM_AAL34; + case FORE200E_AAL5: return ATM_AAL5; + } + + return -EINVAL; +} +#endif + + +static enum fore200e_aal +fore200e_atm2fore_aal(int aal) +{ + switch(aal) { + case ATM_AAL0: return FORE200E_AAL0; + case ATM_AAL34: return FORE200E_AAL34; + case ATM_AAL1: + case ATM_AAL2: + case ATM_AAL5: return FORE200E_AAL5; + } + + return -EINVAL; +} + + +static char* +fore200e_irq_itoa(int irq) +{ +#if defined(__sparc_v9__) + return __irq_itoa(irq); +#else + static char str[8]; + sprintf(str, "%d", irq); + return str; +#endif +} + + +static void* +fore200e_kmalloc(int size, int flags) +{ + void* chunk = kmalloc(size, flags); + + if (chunk) + memset(chunk, 0x00, size); + else + printk(FORE200E "kmalloc() failed, requested size = %d, flags = 0x%x\n", size, flags); + + return chunk; +} + + +static void +fore200e_kfree(void* chunk) +{ + kfree(chunk); +} + + +/* allocate and align a chunk of memory intended to hold the data behing exchanged + between the driver and the adapter (using streaming DVMA on SBUS hosts) */ + +static int +fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int alignment) +{ + unsigned long offset = 0; + + if (alignment <= sizeof(int)) + alignment = 0; + + chunk->alloc_size = size + alignment; + chunk->align_size = size; + + chunk->alloc_addr = fore200e_kmalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA); + if (chunk->alloc_addr == NULL) + return -ENOMEM; + + if (alignment > 0) + offset = FORE200E_ALIGN(chunk->alloc_addr, alignment); + + chunk->align_addr = chunk->alloc_addr + offset; + + chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, chunk->align_size); + + return 0; +} + + +/* free a chunk of memory */ + +static void +fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk) +{ + fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size); + + fore200e_kfree(chunk->alloc_addr); +} + + + +#if 0 /* currently unused */ +static int +fore200e_checkup(struct fore200e* fore200e) +{ + u32 hb1, hb2; + + hb1 = fore200e->bus->read(&fore200e->cp_queues->heartbeat); + fore200e_spin(10); + hb2 = fore200e->bus->read(&fore200e->cp_queues->heartbeat); + + if (hb2 <= hb1) { + printk(FORE200E "device %s heartbeat is not counting upwards, hb1 = %x; hb2 = %x\n", + fore200e->name, hb1, hb2); + return -EIO; + } + printk(FORE200E "device %s heartbeat is ok\n", fore200e->name); + + return 0; +} +#endif + + +static void +fore200e_spin(int msecs) +{ + unsigned long timeout = jiffies + MSECS(msecs); + while (jiffies < timeout); +} + + +static int +fore200e_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs) +{ + unsigned long timeout = jiffies + MSECS(msecs); + int ok; + + mb(); + do { + if ((ok = (*addr == val)) || (*addr & STATUS_ERROR)) + break; + + } while (jiffies < timeout); + +#if 1 + if (!ok) { + printk(FORE200E "cmd polling failed, got status 0x%08x, expected 0x%08x\n", + *addr, val); + } +#endif + + return ok; +} + + +static int +fore200e_io_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs) +{ + unsigned long timeout = jiffies + MSECS(msecs); + int ok; + + do { + if ((ok = (fore200e->bus->read(addr) == val))) + break; + + } while (jiffies < timeout); + +#if 1 + if (!ok) { + printk(FORE200E "I/O polling failed, got status 0x%08x, expected 0x%08x\n", + fore200e->bus->read(addr), val); + } +#endif + + return ok; +} + + +static void +fore200e_free_rx_buf(struct fore200e* fore200e) +{ + int scheme, magn, nbr; + struct buffer* buffer; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + if ((buffer = fore200e->host_bsq[ scheme ][ magn ].buffer) != NULL) { + + for (nbr = 0; nbr < fore200e_rx_buf_nbr[ scheme ][ magn ]; nbr++) { + + struct chunk* data = &buffer[ nbr ].data; + + if (data->alloc_addr != NULL) + fore200e_chunk_free(fore200e, data); + } + } + } + } +} + + +static void +fore200e_uninit_bs_queue(struct fore200e* fore200e) +{ + int scheme, magn; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + struct chunk* status = &fore200e->host_bsq[ scheme ][ magn ].status; + struct chunk* rbd_block = &fore200e->host_bsq[ scheme ][ magn ].rbd_block; + + if (status->alloc_addr) + fore200e->bus->dma_chunk_free(fore200e, status); + + if (rbd_block->alloc_addr) + fore200e->bus->dma_chunk_free(fore200e, rbd_block); + } + } +} + + +static int +fore200e_reset(struct fore200e* fore200e, int diag) +{ + int ok; + + fore200e->cp_monitor = (struct cp_monitor*)(fore200e->virt_base + FORE200E_CP_MONITOR_OFFSET); + + fore200e->bus->write(BSTAT_COLD_START, &fore200e->cp_monitor->bstat); + + fore200e->bus->reset(fore200e); + + if (diag) { + ok = fore200e_io_poll(fore200e, &fore200e->cp_monitor->bstat, BSTAT_SELFTEST_OK, 1000); + if (ok == 0) { + + printk(FORE200E "device %s self-test failed\n", fore200e->name); + return -ENODEV; + } + + printk(FORE200E "device %s self-test passed\n", fore200e->name); + + fore200e->state = FORE200E_STATE_RESET; + } + + return 0; +} + + +static void +fore200e_shutdown(struct fore200e* fore200e) +{ + printk(FORE200E "removing device %s at 0x%lx, IRQ %s\n", + fore200e->name, fore200e->phys_base, + fore200e_irq_itoa(fore200e->irq)); + + if (fore200e->state > FORE200E_STATE_RESET) { + /* first, reset the board to prevent further interrupts or data transfers */ + fore200e_reset(fore200e, 0); + } + + /* then, release all allocated resources */ + switch(fore200e->state) { + + case FORE200E_STATE_COMPLETE: + if (fore200e->stats) + kfree(fore200e->stats); + + case FORE200E_STATE_IRQ: + free_irq(fore200e->irq, fore200e->atm_dev); + + case FORE200E_STATE_ALLOC_BUF: + fore200e_free_rx_buf(fore200e); + + case FORE200E_STATE_INIT_BSQ: + fore200e_uninit_bs_queue(fore200e); + + case FORE200E_STATE_INIT_RXQ: + fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_rxq.status); + fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_rxq.rpd); + + case FORE200E_STATE_INIT_TXQ: + fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_txq.status); + fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_txq.tpd); + + case FORE200E_STATE_INIT_CMDQ: + fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_cmdq.status); + + case FORE200E_STATE_INITIALIZE: + /* nothing to do for that state */ + + case FORE200E_STATE_START_FW: + /* nothing to do for that state */ + + case FORE200E_STATE_LOAD_FW: + /* nothing to do for that state */ + + case FORE200E_STATE_RESET: + /* nothing to do for that state */ + + case FORE200E_STATE_MAP: + fore200e->bus->unmap(fore200e); + + case FORE200E_STATE_CONFIGURE: + /* nothing to do for that state */ + + case FORE200E_STATE_REGISTER: + /* XXX shouldn't we *start* by deregistering the device? */ + atm_dev_deregister(fore200e->atm_dev); + + case FORE200E_STATE_BLANK: + /* nothing to do for that state */ + } +} + + +#ifdef CONFIG_ATM_FORE200E_PCA + +static u32 fore200e_pca_read(volatile u32* addr) +{ + /* on big-endian hosts, the board is configured to convert + the endianess of slave RAM accesses */ + return le32_to_cpu(readl(addr)); +} + + +static void fore200e_pca_write(u32 val, volatile u32* addr) +{ + /* on big-endian hosts, the board is configured to convert + the endianess of slave RAM accesses */ + writel(cpu_to_le32(val), addr); +} + + +static u32 +fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size) +{ + u32 dma_addr = pci_map_single((struct pci_dev*)fore200e->bus_dev, virt_addr, size, PCI_DMA_BIDIRECTIONAL); + + DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n", + virt_addr, size, dma_addr); + + return dma_addr; +} + + +static void +fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size) +{ + DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + + pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, + PCI_DMA_BIDIRECTIONAL); +} + + +static void +fore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size) +{ + DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + + pci_dma_sync_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, + PCI_DMA_BIDIRECTIONAL); +} + + +/* allocate a DMA consistent chunk of memory intended to act as a communication mechanism + (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */ + +static int +fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment) +{ +#if defined(__sparc_v9__) + /* returned chunks are page-aligned */ + chunk->alloc_addr = pci_alloc_consistent((struct pci_dev*)fore200e->bus_dev, + chunk->alloc_size, + &chunk->dma_addr); + + if (chunk->alloc_addr == NULL || chunk->dma_addr == 0) + return -ENOMEM; + + chunk->align_addr = chunk->alloc_addr; +#else + if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment) < 0) + return -ENOMEM; + + chunk->dma_addr = fore200e_pca_dma_map(fore200e, chunk->align_addr, chunk->align_size); +#endif + + return 0; +} + + +/* free a DMA consistent chunk of memory */ + +static void +fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk) +{ +#if defined(__sparc_v9__) + pci_free_consistent((struct pci_dev*)fore200e->bus_dev, + chunk->alloc_size, + chunk->alloc_addr, + chunk->dma_addr); +#else + fore200e_pca_dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size); + + fore200e_chunk_free(fore200e, chunk); +#endif +} + + +static int +fore200e_pca_irq_check(struct fore200e* fore200e) +{ + /* this is a 1 bit register */ + return readl(fore200e->regs.pca.psr); +} + + +static void +fore200e_pca_irq_ack(struct fore200e* fore200e) +{ + writel(PCA200E_HCR_CLRINTR, fore200e->regs.pca.hcr); +} + + +static void +fore200e_pca_reset(struct fore200e* fore200e) +{ + writel(PCA200E_HCR_RESET, fore200e->regs.pca.hcr); + fore200e_spin(10); + writel(0, fore200e->regs.pca.hcr); +} + + +static int __init +fore200e_pca_map(struct fore200e* fore200e) +{ + DPRINTK(2, "device %s being mapped in memory\n", fore200e->name); + + fore200e->virt_base = ioremap(fore200e->phys_base, PCA200E_IOSPACE_LENGTH); + + if (fore200e->virt_base == NULL) { + printk(FORE200E "can't map device %s\n", fore200e->name); + return -EFAULT; + } + + DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); + + /* gain access to the PCA-200E specific registers */ + fore200e->regs.pca.hcr = (u32*)(fore200e->virt_base + PCA200E_HCR_OFFSET); + fore200e->regs.pca.imr = (u32*)(fore200e->virt_base + PCA200E_IMR_OFFSET); + fore200e->regs.pca.psr = (u32*)(fore200e->virt_base + PCA200E_PSR_OFFSET); + + fore200e->state = FORE200E_STATE_MAP; + return 0; +} + + +static void +fore200e_pca_unmap(struct fore200e* fore200e) +{ + DPRINTK(2, "device %s being unmapped from memory\n", fore200e->name); + + /* XXX iounmap() does nothing on PowerPC (at least in 2.2.12 and 2.3.41), + this leads to a kernel panic if the module is loaded and unloaded several times */ + if (fore200e->virt_base != NULL) + iounmap(fore200e->virt_base); +} + + +static int __init +fore200e_pca_configure(struct fore200e* fore200e) +{ + struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev; + u8 master_ctrl; + + DPRINTK(2, "device %s being configured\n", fore200e->name); + + if ((pci_dev->irq == 0) || (pci_dev->irq == 0xFF)) { + printk(FORE200E "incorrect IRQ setting - misconfigured PCI-PCI bridge?\n"); + return -EIO; + } + + pci_read_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, &master_ctrl); + + master_ctrl = master_ctrl +#if 0 + | PCA200E_CTRL_DIS_CACHE_RD + | PCA200E_CTRL_DIS_WRT_INVAL +#endif +#if defined(__BIG_ENDIAN) + /* request the PCA board to convert the endianess of slave RAM accesses */ + | PCA200E_CTRL_CONVERT_ENDIAN +#endif + | PCA200E_CTRL_LARGE_PCI_BURSTS; + + pci_write_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, master_ctrl); + + fore200e->state = FORE200E_STATE_CONFIGURE; + return 0; +} + + +static struct fore200e* __init +fore200e_pca_detect(const struct fore200e_bus* bus, int index) +{ + struct fore200e* fore200e; + struct pci_dev* pci_dev = NULL; + int count = index; + + if (pci_present() == 0) { + printk(FORE200E "no PCI subsystem\n"); + return NULL; + } + + do { + pci_dev = pci_find_device(PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, pci_dev); + if (pci_dev == NULL) + return NULL; + } while (count--); + + fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL); + if (fore200e == NULL) + return NULL; + + fore200e->bus = bus; + fore200e->bus_dev = pci_dev; + fore200e->irq = pci_dev->irq; + fore200e->phys_base = (pci_dev->resource[0].start & PCI_BASE_ADDRESS_MEM_MASK); + +#if defined(__powerpc__) + fore200e->phys_base += KERNELBASE; +#endif + + sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); + + pci_set_master(pci_dev); + + return fore200e; +} + + +static int __init +fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct prom_opcode opcode; + int ok; + u32 prom_dma; + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_GET_PROM; + opcode.pad = 0; + + prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data)); + + fore200e->bus->write(prom_dma, &entry->cp_entry->cmd.prom_block.prom_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.prom_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data)); + + if (ok == 0) { + printk(FORE200E "unable to get PROM data from device %s\n", fore200e->name); + return -EIO; + } + +#if defined(__BIG_ENDIAN) + +#define swap_here(addr) (*((u32*)(addr)) = swab32( *((u32*)(addr)) )) + + /* MAC address is stored as little-endian */ + swap_here(&prom->mac_addr[0]); + swap_here(&prom->mac_addr[4]); +#endif + + return 0; +} + + +static int +fore200e_pca_proc_read(struct fore200e* fore200e, char *page) +{ + struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev; + + return sprintf(page, " PCI bus/slot/function:\t%d/%d/%d\n", + pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); +} + +#endif /* CONFIG_ATM_FORE200E_PCA */ + + + + +#ifdef CONFIG_ATM_FORE200E_SBA + +static u32 +fore200e_sba_read(volatile u32* addr) +{ + return sbus_readl(addr); +} + + +static void +fore200e_sba_write(u32 val, volatile u32* addr) +{ + sbus_writel(val, addr); +} + + +static u32 +fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size) +{ + u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size); + + DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n", virt_addr, size, dma_addr); + + return dma_addr; +} + + +static void +fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size) +{ + DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + + sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size); +} + + +static void +fore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size) +{ + DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + + sbus_dma_sync_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size); +} + + +/* allocate a DVMA consistent chunk of memory intended to act as a communication mechanism + (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */ + +static int +fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment) +{ + chunk->alloc_size = chunk->align_size = size * nbr; + + /* returned chunks are page-aligned */ + chunk->alloc_addr = sbus_alloc_consistent((struct sbus_dev*)fore200e->bus_dev, + chunk->alloc_size, + &chunk->dma_addr); + + if (chunk->alloc_addr == NULL || chunk->dma_addr == 0) + return -ENOMEM; + + chunk->align_addr = chunk->alloc_addr; + + return 0; +} + + +/* free a DVMA consistent chunk of memory */ + +static void +fore200e_sba_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk) +{ + sbus_free_consistent((struct sbus_dev*)fore200e->bus_dev, + chunk->alloc_size, + chunk->alloc_addr, + chunk->dma_addr); +} + + +static void +fore200e_sba_irq_enable(struct fore200e* fore200e) +{ + u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; + fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr); +} + + +static int +fore200e_sba_irq_check(struct fore200e* fore200e) +{ + return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ; +} + + +static void +fore200e_sba_irq_ack(struct fore200e* fore200e) +{ + u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; + fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr); +} + + +static void +fore200e_sba_reset(struct fore200e* fore200e) +{ + fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr); + fore200e_spin(10); + fore200e->bus->write(0, fore200e->regs.sba.hcr); +} + + +static int __init +fore200e_sba_map(struct fore200e* fore200e) +{ + struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev; + unsigned int bursts; + + /* gain access to the SBA-200E specific registers */ + + fore200e->regs.sba.hcr = (u32*)sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR"); + fore200e->regs.sba.bsr = (u32*)sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR"); + fore200e->regs.sba.isr = (u32*)sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR"); + fore200e->virt_base = (u32*)sbus_ioremap(&sbus_dev->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM"); + + if (fore200e->virt_base == NULL) { + printk(FORE200E "unable to map RAM of device %s\n", fore200e->name); + return -EFAULT; + } + + DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); + + fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */ + + /* get the supported DVMA burst sizes */ + bursts = prom_getintdefault(sbus_dev->bus->prom_node, "burst-sizes", 0x00); + + if (sbus_can_dma_64bit(sbus_dev)) + sbus_set_sbus64(sbus_dev, bursts); + +#if 0 + if (bursts & DMA_BURST16) + fore200e->bus->write(SBA200E_BSR_BURST16, fore200e->regs.sba.bsr); + else + if (bursts & DMA_BURST8) + fore200e->bus->write(SBA200E_BSR_BURST8, fore200e->regs.sba.bsr); + else + if (bursts & DMA_BURST4) + fore200e->bus->write(SBA200E_BSR_BURST4, fore200e->regs.sba.bsr); +#endif + + fore200e->state = FORE200E_STATE_MAP; + return 0; +} + + +static void +fore200e_sba_unmap(struct fore200e* fore200e) +{ + sbus_iounmap((ulong)fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH); + sbus_iounmap((ulong)fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH); + sbus_iounmap((ulong)fore200e->regs.sba.isr, SBA200E_ISR_LENGTH); + sbus_iounmap((ulong)fore200e->virt_base, SBA200E_RAM_LENGTH); +} + + +static int __init +fore200e_sba_configure(struct fore200e* fore200e) +{ + fore200e->state = FORE200E_STATE_CONFIGURE; + return 0; +} + + +static struct fore200e* __init +fore200e_sba_detect(const struct fore200e_bus* bus, int index) +{ + struct fore200e* fore200e; + struct sbus_bus* sbus_bus; + struct sbus_dev* sbus_dev = NULL; + + unsigned int count = 0; + + for_each_sbus (sbus_bus) { + for_each_sbusdev (sbus_dev, sbus_bus) { + if (strcmp(sbus_dev->prom_name, SBA200E_PROM_NAME) == 0) { + if (count >= index) + goto found; + count++; + } + } + } + return NULL; + + found: +#if 1 + if (sbus_dev->num_registers != 4) { + printk(FORE200E "this %s device has %d instead of 4 registers\n", + bus->model_name, sbus_dev->num_registers); + return NULL; + } +#endif + + fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL); + if (fore200e == NULL) + return NULL; + + fore200e->bus = bus; + fore200e->bus_dev = sbus_dev; + fore200e->irq = sbus_dev->irqs[ 0 ]; + + fore200e->phys_base = (unsigned long)sbus_dev; + + sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); + + return fore200e; +} + + +static int __init +fore200e_sba_prom_read(struct fore200e* fore200e, struct prom_data* prom) +{ + struct sbus_dev* sbus_dev = (struct sbus_dev*) fore200e->bus_dev; + int len; + + len = prom_getproperty(sbus_dev->prom_node, "macaddrlo2", &prom->mac_addr[ 4 ], 4); + if (len < 0) + return -EBUSY; + + len = prom_getproperty(sbus_dev->prom_node, "macaddrhi4", &prom->mac_addr[ 2 ], 4); + if (len < 0) + return -EBUSY; + + prom_getproperty(sbus_dev->prom_node, "serialnumber", + (char*)&prom->serial_number, sizeof(prom->serial_number)); + + prom_getproperty(sbus_dev->prom_node, "promversion", + (char*)&prom->hw_revision, sizeof(prom->hw_revision)); + + return 0; +} + + +static int +fore200e_sba_proc_read(struct fore200e* fore200e, char *page) +{ + struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev; + + return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n", sbus_dev->slot, sbus_dev->prom_name); +} +#endif /* CONFIG_ATM_FORE200E_SBA */ + + +static void +fore200e_irq_tx(struct fore200e* fore200e) +{ + struct host_txq_entry* entry; + int i; + + entry = fore200e->host_txq.host_entry; + + for (i = 0; i < QUEUE_SIZE_TX; i++) { + + if (*entry->status & STATUS_COMPLETE) { + + DPRINTK(3, "TX COMPLETED: entry = %p, vcc = %p, skb = %p\n", entry, entry->vcc, entry->skb); + + /* free copy of misaligned data */ + if (entry->data) + kfree(entry->data); + + /* remove DMA mapping */ + fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length); + + /* notify tx completion */ + if (entry->vcc->pop) + entry->vcc->pop(entry->vcc, entry->skb); + else + dev_kfree_skb_irq(entry->skb); + + /* check error condition */ + if (*entry->status & STATUS_ERROR) + entry->vcc->stats->tx_err++; + else + entry->vcc->stats->tx++; + + *entry->status = STATUS_FREE; + + fore200e->host_txq.txing--; + } + entry++; + } +} + + +static void +fore200e_supply(struct fore200e* fore200e) +{ + int scheme, magn, i; + + struct host_bsq* bsq; + struct host_bsq_entry* entry; + struct buffer* buffer; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + bsq = &fore200e->host_bsq[ scheme ][ magn ]; + + if (fore200e_rx_buf_nbr[ scheme ][ magn ] - bsq->count > RBD_BLK_SIZE) { + + DPRINTK(2, "supplying rx buffers to queue %d / %d, count = %d\n", + scheme, magn, bsq->count); + + entry = &bsq->host_entry[ bsq->head ]; + + FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS); + + for (i = 0; i < RBD_BLK_SIZE; i++) { + + buffer = &bsq->buffer[ bsq->free ]; + + FORE200E_NEXT_ENTRY(bsq->free, fore200e_rx_buf_nbr[ scheme ][ magn ]); + + entry->rbd_block->rbd[ i ].buffer_haddr = buffer->data.dma_addr; + entry->rbd_block->rbd[ i ].handle = FORE200E_BUF2HDL(buffer); + } + + /* increase the number of supplied rx buffers */ + bsq->count += RBD_BLK_SIZE; + + *entry->status = STATUS_PENDING; + fore200e->bus->write(entry->rbd_block_dma, &entry->cp_entry->rbd_block_haddr); + } + } + } +} + + + +static struct atm_vcc* +fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd) +{ + struct atm_vcc* vcc; + + for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) { + + if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci) + break; + } + + return vcc; +} + + +static void +fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd) +{ + struct atm_vcc* vcc; + struct sk_buff* skb; + struct buffer* buffer; + struct fore200e_vcc* fore200e_vcc; + int i, pdu_len = 0; +#ifdef FORE200E_52BYTE_AAL0_SDU + u32 cell_header = 0; +#endif + + vcc = fore200e_find_vcc(fore200e, rpd); + if (vcc == NULL) { + + printk(FORE200E "no vcc found for PDU received on %d.%d.%d\n", + fore200e->atm_dev->number, rpd->atm_header.vpi, rpd->atm_header.vci); + return; + } + + fore200e_vcc = FORE200E_VCC(vcc); + +#ifdef FORE200E_52BYTE_AAL0_SDU + if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.rxtp.max_sdu == ATM_AAL0_SDU)) { + + cell_header = (rpd->atm_header.gfc << ATM_HDR_GFC_SHIFT) | + (rpd->atm_header.vpi << ATM_HDR_VPI_SHIFT) | + (rpd->atm_header.vci << ATM_HDR_VCI_SHIFT) | + (rpd->atm_header.plt << ATM_HDR_PTI_SHIFT) | + rpd->atm_header.clp; + pdu_len = 4; + } +#endif + + /* compute total PDU length */ + for (i = 0; i < rpd->nseg; i++) + pdu_len += rpd->rsd[ i ].length; + + skb = alloc_skb(pdu_len, GFP_ATOMIC); + if (skb == NULL) { + + printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len); + vcc->stats->rx_drop++; + return; + } + + skb->stamp = vcc->timestamp = xtime; + +#ifdef FORE200E_52BYTE_AAL0_SDU + if (cell_header) { + *((u32*)skb_put(skb, 4)) = cell_header; + } +#endif + + /* reassemble segments */ + for (i = 0; i < rpd->nseg; i++) { + + /* rebuild rx buffer address from rsd handle */ + buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); + + /* ensure DMA synchronisation */ + fore200e->bus->dma_sync(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length); + + memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data.align_addr, rpd->rsd[ i ].length); + } + + DPRINTK(3, "rx skb: len = %d, truesize = %d\n", skb->len, skb->truesize); + + if (pdu_len < fore200e_vcc->rx_min_pdu) + fore200e_vcc->rx_min_pdu = pdu_len; + if (pdu_len > fore200e_vcc->rx_max_pdu) + fore200e_vcc->rx_max_pdu = pdu_len; + + /* push PDU */ + if (atm_charge(vcc, skb->truesize) == 0) { + + DPRINTK(2, "receive buffers saturated for %d.%d.%d - PDU dropped\n", + vcc->itf, vcc->vpi, vcc->vci); + + dev_kfree_skb_irq(skb); + return; + } + + vcc->push(vcc, skb); + vcc->stats->rx++; +} + + +static void +fore200e_collect_rpd(struct fore200e* fore200e, struct rpd* rpd) +{ + struct buffer* buffer; + int i; + + for (i = 0; i < rpd->nseg; i++) { + + /* rebuild rx buffer address from rsd handle */ + buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); + + /* decrease the number of supplied rx buffers */ + fore200e->host_bsq[ buffer->scheme ][ buffer->magn ].count--; + } +} + + +static void +fore200e_irq_rx(struct fore200e* fore200e) +{ + struct host_rxq* rxq = &fore200e->host_rxq; + struct host_rxq_entry* entry; + + for (;;) { + + entry = &rxq->host_entry[ rxq->head ]; + + /* no more received PDUs */ + if ((*entry->status & STATUS_COMPLETE) == 0) + break; + + FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX); + + if ((*entry->status & STATUS_ERROR) == 0) { + + fore200e_push_rpd(fore200e, entry->rpd); + } + else { + printk(FORE200E "damaged PDU on %d.%d.%d\n", + fore200e->atm_dev->number, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci); + } + + fore200e_collect_rpd(fore200e, entry->rpd); + + fore200e_supply(fore200e); + + /* rewrite the rpd address to ack the received PDU */ + fore200e->bus->write(entry->rpd_dma, &entry->cp_entry->rpd_haddr); + *entry->status = STATUS_FREE; + } +} + + +static void +fore200e_interrupt(int irq, void* dev, struct pt_regs* regs) +{ + struct fore200e* fore200e = FORE200E_DEV((struct atm_dev*)dev); + + if (fore200e->bus->irq_check(fore200e) == 0) { + + DPRINTK(3, "unexpected interrupt on device %c\n", fore200e->name[9]); + return; + } + DPRINTK(3, "valid interrupt on device %c\n", fore200e->name[9]); + + fore200e_irq_rx(fore200e); + + if (fore200e->host_txq.txing) + fore200e_irq_tx(fore200e); + + fore200e->bus->irq_ack(fore200e); +} + + +static int +fore200e_select_scheme(struct atm_vcc* vcc) +{ + int scheme; + +#if 1 + /* fairly balance VCs over (identical) buffer schemes */ + scheme = vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO; +#else + /* bit 7 of VPI magically selects the second buffer scheme */ + if (vcc->vpi & (1<<7)) { + vcc->vpi &= ((1<<7) - 1); /* reset the magic bit */ + scheme = BUFFER_SCHEME_TWO; + } + else { + scheme = BUFFER_SCHEME_ONE; + } +#endif + + DPRINTK(1, "vpvc %d.%d.%d uses the %s buffer scheme\n", + vcc->itf, vcc->vpi, vcc->vci, scheme == BUFFER_SCHEME_ONE ? "first" : "second"); + + return scheme; +} + + + +static int +fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* vcc, int mtu) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct activate_opcode activ_opcode; + struct deactivate_opcode deactiv_opcode; + struct vpvc vpvc; + int ok; + enum fore200e_aal aal = fore200e_atm2fore_aal(vcc->qos.aal); + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + if (activate) { + FORE200E_VCC(vcc)->scheme = fore200e_select_scheme(vcc); + + activ_opcode.opcode = OPCODE_ACTIVATE_VCIN; + activ_opcode.aal = aal; + activ_opcode.scheme = FORE200E_VCC(vcc)->scheme; + activ_opcode.pad = 0; + } + else { + deactiv_opcode.opcode = OPCODE_DEACTIVATE_VCIN; + deactiv_opcode.pad = 0; + } + + vpvc.vci = vcc->vci; + vpvc.vpi = vcc->vpi; + + *entry->status = STATUS_PENDING; + + if (activate) { + +#ifdef FORE200E_52BYTE_AAL0_SDU + mtu = 48; +#endif + /* the MTU is unused by the cp, except in the case of AAL0 */ + fore200e->bus->write(mtu, &entry->cp_entry->cmd.activate_block.mtu); + fore200e->bus->write(*(u32*)&vpvc, (u32*)&entry->cp_entry->cmd.activate_block.vpvc); + fore200e->bus->write(*(u32*)&activ_opcode, (u32*)&entry->cp_entry->cmd.activate_block.opcode); + } + else { + fore200e->bus->write(*(u32*)&vpvc, (u32*)&entry->cp_entry->cmd.deactivate_block.vpvc); + fore200e->bus->write(*(u32*)&deactiv_opcode, (u32*)&entry->cp_entry->cmd.deactivate_block.opcode); + } + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + if (ok == 0) { + printk(FORE200E "unable to %s vpvc %d.%d on device %s\n", + activate ? "open" : "close", vcc->vpi, vcc->vci, fore200e->name); + return -EIO; + } + + DPRINTK(1, "vpvc %d.%d %sed on device %s\n", vcc->vpi, vcc->vci, + activate ? "open" : "clos", fore200e->name); + + return 0; +} + + +static int +fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci) +{ + struct atm_vcc* walk; + + /* find a free VPI */ + if (*vpi == ATM_VPI_ANY) { + + for (*vpi = 0, walk = vcc->dev->vccs; walk; walk = walk->next) { + + if ((walk->vci == *vci) && (walk->vpi == *vpi)) { + (*vpi)++; + walk = vcc->dev->vccs; + } + } + } + + /* find a free VCI */ + if (*vci == ATM_VCI_ANY) { + + for (*vci = ATM_NOT_RSV_VCI, walk = vcc->dev->vccs; walk; walk = walk->next) { + + if ((walk->vpi = *vpi) && (walk->vci == *vci)) { + *vci = walk->vci + 1; + walk = vcc->dev->vccs; + } + } + } + + return 0; +} + + +#define FORE200E_MAX_BACK2BACK_CELLS 255 /* XXX depends on CDVT */ + +static void +fore200e_rate_ctrl(struct atm_qos* qos, struct tpd_rate* rate) +{ + if (qos->txtp.max_pcr < ATM_OC3_PCR) { + + /* compute the data cells to idle cells ratio from the PCR */ + rate->data_cells = qos->txtp.max_pcr * FORE200E_MAX_BACK2BACK_CELLS / ATM_OC3_PCR; + rate->idle_cells = FORE200E_MAX_BACK2BACK_CELLS - rate->data_cells; + } + else { + /* disable rate control */ + rate->data_cells = rate->idle_cells = 0; + } +} + + +static int +fore200e_open(struct atm_vcc *vcc, short vpi, int vci) +{ + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + struct fore200e_vcc* fore200e_vcc; + + /* find a free VPI/VCI */ + fore200e_walk_vccs(vcc, &vpi, &vci); + + vcc->vpi = vpi; + vcc->vci = vci; + + /* ressource checking only? */ + if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) + return 0; + + vcc->flags |= ATM_VF_ADDR; + vcc->itf = vcc->dev->number; + + DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " + "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d)\n", + vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + fore200e_traffic_class[ vcc->qos.txtp.traffic_class ], + vcc->qos.txtp.min_pcr, vcc->qos.txtp.max_pcr, vcc->qos.txtp.max_cdv, vcc->qos.txtp.max_sdu, + fore200e_traffic_class[ vcc->qos.rxtp.traffic_class ], + vcc->qos.rxtp.min_pcr, vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_cdv, vcc->qos.rxtp.max_sdu); + + if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { + + down(&fore200e->rate_sf); + if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) { + up(&fore200e->rate_sf); + return -EAGAIN; + } + /* reserving the pseudo-CBR bandwidth at this point grants us + to reduce the length of the critical section protected + by 'rate_sf'. in counterpart, we have to reset the available + bandwidth if we later encounter an error */ + + fore200e->available_cell_rate -= vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + } + + fore200e_vcc = fore200e_kmalloc(sizeof(struct fore200e_vcc), GFP_KERNEL); + if (fore200e_vcc == NULL) { + down(&fore200e->rate_sf); + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + return -ENOMEM; + } + + FORE200E_VCC(vcc) = fore200e_vcc; + + if (fore200e_activate_vcin(fore200e, 1, vcc, vcc->qos.rxtp.max_sdu) < 0) { + kfree(fore200e_vcc); + down(&fore200e->rate_sf); + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + return -EBUSY; + } + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + /* compute rate control parameters */ + if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { + + fore200e_rate_ctrl(&vcc->qos, &fore200e_vcc->rate); + + DPRINTK(3, "tx on %d.%d.%d:%d, tx PCR = %d, rx PCR = %d, data_cells = %u, idle_cells = %u\n", + vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + vcc->qos.txtp.max_pcr, vcc->qos.rxtp.max_pcr, + fore200e_vcc->rate.data_cells, fore200e_vcc->rate.idle_cells); + } + + fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = 65536; + fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0; + + vcc->flags |= ATM_VF_READY; + return 0; +} + + + +static void +fore200e_close(struct atm_vcc* vcc) +{ + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "closing %d.%d.%d:%d\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal)); + + fore200e_activate_vcin(fore200e, 0, vcc, 0); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + + kfree(FORE200E_VCC(vcc)); + + if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { + down(&fore200e->rate_sf); + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + } +} + + +#if 0 +#define FORE200E_SYNC_SEND /* wait tx completion before returning */ +#endif + + +static int +fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); + struct host_txq* txq = &fore200e->host_txq; + struct host_txq_entry* entry; + struct tpd* tpd; + struct tpd_haddr tpd_haddr; + unsigned long flags; + int retry = CONFIG_ATM_FORE200E_TX_RETRY; + int tx_copy = 0; + int tx_len = skb->len; + u32* cell_header = NULL; + unsigned char* skb_data; + int skb_len; + +#ifdef FORE200E_52BYTE_AAL0_SDU + if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.txtp.max_sdu == ATM_AAL0_SDU)) { + cell_header = (u32*) skb->data; + skb_data = skb->data + 4; /* skip 4-byte cell header */ + skb_len = tx_len = skb->len - 4; + + DPRINTK(3, "skipping user-supplied cell header 0x%08x", *cell_header); + } + else +#endif + { + skb_data = skb->data; + skb_len = skb->len; + } + + retry_here: + + spin_lock_irqsave(&fore200e->tx_lock, flags); + + entry = &txq->host_entry[ txq->head ]; + + if (*entry->status != STATUS_FREE) { + + /* try to free completed tx queue entries */ + fore200e_irq_tx(fore200e); + + if (*entry->status != STATUS_FREE) { + + spin_unlock_irqrestore(&fore200e->tx_lock, flags); + + /* retry once again? */ + if(--retry > 0) + goto retry_here; + + vcc->stats->tx_err++; + + printk(FORE200E "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n", + fore200e->name, fore200e->cp_queues->heartbeat); + + return -EIO; + } + } + + tpd = entry->tpd; + + if (((unsigned long)skb_data) & 0x3) { + + DPRINTK(2, "misaligned tx PDU on device %s\n", fore200e->name); + tx_copy = 1; + tx_len = skb_len; + } + + if ((vcc->qos.aal == ATM_AAL0) && (skb_len % ATM_CELL_PAYLOAD)) { + + /* this simply NUKES the PCA-200E board */ + DPRINTK(2, "incomplete tx AAL0 PDU on device %s\n", fore200e->name); + tx_copy = 1; + tx_len = ((skb_len / ATM_CELL_PAYLOAD) + 1) * ATM_CELL_PAYLOAD; + } + + if (tx_copy) { + + entry->data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA); + if (entry->data == NULL) { + + spin_unlock_irqrestore(&fore200e->tx_lock, flags); + return -ENOMEM; + } + + memcpy(entry->data, skb_data, skb_len); + if (skb_len < tx_len) + memset(entry->data + skb_len, 0x00, tx_len - skb_len); + + tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len); + } + else { + entry->data = NULL; + tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len); + } + + tpd->tsd[ 0 ].length = tx_len; + + FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX); + txq->txing++; + + spin_unlock_irqrestore(&fore200e->tx_lock, flags); + + /* ensure DMA synchronisation */ + fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length); + + DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n", + vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + tpd->tsd[0].length, skb_len); + + if (skb_len < fore200e_vcc->tx_min_pdu) + fore200e_vcc->tx_min_pdu = skb_len; + if (skb_len > fore200e_vcc->tx_max_pdu) + fore200e_vcc->tx_max_pdu = skb_len; + + entry->vcc = vcc; + entry->skb = skb; + + /* set tx rate control information */ + tpd->rate.data_cells = fore200e_vcc->rate.data_cells; + tpd->rate.idle_cells = fore200e_vcc->rate.idle_cells; + + if (cell_header) { + tpd->atm_header.clp = (*cell_header & ATM_HDR_CLP); + tpd->atm_header.plt = (*cell_header & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; + tpd->atm_header.vci = (*cell_header & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT; + tpd->atm_header.vpi = (*cell_header & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT; + tpd->atm_header.gfc = (*cell_header & ATM_HDR_GFC_MASK) >> ATM_HDR_GFC_SHIFT; + } + else { + /* set the ATM header, common to all cells conveying the PDU */ + tpd->atm_header.clp = 0; + tpd->atm_header.plt = 0; + tpd->atm_header.vci = vcc->vci; + tpd->atm_header.vpi = vcc->vpi; + tpd->atm_header.gfc = 0; + } + + tpd->spec.length = tx_len; + tpd->spec.nseg = 1; + tpd->spec.aal = fore200e_atm2fore_aal(vcc->qos.aal); +#ifdef FORE200E_SYNC_SEND + tpd->spec.intr = 0; +#else + tpd->spec.intr = 1; +#endif + + tpd_haddr.size = sizeof(struct tpd) / 32; /* size is expressed in 32 byte blocks */ + tpd_haddr.pad = 0; + tpd_haddr.haddr = entry->tpd_dma >> 5; /* shift the address, as we are in a bitfield */ + + *entry->status = STATUS_PENDING; + fore200e->bus->write(*(u32*)&tpd_haddr, (u32*)&entry->cp_entry->tpd_haddr); + + +#ifdef FORE200E_SYNC_SEND + { + int ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 10); + + fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length); + + if (ok == 0) { + printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci); + + entry->vcc->stats->tx_err++; + return -EIO; + } + entry->vcc->stats->tx++; + + DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci); + + /* free tmp copy of misaligned data */ + if (entry->data) + kfree(entry->data); + + /* notify tx completion */ + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); + } +#endif + + return 0; +} + + +static int +fore200e_getstats(struct fore200e* fore200e) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct stats_opcode opcode; + int ok; + u32 stats_dma_addr; + + if (fore200e->stats == NULL) { + fore200e->stats = fore200e_kmalloc(sizeof(struct stats), GFP_KERNEL | GFP_DMA); + if (fore200e->stats == NULL) + return -ENOMEM; + } + + stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats)); + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_GET_STATS; + opcode.pad = 0; + + fore200e->bus->write(stats_dma_addr, &entry->cp_entry->cmd.stats_block.stats_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.stats_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats)); + + if (ok == 0) { + printk(FORE200E "unable to get statistics from device %s\n", fore200e->name); + return -EIO; + } + + return 0; +} + + +static int +fore200e_getsockopt (struct atm_vcc* vcc, int level, int optname, void* optval, int optlen) +{ + // struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "getsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n", + vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen); + + return -EINVAL; +} + + +static int +fore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void* optval, int optlen) +{ + // struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "setsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n", + vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen); + + return -EINVAL; +} + + +#if 0 /* currently unused */ +static int +fore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct oc3_opcode opcode; + int ok; + u32 oc3_regs_dma_addr; + + oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs)); + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_GET_OC3; + opcode.reg = 0; + opcode.value = 0; + opcode.mask = 0; + + fore200e->bus->write(oc3_regs_dma_addr, &entry->cp_entry->cmd.oc3_block.regs_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.oc3_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + fore200e->bus_dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs)); + + if (ok == 0) { + printk(FORE200E "unable to get OC-3 regs of device %s\n", fore200e->name); + return -EIO; + } + + return 0; +} +#endif + + +static int +fore200e_set_oc3(struct fore200e* fore200e, u32 reg, u32 value, u32 mask) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct oc3_opcode opcode; + int ok; + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_SET_OC3; + opcode.reg = reg; + opcode.value = value; + opcode.mask = mask; + + fore200e->bus->write(0, &entry->cp_entry->cmd.oc3_block.regs_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.oc3_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + if (ok == 0) { + printk(FORE200E "unable to set OC-3 reg 0x%02x of device %s\n", reg, fore200e->name); + return -EIO; + } + + return 0; +} + + +static int +fore200e_setloop(struct fore200e* fore200e, int loop_mode) +{ + u32 mct_value, mct_mask; + int error; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + switch (loop_mode) { + + case SUNI_LM_NONE: + mct_value = 0; + mct_mask = SUNI_MCT_DLE | SUNI_MCT_LLE; + break; + + case SUNI_LM_DIAG: + mct_value = mct_mask = SUNI_MCT_DLE; + break; + + case SUNI_LM_LOOP: + mct_value = mct_mask = SUNI_MCT_LLE; + break; + + default: + return -EINVAL; + } + + error = fore200e_set_oc3(fore200e, SUNI_MCT, mct_value, mct_mask); + if ( error == 0) + fore200e->loop_mode = loop_mode; + + return error; +} + + +static inline unsigned int +fore200e_swap(unsigned int in) +{ +#if defined(__LITTLE_ENDIAN) + return swab32(in); +#else + return in; +#endif +} + + +static int +fore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats* arg) +{ + struct sonet_stats tmp; + + if (fore200e_getstats(fore200e) < 0) + return -EIO; + + tmp.section_bip = fore200e_swap(fore200e->stats->oc3.section_bip8_errors); + tmp.line_bip = fore200e_swap(fore200e->stats->oc3.line_bip24_errors); + tmp.path_bip = fore200e_swap(fore200e->stats->oc3.path_bip8_errors); + tmp.line_febe = fore200e_swap(fore200e->stats->oc3.line_febe_errors); + tmp.path_febe = fore200e_swap(fore200e->stats->oc3.path_febe_errors); + tmp.corr_hcs = fore200e_swap(fore200e->stats->oc3.corr_hcs_errors); + tmp.uncorr_hcs = fore200e_swap(fore200e->stats->oc3.ucorr_hcs_errors); + tmp.tx_cells = fore200e_swap(fore200e->stats->aal0.cells_transmitted) + + fore200e_swap(fore200e->stats->aal34.cells_transmitted) + + fore200e_swap(fore200e->stats->aal5.cells_transmitted); + tmp.rx_cells = fore200e_swap(fore200e->stats->aal0.cells_received) + + fore200e_swap(fore200e->stats->aal34.cells_received) + + fore200e_swap(fore200e->stats->aal5.cells_received); + + if (arg) + return copy_to_user(arg, &tmp, sizeof(struct sonet_stats)) ? -EFAULT : 0; + + return 0; +} + + +static int +fore200e_ioctl(struct atm_dev* dev, unsigned int cmd, void* arg) +{ + struct fore200e* fore200e = FORE200E_DEV(dev); + + DPRINTK(2, "ioctl cmd = 0x%x (%u), arg = 0x%p (%lu)\n", cmd, cmd, arg, (unsigned long)arg); + + switch (cmd) { + + case SONET_GETSTAT: + return fore200e_fetch_stats(fore200e, (struct sonet_stats*)arg); + + case SONET_GETDIAG: + return put_user(0, (int*)arg) ? -EFAULT : 0; + + case SUNI_SETLOOP: + return fore200e_setloop(fore200e, (int)(unsigned long)arg); + + case SUNI_GETLOOP: + return put_user(fore200e->loop_mode, (int*)arg) ? -EFAULT : 0; + } + + return -ENOSYS; /* not implemented */ +} + + +static int +fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags) +{ + struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "change_qos %d.%d.%d, " + "(tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " + "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d), flags = 0x%x\n" + "available_cell_rate = %u", + vcc->itf, vcc->vpi, vcc->vci, + fore200e_traffic_class[ qos->txtp.traffic_class ], + qos->txtp.min_pcr, qos->txtp.max_pcr, qos->txtp.max_cdv, qos->txtp.max_sdu, + fore200e_traffic_class[ qos->rxtp.traffic_class ], + qos->rxtp.min_pcr, qos->rxtp.max_pcr, qos->rxtp.max_cdv, qos->rxtp.max_sdu, + flags, fore200e->available_cell_rate); + + if ((qos->txtp.traffic_class == ATM_CBR) && (qos->txtp.max_pcr > 0)) { + + down(&fore200e->rate_sf); + if (fore200e->available_cell_rate + vcc->qos.txtp.max_pcr < qos->txtp.max_pcr) { + up(&fore200e->rate_sf); + return -EAGAIN; + } + + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + fore200e->available_cell_rate -= qos->txtp.max_pcr; + up(&fore200e->rate_sf); + + memcpy(&vcc->qos, qos, sizeof(struct atm_qos)); + + /* update rate control parameters */ + fore200e_rate_ctrl(qos, &fore200e_vcc->rate); + + vcc->flags |= ATM_VF_HASQOS; + return 0; + } + + return -EINVAL; +} + + +static int __init +fore200e_irq_request(struct fore200e* fore200e) +{ + if (request_irq(fore200e->irq, fore200e_interrupt, SA_SHIRQ, fore200e->name, fore200e->atm_dev) < 0) { + + printk(FORE200E "unable to reserve IRQ %s for device %s\n", + fore200e_irq_itoa(fore200e->irq), fore200e->name); + return -EBUSY; + } + + printk(FORE200E "IRQ %s reserved for device %s\n", + fore200e_irq_itoa(fore200e->irq), fore200e->name); + + fore200e->state = FORE200E_STATE_IRQ; + return 0; +} + + +static int __init +fore200e_get_esi(struct fore200e* fore200e) +{ + struct prom_data* prom = fore200e_kmalloc(sizeof(struct prom_data), GFP_KERNEL | GFP_DMA); + int ok, i; + + ok = fore200e->bus->prom_read(fore200e, prom); + if (ok < 0) + return -EBUSY; + + printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %02x:%02x:%02x:%02x:%02x:%02x\n", + fore200e->name, + (prom->hw_revision & 0xFF) + '@', /* probably meaningless with SBA boards */ + prom->serial_number & 0xFFFF, + prom->mac_addr[ 2 ], prom->mac_addr[ 3 ], prom->mac_addr[ 4 ], + prom->mac_addr[ 5 ], prom->mac_addr[ 6 ], prom->mac_addr[ 7 ]); + + for (i = 0; i < ESI_LEN; i++) { + fore200e->esi[ i ] = fore200e->atm_dev->esi[ i ] = prom->mac_addr[ i + 2 ]; + } + + fore200e_kfree(prom); + + return 0; +} + + +static int __init +fore200e_alloc_rx_buf(struct fore200e* fore200e) +{ + int scheme, magn, nbr, size, i; + + struct host_bsq* bsq; + struct buffer* buffer; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + bsq = &fore200e->host_bsq[ scheme ][ magn ]; + + nbr = fore200e_rx_buf_nbr[ scheme ][ magn ]; + size = fore200e_rx_buf_size[ scheme ][ magn ]; + + DPRINTK(2, "rx buffers %d / %d are being allocated\n", scheme, magn); + + /* allocate the array of receive buffers */ + buffer = bsq->buffer = fore200e_kmalloc(nbr * sizeof(struct buffer), GFP_KERNEL); + + if (buffer == NULL) + return -ENOMEM; + + for (i = 0; i < nbr; i++) { + + buffer[ i ].scheme = scheme; + buffer[ i ].magn = magn; + + /* allocate the receive buffer body */ + if (fore200e_chunk_alloc(fore200e, + &buffer[ i ].data, size, fore200e->bus->buffer_alignment) < 0) { + + while (i > 0) + fore200e_chunk_free(fore200e, &buffer[ --i ].data); + fore200e_kfree(buffer); + + return -ENOMEM; + } + } + /* set next free buffer index */ + bsq->free = 0; + } + } + + fore200e->state = FORE200E_STATE_ALLOC_BUF; + return 0; +} + + +static int __init +fore200e_init_bs_queue(struct fore200e* fore200e) +{ + int scheme, magn, i; + + struct host_bsq* bsq; + struct cp_bsq_entry* cp_entry; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + DPRINTK(2, "buffer supply queue %d / %d is being initialized\n", scheme, magn); + + bsq = &fore200e->host_bsq[ scheme ][ magn ]; + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &bsq->status, + sizeof(enum status), + QUEUE_SIZE_BS, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* allocate and align the array of receive buffer descriptors */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &bsq->rbd_block, + sizeof(struct rbd_block), + QUEUE_SIZE_BS, + fore200e->bus->descr_alignment) < 0) { + + fore200e->bus->dma_chunk_free(fore200e, &bsq->status); + return -ENOMEM; + } + + /* get the base address of the cp resident buffer supply queue entries */ + cp_entry = (struct cp_bsq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_bsq[ scheme ][ magn ])); + + /* fill the host resident and cp resident buffer supply queue entries */ + for (i = 0; i < QUEUE_SIZE_BS; i++) { + + bsq->host_entry[ i ].status = + FORE200E_INDEX(bsq->status.align_addr, enum status, i); + bsq->host_entry[ i ].rbd_block = + FORE200E_INDEX(bsq->rbd_block.align_addr, struct rbd_block, i); + bsq->host_entry[ i ].rbd_block_dma = + FORE200E_DMA_INDEX(bsq->rbd_block.dma_addr, struct rbd_block, i); + bsq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *bsq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(bsq->status.dma_addr, enum status, i), + &cp_entry[ i ].status_haddr); + } + } + } + + fore200e->state = FORE200E_STATE_INIT_BSQ; + return 0; +} + + +static int __init +fore200e_init_rx_queue(struct fore200e* fore200e) +{ + struct host_rxq* rxq = &fore200e->host_rxq; + struct cp_rxq_entry* cp_entry; + int i; + + DPRINTK(2, "receive queue is being initialized\n"); + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &rxq->status, + sizeof(enum status), + QUEUE_SIZE_RX, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* allocate and align the array of receive PDU descriptors */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &rxq->rpd, + sizeof(struct rpd), + QUEUE_SIZE_RX, + fore200e->bus->descr_alignment) < 0) { + + fore200e->bus->dma_chunk_free(fore200e, &rxq->status); + return -ENOMEM; + } + + /* get the base address of the cp resident rx queue entries */ + cp_entry = (struct cp_rxq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_rxq)); + + /* fill the host resident and cp resident rx entries */ + for (i=0; i < QUEUE_SIZE_RX; i++) { + + rxq->host_entry[ i ].status = + FORE200E_INDEX(rxq->status.align_addr, enum status, i); + rxq->host_entry[ i ].rpd = + FORE200E_INDEX(rxq->rpd.align_addr, struct rpd, i); + rxq->host_entry[ i ].rpd_dma = + FORE200E_DMA_INDEX(rxq->rpd.dma_addr, struct rpd, i); + rxq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *rxq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(rxq->status.dma_addr, enum status, i), + &cp_entry[ i ].status_haddr); + + fore200e->bus->write(FORE200E_DMA_INDEX(rxq->rpd.dma_addr, struct rpd, i), + &cp_entry[ i ].rpd_haddr); + } + + /* set the head entry of the queue */ + rxq->head = 0; + + fore200e->state = FORE200E_STATE_INIT_RXQ; + return 0; +} + + +static int __init +fore200e_init_tx_queue(struct fore200e* fore200e) +{ + struct host_txq* txq = &fore200e->host_txq; + struct cp_txq_entry* cp_entry; + int i; + + DPRINTK(2, "transmit queue is being initialized\n"); + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &txq->status, + sizeof(enum status), + QUEUE_SIZE_TX, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* allocate and align the array of transmit PDU descriptors */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &txq->tpd, + sizeof(struct tpd), + QUEUE_SIZE_TX, + fore200e->bus->descr_alignment) < 0) { + + fore200e->bus->dma_chunk_free(fore200e, &txq->status); + return -ENOMEM; + } + + /* get the base address of the cp resident tx queue entries */ + cp_entry = (struct cp_txq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_txq)); + + /* fill the host resident and cp resident tx entries */ + for (i=0; i < QUEUE_SIZE_TX; i++) { + + txq->host_entry[ i ].status = + FORE200E_INDEX(txq->status.align_addr, enum status, i); + txq->host_entry[ i ].tpd = + FORE200E_INDEX(txq->tpd.align_addr, struct tpd, i); + txq->host_entry[ i ].tpd_dma = + FORE200E_DMA_INDEX(txq->tpd.dma_addr, struct tpd, i); + txq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *txq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(txq->status.dma_addr, enum status, i), + &cp_entry[ i ].status_haddr); + + /* although there is a one-to-one mapping of tx queue entries and tpds, + we do not write here the DMA (physical) base address of each tpd into + the related cp resident entry, because the cp relies on this write + operation to detect that a new pdu has been submitted for tx */ +} + + /* set the head entry of the queue */ + txq->head = 0; + + fore200e->state = FORE200E_STATE_INIT_TXQ; + return 0; +} + + +static int __init +fore200e_init_cmd_queue(struct fore200e* fore200e) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct cp_cmdq_entry* cp_entry; + int i; + + DPRINTK(2, "command queue is being initialized\n"); + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &cmdq->status, + sizeof(enum status), + QUEUE_SIZE_CMD, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* get the base address of the cp resident cmd queue entries */ + cp_entry = (struct cp_cmdq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_cmdq)); + + /* fill the host resident and cp resident cmd entries */ + for (i=0; i < QUEUE_SIZE_CMD; i++) { + + cmdq->host_entry[ i ].status = + FORE200E_INDEX(cmdq->status.align_addr, enum status, i); + cmdq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *cmdq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(cmdq->status.dma_addr, enum status, i), + &cp_entry[ i ].status_haddr); + } + + /* set the head entry of the queue */ + cmdq->head = 0; + + fore200e->state = FORE200E_STATE_INIT_CMDQ; + return 0; +} + + +static void __init +fore200e_param_bs_queue(struct fore200e* fore200e, + enum buffer_scheme scheme, enum buffer_magn magn, + int queue_length, int pool_size, int supply_blksize) +{ + struct bs_spec* bs_spec = &fore200e->cp_queues->init.bs_spec[ scheme ][ magn ]; + + /* dumb value; the firmware doesn't allow us to activate a VC while + selecting a buffer scheme with zero-sized rbd pools */ + + if (pool_size == 0) + pool_size = 64; + + fore200e->bus->write(queue_length, &bs_spec->queue_length); + fore200e->bus->write(fore200e_rx_buf_size[ scheme ][ magn ], &bs_spec->buffer_size); + fore200e->bus->write(pool_size, &bs_spec->pool_size); + fore200e->bus->write(supply_blksize, &bs_spec->supply_blksize); +} + + +static int __init +fore200e_initialize(struct fore200e* fore200e) +{ + struct cp_queues* cpq; + int ok, scheme, magn; + + DPRINTK(2, "device %s being initialized\n", fore200e->name); + + spin_lock_init(&fore200e->tx_lock); + init_MUTEX(&fore200e->rate_sf); + + cpq = fore200e->cp_queues = (struct cp_queues*) (fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET); + + /* enable cp to host interrupts */ + fore200e->bus->write(1, &cpq->imask); + + if (fore200e->bus->irq_enable) + fore200e->bus->irq_enable(fore200e); + + fore200e->bus->write(NBR_CONNECT, &cpq->init.num_connect); + + fore200e->bus->write(QUEUE_SIZE_CMD, &cpq->init.cmd_queue_len); + fore200e->bus->write(QUEUE_SIZE_RX, &cpq->init.rx_queue_len); + fore200e->bus->write(QUEUE_SIZE_TX, &cpq->init.tx_queue_len); + + fore200e->bus->write(RSD_EXTENSION, &cpq->init.rsd_extension); + fore200e->bus->write(TSD_EXTENSION, &cpq->init.tsd_extension); + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) + fore200e_param_bs_queue(fore200e, scheme, magn, + QUEUE_SIZE_BS, + fore200e_rx_buf_nbr[ scheme ][ magn ], + RBD_BLK_SIZE); + + /* issue the initialize command */ + fore200e->bus->write(STATUS_PENDING, &cpq->init.status); + fore200e->bus->write(OPCODE_INITIALIZE, &cpq->init.opcode); + + ok = fore200e_io_poll(fore200e, &cpq->init.status, STATUS_COMPLETE, 3000); + if (ok == 0) { + printk(FORE200E "device %s initialization failed\n", fore200e->name); + return -ENODEV; + } + + printk(FORE200E "device %s initialized\n", fore200e->name); + + fore200e->state = FORE200E_STATE_INITIALIZE; + return 0; +} + + +static void __init +fore200e_monitor_putc(struct fore200e* fore200e, char c) +{ + struct cp_monitor* monitor = fore200e->cp_monitor; + +#if 0 + printk("%c", c); +#endif + fore200e->bus->write(((u32) c) | FORE200E_CP_MONITOR_UART_AVAIL, &monitor->soft_uart.send); +} + + +static int __init +fore200e_monitor_getc(struct fore200e* fore200e) +{ + struct cp_monitor* monitor = fore200e->cp_monitor; + unsigned long timeout = jiffies + MSECS(50); + int c; + + while (jiffies < timeout) { + + c = (int) fore200e->bus->read(&monitor->soft_uart.recv); + + if (c & FORE200E_CP_MONITOR_UART_AVAIL) { + + fore200e->bus->write(FORE200E_CP_MONITOR_UART_FREE, &monitor->soft_uart.recv); +#if 0 + printk("%c", c & 0xFF); +#endif + return c & 0xFF; + } + } + + return -1; +} + + +static void __init +fore200e_monitor_puts(struct fore200e* fore200e, char* str) +{ + while(*str) { + + /* the i960 monitor doesn't accept any new character if it has something to say */ + while (fore200e_monitor_getc(fore200e) >= 0); + + fore200e_monitor_putc(fore200e, *str++); + } + + while (fore200e_monitor_getc(fore200e) >= 0); +} + + +static int __init +fore200e_start_fw(struct fore200e* fore200e) +{ + int ok; + char cmd[ 48 ]; + struct fw_header* fw_header = (struct fw_header*) fore200e->bus->fw_data; + + DPRINTK(2, "device %s firmware being started\n", fore200e->name); + + sprintf(cmd, "\rgo %x\r", le32_to_cpu(fw_header->start_offset)); + + fore200e_monitor_puts(fore200e, cmd); + + ok = fore200e_io_poll(fore200e, &fore200e->cp_monitor->bstat, BSTAT_CP_RUNNING, 1000); + if (ok == 0) { + printk(FORE200E "device %s firmware didn't start\n", fore200e->name); + return -ENODEV; + } + + printk(FORE200E "device %s firmware started\n", fore200e->name); + + fore200e->state = FORE200E_STATE_START_FW; + return 0; +} + + +static int __init +fore200e_load_fw(struct fore200e* fore200e) +{ + u32* fw_data = (u32*) fore200e->bus->fw_data; + u32 fw_size = (u32) *fore200e->bus->fw_size / sizeof(u32); + + struct fw_header* fw_header = (struct fw_header*) fw_data; + + u32* load_addr = fore200e->virt_base + le32_to_cpu(fw_header->load_offset); + + DPRINTK(2, "device %s firmware being loaded at 0x%p (%d words)\n", + fore200e->name, load_addr, fw_size); + +#if 1 + if (le32_to_cpu(fw_header->magic) != FW_HEADER_MAGIC) { + printk(FORE200E "corrupted %s firmware image\n", fore200e->bus->model_name); + return -ENODEV; + } +#endif + + for (; fw_size--; fw_data++, load_addr++) + fore200e->bus->write(le32_to_cpu(*fw_data), load_addr); + + fore200e->state = FORE200E_STATE_LOAD_FW; + return 0; +} + + +static int __init +fore200e_register(struct fore200e* fore200e) +{ + struct atm_dev* atm_dev; + + DPRINTK(2, "device %s being registered\n", fore200e->name); + + atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1, 0); + if (atm_dev == NULL) { + printk(FORE200E "unable to register device %s\n", fore200e->name); + return -ENODEV; + } + + FORE200E_DEV(atm_dev) = fore200e; + fore200e->atm_dev = atm_dev; + + atm_dev->ci_range.vpi_bits = 8; + atm_dev->ci_range.vci_bits = 10; + + fore200e->available_cell_rate = ATM_OC3_PCR; + + fore200e->state = FORE200E_STATE_REGISTER; + return 0; +} + + +static int __init +fore200e_init(struct fore200e* fore200e) +{ + if (fore200e_register(fore200e) < 0) + return -ENODEV; + + if (fore200e->bus->configure(fore200e) < 0) + return -ENODEV; + + if (fore200e->bus->map(fore200e) < 0) + return -ENODEV; + + if (fore200e_reset(fore200e, 1) < 0) + return -ENODEV; + + if (fore200e_load_fw(fore200e) < 0) + return -ENODEV; + + if (fore200e_start_fw(fore200e) < 0) + return -ENODEV; + + if (fore200e_initialize(fore200e) < 0) + return -ENODEV; + + if (fore200e_init_cmd_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_init_tx_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_init_rx_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_init_bs_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_alloc_rx_buf(fore200e) < 0) + return -ENOMEM; + + if (fore200e_get_esi(fore200e) < 0) + return -EIO; + + if (fore200e_irq_request(fore200e) < 0) + return -EBUSY; + + fore200e_supply(fore200e); + + /* all done, board initialization is now complete */ + fore200e->state = FORE200E_STATE_COMPLETE; + return 0; +} + + +int __init +fore200e_detect(void) +{ + const struct fore200e_bus* bus; + struct fore200e* fore200e; + int index, link; + + printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n"); + + /* for each configured bus interface */ + for (link = 0, bus = fore200e_bus; bus->model_name; bus++) { + + /* detect all boards present on that bus */ + for (index = 0; (fore200e = bus->detect(bus, index)); index++) { + + printk(FORE200E "device %s found at 0x%lx, IRQ %s\n", + fore200e->bus->model_name, + fore200e->phys_base, fore200e_irq_itoa(fore200e->irq)); + + sprintf(fore200e->name, "%s-%d", bus->model_name, index); + + if (fore200e_init(fore200e) < 0) { + + fore200e_shutdown(fore200e); + break; + } + + link++; + + fore200e->next = fore200e_boards; + fore200e_boards = fore200e; + } + } + +#if 0 /* XXX uncomment this to forbid module unloading */ +#ifdef MODULE + if (link > 0) + MOD_INC_USE_COUNT; +#endif +#endif + + return link; +} + + +#ifdef MODULE +static void +fore200e_cleanup(struct fore200e** head) +{ + struct fore200e* fore200e = *head; + + fore200e_shutdown(fore200e); + + *head = fore200e->next; + + kfree(fore200e); +} +#endif + + +static int +fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) +{ + struct fore200e* fore200e = FORE200E_DEV(dev); + int len, left = *pos; + + if (!left--) { + + if (fore200e_getstats(fore200e) < 0) + return -EIO; + + len = sprintf(page,"\n" + " device:\n" + " internal name:\t\t%s\n", fore200e->name); + + /* print bus-specific information */ + if (fore200e->bus->proc_read) + len += fore200e->bus->proc_read(fore200e, page + len); + + len += sprintf(page + len, + " interrupt line:\t\t%s\n" + " physical base address:\t0x%p\n" + " virtual base address:\t0x%p\n" + " factory address (ESI):\t%02x:%02x:%02x:%02x:%02x:%02x\n" + " board serial number:\t\t%d\n\n", + fore200e_irq_itoa(fore200e->irq), + (void*)fore200e->phys_base, + (void*)fore200e->virt_base, + fore200e->esi[0], fore200e->esi[1], fore200e->esi[2], + fore200e->esi[3], fore200e->esi[4], fore200e->esi[5], + fore200e->esi[4] * 256 + fore200e->esi[5]); + + return len; + } + + if (!left--) + return sprintf(page, + " supplied small bufs (1):\t%d\n" + " supplied large bufs (1):\t%d\n" + " supplied small bufs (2):\t%d\n" + " supplied large bufs (2):\t%d\n", + fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].count, + fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].count, + fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].count, + fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].count); + if (!left--) { + u32 hb = fore200e->bus->read(&fore200e->cp_queues->heartbeat); + + len = sprintf(page,"\n\n" + " cell processor:\n" + " heartbeat state:\t\t"); + + if (hb >> 16 != 0xDEAD) + len += sprintf(page + len, "0x%08x\n", hb); + else + len += sprintf(page + len, "*** FATAL ERROR %04x ***\n", hb & 0xFFFF); + + return len; + } + + if (!left--) { + static const char* media_name[] = { + "unshielded twisted pair", + "multimode optical fiber ST", + "multimode optical fiber SC", + "single-mode optical fiber ST", + "single-mode optical fiber SC", + "unknown" + }; + + static const char* oc3_mode[] = { + "normal operation", + "diagnostic loopback", + "line loopback" + }; + + u32 fw_release = fore200e->bus->read(&fore200e->cp_queues->fw_release); + u32 mon960_release = fore200e->bus->read(&fore200e->cp_queues->mon960_release); + u32 oc3_revision = fore200e->bus->read(&fore200e->cp_queues->oc3_revision); + u32 media_index = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type)); + + if (media_index < 0 || media_index > 4) + media_index = 5; + + return sprintf(page, + " firmware release:\t\t%d.%d.%d\n" + " monitor release:\t\t%d.%d\n" + " media type:\t\t\t%s\n" + " OC-3 revision:\t\t0x%x\n" + " OC-3 mode:\t\t\t%s", + fw_release >> 16, fw_release << 16 >> 24, fw_release << 24 >> 24, + mon960_release >> 16, mon960_release << 16 >> 16, + media_name[ media_index ], + oc3_revision, + oc3_mode[ fore200e->loop_mode ]); + } + + if (!left--) { + struct cp_monitor* cp_monitor = fore200e->cp_monitor; + + return sprintf(page, + "\n\n" + " monitor:\n" + " version number:\t\t%d\n" + " boot status word:\t\t0x%08x\n", + fore200e->bus->read(&cp_monitor->mon_version), + fore200e->bus->read(&cp_monitor->bstat)); + } + + if (!left--) + return sprintf(page, + "\n" + " device statistics:\n" + " 4b5b:\n" + " crc_header_errors:\t\t%10u\n" + " framing_errors:\t\t%10u\n", + fore200e_swap(fore200e->stats->phy.crc_header_errors), + fore200e_swap(fore200e->stats->phy.framing_errors)); + + if (!left--) + return sprintf(page, "\n" + " OC-3:\n" + " section_bip8_errors:\t%10u\n" + " path_bip8_errors:\t\t%10u\n" + " line_bip24_errors:\t\t%10u\n" + " line_febe_errors:\t\t%10u\n" + " path_febe_errors:\t\t%10u\n" + " corr_hcs_errors:\t\t%10u\n" + " ucorr_hcs_errors:\t\t%10u\n", + fore200e_swap(fore200e->stats->oc3.section_bip8_errors), + fore200e_swap(fore200e->stats->oc3.path_bip8_errors), + fore200e_swap(fore200e->stats->oc3.line_bip24_errors), + fore200e_swap(fore200e->stats->oc3.line_febe_errors), + fore200e_swap(fore200e->stats->oc3.path_febe_errors), + fore200e_swap(fore200e->stats->oc3.corr_hcs_errors), + fore200e_swap(fore200e->stats->oc3.ucorr_hcs_errors)); + + if (!left--) + return sprintf(page,"\n" + " ATM:\t\t\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " vpi out of range:\t\t%10u\n" + " vpi no conn:\t\t%10u\n" + " vci out of range:\t\t%10u\n" + " vci no conn:\t\t%10u\n", + fore200e_swap(fore200e->stats->atm.cells_transmitted), + fore200e_swap(fore200e->stats->atm.cells_received), + fore200e_swap(fore200e->stats->atm.vpi_bad_range), + fore200e_swap(fore200e->stats->atm.vpi_no_conn), + fore200e_swap(fore200e->stats->atm.vci_bad_range), + fore200e_swap(fore200e->stats->atm.vci_no_conn)); + + if (!left--) + return sprintf(page,"\n" + " AAL0:\t\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n", + fore200e_swap(fore200e->stats->aal0.cells_transmitted), + fore200e_swap(fore200e->stats->aal0.cells_received), + fore200e_swap(fore200e->stats->aal0.cells_dropped)); + + if (!left--) + return sprintf(page,"\n" + " AAL3/4:\n" + " SAR sublayer:\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " CRC errors:\t\t%10u\n" + " protocol errors:\t\t%10u\n\n" + " CS sublayer:\t\t PDUs\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " protocol errors:\t\t%10u\n", + fore200e_swap(fore200e->stats->aal34.cells_transmitted), + fore200e_swap(fore200e->stats->aal34.cells_received), + fore200e_swap(fore200e->stats->aal34.cells_dropped), + fore200e_swap(fore200e->stats->aal34.cells_crc_errors), + fore200e_swap(fore200e->stats->aal34.cells_protocol_errors), + fore200e_swap(fore200e->stats->aal34.cspdus_transmitted), + fore200e_swap(fore200e->stats->aal34.cspdus_received), + fore200e_swap(fore200e->stats->aal34.cspdus_dropped), + fore200e_swap(fore200e->stats->aal34.cspdus_protocol_errors)); + + if (!left--) + return sprintf(page,"\n" + " AAL5:\n" + " SAR sublayer:\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " congestions:\t\t%10u\n\n" + " CS sublayer:\t\t PDUs\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " CRC errors:\t\t%10u\n" + " protocol errors:\t\t%10u\n", + fore200e_swap(fore200e->stats->aal5.cells_transmitted), + fore200e_swap(fore200e->stats->aal5.cells_received), + fore200e_swap(fore200e->stats->aal5.cells_dropped), + fore200e_swap(fore200e->stats->aal5.congestion_experienced), + fore200e_swap(fore200e->stats->aal5.cspdus_transmitted), + fore200e_swap(fore200e->stats->aal5.cspdus_received), + fore200e_swap(fore200e->stats->aal5.cspdus_dropped), + fore200e_swap(fore200e->stats->aal5.cspdus_crc_errors), + fore200e_swap(fore200e->stats->aal5.cspdus_protocol_errors)); + + if (!left--) + return sprintf(page,"\n" + " AUX:\t\t allocation failures\n" + " small b1:\t\t\t%10u\n" + " large b1:\t\t\t%10u\n" + " small b2:\t\t\t%10u\n" + " large b2:\t\t\t%10u\n" + " RX PDUs:\t\t\t%10u\n", + fore200e_swap(fore200e->stats->aux.small_b1_failed), + fore200e_swap(fore200e->stats->aux.large_b1_failed), + fore200e_swap(fore200e->stats->aux.small_b2_failed), + fore200e_swap(fore200e->stats->aux.large_b2_failed), + fore200e_swap(fore200e->stats->aux.rpd_alloc_failed)); + + if (!left--) + return sprintf(page,"\n" + " receive carrier:\t\t\t%s\n", + fore200e->stats->aux.receive_carrier ? "ON" : "OFF!"); + + if (!left--) { + struct atm_vcc *vcc; + struct fore200e_vcc* fore200e_vcc; + + len = sprintf(page,"\n" + " VCCs:\n address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n"); + + for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) { + + fore200e_vcc = FORE200E_VCC(vcc); + + len += sprintf(page + len, + " %x\t%d.%d:%d\t\t(%d/%d)\t(%d/%d)\n", + (u32)(unsigned long)vcc, + vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + fore200e_vcc->tx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->tx_min_pdu, + fore200e_vcc->tx_max_pdu, + fore200e_vcc->rx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->rx_min_pdu, + fore200e_vcc->rx_max_pdu + ); + } + + return len; + } + + return 0; +} + + +#ifdef MODULE +unsigned int +init_module(void) +{ + DPRINTK(1, "module loaded\n"); + return fore200e_detect() == 0; +} + +void +cleanup_module(void) +{ + while (fore200e_boards) { + fore200e_cleanup(&fore200e_boards); + } + DPRINTK(1, "module being removed\n"); +} +#endif + + +static const struct atmdev_ops fore200e_ops = +{ + NULL, /* fore200e_dev_close */ + fore200e_open, + fore200e_close, + fore200e_ioctl, + fore200e_getsockopt, + fore200e_setsockopt, + fore200e_send, + NULL, /* fore200e_sg_send, */ + NULL, /* fore200e_send_oam, */ + NULL, /* fore200e_phy_put, */ + NULL, /* fore200e_phy_get, */ + NULL, /* fore200e_feedback, */ + fore200e_change_qos, + NULL, /* fore200e_free_rx_skb */ + fore200e_proc_read +}; + + +#ifdef CONFIG_ATM_FORE200E_PCA +extern const unsigned char _fore200e_pca_fw_data[]; +extern const unsigned int _fore200e_pca_fw_size; +#endif +#ifdef CONFIG_ATM_FORE200E_SBA +extern const unsigned char _fore200e_sba_fw_data[]; +extern const unsigned int _fore200e_sba_fw_size; +#endif + +static const struct fore200e_bus fore200e_bus[] = { +#ifdef CONFIG_ATM_FORE200E_PCA + { "PCA-200E", "pca200e", 32, 4, 32, + _fore200e_pca_fw_data, &_fore200e_pca_fw_size, + fore200e_pca_read, + fore200e_pca_write, + fore200e_pca_dma_map, + fore200e_pca_dma_unmap, + fore200e_pca_dma_sync, + fore200e_pca_dma_chunk_alloc, + fore200e_pca_dma_chunk_free, + fore200e_pca_detect, + fore200e_pca_configure, + fore200e_pca_map, + fore200e_pca_reset, + fore200e_pca_prom_read, + fore200e_pca_unmap, + NULL, + fore200e_pca_irq_check, + fore200e_pca_irq_ack, + fore200e_pca_proc_read, + }, +#endif +#ifdef CONFIG_ATM_FORE200E_SBA + { "SBA-200E", "sba200e", 32, 64, 32, + _fore200e_sba_fw_data, &_fore200e_sba_fw_size, + fore200e_sba_read, + fore200e_sba_write, + fore200e_sba_dma_map, + fore200e_sba_dma_unmap, + fore200e_sba_dma_sync, + fore200e_sba_dma_chunk_alloc, + fore200e_sba_dma_chunk_free, + fore200e_sba_detect, + fore200e_sba_configure, + fore200e_sba_map, + fore200e_sba_reset, + fore200e_sba_prom_read, + fore200e_sba_unmap, + fore200e_sba_irq_enable, + fore200e_sba_irq_check, + fore200e_sba_irq_ack, + fore200e_sba_proc_read, + }, +#endif + {} +}; diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h new file mode 100644 index 000000000..eea20162b --- /dev/null +++ b/drivers/atm/fore200e.h @@ -0,0 +1,952 @@ +#ifndef _FORE200E_H +#define _FORE200E_H + +#ifdef __KERNEL__ + +/* rx buffer sizes */ + +#define SMALL_BUFFER_SIZE 384 /* size of small buffers (multiple of 48 (PCA) and 64 (SBA) bytes) */ +#define LARGE_BUFFER_SIZE 4032 /* size of large buffers (multiple of 48 (PCA) and 64 (SBA) bytes) */ + + +#define RBD_BLK_SIZE 32 /* nbr of supplied rx buffers per rbd */ + + +#define MAX_PDU_SIZE 65535 /* maximum PDU size supported by AALs */ + + +#define BUFFER_S1_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 1 */ +#define BUFFER_L1_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 1 */ + +#define BUFFER_S2_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 2 */ +#define BUFFER_L2_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 2 */ + +#define BUFFER_S1_NBR (RBD_BLK_SIZE * 2) +#define BUFFER_L1_NBR (RBD_BLK_SIZE * 2) + +#define BUFFER_S2_NBR (RBD_BLK_SIZE * 2) +#define BUFFER_L2_NBR (RBD_BLK_SIZE * 2) + + +#define QUEUE_SIZE_CMD 16 /* command queue capacity */ +#define QUEUE_SIZE_RX 64 /* receive queue capacity */ +#define QUEUE_SIZE_TX 256 /* transmit queue capacity */ +#define QUEUE_SIZE_BS 16 /* buffer supply queue capacity */ + +#define NBR_CONNECT 1024 /* number of ATM connections */ + + +#define TSD_FIXED 2 +#define TSD_EXTENSION 0 +#define TSD_NBR (TSD_FIXED + TSD_EXTENSION) + + +/* the cp starts putting a received PDU into one *small* buffer, + then it uses a number of *large* buffers for the trailing data. + we compute here the total number of receive segment descriptors + required to hold the largest possible PDU */ + +#define RSD_REQUIRED (((MAX_PDU_SIZE - SMALL_BUFFER_SIZE + LARGE_BUFFER_SIZE) / LARGE_BUFFER_SIZE) + 1) + +#define RSD_FIXED 3 + +/* RSD_REQUIRED receive segment descriptors are enough to describe a max-sized PDU, + but we have to keep the size of the receive PDU descriptor multiple of 32 bytes, + so we add one extra RSD to RSD_EXTENSION + (WARNING: THIS MAY CHANGE IF BUFFER SIZES ARE MODIFIED) */ + +#define RSD_EXTENSION ((RSD_REQUIRED - RSD_FIXED) + 1) +#define RSD_NBR (RSD_FIXED + RSD_EXTENSION) + + +#define FORE200E_DEV(d) ((struct fore200e*)((d)->dev_data)) +#define FORE200E_VCC(d) ((struct fore200e_vcc*)((d)->dev_data)) + +/* bitfields endian games */ + +#if defined(__LITTLE_ENDIAN_BITFIELD) +#define BITFIELD2(b1, b2) b1; b2; +#define BITFIELD3(b1, b2, b3) b1; b2; b3; +#define BITFIELD4(b1, b2, b3, b4) b1; b2; b3; b4; +#define BITFIELD5(b1, b2, b3, b4, b5) b1; b2; b3; b4; b5; +#define BITFIELD6(b1, b2, b3, b4, b5, b6) b1; b2; b3; b4; b5; b6; +#elif defined(__BIG_ENDIAN_BITFIELD) +#define BITFIELD2(b1, b2) b2; b1; +#define BITFIELD3(b1, b2, b3) b3; b2; b1; +#define BITFIELD4(b1, b2, b3, b4) b4; b3; b2; b1; +#define BITFIELD5(b1, b2, b3, b4, b5) b5; b4; b3; b2; b1; +#define BITFIELD6(b1, b2, b3, b4, b5, b6) b6; b5; b4; b3; b2; b1; +#else +#error unknown bitfield endianess +#endif + + +/* ATM cell header (minus HEC byte) */ + +typedef struct atm_header { + BITFIELD5( + u32 clp : 1, /* cell loss priority */ + u32 plt : 3, /* payload type */ + u32 vci : 16, /* virtual channel identifier */ + u32 vpi : 8, /* virtual path identifier */ + u32 gfc : 4 /* generic flow control */ + ) +} atm_header_t; + + +/* ATM adaptation layer id */ + +typedef enum fore200e_aal { + FORE200E_AAL0 = 0, + FORE200E_AAL34 = 4, + FORE200E_AAL5 = 5, +} fore200e_aal_t; + + +/* transmit PDU descriptor specification */ + +typedef struct tpd_spec { + BITFIELD4( + u32 length : 16, /* total PDU length */ + u32 nseg : 8, /* number of transmit segments */ + enum fore200e_aal aal : 4, /* adaptation layer */ + u32 intr : 4 /* interrupt requested */ + ) +} tpd_spec_t; + + +/* transmit PDU rate control */ + +typedef struct tpd_rate +{ + BITFIELD2( + u32 idle_cells : 16, /* number of idle cells to insert */ + u32 data_cells : 16 /* number of data cells to transmit */ + ) +} tpd_rate_t; + + +/* transmit segment descriptor */ + +typedef struct tsd { + u32 buffer; /* transmit buffer DMA address */ + u32 length; /* number of bytes in buffer */ +} tsd_t; + + +/* transmit PDU descriptor */ + +typedef struct tpd { + struct atm_header atm_header; /* ATM header minus HEC byte */ + struct tpd_spec spec; /* tpd specification */ + struct tpd_rate rate; /* tpd rate control */ + u32 pad; /* reserved */ + struct tsd tsd[ TSD_NBR ]; /* transmit segment descriptors */ +} tpd_t; + + +/* receive segment descriptor */ + +typedef struct rsd { + u32 handle; /* host supplied receive buffer handle */ + u32 length; /* number of bytes in buffer */ +} rsd_t; + + +/* receive PDU descriptor */ + +typedef struct rpd { + struct atm_header atm_header; /* ATM header minus HEC byte */ + u32 nseg; /* number of receive segments */ + struct rsd rsd[ RSD_NBR ]; /* receive segment descriptors */ +} rpd_t; + + +/* buffer scheme */ + +typedef enum buffer_scheme { + BUFFER_SCHEME_ONE, + BUFFER_SCHEME_TWO, + BUFFER_SCHEME_NBR /* always last */ +} buffer_scheme_t; + + +/* buffer magnitude */ + +typedef enum buffer_magn { + BUFFER_MAGN_SMALL, + BUFFER_MAGN_LARGE, + BUFFER_MAGN_NBR /* always last */ +} buffer_magn_t; + + +/* receive buffer descriptor */ + +typedef struct rbd { + u32 handle; /* host supplied handle */ + u32 buffer_haddr; /* host DMA address of host buffer */ +} rbd_t; + + +/* receive buffer descriptor block */ + +typedef struct rbd_block { + struct rbd rbd[ RBD_BLK_SIZE ]; /* receive buffer descriptor */ +} rbd_block_t; + + +/* tpd DMA address */ + +typedef struct tpd_haddr { + BITFIELD3( + u32 size : 4, /* tpd size expressed in 32 byte blocks */ + u32 pad : 1, /* reserved */ + u32 haddr : 27 /* tpd DMA addr aligned on 32 byte boundary */ + ) +} tpd_haddr_t; + + +/* cp resident transmit queue entry */ + +typedef struct cp_txq_entry { + struct tpd_haddr tpd_haddr; /* host DMA address of tpd */ + u32 status_haddr; /* host DMA address of completion status */ +} cp_txq_entry_t; + + +/* cp resident receive queue entry */ + +typedef struct cp_rxq_entry { + u32 rpd_haddr; /* host DMA address of rpd */ + u32 status_haddr; /* host DMA address of completion status */ +} cp_rxq_entry_t; + + +/* cp resident buffer supply queue entry */ + +typedef struct cp_bsq_entry { + u32 rbd_block_haddr; /* host DMA address of rbd block */ + u32 status_haddr; /* host DMA address of completion status */ +} cp_bsq_entry_t; + + +/* completion status */ + +typedef volatile enum status { + STATUS_PENDING = (1<<0), /* initial status (written by host) */ + STATUS_COMPLETE = (1<<1), /* completion status (written by cp) */ + STATUS_FREE = (1<<2), /* initial status (written by host) */ + STATUS_ERROR = (1<<3) /* completion status (written by cp) */ +} status_t; + + +/* cp operation code */ + +typedef enum opcode { + OPCODE_INITIALIZE = 1, /* initialize board */ + OPCODE_ACTIVATE_VCIN, /* activate incoming VCI */ + OPCODE_ACTIVATE_VCOUT, /* activate outgoing VCI */ + OPCODE_DEACTIVATE_VCIN, /* deactivate incoming VCI */ + OPCODE_DEACTIVATE_VCOUT, /* deactivate incoing VCI */ + OPCODE_GET_STATS, /* get board statistics */ + OPCODE_SET_OC3, /* set OC-3 registers */ + OPCODE_GET_OC3, /* get OC-3 registers */ + OPCODE_RESET_STATS, /* reset board statistics */ + OPCODE_GET_PROM, /* get expansion PROM data (PCI specific) */ + OPCODE_SET_VPI_BITS, /* set x bits of those decoded by the + firmware to be low order bits from + the VPI field of the ATM cell header */ + OPCODE_REQUEST_INTR = (1<<7) /* request interrupt */ +} opcode_t; + + +/* virtual path / virtual channel identifers */ + +typedef struct vpvc { + BITFIELD3( + u32 vci : 16, /* virtual channel identifier */ + u32 vpi : 8, /* virtual path identifier */ + u32 pad : 8 /* reserved */ + ) +} vpvc_t; + + +/* activate VC command opcode */ + +typedef struct activate_opcode { + BITFIELD4( + enum opcode opcode : 8, /* cp opcode */ + enum fore200e_aal aal : 8, /* adaptation layer */ + enum buffer_scheme scheme : 8, /* buffer scheme */ + u32 pad : 8 /* reserved */ + ) +} activate_opcode_t; + + +/* activate VC command block */ + +typedef struct activate_block { + struct activate_opcode opcode; /* activate VC command opcode */ + struct vpvc vpvc; /* VPI/VCI */ + u32 mtu; /* for AAL0 only */ + +} activate_block_t; + + +/* deactivate VC command opcode */ + +typedef struct deactivate_opcode { + BITFIELD2( + enum opcode opcode : 8, /* cp opcode */ + u32 pad : 24 /* reserved */ + ) +} deactivate_opcode_t; + + +/* deactivate VC command block */ + +typedef struct deactivate_block { + struct deactivate_opcode opcode; /* deactivate VC command opcode */ + struct vpvc vpvc; /* VPI/VCI */ +} deactivate_block_t; + + +/* OC-3 registers */ + +typedef struct oc3_regs { + u32 reg[ 128 ]; /* see the PMC Sierra PC5346 S/UNI-155-Lite + Saturn User Network Interface documentation + for a description of the OC-3 chip registers */ +} oc3_regs_t; + + +/* set/get OC-3 regs command opcode */ + +typedef struct oc3_opcode { + BITFIELD4( + enum opcode opcode : 8, /* cp opcode */ + u32 reg : 8, /* register index */ + u32 value : 8, /* register value */ + u32 mask : 8 /* register mask that specifies which + bits of the register value field + are significant */ + ) +} oc3_opcode_t; + + +/* set/get OC-3 regs command block */ + +typedef struct oc3_block { + struct oc3_opcode opcode; /* set/get OC-3 regs command opcode */ + u32 regs_haddr; /* host DMA address of OC-3 regs buffer */ +} oc3_block_t; + + +/* physical encoding statistics */ + +typedef struct stats_phy { + u32 crc_header_errors; /* cells received with bad header CRC */ + u32 framing_errors; /* cells received with bad framing */ + u32 pad[ 2 ]; /* i960 padding */ +} stats_phy_t; + + +/* OC-3 statistics */ + +typedef struct stats_oc3 { + u32 section_bip8_errors; /* section 8 bit interleaved parity */ + u32 path_bip8_errors; /* path 8 bit interleaved parity */ + u32 line_bip24_errors; /* line 24 bit interleaved parity */ + u32 line_febe_errors; /* line far end block errors */ + u32 path_febe_errors; /* path far end block errors */ + u32 corr_hcs_errors; /* correctable header check sequence */ + u32 ucorr_hcs_errors; /* uncorrectable header check sequence */ + u32 pad[ 1 ]; /* i960 padding */ +} stats_oc3_t; + + +/* ATM statistics */ + +typedef struct stats_atm { + u32 cells_transmitted; /* cells transmitted */ + u32 cells_received; /* cells received */ + u32 vpi_bad_range; /* cell drops: VPI out of range */ + u32 vpi_no_conn; /* cell drops: no connection for VPI */ + u32 vci_bad_range; /* cell drops: VCI out of range */ + u32 vci_no_conn; /* cell drops: no connection for VCI */ + u32 pad[ 2 ]; /* i960 padding */ +} stats_atm_t; + +/* AAL0 statistics */ + +typedef struct stats_aal0 { + u32 cells_transmitted; /* cells transmitted */ + u32 cells_received; /* cells received */ + u32 cells_dropped; /* cells dropped */ + u32 pad[ 1 ]; /* i960 padding */ +} stats_aal0_t; + + +/* AAL3/4 statistics */ + +typedef struct stats_aal34 { + u32 cells_transmitted; /* cells transmitted from segmented PDUs */ + u32 cells_received; /* cells reassembled into PDUs */ + u32 cells_crc_errors; /* payload CRC error count */ + u32 cells_protocol_errors; /* SAR or CS layer protocol errors */ + u32 cells_dropped; /* cells dropped: partial reassembly */ + u32 cspdus_transmitted; /* CS PDUs transmitted */ + u32 cspdus_received; /* CS PDUs received */ + u32 cspdus_protocol_errors; /* CS layer protocol errors */ + u32 cspdus_dropped; /* reassembled PDUs drop'd (in cells) */ + u32 pad[ 3 ]; /* i960 padding */ +} stats_aal34_t; + + +/* AAL5 statistics */ + +typedef struct stats_aal5 { + u32 cells_transmitted; /* cells transmitted from segmented SDUs */ + u32 cells_received; /* cells reassembled into SDUs */ + u32 cells_dropped; /* reassembled PDUs dropped (in cells) */ + u32 congestion_experienced; /* CRC error and length wrong */ + u32 cspdus_transmitted; /* CS PDUs transmitted */ + u32 cspdus_received; /* CS PDUs received */ + u32 cspdus_crc_errors; /* CS PDUs CRC errors */ + u32 cspdus_protocol_errors; /* CS layer protocol errors */ + u32 cspdus_dropped; /* reassembled PDUs dropped */ + u32 pad[ 3 ]; /* i960 padding */ +} stats_aal5_t; + + +/* auxiliary statistics */ + +typedef struct stats_aux { + u32 small_b1_failed; /* receive BD allocation failures */ + u32 large_b1_failed; /* receive BD allocation failures */ + u32 small_b2_failed; /* receive BD allocation failures */ + u32 large_b2_failed; /* receive BD allocation failures */ + u32 rpd_alloc_failed; /* receive PDU allocation failures */ + u32 receive_carrier; /* no carrier = 0, carrier = 1 */ + u32 pad[ 2 ]; /* i960 padding */ +} stats_aux_t; + + +/* whole statistics buffer */ + +typedef struct stats { + struct stats_phy phy; /* physical encoding statistics */ + struct stats_oc3 oc3; /* OC-3 statistics */ + struct stats_atm atm; /* ATM statistics */ + struct stats_aal0 aal0; /* AAL0 statistics */ + struct stats_aal34 aal34; /* AAL3/4 statistics */ + struct stats_aal5 aal5; /* AAL5 statistics */ + struct stats_aux aux; /* auxiliary statistics */ +} stats_t; + + +/* get statistics command opcode */ + +typedef struct stats_opcode { + BITFIELD2( + enum opcode opcode : 8, /* cp opcode */ + u32 pad : 24 /* reserved */ + ) +} stats_opcode_t; + + +/* get statistics command block */ + +typedef struct stats_block { + struct stats_opcode opcode; /* get statistics command opcode */ + u32 stats_haddr; /* host DMA address of stats buffer */ +} stats_block_t; + + +/* expansion PROM data (PCI specific) */ + +typedef struct prom_data { + u32 hw_revision; /* hardware revision */ + u32 serial_number; /* board serial number */ + u8 mac_addr[ 8 ]; /* board MAC address */ +} prom_data_t; + + +/* get expansion PROM data command opcode */ + +typedef struct prom_opcode { + BITFIELD2( + enum opcode opcode : 8, /* cp opcode */ + u32 pad : 24 /* reserved */ + ) +} prom_opcode_t; + + +/* get expansion PROM data command block */ + +typedef struct prom_block { + struct prom_opcode opcode; /* get PROM data command opcode */ + u32 prom_haddr; /* host DMA address of PROM buffer */ +} prom_block_t; + + +/* cp command */ + +typedef union cmd { + enum opcode opcode; /* operation code */ + struct activate_block activate_block; /* activate VC */ + struct deactivate_block deactivate_block; /* deactivate VC */ + struct stats_block stats_block; /* get statistics */ + struct prom_block prom_block; /* get expansion PROM data */ + struct oc3_block oc3_block; /* get/set OC-3 registers */ + u32 pad[ 4 ]; /* i960 padding */ +} cmd_t; + + +/* cp resident command queue */ + +typedef struct cp_cmdq_entry { + union cmd cmd; /* command */ + u32 status_haddr; /* host DMA address of completion status */ + u32 pad[ 3 ]; /* i960 padding */ +} cp_cmdq_entry_t; + + +/* host resident transmit queue entry */ + +typedef struct host_txq_entry { + struct cp_txq_entry* cp_entry; /* addr of cp resident tx queue entry */ + enum status* status; /* addr of host resident status */ + struct tpd* tpd; /* addr of transmit PDU descriptor */ + u32 tpd_dma; /* DMA address of tpd */ + struct sk_buff* skb; /* related skb */ + struct atm_vcc* vcc; /* related vcc */ + void* data; /* copy of misaligned data */ +} host_txq_entry_t; + + +/* host resident receive queue entry */ + +typedef struct host_rxq_entry { + struct cp_rxq_entry* cp_entry; /* addr of cp resident rx queue entry */ + enum status* status; /* addr of host resident status */ + struct rpd* rpd; /* addr of receive PDU descriptor */ + u32 rpd_dma; /* DMA address of rpd */ +} host_rxq_entry_t; + + +/* host resident buffer supply queue entry */ + +typedef struct host_bsq_entry { + struct cp_bsq_entry* cp_entry; /* addr of cp resident buffer supply queue entry */ + enum status* status; /* addr of host resident status */ + struct rbd_block* rbd_block; /* addr of receive buffer descriptor block */ + u32 rbd_block_dma; /* DMA address od rdb */ +} host_bsq_entry_t; + + +/* host resident command queue entry */ + +typedef struct host_cmdq_entry { + struct cp_cmdq_entry* cp_entry; /* addr of cp resident cmd queue entry */ + enum status* status; /* addr of host resident status */ +} host_cmdq_entry_t; + + +/* chunk of memory */ + +typedef struct chunk { + void* alloc_addr; /* base address of allocated chunk */ + void* align_addr; /* base address of aligned chunk */ + u32 dma_addr; /* DMA address of aligned chunk */ + u32 alloc_size; /* length of allocated chunk */ + u32 align_size; /* length of aligned chunk */ +} chunk_t; + +#define dma_size align_size /* DMA useable size */ + + +/* host resident receive buffer */ + +typedef struct buffer { + struct buffer* next; /* next receive buffer */ + enum buffer_scheme scheme; /* buffer scheme */ + enum buffer_magn magn; /* buffer magnitude */ + struct chunk data; /* data buffer */ +} buffer_t; + + +#if (BITS_PER_LONG == 32) +#define FORE200E_BUF2HDL(buffer) ((u32)(buffer)) +#define FORE200E_HDL2BUF(handle) ((struct buffer*)(handle)) +#else /* deal with 64 bit pointers */ +#define FORE200E_BUF2HDL(buffer) ((u32)((u64)(buffer))) +#define FORE200E_HDL2BUF(handle) ((struct buffer*)(((u64)(handle)) | PAGE_OFFSET)) +#endif + + +/* host resident command queue */ + +typedef struct host_cmdq { + struct host_cmdq_entry host_entry[ QUEUE_SIZE_CMD ]; /* host resident cmd queue entries */ + int head; /* head of cmd queue */ + struct chunk status; /* array of completion status */ +} host_cmdq_t; + + +/* host resident transmit queue */ + +typedef struct host_txq { + struct host_txq_entry host_entry[ QUEUE_SIZE_TX ]; /* host resident tx queue entries */ + int head; /* head of tx queue */ + struct chunk tpd; /* array of tpds */ + struct chunk status; /* arry of completion status */ + int txing; /* number of pending PDUs in tx queue */ +} host_txq_t; + + +/* host resident receive queue */ + +typedef struct host_rxq { + struct host_rxq_entry host_entry[ QUEUE_SIZE_RX ]; /* host resident rx queue entries */ + int head; /* head of rx queue */ + struct chunk rpd; /* array of rpds */ + struct chunk status; /* array of completion status */ +} host_rxq_t; + + +/* host resident buffer supply queues */ + +typedef struct host_bsq { + struct host_bsq_entry host_entry[ QUEUE_SIZE_BS ]; /* host resident buffer supply queue entries */ + int head; /* head of buffer supply queue */ + struct chunk rbd_block; /* array of rbds */ + struct chunk status; /* array of completion status */ + struct buffer* buffer; /* array of rx buffers */ + int free; /* index of first free rx buffer */ + volatile int count; /* count of supplied rx buffers */ +} host_bsq_t; + + +/* header of the firmware image */ + +typedef struct fw_header { + u32 magic; /* magic number */ + u32 version; /* firware version id */ + u32 load_offset; /* fw load offset in board memory */ + u32 start_offset; /* fw execution start address in board memory */ +} fw_header_t; + +#define FW_HEADER_MAGIC 0x65726f66 /* 'fore' */ + + +/* receive buffer supply queues scheme specification */ + +typedef struct bs_spec { + u32 queue_length; /* queue capacity */ + u32 buffer_size; /* host buffer size */ + u32 pool_size; /* number of rbds */ + u32 supply_blksize; /* num of rbds in I/O block (multiple + of 4 between 4 and 124 inclusive) */ +} bs_spec_t; + + +/* initialization command block (one-time command, not in cmd queue) */ + +typedef struct init_block { + enum opcode opcode; /* initialize command */ + enum status status; /* related status word */ + u32 receive_threshold; /* not used */ + u32 num_connect; /* ATM connections */ + u32 cmd_queue_len; /* length of command queue */ + u32 tx_queue_len; /* length of transmit queue */ + u32 rx_queue_len; /* length of receive queue */ + u32 rsd_extension; /* number of extra 32 byte blocks */ + u32 tsd_extension; /* number of extra 32 byte blocks */ + u32 conless_vpvc; /* not used */ + u32 pad[ 2 ]; /* force quad alignment */ + struct bs_spec bs_spec[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; /* buffer supply queues spec */ +} init_block_t; + + +typedef enum media_type { + MEDIA_TYPE_CAT5_UTP = 0x06, /* unshielded twisted pair */ + MEDIA_TYPE_MM_OC3_ST = 0x16, /* multimode fiber ST */ + MEDIA_TYPE_MM_OC3_SC = 0x26, /* multimode fiber SC */ + MEDIA_TYPE_SM_OC3_ST = 0x36, /* single-mode fiber ST */ + MEDIA_TYPE_SM_OC3_SC = 0x46 /* single-mode fiber SC */ +} media_type_t; + +#define FORE200E_MEDIA_INDEX(media_type) ((media_type)>>4) + + +/* cp resident queues */ + +typedef struct cp_queues { + u32 cp_cmdq; /* command queue */ + u32 cp_txq; /* transmit queue */ + u32 cp_rxq; /* receive queue */ + u32 cp_bsq[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; /* buffer supply queues */ + u32 imask; /* 1 enables cp to host interrupts */ + u32 istat; /* 1 for interrupt posted */ + u32 heap_base; /* offset form beginning of ram */ + u32 heap_size; /* space available for queues */ + u32 hlogger; /* non zero for host logging */ + u32 heartbeat; /* cp heartbeat */ + u32 fw_release; /* firmware version */ + u32 mon960_release; /* i960 monitor version */ + u32 tq_plen; /* transmit throughput measurements */ + /* make sure the init block remains on a quad word boundary */ + struct init_block init; /* one time cmd, not in cmd queue */ + enum media_type media_type; /* media type id */ + u32 oc3_revision; /* OC-3 revision number */ +} cp_queues_t; + + +/* boot status */ + +typedef enum boot_status { + BSTAT_COLD_START = (u32) 0xc01dc01d, /* cold start */ + BSTAT_SELFTEST_OK = (u32) 0x02201958, /* self-test ok */ + BSTAT_SELFTEST_FAIL = (u32) 0xadbadbad, /* self-test failed */ + BSTAT_CP_RUNNING = (u32) 0xce11feed, /* cp is running */ + BSTAT_MON_TOO_BIG = (u32) 0x10aded00 /* i960 monitor is too big */ +} boot_status_t; + + +/* software UART */ + +typedef struct soft_uart { + u32 send; /* write register */ + u32 recv; /* read register */ +} soft_uart_t; + +#define FORE200E_CP_MONITOR_UART_FREE 0x00000000 +#define FORE200E_CP_MONITOR_UART_AVAIL 0x01000000 + + +/* i960 monitor */ + +typedef struct cp_monitor { + struct soft_uart soft_uart; /* software UART */ + enum boot_status bstat; /* boot status */ + u32 app_base; /* application base offset */ + u32 mon_version; /* i960 monitor version */ +} cp_monitor_t; + + +/* device state */ + +typedef enum fore200e_state { + FORE200E_STATE_BLANK, /* initial state */ + FORE200E_STATE_REGISTER, /* device registered */ + FORE200E_STATE_CONFIGURE, /* bus interface configured */ + FORE200E_STATE_MAP, /* board space mapped in host memory */ + FORE200E_STATE_RESET, /* board resetted */ + FORE200E_STATE_LOAD_FW, /* firmware loaded */ + FORE200E_STATE_START_FW, /* firmware started */ + FORE200E_STATE_INITIALIZE, /* initialize command successful */ + FORE200E_STATE_INIT_CMDQ, /* command queue initialized */ + FORE200E_STATE_INIT_TXQ, /* transmit queue initialized */ + FORE200E_STATE_INIT_RXQ, /* receive queue initialized */ + FORE200E_STATE_INIT_BSQ, /* buffer supply queue initialized */ + FORE200E_STATE_ALLOC_BUF, /* receive buffers allocated */ + FORE200E_STATE_IRQ, /* host interrupt requested */ + FORE200E_STATE_COMPLETE /* initialization completed */ +} fore200e_state; + + +/* PCA-200E registers */ + +typedef struct fore200e_pca_regs { + volatile u32* hcr; /* address of host control register */ + volatile u32* imr; /* address of host interrupt mask register */ + volatile u32* psr; /* address of PCI specific register */ +} fore200e_pca_regs_t; + + +/* SBA-200E registers */ + +typedef struct fore200e_sba_regs { + volatile u32* hcr; /* address of host control register */ + volatile u32* bsr; /* address of burst transfer size register */ + volatile u32* isr; /* address of interrupt level selection register */ +} fore200e_sba_regs_t; + + +/* model-specific registers */ + +typedef union fore200e_regs { + struct fore200e_pca_regs pca; /* PCA-200E registers */ + struct fore200e_sba_regs sba; /* SBA-200E registers */ +} fore200e_regs; + + +struct fore200e; + +/* bus-dependent data */ + +typedef struct fore200e_bus { + char* model_name; /* board model name */ + char* proc_name; /* board name under /proc/atm */ + int descr_alignment; /* tpd/rpd/rbd DMA alignment requirement */ + int buffer_alignment; /* rx buffers DMA alignment requirement */ + int status_alignment; /* status words DMA alignment requirement */ + const unsigned char* fw_data; /* address of firmware data start */ + const unsigned int* fw_size; /* address of firmware data size */ + u32 (*read)(volatile u32*); + void (*write)(u32, volatile u32*); + u32 (*dma_map)(struct fore200e*, void*, int); + void (*dma_unmap)(struct fore200e*, u32, int); + void (*dma_sync)(struct fore200e*, u32, int); + int (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int); + void (*dma_chunk_free)(struct fore200e*, struct chunk*); + struct fore200e* (*detect)(const struct fore200e_bus*, int); + int (*configure)(struct fore200e*); + int (*map)(struct fore200e*); + void (*reset)(struct fore200e*); + int (*prom_read)(struct fore200e*, struct prom_data*); + void (*unmap)(struct fore200e*); + void (*irq_enable)(struct fore200e*); + int (*irq_check)(struct fore200e*); + void (*irq_ack)(struct fore200e*); + int (*proc_read)(struct fore200e*, char*); +} fore200e_bus_t; + + +/* per-device data */ + +typedef struct fore200e { + struct fore200e* next; /* next device */ + const struct fore200e_bus* bus; /* bus-dependent code and data */ + union fore200e_regs regs; /* bus-dependent registers */ + struct atm_dev* atm_dev; /* ATM device */ + + enum fore200e_state state; /* device state */ + + char name[16]; /* device name */ + void* bus_dev; /* bus-specific kernel data */ + int irq; /* irq number */ + unsigned long phys_base; /* physical base address */ + void* virt_base; /* virtual base address */ + + unsigned char esi[ ESI_LEN ]; /* end system identifier */ + + struct cp_monitor* cp_monitor; /* i960 monitor address */ + struct cp_queues* cp_queues; /* cp resident queues */ + struct host_cmdq host_cmdq; /* host resident cmd queue */ + struct host_txq host_txq; /* host resident tx queue */ + struct host_rxq host_rxq; /* host resident rx queue */ + /* host resident buffer supply queues */ + struct host_bsq host_bsq[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; + + u32 available_cell_rate; /* remaining pseudo-CBR bw on link */ + + int loop_mode; /* S/UNI loopback mode */ + + struct stats* stats; /* last snapshot of the stats */ + + struct semaphore rate_sf; /* protects rate reservation ops */ + spinlock_t tx_lock; /* protects tx ops */ + +} fore200e_t; + + +/* per-vcc data */ + +typedef struct fore200e_vcc { + enum buffer_scheme scheme; /* rx buffer scheme */ + struct tpd_rate rate; /* tx rate control data */ + int rx_min_pdu; /* size of smallest PDU received */ + int rx_max_pdu; /* size of largest PDU received */ + int tx_min_pdu; /* size of smallest PDU transmitted */ + int tx_max_pdu; /* size of largest PDU transmitted */ +} fore200e_vcc_t; + + + +/* 200E-series common memory layout */ + +#define FORE200E_CP_MONITOR_OFFSET 0x00000400 /* i960 monitor interface */ +#define FORE200E_CP_QUEUES_OFFSET 0x00004d40 /* cp resident queues */ + + +/* PCA-200E memory layout */ + +#define PCA200E_IOSPACE_LENGTH 0x00200000 + +#define PCA200E_HCR_OFFSET 0x00100000 /* board control register */ +#define PCA200E_IMR_OFFSET 0x00100004 /* host IRQ mask register */ +#define PCA200E_PSR_OFFSET 0x00100008 /* PCI specific register */ + + +/* PCA-200E host control register */ + +#define PCA200E_HCR_RESET (1<<0) /* read / write */ +#define PCA200E_HCR_HOLD_LOCK (1<<1) /* read / write */ +#define PCA200E_HCR_I960FAIL (1<<2) /* read */ +#define PCA200E_HCR_INTRB (1<<2) /* write */ +#define PCA200E_HCR_HOLD_ACK (1<<3) /* read */ +#define PCA200E_HCR_INTRA (1<<3) /* write */ +#define PCA200E_HCR_OUTFULL (1<<4) /* read */ +#define PCA200E_HCR_CLRINTR (1<<4) /* write */ +#define PCA200E_HCR_ESPHOLD (1<<5) /* read */ +#define PCA200E_HCR_INFULL (1<<6) /* read */ +#define PCA200E_HCR_TESTMODE (1<<7) /* read */ + + +/* PCA-200E PCI bus interface regs (offsets in PCI config space) */ + +#define PCA200E_PCI_LATENCY 0x40 /* maximum slave latenty */ +#define PCA200E_PCI_MASTER_CTRL 0x41 /* master control */ +#define PCA200E_PCI_THRESHOLD 0x42 /* burst / continous req threshold */ + +/* PBI master control register */ + +#define PCA200E_CTRL_DIS_CACHE_RD (1<<0) /* disable cache-line reads */ +#define PCA200E_CTRL_DIS_WRT_INVAL (1<<1) /* disable writes and invalidates */ +#define PCA200E_CTRL_2_CACHE_WRT_INVAL (1<<2) /* require 2 cache-lines for writes and invalidates */ +#define PCA200E_CTRL_IGN_LAT_TIMER (1<<3) /* ignore the latency timer */ +#define PCA200E_CTRL_ENA_CONT_REQ_MODE (1<<4) /* enable continuous request mode */ +#define PCA200E_CTRL_LARGE_PCI_BURSTS (1<<5) /* force large PCI bus bursts */ +#define PCA200E_CTRL_CONVERT_ENDIAN (1<<6) /* convert endianess of slave RAM accesses */ + + + +#define SBA200E_PROM_NAME "FORE,sba-200e" /* device name in openprom tree */ + + +/* size of SBA-200E registers */ + +#define SBA200E_HCR_LENGTH 4 +#define SBA200E_BSR_LENGTH 4 +#define SBA200E_ISR_LENGTH 4 +#define SBA200E_RAM_LENGTH 0x40000 + + +/* SBA-200E SBUS burst transfer size register */ + +#define SBA200E_BSR_BURST4 0x04 +#define SBA200E_BSR_BURST8 0x08 +#define SBA200E_BSR_BURST16 0x10 + + +/* SBA-200E host control register */ + +#define SBA200E_HCR_RESET (1<<0) /* read / write (sticky) */ +#define SBA200E_HCR_HOLD_LOCK (1<<1) /* read / write (sticky) */ +#define SBA200E_HCR_I960FAIL (1<<2) /* read */ +#define SBA200E_HCR_I960SETINTR (1<<2) /* write */ +#define SBA200E_HCR_OUTFULL (1<<3) /* read */ +#define SBA200E_HCR_INTR_CLR (1<<3) /* write */ +#define SBA200E_HCR_INTR_ENA (1<<4) /* read / write (sticky) */ +#define SBA200E_HCR_ESPHOLD (1<<5) /* read */ +#define SBA200E_HCR_INFULL (1<<6) /* read */ +#define SBA200E_HCR_TESTMODE (1<<7) /* read */ +#define SBA200E_HCR_INTR_REQ (1<<8) /* read */ + +#define SBA200E_HCR_STICKY (SBA200E_HCR_RESET | SBA200E_HCR_HOLD_LOCK | SBA200E_HCR_INTR_ENA) + + +#endif /* __KERNEL__ */ +#endif /* _FORE200E_H */ diff --git a/drivers/atm/fore200e_firmware_copyright b/drivers/atm/fore200e_firmware_copyright new file mode 100644 index 000000000..d58e64908 --- /dev/null +++ b/drivers/atm/fore200e_firmware_copyright @@ -0,0 +1,31 @@ + +These microcode data are placed under the terms of the GNU General Public License. + +We would prefer you not to distribute modified versions of it and not to ask +for assembly or other microcode source. + +Copyright (c) 1995-2000 FORE Systems, Inc., as an unpublished work. This +notice does not imply unrestricted or public access to these materials which +are a trade secret of FORE Systems, Inc. or its subsidiaries or affiliates +(together referred to as "FORE"), and which may not be reproduced, used, sold +or transferred to any third party without FORE's prior written consent. All +rights reserved. + +U.S. Government Restricted Rights. If you are licensing the Software on +behalf of the U.S. Government ("Government"), the following provisions apply +to you. If the software is supplied to the Department of Defense ("DoD"), it +is classified as "Commercial Computer Software" under paragraph 252.227-7014 +of the DoD Supplement to the Federal Acquisition Regulations ("DFARS") (or any +successor regulations) and the Government is acquiring only the license +rights granted herein (the license rights customarily provided to non-Government +users). If the Software is supplied to any unit or agency of the Government +other than the DoD, it is classified as "Restricted Computer Software" and +the Government's rights in the Software are defined in paragraph 52.227-19 of +the Federal Acquisition Regulations ("FAR") (or any successor regulations) or, +in the cases of NASA, in paragraph 18.52.227-86 of the NASA Supplement to the FAR +(or any successor regulations). + +FORE Systems is a registered trademark, and ForeRunner, ForeRunnerLE, and +ForeThought are trademarks of FORE Systems, Inc. All other brands or product +names are trademarks or registered trademarks of their respective holders. + diff --git a/drivers/atm/fore200e_mkfirm.c b/drivers/atm/fore200e_mkfirm.c new file mode 100644 index 000000000..10e972840 --- /dev/null +++ b/drivers/atm/fore200e_mkfirm.c @@ -0,0 +1,155 @@ +/* + $Id: fore200e_mkfirm.c,v 1.1 2000/02/21 16:04:32 davem Exp $ + + mkfirm.c: generates a C readable file from a binary firmware image + + Christophe Lizzi (lizzi@{csti.fr, cnam.fr}), June 1999. + + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. +*/ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/time.h> + +char* default_basename = "pca200e"; /* was initially written for the PCA-200E firmware */ +char* default_infname = "<stdin>"; +char* default_outfname = "<stdout>"; + +char* progname; +int verbose = 0; +int inkernel = 0; + + +void usage(void) +{ + fprintf(stderr, + "%s: [-v] [-k] [-b basename ] [-i firmware.bin] [-o firmware.c]\n", + progname); + exit(-1); +} + + +int main(int argc, char** argv) +{ + time_t now; + char* infname = NULL; + char* outfname = NULL; + char* basename = NULL; + FILE* infile; + FILE* outfile; + unsigned firmsize; + int c; + + progname = *(argv++); + + while (argc > 1) { + if ((*argv)[0] == '-') { + switch ((*argv)[1]) { + case 'i': + if (argc-- < 3) + usage(); + infname = *(++argv); + break; + case 'o': + if (argc-- < 3) + usage(); + outfname = *(++argv); + break; + case 'b': + if (argc-- < 3) + usage(); + basename = *(++argv); + break; + case 'v': + verbose = 1; + break; + case 'k': + inkernel = 1; + break; + default: + usage(); + } + } + else { + usage(); + } + argc--; + argv++; + } + + if (infname != NULL) { + infile = fopen(infname, "r"); + if (infile == NULL) { + fprintf(stderr, "%s: can't open %s for reading\n", + progname, infname); + exit(-2); + } + } + else { + infile = stdin; + infname = default_infname; + } + + if (outfname) { + outfile = fopen(outfname, "w"); + if (outfile == NULL) { + fprintf(stderr, "%s: can't open %s for writing\n", + progname, outfname); + exit(-3); + } + } + else { + outfile = stdout; + outfname = default_outfname; + } + + if (basename == NULL) + basename = default_basename; + + if (verbose) { + fprintf(stderr, "%s: input file = %s\n", progname, infname ); + fprintf(stderr, "%s: output file = %s\n", progname, outfname ); + fprintf(stderr, "%s: firmware basename = %s\n", progname, basename ); + } + + time(&now); + fprintf(outfile, "/*\n generated by %s from %s on %s" + " DO NOT EDIT!\n*/\n\n", + progname, infname, ctime(&now)); + + if (inkernel) + fprintf(outfile, "#include <linux/init.h>\n\n" ); + + /* XXX force 32 bit alignment? */ + fprintf(outfile, "const unsigned char%s %s_data[] = {\n", + inkernel ? " __initdata" : "", basename ); + + c = getc(infile); + fprintf(outfile,"\t0x%02x", c); + firmsize = 1; + + while ((c = getc(infile)) >= 0) { + + if (firmsize++ % 8) + fprintf(outfile,", 0x%02x", c); + else + fprintf(outfile,",\n\t0x%02x", c); + } + + fprintf(outfile, "\n};\n\n"); + + fprintf(outfile, "const unsigned int%s %s_size = %u;\n", + inkernel ? " __initdata" : "", basename, firmsize ); + + if (infile != stdin) + fclose(infile); + if (outfile != stdout) + fclose(outfile); + + if(verbose) + fprintf(stderr, "%s: firmware size = %u\n", progname, firmsize); + + exit(0); +} diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 5208fd62d..84bdda6d6 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -2359,7 +2359,7 @@ __initfunc(static int ia_init(struct atm_dev *dev)) { printk(DEV_LABEL "(itf %d): can't enable memory (0x%x)\n", dev->number,error); - return error; + return -EIO; } /* * Delay at least 1us before doing any mem accesses (how 'bout 10?) @@ -2499,7 +2499,7 @@ __initfunc(static int ia_start(struct atm_dev *dev)) printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+" "master (0x%x)\n",dev->number, error); free_irq(iadev->irq, dev); - return error; + return -EIO; } udelay(10); @@ -3074,7 +3074,7 @@ static int ia_send(struct atm_vcc *vcc, struct sk_buff *skb) { if (!skb) printk(KERN_CRIT "null skb in ia_send\n"); - dev_kfree_skb(skb); + else dev_kfree_skb(skb); return -EINVAL; } spin_lock_irqsave(&iadev->tx_lock, flags); diff --git a/drivers/atm/pca200e.data b/drivers/atm/pca200e.data new file mode 100644 index 000000000..e78e83bec --- /dev/null +++ b/drivers/atm/pca200e.data @@ -0,0 +1,850 @@ +:150000001F8B0808AB5A10380203706361323030652E62696E4D +:150015007D00E43A0D7014D7796FA5BDE84EC86211A7333020EE +:15002A00AD89C00A23EA83AA589C7E7C38D8152EB887477677D3 +:15003F0095C39C3DB2AB388CA324C4A509352BFBB085BBD0C73F +:150054007210B903C92991CCD1B1C242255BCCD81EA5C34C6826 +:1500690006271AC6D36A3A31B976D4A9A683DB4B07BB38265C56 +:15007E00BFEFBDB7777BA7030B2733994C35737AFBBEF7BDEFE7 +:15009300EF7DDFF7BEF7769FFEEAD79F221221E1ED844C3E4677 +:1500A8007EA3BFF036F827CF8597C3AF0C7E920B16595BCE5AA8 +:1500BD00296B6483D83E9F7DBE8FF50BE74A0B45FB1F274FAA79 +:1500D200D82E2867139DF637FD937EF1D55FB0769FE8678BDAFB +:1500E7007D9BD8885451515172FE27E4138E9FC9949CBFF026BC +:1500FC00741DF83ECE59823FF23BF89346493F6B4F17C1B3A7CE +:15011100B3B79C97D3275B5ABFEC3CF9579457703B3CBFEFD600 +:15012600FC38236CA91B5E347EDBFA67F7ED4397956EA4D3C5F4 +:15013B007CE6A567799EFFF5CFC4FF7BDF938BF83E83EDE59F02 +:15015000FEAC24BF8A3C3F2FF9FDFF933CF51EF2FFEC2FEBFA11 +:150165002341C38CBC5F4EAA265F5EAF04BC51F0059FD1419ED8 +:15017A00063493D465A2384E66A0171C30231F40AB5CB5646FC8 +:15018F005CBFB633DECCC614D2DAF622F15D3189EFEA3EE28B83 +:1501A4007D99F8DABE4D7C2418A438AF3129015D7507F1032EBA +:1501B900E174827F46C82229AE2BC63A9D50E9253960EC005FCA +:1501CE00F2EDFE0AF12A9D5EBD6A35F1B5AC441A49BAD94F22C6 +:1501E300DECB544F180D1A51FACD8C4A7C034B93DAFD6455A8F9 +:1501F8009AAC5AB74C9542EF11E23DB0946A0F1B0DA10BF0CC0C +:15020D00F9A4A8097BCA1D751474A02FEC02593C75C9E870D176 +:15022200B8CF352EC3783C379E1C2893C98017C6A57B3CDD0E4D +:15023700CE32426A9CB99F03FC2E81BF46AD0D06544FD0190B08 +:15024C00C0580B8E897EFDF490DE08FD652E9CFAE911DD5F24FE +:15026100CF832469DAB1116BE0F3C437B686F8D275C437AC9220 +:150276000542BFF6CC0320B22AB7237E1F5B97A4E927A397490C +:15028B0064C43AFF0CD8ACCE8886D37F632A7F4C16005E289CAF +:1502A0003E491DDAFB083513C6B0A6B8E4929626F531E0877479 +:1502B50082E58C9E2503DDD45DC4777E3BF1051F253E09684E42 +:1502CA00C3BAC26825AC39F5225F6598EE23B366227C52ABFC3A +:1502DF00BC2754E61BD1FFEBAE6DCDFE8D49AAEA38EE89A35A1B +:1502F4009DF0DCF4254234681BBB09E98536033F2F3C5F835F24 +:15030900107E147E1AE8AA0406A36989DB63C95ADE9F9272EBA7 +:15031E00C17C6131AC4519193457028723BE118D0433D6F063E5 +:150333005C6E1C77EC2981FD118663B2FA3A455F8D11A2D66BC0 +:15034800AFE9B096E6D4A38454D70D004ECA8235541117C7A5F2 +:15035D002D26F8E4B07D3848BA956402FC7BF8EC956CB6B6D35F +:1503720091EB21B280C218CAB04122B5957583D126189B7D88FF +:15038700FB2BDA46560F52056C867C6CE85FF1135F19E0C948D1 +:15039C0023873342916798F3A6E45FA58C9021887DB9A8DF9307 +:1503B1002EECF7421F693AB054DE6F73F4FDF414E83A6B66B2C0 +:1503C6000B11C3BA0E45D0D1074E3318C92C24FE074FF267E847 +:1503DB00E03AE67193D635C40D9FD66A65B471CABA5AC66D9C17 +:1503F00081B68DE4F5200AEA316B3E3EF5F8D4CAF0C902BFBC6E +:1504050003FD12ED00BE39F8E7C4E765F2A6F8BCC8083DA6B648 +:15041A00335DAAA0AFC4DEA66A6CDC8418EA26910FAD6A0821BE +:15042F0012B4A9C269D1DDAC9DB05A98BD06B91D807702D6021B +:15044400F02CA479BF88CD3D82BE3F92D49137C262E0EB5969BB +:15045900D6AC8DA4F4A3A0EB808FEB8570E6F34897F9F77CE4C2 +:15046E0071E4E07C73F2C0FC256AC3208B2D5C834D43BA3F060F +:15048300F39566B386103FC611E321E23D02F1168A79426C3DFD +:15049800E159DA32AAA34C083FBA62DC2474847A94BF031D86A2 +:1504AD00ACE5EAEB969CDC4FF3F3216F03DE5414FD8ED3DA3050 +:1504C2005F5AC953795A804F2146D05612811C0DB6A0BC0E67DE +:1504D7007C6E471FC3A5CFA04B06639EFA201E11FA182E7D3E53 +:1504EC009556913E89227D129F511FDBA5CF05970CF63CF54199 +:15050100BCE097B83EB64B9F4FA555A4CF60913E839F511F752A +:1505160026AF4FCB4C5E0684CF471FC48B75737DF079C37C69B3 +:15052B0015E973BC489FE32E7DC231AFD997FEF15925301975DC +:150540007CBC5E33F5D918F2E53E82FD69D1B745FF82E8237F22 +:15055500EC4FB07ED2A4626FD8C3F7363321FA29D11F14FD6938 +:15056A00D13F2EFA9D40678FFA1ACBD131181B507F88FBA8451E +:15057F00E179507D8362EC4FC2734A7D8786D5D526CF431356CC +:1505940010E6D51152BB2CE6690F243DED35694FBB17D6017487 +:1505A900B251C766F514A3D3037337AB67189D043C77A9E728AB +:1505BE00CE3FCFE5A0C8B347ED17F9CDB09A812EE4A09AFBC861 +:1505D30005F3ECCE1F76B0B8059C6AD51342D87777BEC16093F7 +:1505E8002ED82B3BDF613094C9813DB7F3A50E87FE6A95AF1F58 +:1505FD00D259C69E53B447F047991EAA1FDDE8D0747091968332 +:15061200EBC88AB2D5095CA4FB07AA87ED030961D37494DB348F +:15062700C27225D77D497EBF32958271CE6F8DA0D12CF612E37F +:15063C00718ED32568206F3FDF874C7B477EAC4DD8310AE35B40 +:15065100C17E683B139EA3EA6178A6D65B4CA65926E72EF555F4 +:150666007A82D977D06A9A610E58F3D80D4F6BFDF4DDFAC37506 +:15067B00E7D67D672AA93DD881720C301B55C6E4D0860EB97506 +:150690007D5DFF3A0A636BD898CDE4AD4C7A42CBDE915B037587 +:1506A50087D7593056DDC1E5477B55429CDCF8B5DCFAAB15AFBD +:1506BA00AE3B0263FFD3EE69AF8C5584FEF3FD0FDA90E6BFADE7 +:1506CF0030DB70FEBF9C186B43DC4BEFBFDE4682BD8C27C86F5A +:1506E400B3BC185CC264063DED086BF730DA2418B655D6F63110 +:1506F900394850B53126EEFCD1AC2EBD1B83F83B6D56056C5662 +:15070E0027F079B3565739DFC3A2AC8D591AB48B37FD4097B6BD +:150723007D4527CA41F38E00D6C48665887A30CEDA5E6BA09CE8 +:15073800EF7568CF8A7EC03FF80DC05F6B56078280AFB25C86D9 +:15074D00F863ACEDB32658DBC26CBEE04780FFEEB7017F9BB98C +:15076200301001FCB0C5E54E5A0DD0BEC8D6618FD53893DFDBC0 +:15077700489D0A781A5B9B27616DFAD4435409C08E179C365B01 +:15078C00B86D2C5EB34E5BCDD0CEC0B98106CBBA25A29A87AEC7 +:1507A100676BD0977601BC4A7DCDC2BA15ED575E1DD7B78610CF +:1507B6008FC715EE954F0A5CB4B78837139F9F079E8AEFA21E32 +:1507CB00DF9814679714AB9163E99F59FEBDE3263A704FFA4DF8 +:1507E0000BFAD400D9FCE1115DF1C541C7772D591DB7BA1C7929 +:1507F500D4BBCC1B9F701EC761BE22E4A1429EB736E6E5C1BDA9 +:15080A00EE92C09D74C933790B79222E79BA401EE8535A429E39 +:15081F00F3ABF2F23C2B785CC43812F24C0A799A5CF2E05E759D +:15083400BFC0457F73E4C1E79BC91376C9B319E4813E4D9690D5 +:15084900A7D925CFE55F711E6D33B8A771799007CA73BC252F86 +:15085E000FEE3567392EE35506B935DE3E625D87B3AC9363DDC5 +:15087300675D387B325FEEC53DCA370CF1D064D2707F1F9E1BAD +:15088800BCCC7732962CFCB60AF76B17AFD80C1694A4D6EBDAB7 +:15089D0047E58DFC1CEB75E1E10563311E21B6794C95704FA00C +:1508B20031EEBF8BC93DD0270326EC0F8A54674771FCCEF0B040 +:1508C7007E67F81CD864D8EA401CC819480FE1811DBC76E5FDFE +:1508DC00733A83FDD508D6AA24406D9DCF3FA75FCC66FD65D592 +:1508F100FDFAEE7BF332F5F0FDC225936D769033AD01550A3A24 +:15090600BCF12CBF86F184F305E007567C68E59EDB3FCCF1498D +:15091B00D79F692B73E8803CC25E4CAEDA152370463A4A2DE42F +:15093000AB34998BC0DE1BD01C0AA7C5715314ED0FC74F4B510E +:150945005ED2BDC9319893001F18B3A2AE734B17D4E2CFA89EB1 +:15095A00D6B7245E6394E2F350520E95A6DD6079943780F65B70 +:15096F00507B1C857AE36D0B6B12491D8133EA88E6D41A72B92A +:15098400A835607E52D421448C255D7548EE0F723FD656E84744 +:15099900CA3D28974DE33C4751AF90CFEB9603D61BE545BA8197 +:1509AE00906D2A44D446CA190BE550DE5F85B273DF637264CCC1 +:1509C300C15E487501388B928C8974B4ED9C4E8FD80F395D9B32 +:1509D800D9A7F6FDFD5482B3B6141B358F92514D3A30CEEA2EE8 +:1509ED003EC7B6108744E478BE6ECB98555F46FA54D0E77A23D8 +:150A0200FDE876AE1FE7932AE0C3EC226CC2EC98E676BC7347DE +:150A1700DC0A446C361675F3A48267306C72595A4C85D9A5D310 +:150A2C006467AB60D0E4761AA00C1E19A6CFDE057584F27DAC4C +:150A4100810A64F09F5845DD6B073896ACC05936324E1D3FC1D0 +:150A56001C843796C7485C2391FD168998CC2EAC0E807119F419 +:150A6B00A52D86899716E555719D1E5CABF77860FDA686D87D2E +:150A8000881FD74839ABCBEADB34C06AE6FC196F49F9DC3367A7 +:150A9500FF9653FCBCE83E774E9DC198FD9433E7203F734E0EF2 +:150AAA00E7CE9BECEC19F9BEE5F8961C30A2634DFCFEA0D0B70D +:150ABF00B82FA14CBDC23E6C6D4249E6574419B2081DA247F1E2 +:150AD400AE02FC0A7D81D9CC00FA74C84ADCC82E72F9336B3524 +:150AE90075186487D8A757CCC5B06FE37D56B5BAAAF912D674D6 +:150AFE0012F13EA3AE0D5D83985C9FF6B7B3DAEE31CEB713DA06 +:150B130045E420F33B90DB12700BE117C47D4058E0468A700568 +:150B2800DC42F87111EF0EFD1E316777D11C01B710DE2BE8F75C +:150B3D000A5CA30857C02D84B709FA2B05FD06818B78F8BCDCC9 +:150B5200956F1A5D63F88C67293C4379C18FCAAB46C037862CF0 +:150B6700B497ACBCA2E37A07D5613B00F6AA091FED901553AFF3 +:150B7C00EDBFA257A9A7AC65C6076D814DFFADCBB131EB44D2FC +:150B9100D3ED8D9966269B5D0C355EAB1CBB62393E5B09B92DA1 +:150BA6007D3DEB73C7C0B7A0CE95599D4AE7C4A388AF5C5E4121 +:150BBB001ACAA1213D513EACA16C353B1A2C279ED9DA634E30EB +:150BD0002027A4DFC63C22E273C22A8E67F405C61362C61D27AE +:150BE5002FDE11D7C365DC0F1591D33E2D4E5E82FD3B17230768 +:150BFA008634CC078AD84F31565642CAC2B3E0D3AC9E17310500 +:150C0F00F1F318F89BA8DF73B0FBC5B9E2E6B1D4226269A8F448 +:150C2400FD8D2B9E7ABEF0DBCFD57473E2296C3D2DEC7EBCF2E1 +:150C3900AE00DF13950DDEA802CFB7FA713CC25A35E0ECA52AC3 +:150C4E00D412F544A96ED2E3655F78CA23E0B4C678CA19C73BC6 +:150C63007A25DCF084ECD008279EA8719E37E5E1B9FD8ADDB182 +:150C78000DC0764CD423AADC4D73B519BFDF7C84EDF7B3589BA5 +:150C8D002978178F2324729206D4F666ACDF181C6C7FFDBEF62F +:150CA2003F04FFB4091D3E8BEDE2C8A08EF7A1481361354A427E +:150CB700BF0075C79CFD52F0EFBA09FFF58CFF80C9F2281DB6EB +:150CCC00918E943ECEE946809780E173BA047D6A637DC3E9E326 +:150CE100FD30D41426ABD5A0BF066353F5B7AD57AB426111E732 +:150CF6002175793BD0A435CA01DD9101E36E51513FF72CF85916 +:150D0B00533FD0D6AB0F846AD4079A03EAAAD056276FA94F71C2 +:150D2000DA82A6E43B3E87AEF48FB786AD4E2F6F75EEA36584E2 +:150D3500837D8F64208743DE10F7CD8B56A7E5565C0F7627CD82 +:150D4A0071E811C84132E2404C200ECA9A85BA8E1AFB35425244 +:150D5F00980BCDECDF9F97C1AF71CF55D02E2C2EA660BF823D2D +:150D74006135190E61FC6476BEDEE1BEA7FD9C787F107F84E908 +:150D89005860EF2C9930495D2A9AA76D08DAB6C1624F81FD644F +:150D9E0072445B638C94A45D2168373E42BCEE7D285F5F65CC2D +:150DB300E4D7B03E3172F5C9FCF381CDF301E856321F28AE3A51 +:150DC80028771E688C4A5BD641CD07B107B58A72379C210E6DFD +:150DDD00D477415EF648712D0AAD1C4846132A3F977C1772DDE5 +:150DF200B1E4C7CDE4EA10BDF6B5FC7B8D3D5FFFDDFEA623C476 +:150E070037F149D60767196DF37D72BB73D787F76764B77176CD +:150E1C0012DFEDED4E9E9D62ED24C612B4E9B319F6CE0FCEC553 +:150E310060A795E28EC5592B49ACD55EA03DFBA77C1F408D2F19 +:150E4600C19925111ED61AB1FD22D431CC768DCC76686BC46913 +:150E5B00025948755C5BFE89B05F4C62F603E3079A805E15C03F +:150E70007F7E9F7C2F5BCFEDA2BE82166B17AC59900EF6BB59E8 +:150E85003D95F781473ED50706C49DFE70491F5072FB7DC6422E +:150E9A009DC136B6B08D2D6C630BDBD8689B72C8E56E9F99AF8B +:150EAF003DF1DD13D451C14A757F10CEF8BE3C6C2DC00E06535C +:150EC40005B03F02D8D1E09803AB42582DC056042711C6EE3D4A +:150ED900B87DDFFB18EC09763DFFF15CBBBEF730F18D7D8C764C +:150EEE006DB877BE7ACD579F7809FF2813FE1105BE17B615CA1F +:150F0300D922135F23C8E20159979490B511E67899AC4DF7DEFF +:150F1800CE1ACC57DEDE12F2960B795F0759976C9BEBCF06FAC8 +:150F2D004B095F8E5DCBFACA408FC8B5B97AC4804EF81AEAE194 +:150F4200BFF7767DE976F4E929A18F2CF4F9F956E2EB84DF675D +:150F5700E1BFF97F4127B5812A6A1365EFE620074AB029B701EC +:150F6C001CFB32E934357C0E6AA60AD659AEEA96A26EFA5B76F9 +:150F8100970E79676B6C88BD2B8E7D53DCF73CC76A5433FD0D60 +:150F9600A89D643847E33B55DC9401EF62EC9455F5C419EBC295 +:150FAB00479C3601BAD9858639057D89F7BD631F15CA33267057 +:150FC000DF83B68B244DBFCAF9118DF3433EC8CFDE5DC86F3932 +:150FD500E0553D71CADA0AFC3441837EC4F9C5043FE87BDDF609 +:150FEA0054843DCD3FE1EFB8AF3E440AC61789F15D62FCBDA29D +:150FFF00F11A31BE558C8F158D2F16E34D623CC1C63366D79E29 +:15101400FC793F0B3A5202FB37ECD5DEE52452707687BF81A5FC +:15102900B646E14C41EA923BF0AC5963EC5F87EFF53591D70ED8 +:15103E002C9DD53AC22F873A5DF7E92F4C3CF113B4D573BB2F35 +:1510530075045DF0CBAFFEF57584B7EEF84987FBFE7DFA8D6F83 +:151068009D40F893FFF0E30EC2BE871834E3FFFC179BFC0163E8 +:15107D0047B297F8269F24BE3972BAEE17827F59B87FCB380E23 +:15109200F9167388548D39197231C24AECC74EAE81B351FBEE40 +:1510A7002DE2DE07700F6C19D52A638F065F811671F66EE7672C +:1510BC003C1C73CE320C5644AF8EDFF7F1EF332E0FE8F683F8F2 +:1510D1001D01FB1640C47E8ADD2918BE51B6571056CB2419BE69 +:1510E6005F39CDEE52768B7B1784A9EA283B4BED71C18202D67F +:1510FB00E7823509D8DE99FCB707866B1CED4B26086954472D8C +:15111000370CBF436C2882554932692E84518A67BFD838550E10 +:151125008DEA2D3826F4C6EF6508BD9BD99D8AF91FDC58F453B2 +:15113A002F9B9FF345D18A7E649C4A07F09C0338ECFD3DE713EE +:15114F005647E93EA827B19EC2F3EE65F0B7441FE9C6F74ED3D0 +:15116400397FE1B66DACE2760DA74FE6E40CA74FD3FE2DE3DA2C +:151179006675DC72D37C79E98086FB33D28C15ECEFA3ECEE6226 +:15118E00AB80ED1132EE113206605F6732E27B2576864DE1DED8 +:1511A300CF6A05B6F78BB51C106B298B6F2998CDA06605DE16C5 +:1511B8007EFF9280338317CFA17866127A7845AB14B5176F64D1 +:1511CD000BEA546EDF93EC5E0EF76903F4C3332E3E3B30F2F086 +:1511E2005C58991BC6EAE794D509272B493C6F56381C6C66A124 +:1511F700DD6A33CCCE0143C8C160013B1AD89812E727389FC223 +:15120C009C5A03D60DD688B591717321D2A3A356297C52029F42 +:15122100E4F0DFE4F605183C5B7B9DCFF944FCBD20F4E4B19C55 +:1512360062758BE4E804CF57A514F3F7A03F3FFEF296FCB8034D +:15124B007BA9044C7E782ECCE386B9623AE7DF22A69C7875C78E +:15126000727F512C633B25C66E36C72831C7196BC4F68BF9B97C +:151275009590BB8DBBC902278FA04D5E747C0E9EEBA7E37AAC39 +:15128A00687CC1E594CE69A4CC1648B68998A71B7CAC06F7016D +:15129F0073733E27A17F605C38637DEE31F6ED1BA7C35A178D76 +:1512B400CE221A8E0DB80F7298510C037A2F38307F1E66948027 +:1512C900555617C250A7FD2E9D1D58BC04ACBCDA0D334CBB4EC1 +:1512DE0026E1D5C23EB08F60CEC0B8F483CF634D85DFE4B17ECD +:1512F3002015AD75BD4B225584BD3342FFF533FF1D311D3FAFDB +:151308003C84DF1BD87400BFB50BF35C568A8672DB34600CF7B2 +:15131D00176514F12C2D1717498AF91CF3E12ECC25D0C77907C1 +:1513320097A634461F7DC54F6829B8E2829B6EFC25A5E10AC018 +:151347007B9DEFDEEA788E75DB6BAB74137BF94BEBBAE0B20DCC +:15135C0067E4D1BE83504BB03C301FBBFD1669A19EB75A03F3CC +:1513710076E4FACCB40AD7D51679DED9AB793E2EB475613E2E11 +:15138600210BCCE1B2A44CD602ED85480F6ABE927628814F729C +:15139B00F885F2ED75F91DC6AF543D37BE49F5DCF82EAB9E1BB7 +:1513B000CBA404EC15DFDCF8F654CF8D65B90886F847DC73F32E +:1513C500EF3C2B79FD8531CEF706B469BD6BEF83D6D825BEDF9F +:1513DA0020AEBD50291A935D63FEA231AF6B6C49D158956B6C58 +:1513EF00B922F611E52D4A1493CAEA307BCFC4BF63A4F41A6BD3 +:1514040007E9F532BEE765581B34A1A82072F5889E30C635FCEE +:151419005676B13CA21F2B1FD78E854735AC55BE639CD3BC1730 +:15142E003FD0192E201F360E68CA5653AF81BC5CE97AFF8BDFE1 +:151443008FCAE638833F17AB0ACDB8D613DFFBFFD37DFC7B9AE7 +:1514580058EEDB1B80CFF0335F65F2D7CDCB92DFC4EF4EC4B7BF +:15146D003313ECBB277E5F3EC1BF8D080E50FEBD0C1538830C25 +:15148200A7D7F57E03DF9F3F2BF84CCEE17347011FFE7DCD0460 +:15149700FB7ECAE1630B3E5D820FC719345551A725A13D119479 +:1514AC00BA2B0E8DE8FEF02AFD353C9FC4EE6E0BC42A425745A7 +:1514C1007C5D8ADD139A85672FD8BF5E8BEBD433DA5719F3B4AB +:1514D600E33A292ABE8B033BBE097935297577A9A72C388AD66C +:1514EB00C8CA5A88EB03B42E7CB0ED30665CA5DFC46F5D37FF53 +:151500003B9CEB22BFB41AD45F5ACEFBE836F58015560F5BFEA9 +:15151500F408FDBFF6BE3E3A8AEBCAF355AB5A6A498DA816ADA6 +:15152A0046C2209588708447715A422648964C43182F78306934 +:15153F00639CAD12C26EDB644C1C26A3DD61E7704E58BB255AC4 +:1515540020E10729D548462638B4B064E30938322B123C47248E +:1515690062E275F02C61B48CC390C4269D19C626332456BC4A65 +:15157E0086CD38F4DEDFABAAEE9210FE9839B367FF58D5D1A9A8 +:15159300EA57EFE3BE7BEFBBEFDEF7EEBB657887B6D5087BF17D +:1515A800081FA63A83A941B22B5F3491CE945E0EDF6E779BEBA1 +:1515BD00BF3ED0EC2E5FA1FD996EDA75A02C9E5157FCDBF00DF9 +:1515D200AF6E8D4C2B5F4CE523EA336693FA8A5DBE77C6F2D17B +:1515E700E31818D5AD80254CEF6AD47623AC7673ACFB9A2CD1D0 +:1515FC00A6A93F37BD12FC228E7293F5B5C9B184594CF2CC8307 +:151611007DE9E8A0E98BF59AFED8A869EDDBB8F9F8A4CDC7F152 +:15162600297C9CE1DFB1214D71F16F51CCDB98E151EC1B61AFE5 +:15163B008478348FE466095BA45B7DABB6FA16196876F3735093 +:15165000ED364231F94E6BBFC1E0F0E51DF97BAC8FC45BA1DF9D +:15166500AF6E60F987CA929AA22E16B459053AC0F5491D31629D +:15167A00EA5123A26EE04A68756B1FE9A75864EF1B7F41737C57 +:15168F00777BEDF1DB6FF95B14BBFD285AA9BF3945A7743575DF +:1516A4008C67CB1C31B9ED0FE7E415FB9AE349AD9878DC5D3E9C +:1516B900AAF61A1BA87D8DE0D0D483F47FD56853AB8CED6A8D70 +:1516CE001157EB8D2EB5C930D45544BB477493FD595B754AEC79 +:1516E3009FB6F553FEA43A6A1C51B9D1F7EC515EC28EE97336A4 +:1516F8003DCB17BC759527367D92772E58CC776DAAE5BB9F6D89 +:15170D00E05D6FADE04F2F38CEB166F2B91FC0892426ECBAFDF3 +:15172200CF9EE2FED387F59EB7F6F262B677A91B2E3205F38BA3 +:15173700D455CD99B46807AF92587EB13B4D74A083F39BA4BF13 +:15174C0071217D43BA16EB3032FB606FDDF89E191DFCFD821912 +:15176100EA235E1B79279D5F953C6C88B1053FE0CB37DAD7F014 +:151776008388129F788B3A85AE7290F2BC1FCCFA9DF8A6FB9DCA +:15178B0010AF1E14B65E3B7C7A4CE13F4D63DF4B32A32F49FA86 +:1517A0006CD3104F596B5EA6DF3A5F31A744D87D9326DEAB6A39 +:1517B500027BA94167BC63FD5E8B55124FE0EC483B8FBBDA56CD +:1517CA0066F0C3F1C5A85D3127C44DEC57F6A9528B323AC0AF33 +:1517DF00D96D627F734A9BF4DE37ADCDE9FB071B5CED3357FB1F +:1517F400EA0CEDCBAEF6E7CFD07ED5C76C1FFE3589863077601A +:15180900010C3BE65830CCA7B6A6B7AF8CBE28DA526303A46BCC +:15181E000CB732A5D384EF8F4CB67188DA9D1F1B309E5EF06B13 +:15183300E1D331E9F6F371EDCFAC7D2AEB3F22E52774A9ECA464 +:15184800BE7EACB3D1B78E0B5D46B92FA995EC18E1511F8B60C6 +:15185D007C96EC18E4317A866F01F21B296F0B337E6D62EF18A4 +:15187200699E6969D4D712C77F24188AB5865929DFD939B88DCC +:15188700190F70F08FFA790234A4B5FACEEDA1F64EF292D096AF +:15189C00D6B93B8EF208B5118C5B3A33F2083F10E3707FF1B807 +:1518B10021F67738C13277473D27B9DDD6B177ADF0F3098696FE +:1518C600B576DCFB29FD3CE1E9B598E74ECFA5FF20CE4084AD8B +:1518DB00730562BF0D739DBD9F2CF6434331A9B94059AFA36E52 +:1518F00094654A3397A5C37AA7381BF0B258170EC2C732BA3C2A +:15190500B35621C717E9589F484C785A426F35F0D08A7B74362A +:15191A003E6286562CB6FD5AC4BA96B557611C3597624F3D3A72 +:15192F0018BF4DDDB4043693D88735068633FFCA603C4875F9B3 +:15194400F32BF52BE974E08DE57AD3E34F7A9A1C5A5DA0BEB02D +:15195900F0761BEEB69BC2EDB954A1CBA79337C21E5E6686ED09 +:15196E00F593E9F04346032FE883D59719FA30FE0D731DFA6039 +:151983003C175F29FA10113028D1B80EF80D35A70577C08F3B83 +:15199800F15EC92CCC25E37BF8E0EFD285428F540EC7C7976FC2 +:1519AD00AA1FA5BEADA2BE39EF77FCCE75D410FE24048BAFE8E2 +:1519C200A8E085B93B4EF00999C598B16838A00CEA993335F4F6 +:1519D7005B8D25E8FD31FE3EDEC37710FB414A3B6C06E386DFF9 +:1519EC006E7FA97D597EF71525048FB3FA041F233316FB9D6202 +:151A0100BF69D883FD6A137BBB57D3E950D6FF89C6CBBFB17C5F +:151A1600625F767D5894CF961DB6FF8DCCFFB4F5E2B6988F27FD +:151A2B0053DF3715E2733535305C1CDA4EF56CE1C154A5312B41 +:151A400095D3B22AB5D80884DA88DE63A2CE10CDC92CFAFBFC5E +:151A55003519FBF21A87AF8EFCFA2384C752BE16FABD021FF809 +:151A6A00A8F0B5EA8DD7697F1EA96DBE47F5349FF75EE1A1C844 +:151A7F002797826E1BD2E9C249C9B193BA8D3CD02D2AEF32DA11 +:151A9400E013B89683D6C85743F9CEDAF9C2A91554EF6A739572 +:151AA900C573C38286F6BD26760FEF16FB8295246F5682A68619 +:151ABE0045C3A9F70E09EB8657787A391C7107881F3FAD4DE607 +:151AD30058F517F101FD41755663B13AABF6A5CA924673E18293 +:151AE800C657F18EE018BC9E2E5CA84A8D024E85F4B072A3D58F +:151AFD00C7FAF9E51FA7F333E7F1C60F5B7B8DE387CD4365D585 +:151B12001AF58C63BFABD7AE9FCA37A32E8DEA72F23AF9B6524A +:151B27009E7D6B06B45D34C6D0875B49E64D6F6BFB8FAD3D8A0C +:151B3C00522AFFAA64C185737B5D180BE37163BE7F500FFE6E98 +:151B5100BF8101BE3AF5A2619DD34A3333F282D647F5CEF3D710 +:151B6600E8A42B97C0D7BC865DE189C837DB70F62E89B1BB66B3 +:151B7B00B16E12AD72D990EE25FEC7DE506364A89129CF59B491 +:151B9000B1F5378C6159F0994A70455A05FCCA73E69B3F4AE70C +:151BA5001FF558FD5C49B46E9A81A6B751DBD3FB34F8A3B4D82E +:151BBA0013443D5BEDF2F36252A3779C6440740FF7F8137A2424 +:151BCF00B59F375D4AE73B6573699CE02CDDA88D779CE714B2F2 +:151BE40080F0E0E4E9A777E2D9788AC77F98B6CE3F529E37DF4D +:151BF9009F8A7BF0E04CB012FE4B4A53ED46FD050BE783D3CA28 +:151C0E008D02FFE07371566D0F77708D3371AB530326C73E7BDE +:151C2300785ABF5957A6DF472F5AFD06ED515F1BD55763D34CAD +:151C3800F0E6A0C59BF04B97D6FCBE1EA5F7B73AFC67D3C2C2FA +:151C4D0063B60EEDA2056B1BF1C4C8BF583C31CF5FAF8706A432 +:151C6200468737B662BC5BE73B6DDE209D3F32A42D64279AC1E8 +:151C770017C18661C10F667CA1E6EB7E519769AE5C68F381E5DB +:151C8C00F73A95EEA493FA42CA61E2F9765E447C116CAFD595EC +:151CA100376C7C3BE3C15506F6D44CF8BE1DE39DF203E737B4A5 +:151CB60043E3E928D5E9F8D3E4BA78631BF186FAA6C51B12E1DB +:151CCB0057B67963EDDF5AF8157B568493CBBFCDD20FF5CD8A7C +:151CE0006ED1B59F7CA99E649C599D5A6356A5569824E74C9214 +:151CF50083C60CFB4DE21C33F4143FD901C2276E063F6FD2937B +:151D0A00785E51B7DE06BF4CD2DFA09749F9033AF6B5BAEC73CC +:151D1F000BF02D7B50F8330D0B5B4AF877E34C34D94F87CA4E3B +:151D34006ACC1812BEDE4AB2D384BDBB2A794AE877F1E410782A +:151D4900728EA2769AABD453A641F712E388FEAA6ABD67954398 +:151D5E00FCF24DF43FD8438150B4750FE66FA58A17939CAF263F +:151D73003BE676F8E23B7633D96915DA55BD27B2BF0DF8F35FD4 +:151D8800C8DACDADEA7DE6DB3F93EE94957BF52A7505AF225DD7 +:151D9D00FE92EA6D0ED2FD5BF04514E36C0F2F3D9FCE7FAD5214 +:151DB2006E249BDC207BD698C78EDD15211B50B6694D76AC01A8 +:151DC70059D9E44A433E25146EA53ACD2ED5DFECF8589692BDD0 +:151DDC009BC72C3D0DBF8F52DDBB95A7DAA08F55CF618580CB48 +:151DF1006D67BA6DCCE80FAD71D029F257F36BC5AC9029EF99AF +:151E0600412A0399E186C9E2BF7A7E3BCD0B800F7004D5970D68 +:151E1B00F4218F781FEBE76C7C31749E6068C5A774F41D7A90B7 +:151E3000F774834E6085AAA82E21038C1E1E559FE1AFCE26DABE +:151E45002BC46754DE6907766090F41F4A33DD6DDE934E8B36D0 +:151E5A00855EA51C364748472B8FD9B22C6AC939D4D9361BEBFD +:151E6F00F6614A3B2CE0F2B2BD7A0FE08AEE3121A71CBA396BC1 +:151E84001ED13740BBF704ED707E5C55498F573A877DEA1DA687 +:151E99007705E940D1BDA26EE8F5D0E9FDEAB366CD75A929AB9C +:151EAE00CF583470F0EDA6C360C0F2BFBCD97B1E60856E7A0042 +:151EC3009EB1BFA139D2A117E495526526D6701D7AD4E49355C5 +:151ED800774DE7D7A87D9E2F9E7AC72C095D6CCD49922D7DFE54 +:151EED000A8D8D2FF00AED4FF425B16FF37D9D27DAC43E90ED91 +:151F0200971EA6BBB087B08608C28CC1C77DD80C8BB3DCDF30DF +:151F1700E684CE50BB3F249952DAEA8B3D493AED72CC2B66C792 +:151F2C00BD0F918E7BBFD171EFBD7A774A024E857E9B87392E76 +:151F41001CB5F5DB2ECB2F8FC66CCCF6B31F16F76ADB0638627B +:151F56008CDC073B2B4265B6087D3A2D7C44525C444EC819E394 +:151F6B00E1582D9F9DCC69093CBB9E074EB7E852F2040F40BFA2 +:151F8000879E7C1F7CD25F163EB87DEC9B1ACABD4FCA53DF677C +:151F9500BF69EDA7517DFBD97734B6ED1847F4903EF66D0DBA40 +:151FAA0018E4771F7B4D832F2DE089920E87FC80E55689059E76 +:151FBF00227915185BA9DF4DFDF12B8FE8B2FA9C81BE3A7E50F6 +:151FD4002C7A9FD931EB5EE1039C4F3031638DD9C70632FE501A +:151FE90028CFA2CF99AF125FFACE8DE86CA4D384FD04FA0FDB39 +:151FFE007BCC68ABE8524AEFCD7941E8F56BB1AE3C72CC1C63DA +:15201300225F1CFA3CFCE2B0B78867D80758AF213917C7BC7364 +:15202800ADE27073B9EA69F49D233DBCFE18A7726DED852B5BE4 +:15203D00A05F930D5A124DBD635468DFD3674BCF0B9DD8E33F85 +:15205200A1236F09FC1BEA87903F7270672FCD457DC236050FD3 +:15206700887764234E923CF49D3BA8CF3BF79CCE2607054C382D +:15207C00EF437C2564FC1FC6D6365978F986E13BFD72960F9219 +:15209100DE0C1F84C007842787F6BEC82ABDABCD63D111F4336D +:1520A600BA4D879E4FB31735879E2CFA0D73103ABACD2B53F1A0 +:1520BB0067E1EDABAFFF9186337253717644E0ACA44DF848DBB0 +:1520D000381B06CE026CFC581CBEDAD79EBC7789A80FB6CCA84C +:1520E5008533165D346CFD77F65B733B1B9E3B7A42E047AC7FA6 +:1520FA0019C7CC02E8C5935FE16F104B127F9414A53CCDC0ED45 +:15210F00E39E2796FE69CA736728E66976F30978C373E91DDDF8 +:1521240027BDA077AB599C04A78C0DCBF6035D2D7EB6C60AF085 +:1521390094E1F5E9769FBDEF6EAAEBEFF49DBBAAC367D9EAA701 +:15214E00C1710644E83FE1301778D9F669AB7FCA401C6BEB2D2E +:15216300EA034BB0FFE1659D7A70C75745FFD8E6E778EFD81756 +:15217800493E7CD174D93BFDC2D6C19E36E18245474CA78E203C +:15218D00D951852E5C8C117F2797AF6FBA7EDDC2C76FCA9FA8EE +:1521A200DD40FA96859FBFD7EBA4273F003FDF27FC3CFFEF82DF +:1521B7009F97809F7577E98E6D9E6661CE267F6EE1836CE6DE14 +:1521CC0038EC050B1F0BD8223DF8FE62818F9C68A95E1E2F6F3A +:1521E100BE45CC71FB782CF5AEB9ED97B0974B5BE9D9807CB1CE +:1521F600EC1FC21BFBE32C0F2A583310FF84BB0117EE5E369D99 +:15220B00F6A6E3AE9770B78D70F77736EE2E12EED07EC8D5FE2D +:15222000B55F586D4F6DF7056D5FFE505666DC5C56CC71C98A24 +:15223500A64C3EEBEC74667C2CC4BAEEBAE7333244D8E7E3545F +:15224A002E3EA44D2EF70AD8204B204722A4E3418E604D0A67B3 +:15225F002050EEE9944B9EE4BCA461FF0FE736F05EBCB3E449EC +:15227400896FDD4BFA016A5BC8946D4362CC627D0A7D2E76F53C +:1522890059A63EBB65CD74FFA551F8E6285C2FBA64E801D20F34 +:15229E00FA9232F547354EDE27F4CA906B8F8C063EE99034B72D +:1522B3000357276DFE4079DF42962F8FEFD495F33BB5A9FEFC1E +:1522C80086B0357697F56B42B7945917703526D65C86E20BB10B +:1522DD00A743632327752C2EA74EC47D7ED27308BF05F1A1C669 +:1522F200E2A841F301E73D29B94556137CAEF217382B182AC2CA +:1523070019BA0C4C5161776CC799BBF2D5ADD0B1587958D821CF +:15231C00D095271EB07C67AFE15EBE8CE6DDDF3F207CF7C2EA17 +:15233100F1D40333FB731B87B07ED12FD62F76931E5C34D629A3 +:15234600D609D8B89C301A8E58B04787E245F06FB4D33DB1A12D +:15235B00B8D2302CFAD7C3F66A384FE85B47F3883104BD08739A +:152370008C41735BA67FC591C146A7ACB58F9B79BE019E6B8741 +:15238500B2EB31BBCB86B5A2B80D8F711378285D215B1AB0B83F +:15239A00DB94ACFD988ECC5A8DBD3F8FBD68567ED2DAF7B4FD65 +:1523AF00110977167EACB5F4A978543A0F4CF12FA27110BF1F74 +:1523C4007D305A31164897E928B77CA2E21D94DE1B4D6ABE22CE +:1523D9004B2F4B114C5772E258F32AC4FBE87ACB96C1DAC1428D +:1523EE00DB8F6AB5E09123F1FBE89D03BB809BF26BEBC51EA3A5 +:15240300D8075C6BE7D35DF956A45EE8A0FF38D28DF558CFF983 +:15241800761CF31EFA82FD4FC0D1BB73480B8ED9F050BAD3EE10 +:15242D0016BBBE9E19DAED77B5BBD5CEF78C2BDF4A6A17F99220 +:15244200AE7C6D76BE8119E05B99FA661C67108E0818BF1BC70A +:152457001ED815824521F89E16BC734CF8CDF47E8F6065D6BA3B +:15246C00E01517ACDBECBA5F9C01D661170CDBED7C2FCF00EB9F +:152481004957BE1D76BE573E0056D0D881F5EA87C07AD5056B9E +:15249600CAAEBBFDFE1B61EDBA3F0BC3653B5FF7FD37A1E7FD24 +:1524AB00597A5EBE093D2FBBDABDE2D0738676FB5DED5E75E845 +:1524C000799376B76CC0F81A050E8C0977BBE8AFBD7E8F74875A +:1524D500E71FA7FCFBD95086E737782D9E7F5FB2783EB621DB46 +:1524EA0076D46BB5FDF0860F681BFBA576BB4E7B93AE7E6EB0F7 +:1524FF00EBF8E2CC751818B38E6FCEB5E9328FE4CBE5C1ACBCF8 +:1525140013E359ACCD22E69421FC099832624057F1F93BF5DD6E +:152529006586A6D0FCA0AC3DA597F213FA3E9A12DC32E809EAA9 +:15253E00D74CB2C729179286B4FDA437825F2CFFC7BD644B24A5 +:152553003BE0EFBD52D4959D1BEAA82E0FCD0B19B94A7A896F04 +:15256800DD9090A9429E3AF3451CF27448C853650DC14F725439 +:15257D00723D4F9D8FB0DFDBAF4965869EC61A18F6DAADB37498 +:15259200F6DC346CB56FD8F234DA678A35D5F121C3EACBA0069B +:1525A7007F17EC0B189897C85E99ABBCA2FB48E7C6DC34E37C24 +:1525BC0032945D0FC73A1CF6944270D7856FBEFD9BE6F339D379 +:1525D100D7C2AD75DCA3864CF348A0419C756301E917FA933497 +:1525E600B72D10BAC911331264D1D7688EF6150D0A9F0E2B1601 +:1525FB0058B5D807DA5DA66AAC7E2F6F13FB0B3D64EF579AE254 +:152610004CDCFFEDFFC3BD1C30B36DEFF238D159C0EE7ABF99F3 +:15262500F4B6E5F4FECBEC1F9722C609FAB0ABEC88735E5915B9 +:15263A007D237D48F44321BBE2E3FE0FF4F29215EFEAD9B4A1AD +:15264F00E175B1F412A7AD0ACDB2D53F4A5BF1E48D7535C6BE43 +:152664002BEA8A7E40F918952B5D33B5DCEDB18796587433CC8C +:15267900D5A09B5D2E4C79FDD3F2D6C52AECBC2A17FB43365DAB +:15268E006591AFC75C3061C77B237CE26C5D5D2CAF51ECBDC060 +:1526A3007F53E44F7092F13109F989A7113746B6E2C319880F2E +:1526B80027CE3F132F89B399E383A67B3FA9F5886B3F087BA603 +:1526CD00DB388F603F272A6C1B71BE5251E0FF613FAB3807990B +:1526E200DD0FEA75955F18931B9D3D21D421AFE17A8F589B1E44 +:1526F7001C9E74EDA33AECEF63A3F96FC977E57CD9F39EF47519 +:15270C00E951E9335250BAC6FE8EFD35FB2E7B990DB1AF319314 +:1527210075B30EB683FD2929DA5F628FB147D9436C23D3D8036A +:152736006C3DFB1CBB97FD015BCDEE66ABD84AB6822D67CDACF0 +:15274B008935B206B68C2D6577B07AB684D5B15A16669F66B73C +:15276000B34FB11ABA7E8FDDC616D355CD3E49D7AD6C115D55E8 +:15277500747D82AE857455D2A5D25521AE72BA16886BBEB86E5A +:15278A0011D73CFB2A1357A97DCDCD5C21FB2AC95C41D735C7EC +:15279F0075154FB902D32EE5866BF60D57D18CD7AC9B5EFE0F7A +:1527B400BC0A3FF42AF8C857FE875E3E26CE181FB7D6B754E111 +:1527C9008B4EBA3DE9F151A61E475A15A519F673353D8FDBCFB4 +:1527DE0035F4AC48F48C35BEF26ACA1FE1065BCDC7C95E5024A0 +:1527F3008D2BEAC2E34A8CFE93F49F5A785C8C2BB11E522DF667 +:15280800DB55D54ECBB7D3244A8BD96905769A87D292765AA167 +:15281D009D964369A88FDA14B02B2C1AB6EB825F60D8AE037E98 +:152832008061BB2CFCFEC254262AC16651F9F04B5828BD8D33C0 +:1528470075E1016F6899A8272AE2EED41AC549A9CE776631CD9E +:15285C006B95077C671A843C887FC0BBE10F78073F38BC2BA2B2 +:1528710077946E225D7EBD41176D8F2F361DDC3938473FC66D43 +:15288600189561411343153E7661037E200CFD1465C2ADC02FED +:15289B0070A878ACFCA96FDBEF99CA9BD485A661D7C35EB1D235 +:1528B000A3942F8A754A65A129FBC8A6BFC93D2A65F38CBB9EA0 +:1528C500154FF6D9B0D345FD63E9D988ED64F947AA7C42ACE7CD +:1528DA00A8563C48B12EAA8A5891B9F6B3F043F310AF617D2323 +:1528EF00BC8C477FE16109CF32332FA4B6CA91067DA2B241C487 +:15290400A998F8AEF70EE004BFE12B3046E5FC6C19CEE49A35C6 +:15291900840B529EB84FAD33F3D86D04FB6DA63714691D9F2168 +:15292E004D91AC34A6BE67C2BEAACE99AE9FA98648037FD3FD64 +:152943004155AA9389664ABCBD4E86FF8C5209F9ED634A2D354B +:15295800B9CCA81171196A4DA6002E55C012F594521B8B0DB4AE +:15296D002F9F29D595F8E27ADC7DF1C575B847D1D7F1B090F94B +:15298200C82BF818F29DF489B81813CB7844F8D946901E4BCFE8 +:152997005E4D79A2464CAC776BF659FC188F88B5932DD699FCEB +:1529AC00709B75469E6DB7E3F076D9677810F764360195205DD9 +:1529C1002461182CA141FFC1EFF796CB77B0F10EC3AFCA752C4C +:1529D600BAD39844BFC655C35A07B2CE2DD7A472EA449D549F2D +:1529EB00386783E768AFD15516D72431FFF59A9973E3D1FFDE24 +:152A00008FFECD579F3664F575D21913464495EF78E9A197A820 +:152A1500FED7FA918EB41A4A3B302DAD94D2764D4BDBB69CE0E0 +:152A2A0052DEEEFFF243EFD49262C6FDEA25633B3BC3E7AF7812 +:152A3F00476FA9F869EDD7965DB17DA5E362BD6D41FC027C739B +:152A5400845EB160C5395D4E0E1A9EF223ADAAFAAD7E664C9A2E +:152A6900BEAE5EA193637EF68DF52D0D618EA47698F10DF3161F +:152A7E00E91D1D7828603FAD1D7EE8974B0906A2E92582EB9C07 +:152A930021F17DFAD736BDCD6F89D05CACEC330967F1EBCB57B1 +:152AA800D5FABAA9BDE8CE617624176BE5C33E1F7483DD077C9B +:152ABD00ABDFA1F4FD07ACDF2FD8BFBF7DE00CCDB7C9EBD3C29B +:152AD20060477FD89FF09C3180B7ED6C8CC7BF935BF7C413B97E +:152AE70075581F3830FE356DDEF9FD5ACEB937F4BBD985DA799A +:152AFC0063A774C41685FE62AD2F8E8BBE96287FAE4F3E7CC918 +:152B11009C27BD46EF2F98BEF8B1A5D88342DD130F9F337CC974 +:152B2600DCBA912773EF10671887451C98E3090FD90CCA090325 +:152B3B007DF9EDA1CEFAD069AA5BF9078EFE28803BFABD611FD5 +:152B5000620529BB8F2B02FEEF1F7F9BC66081BAB70B6BB57987 +:152B65006A67BC27CE3589F49389CA1F1AD05192A4777CD58762 +:152B7A00F83ABC6BA2F2D726E5DDF34BB5E68E28E5DF115B5586 +:152B8F0007BB4A8C2DE59821279F2519E9AD8B8D1DAD63C60920 +:152BA4006302BC47EF317ED653BA9C3C46FCD3297C13ABEDD81E +:152BB9006D62AC197BC53E47B5186706F725F7D2388B73996858 +:152BCE00AB305E8FBB8FF13ADC113FCA97ECA33AC68C36EC2BC0 +:152BE300261386E4231C85C74CFC061F627C9CF92EDE0D923EE6 +:152BF800493A7F3261DE16E7227D8CD2F11BFBC81395DCF0C751 +:152C0D00E4BA00E96B1827139583E63CB22746AF7BEF205C9AE6 +:152C220067DE4FFB1482A789DAB8807115EEE71324839BA85E80 +:152C3700963C68BE91F1E7EE32FC8481300177A193D733E374C9 +:152C4C00BFF0632179D61D39A7FDE51772EBFA59A7D61FEFD3ED +:152C61007E5925DFD14FF6DADC44AFDEB3936B3D0D17C55EB4FD +:152C7600927ABAFFB645E59F11BA5B383E8C9824810509C4C806 +:152C8B0032E627459FAC182F3EE8A37111C3A55AC6DEFBDB8611 +:152CA000B41AF18A5F357BC6B806FF415FF22095DB0D3C8B58F6 +:152CB50057A5A9A7CDF9A9AF9BD5849BF9D4D7642EF634778BAF +:152CCA00F159ADEE16BEF1A20E85236E9FAF54FDAA217CF63673 +:152CDF00714EE50CC806393662D4A7BE437977D358E9A579EE05 +:152CF400A08E3A3D6787442CE5B6BF60AC0CF62FD980885722D7 +:152D0900AFDBA5539F0E78D6EDD3B7E4B1A9E3631CB16EBAF850 +:152D1E0057DE92BFFFB424E82262000553F033EA177E46C029AE +:152D3300E2FE045942AC5F8A78669FB77CBF906E8EF56AA5A9CF +:152D48005DFDE1D4F3496505D77DA403E7ACE5BAAC72D3EF4371 +:152D5D008CB783BC3AD2B714EBBE25EDC43FEA102F8DE3F709B1 +:152D72003364FF464C0D4BEE937D9AF2D7210DEBC2BE8CFF7CCB +:152D8700BF8881E3016EC67B8D2A4107EB8CA2447637CEE55AC6 +:152D9C006713AD3DBD37A92E896000ED413FA9EB981E5AD069C0 +:152DB100EE8F58E7DA104346FA032EF47445D0D1107E6A8AE003 +:152DC600EBE78E5F1636449788B723A748868D4F0A3C07C84604 +:152DDB00F60B1F837E116FC72362565BBE6BCC78CA443C46C088 +:152DF00029A5BEC2AB539FA875CB76C874D04FC8F58C4C27F975 +:152E0500BE25B72598FA8D29E22C1E07FFED32F7FC2E5D520F81 +:152E1A003F3B9B06C07130B5CFF0F05E3DD068C5BCF3906C4040 +:152E2F00DC763FEB5DE2271E99C77A6B41BFAD2EDEDC6AD1C9B0 +:152E4400D88E7BF99556C15B4437FC96C5B982B888E3047A8367 +:152E5900BE22361FC632D1733A2D6551D6A2C387E1F623D3083F +:152E6E003470E3DEA1C7C7A04181A041BF1DE7284B8B0FA58182 +:152E83006B6E75F03FF62DC4A72C0ABB69511CFB64ADB04BA3BE +:152E9800EDC3D79EFCE452259647F368BB01DB13B28A7F25B730 +:152EAD00EEE2BF38F2C79217A544ABE205DC94A84FA01DFA68E6 +:152EC200C53AB2DA407BA83B130F23A31F59F42873D1628780A9 +:152ED700A7CB3AB740EF11574B49ED33253521F808BF35D77979 +:152EEC00E0A0AB7CF0F399F8E022AE783F1B12FB163ED0BC7DCA +:152F010048F3AB5E218B15F007C99EB288257B32E38EFA2C6D48 +:152F1600C1FC4BF735E7040E689C06FB7F6BF53735EDB313D89E +:152F2B00A3290D75B596D1DCAFB2E4F1301B3B1E61A9E3D72E7F +:152F4000A4F3E93E4CBF87297D58B3CBDF2CFF9137A7E6AFB6EC +:152F5500F3631E1FFD8DDBFF14F32C8BBACB8AB8C362CF8D1B4F +:152F6A00D79F94EF6882BF8B3A1AFFEA99535A2E9917B2DADB5D +:152F7F0085B84805EAAB5D38FF68F9838F8933508A3A42764A45 +:152F9400C2F0A716D5C97F93CE071ECE5E4AE74FAFD30D9B3808 +:152FA9003B48659BD4678CC99F71D2890C1173C9E2C33F330520 +:152FBE00EF5AB19D267A483FAC233DE8E3F0E6C4CF7A8D84A7CE +:152FD300CB6047E496899F7133E1E9379BD41EF337D7313EE251 +:152FE800B62DD26E5E86EE13361CBDD48AEB6E1C34A0034B3494 +:152FFD006E003BFD3677FC17D2FBC25113FAAE83B39387B2F8C4 +:153012006EFD7516BFF3110B22544A7A79BB7196E0DECE629CE6 +:15302700A5C2FDD88FF2A7AA8DDCD3B5FAB7E28B6B3B972D9B72 +:15303C00A22BE631F8892E13FA539EF428C98F35869A8AF63372 +:15305100E557A6CF57A9C3D7D4D213172E2D205BC453AE8936F5 +:15306600105F167AB6B7BD562F8AD4D617509B472BEE5C3A3F3C +:15307B00A5D25C576D94A6C286E46FD43B9FADE5DE31B2FBC612 +:153090009799CE1E37621B0A5D5D6927FDB1AA56C65E6AF49146 +:1530A50061663C7CC0D785F301FF49DC53CB3D7764D7834AED9C +:1530BA00B882D5B69C0A939C5AA6414F9FA74A61118F54C869C1 +:1530CF00B241A83FB22B2695357F3E3F5C3676502FB3D7338382 +:1530E400340F63BE65E3AF9801E9B25E5759F419567EA695B16D +:1530F9002B5C61FFB03428BDABEF53BD75D005C32413E74B43AF +:15310E007A49E864AB2FF20F4BE6D3DD73AE4FF8AD601D6FEEF2 +:153123000AC4C23B69FBC7C4F9159AD78BE327F4C07CD24B94E8 +:153138008EE18FFA3F97746FDCFB97E7D517C7F2C82679C5604B +:15314D00A9E78FBF41E3687EEA6903B24AC411A0FE07683EBE55 +:153162005AD6BB2442BA0CE69B07BC86D05F7EFC0CAF75749694 +:15317700ABBF4BDF546719FEDFE99BEA2CCB6EA6B344DFE129A5 +:15318C00E7FC27640CE1CA57F985A505620F0F783BB53478FAFC +:1531A1001754FF29BE9E70B77F99E19CA917780AC54732780A6C +:1531B600A516D5FAAE604FB963587EFD14E473685E6A562DFD13 +:1531CB00368A5325E25E905A20EE06C9F199FA4FF369BD67F568 +:1531E000BBFAE56B691FF080BED6D87D9F78DFEAFBFC19FA8E7C +:1531F50032C3D73E7EFF1710DD4B2147A33DFD6DBF9966BF5070 +:15320A001FC55AAA8B9E6BDD79A27DC63DAC9F6F201D3DF78709 +:15321F00BD4B54F5345920295E2C91DEA55C3083365FCA381F10 +:15323400A4FCC4DCCE2EF280745587DCBB65C5BB7A78EC3BF5FD +:15324900B73458F8BC85BD63F975517BB7C05E095F143805CF3D +:15325E00C1BF133EA2E5296F9D9367EEE94B19BCCFA5B28ADA53 +:15327300DE1F2F4CB420EF56ECE54447FA117B31E7CC29BC3BCF +:15328800E0397B4A37D26427D1FB6AF50B4B71073C93CBF3EE4B +:15329D00D8F6D04F491FFC89E1535F3E50A3FEC85C3669F73195 +:1532B200BA6BD88FF8AAC9F5DC7A86ADB46BF8CA72ABFC49C28D +:1532C7005BD0AEEBDAF2C796DECE5EA813B68E2B2FCAA20E77B1 +:1532DC00B9B394A7E3A90B5A58FD8F4B908EF99154E5CFE1F98C +:1532F10019CC91D15D49E89F285B803D65C225BE1F33BFE7B062 +:15330600C0EB3C957402BBFEA229CF736B3DD6737F813ABB967E +:15331B00EE86A7C8D2CB51BFE7EB7B74A1037C876405E9576696 +:15333000E4794D8924F4529A3B443C16C53A83F361FF34A7745C +:15334500495DEB75F8193265A7987794129A3FEC7947CC41785F +:15335A00F731E61F67EEB1E7A119E71FCC3D9883EAC599FBCC51 +:15336F005CC3D5316BAEB1DA5159A9FA2B730E74099A977C6AF3 +:15338400B7B9E5BDB4AF20C9BB0A08EEFA48A2CEB1FF4A691EE8 +:15339900439ED5EF39F4EE349AEA2CBB716254BC37F03E4CF834 +:1533AE00417996BC6C486557881F39D98D5D3C37998817533BB2 +:1533C3004A72A41F632E27758AA34EF01A78AE5AFDD901F0D4A9 +:1533D800C5F71DFDCC8699607DA3E7591AC3EDC6D65F58F3BB94 +:1533ED005897A5B6467F951D5F8190E5EFE1B3CF1924432C9F18 +:1534020074CFFC2B01EB77DCCBF23748AC707B0ECBC77986F8A2 +:15341700D8D46F3B4DFC2D4D4C1711129DBA46FF6DF46FD0FFC6 +:15342C0030FD8FD3FF04FD2B3FA2F73FB2F28ABD83A0EAC46896 +:15344100E467C7F0E1884A1DB1F06F555B97B0FA5F755EA47C51 +:1534560015FDCF100EAE926CBE6AB2FA761EFB4B7B9DAD7E8045 +:15346B0027E9B947F5B62834AEC7DE465F470DC4BC14E73EEA46 +:15348000BB39DAA977F43BCA1FA7FCB7B2BDCDE299DA539A5FFA +:15349500340CF4433961C0BF36B4E298CE627B39DEA3EC7EF867 +:1534AA0063217634D5592CEA7C45B429621B7D601DC77851E412 +:1534BF005433F2A3CDB9A11BFDA9597082F7B2ECFEADF0DF0892 +:1534D40066CFECBF799A1AA43993D59FE216AEE1DB316CF5B34B +:1534E9007E888B36C73B0DAC81948C1DD3156AB7247E54878F79 +:1534FE009EAC4E4DC31A888FD202E35D7ACF84A7C5FDCE47EF92 +:1535130042CA7FD3FD64878E601FD4D97725F8FCCC155F697AF0 +:153528000CA57FE37B9C131A0922364775EB55BA7B953A1D3188 +:15353D0072FDB14A3397CA5C0BB142F9BFB61B56BC617917D2C3 +:153552000629CD1F1BA03967917E71B9749757E9D0C7290DF1AC +:153567004BBB903F5669E07C8D8A73A29426C706CC61A4D3B355 +:15357C00417C7B9164217CFC6BE63271C68307B23609CE1C5FF6 +:15359100F558F1B2B6219DE007C079471077F45DAE9C7F464330 +:1535A6003F4AE11BA48C709FFF98BE8E6CB339AADC92973A2800 +:1535BB00E2B610FCC5A114F2EFED90BA7B853F27CE18DE966C99 +:1535D0005AA2F82D5F0BC466982DEA1C3AE0A33C3E2B4FB034D1 +:1535E500292F918EDC589645F304DE0C9AF7AAE658DF8082FF11 +:1535FA00BDC3E7E373E0979EC8F887C9EAA4D95A427822B92460 +:15360F00137EA2F4CC66F0E72F25BC5BDF3CF96B737BEA6F0F36 +:15362400C897DAF5CBC553EBC7F744DAECFABDA1B156CA6B50E9 +:15363900DE7ED4B58764E75A196B3AED343E2254FF6AEE53F13D +:15364E001C6D853FB7447A2EE9C2A65FD5CDB504838C33722494 +:15366300A7F17D95F96A3B87DCDC537646C37AECAAD43F13CFF4 +:15367800FEC05C4DF724F1C25ABAAF4E7DA61FB410FEE76AEDB5 +:15368D00011FD5514FF59706587E581DE0169C5FE8079C388F73 +:1536A200BD92F475D8309EF258EB9EB2360DF23E42EDC4A82EF4 +:1536B700CA773C4AF7CDF41FA1FA733167184D7C436AB919A3B7 +:1536CC0076A2A9FDFD38F3B09ADA89AA3D070E521E8DDA3AAA9F +:1536E100D8676C4987403B84C0923D6549AD551D306304D7662A +:1536F600AA7F82F07335C00A7D54E632DD714E9EF8CFBC46CFF7 +:15370B00ABA88E8900CE1924F8167A7E35007E575BDFA4FB6AE1 +:153720004A93296D989EFD418B46D371ECA697F7525CDF4C7926 +:153735008B55B939C745CFB03A48B8867F31F68427699C0F9A63 +:15374A008A4A73DA349A875F9B2AAFE12FA284734806776564EA +:15375F00301C123057DF4DD38107E71CB78D7051CE386594ECF6 +:1537740018B4E4DCB663960C8AEE35E0D33217320A6B58888D3C +:1537890019957765DADD3669CBEF1E9249581B3C684A65713D24 +:15379E00E37F4678A0692F9FE62E23389BE5E3AC06D9408DFDF8 +:1537B30012CB273E32A89F8D7E1AC705EA82CFACCA63F9F3E96C +:1537C80019DF929195DDFA28F169BFC20ABFCCAA1A494008FC7C +:1537DD003E42CF09C5C26B39AB6A8EDA721FB240C04675602E4B +:1537F20088501E12E685CBE8AE282FEA997874341F5FA8686FF7 +:1538070084CFA788BD46F7ABCBBDCD0AE5DB5A7CE31872C60954 +:15381C00F6CC300E2798F50D3C278F9FF860A7FD9DBA72D5DBD0 +:153831005C4DF5E4975F213A1D9A820B85FA73167CA3DC26CE74 +:15384600D0EC8AE13B033DC613915ED1FFFC4FD3FC46F800FFDC +:15385B002D25B4416F7FB508E30EFD7AD1C01CD1C83A455EA932 +:153870002CAC77E663AD63C0AC72FAA5741B32E916D5E0BD40AC +:1538850017740503FE7E0AD581323EF5457AFF2B33BFC82AC7C6 +:15389A0094174DE0783BE5CF75CD5B6AD1D4F59B6B45AC3048CA +:1538AF0079268AC0F35546428C936A314EE0DF0499FBE6F5749D +:1538C4003EFC750AE289466FB45A57D54AE3CA72A97994CAD023 +:1538D900382EF4BAEA2FB6CFD665ED55D598781B01B576EAA8ED +:1538EE005B39FF7B22D6307CB5B09624931C95A9BE2292F7E8B6 +:15390300C7C44303F50FD2337CAD64711EC8D603E0E3F536F634 +:15391800F82CF8E5D810C9A4170D712EDDD255D3C53407E3FBCC +:15392D0055B2FA8C69CB9300BE0D09F926C33FC2FEFEC424D5C1 +:15394200F3E318F1606CC85E334EA7FF6A6CB0D14FBF713687E5 +:1539570045DBF9F642969F5B4934B4EBFE2DF5DDE90BD67050D7 +:15396C008785AB230257F0FB0DB1458D4E7F0AA80F93158B9A3D +:1539810071CE7372162BACB8981D3F326414D96517C986FC2802 +:15399600FDC4FE9B809FF409C0E21D233B3B3A4A750D4057248D +:1539AB003C7467FC45BC946FB480E5DFA30276AB6F778D250892 +:1539C000B735A60337F611FFC7B19F1CC5FA83A82F84B58C55BA +:1539D50007A03FE3BD903D36BEEAA7ED4F59E36515B7F15B828E +:1539EA00FD0F3FE5298EC9CD9B73B26347C9AFC1B7BB047ED1E3 +:1539FF00D6BCB141D2A306B1A79816E71AE9AF3CF242E3453F3E +:153A140070F373DD194F23F6F95EE80781F1A7F4C0F9255AB02E +:153A2900BD419F97929A049F19DD7C07CDEFBE50360E0960AEE7 +:153A3E00639F6A862E3096EFD0CDEAFB6FD177AA0BF97136C947 +:153A53001FB3E28A20CDDBB448C46C9745DC120BA6BF2298E058 +:153A6800DF081AECC7593A9A0333F44D791BA103CAA9534601AC +:153A7D007BA57132ED6D9E97F23607A7F58164880F78925343FB +:153A920037A72BE1183038FCE84F9D30FA52DE9650D3908009B9 +:153AA7007066F4D570B5A08B22F42AC0FD29EC41091CCD8B0F3C +:153ABC00D43B78D94C32D76BD3CD473A5451A5D468F5CDC2C5E5 +:153AD10075C1E30306C64D89DDCE3F52F98FD3DF85D4DFAA4288 +:153AE600F437ABCF839FB723662FF1815F75F529F6B2D117930E +:153AFB00B27D52AD3E59F850459F9CF3D2363D44BF0CD798284B +:153B100076E10E7A01F0E6F4674EE84A2BC9419A7F7F6EE6B539 +:153B2500D3F852F6F0373C969E087C6C60D9710F19B839730EAD +:153B3A00D7D28BC4B96ABBDC412A071E49A28C4B9E857F379504 +:153B4F00FFFDEA51923983FC4F2343B5CA8E11D12F5FB2D374B5 +:153B6400FA0C79017E2F16B1E59F35DDB20973899C7CD6EC230E +:153B79005D5321FB3E4032DF9F841CE3A6D5CFE12C9D934346AA +:153B8E00A8E984C04788FA60AF6F171440BE8AF1C5752BEEFC13 +:153BA30015D1DEC2152FB8C697859FA2D38322FE2F70F7C8C3D1 +:153BB80096BF2BEAFF0EDB4B7C3068049A3A6DFE1FCCF0FF61C9 +:153BCD00E27FC0073B05EB7C820F62E003C3E683D10CDFCFCFB8 +:153BE2009FCAF747057F0E66E9AF8E18A82BCBD3832EFA774D11 +:153BF700A33FE0D96BF537293763ECB8C70C7ECB49C4324A1863 +:153C0C004F936CB360B6FAB98BF8DAE1E110C1574C7CEBC07AA5 +:153C21008D602D2758DB7C37F2ECABBF01BFBAE08D11BC311723 +:153C3600BCAA1B5E4B36BAF502A5A953C0EBC8216B6EE8123030 +:153C4B00CB31CB87CF8824DA8A5C7362EADA541EC4B91256DF0C +:153C60006BE0FB53B01DB5FF952ECCF01FD92E6F2256C061F98F +:153C75004E2566D92FC591A33AA972C52595724BE07CBFE6913D +:153C8A0058600EDE8D8F18CAF9A426930D739CE055C8E6958910 +:153C9F00C7B0AEE5F321561CE721A2A74AB64FFCA9DE960EA415 +:153CB40077FD33E6910EDFD953629FF44AC5DE3BD8F8A8618648 +:153CC900A516D4539ED88B98C1C1B988EF41E9896EEC77ED3513 +:153CDE0065AA0F7B61E237B52B8BB5FABDA62887B68CBD387FDC +:153CF3003CA73C2937B65B653AE26413E16C936F2DD785BF237A +:153D08007C526C9B08B0A2FE9DABB996B36E528FD370E9FD2C8B +:153D1D00D7D06799CA94278E6D02FC98CF010B60036F2E2318BE +:153D32004ACE9FD4E662CE7FFD59BD98719A2F92DAB7302FD91C +:153D470075E2FB086DD4579473FABE8BEAEFDA7742F851827F75 +:153D5C0044DEE84887AFFB9FF51460A33EA12F6CF220CE5EA6C6 +:153D71008107D29D39F0B9142C4BEF1D5C5CCCE0C16A2B830789 +:153D8600ACDF8D5B78087D576EEC5A873DC921DE4EE9BD185FB6 +:153D9B008413A4C13644AC330BDE538483631AEACF59F76B7D0D +:153DB00087C0C3312D40FD030E149C3BC6DA3BF4326A0B310BAB +:153DC500C3D47E39C941271EA1751E24CED93B8CED29EBD2DED5 +:153DDA0023DD754198FD61952ADFE5C45B1FFEBC88472874DE64 +:153DEF00D5C2AE5A7420286268EE16DF804059E2EB7CFA3D8C92 +:153E04007DC0F17F72C5B3251B113184845E087F7AF8A685976F +:153E190071863C4ADD01D249C6E2D5DE16C957A3CB91C5FA20AF +:153E2E00C18AF80B48AFD0FA750573907A6FA34FFDA346457D70 +:153E4300A0598EAA3ADEA54847C77DB3388FF4E722966149836F +:153E58006A5AF51E860E34B68CDE5568861E8E0F36D6501DD54A +:153E6D00544795FA40A35347A9783FB58DCBCB1F10F5FA45BD41 +:153E8200BFEA70F25ABF0F1B89E57D778A33DA0D13565B510BB7 +:153E97007EE0EAACF0EFAF36A3948E39F62A6385D2EAC5BA120B +:153EAC00818E68F793F20D8A7C61BE01E58DC526F28ECD90178A +:153EC1006D6F07ED92569E8337C9B30163D3CEB3FD2679C294B6 +:153ED600C76FE7D9302D4FAE522FBE37847CE095ADCB7F762708 +:153EEB006425FA21533F719F43F2DCA79AE64CEB596166FBCB27 +:153F0000638C2A8363D86F147A0B3DE34CAD88371B8D0BDE2D37 +:153F1500B1CECE67D68424C9E2B74CBD549FEAAC1F093F34B224 +:153F2A004F7F90C3B07E029FEF94A06FB6BC150BEB8881746A9C +:153F3F00D3AA9FDE958C3FA707CF3FA7C1462DA1B1126C1A1181 +:153F54006397F836A0B013F598673FF7560E53E3234B133497BD +:153F6900FBC9362A461F146E5A3E6FC233A400318BFDF1634B40 +:153F7E00A04B237F10F53B700839DE65C11749D48BEFFDD9F533 +:153F9300CE8F0F2EAD99566FC60EA6B941949F617DE61FEDF10C +:153FA800877EC15626788B2F63DC2855D9F2EE785B347E71160F +:153FBD00EB9F662877745A391A9F379C27B4CA1FE23F9FA1FCAC +:153FD200D68F50FEDD19CAD57F28BC87F89519CABDCF3EBCBDF5 +:153FE700D434FD0AFC1274F31FD6D5FFC9F54DBA19DEC7AF7EC8 +:153FFC00F0FB890F7BFFEF5DFFB4F77EF778F8A0F5D6FFFFFE71 +:154011005FF55E71E1BF789A7CFA7F077E9B3FA69D399A78FFE4 +:15402600C6F1F061F5B9F94D2A3BA2F779129B3F2ABF61BCCE52 +:15403B009155FE79711EAABAB553896D5E49C3DA1FF8828EF8BF +:1540500077F80EB8FFEE6E1D631E3A823FB0459FB5AA5B57D5B8 +:154065002FF15977B7EBC1755CF34B957AB0A8524F90CE66CB4D +:15407A00874DD7482F5102D53AEAFBD7D675680DD786E173B5CB +:15408F00AE4A877F33BC776435A7E57192F925FE4ABD605D8D23 +:1540A400FEF5358BB58A758BB5907FB3DE99F37B1AF6A316C828 +:1540B90031C4C70922AF2C7D4217EB40ABDA850C822CAA284A4F +:1540CE0068F08372DE178BF78B756F202EF4DA8A07E3BAF0CFA1 +:1540E3002438CFCED0FE4ABBFD426AFF10B55FE26A1BED9653F3 +:1540F800FBC827EAA5FADD6D5FB3EB9D70D59B4EFF34ED474C7B +:15410D00C55AD6B29E4C18D41DCF8971E022CDACBA6EA7297B4C +:154122002EE1C54F6DE6AF5D4CF8A9D416F86BF4F99F965BBC93 +:15413700AC7D63C51FCB2D87662704FEB12E457378106BA2B712 +:15414C0009DD240BBB881D01FD90C59F147D2398CEDA308DA2A4 +:15416100EFFE0D7AC5BEF5BA54E4C096BEEEC0D648B095FA2B21 +:15417600457A9C14638756F94535BA5FC0D4AD2D284AE83D3BB9 +:15418B00F764F80078FE6D3A6DC3C0443F71F6CEDA779D78128F +:1541A000ED8EDB7048655DF8269C6F36B76008ECABD203D41E5E +:1541B500FAD662FBB8C3394CE0252F8B970AE29BC2B54D7AC9E4 +:1541CA00BA7A01CFEE9C6EAD80F052E84FE8B92CB1718FCD975C +:1541DF000B45DFB3ED5EA1B60C7A17207C11DD8B1D1840FB8A9B +:1541F400D51B34D8DC15EB3668D3E94F83275020CE13B2828A7C +:154209003307C57BE95C8D5EF2604C97D997F45994E780C44203 +:15421E005EFB791F3D17AE23F8884F0A8BEA75FEBD06EDD0EB49 +:154233000D5AE1B9B57A09A7B47DAB74FED97B88DFEFD140FB92 +:1542480012C265C55A0B07724C6A51D9165E4F38F34A0FEBFE75 +:15425D00580E62F807F3B15753BEBA7596F4A8EE9757EAFE153F +:15427200D4D6DD8FEBFE55F7E87B73566A5823975764F3E7852A +:15428700AC3324227FA2D6CAFFDA1775FFAB0DFADE9DB59A97C5 +:15429C00E6ECC0F7366B159FCE69C177627CF1DA8DF9630D1B06 +:1542B1009FC6B78679AD5E71EE615D3ADBA073CA2BF9B2F8DF16 +:1542C60086311D12674E362176B4AF9DCA9D6ED828ECDA65ACCF +:1542DB00253710DE981758B6B1A26BBDB69B6401E982C5BBE8C3 +:1542F000FE879031FFF331DDBFAB41870DA1AA8F72B16F98F838 +:15430500A22EADFD922EDEBDD640EF6BF5BD842FD01C7C0DFB89 +:15431A00ABE09B524BC539C21F6FD74BCE7D512F3CDB2DE8DE86 +:15432F0043749F45F42E88F08D6E39045A835EC25FD7A623F818 +:15434400F06E82A505F0138E11377A1D3D2772B66AB3A81DC03C +:15435900DFB9D37ABEFB7ABA0472C8F98DBC34AF6C3A4869289B +:15436E000B7E36C98C04FE20E7C8BE9CE3F0D276CA237CAB09C3 +:1543830086ADF41CF8DE7CADE26C29E1B3549F896F7EC9B27C78 +:15439800F377CCE21BE0BD80F826E4DF2A70F1759B77C03725B1 +:1543AD009CD2A6F14E77FCBEC70A425B8826B1D66EF6E863B372 +:1543C20042D156C9FFB8EEFC2E8C3CFA186833AB7DFD46F67A95 +:1543D700CB46E75EF1AE477C1FA220BE7E63E158CB46299FE89F +:1543EC00FC894AEE25DC5F277A0367B70BFC7B5A0A7907E1FE98 +:1544010071C2FD1E21B7DDF8CFB1F19FB0BE4B11947C9FA0B6CC +:15441600A39BCE085A8057A29B46A7D102DF6D7BD0A605C9D76D +:15442B00E2F52E5ADCEAA2C57BC287303B8677D2F8ED75D106C1 +:15444000EB55A03BD277D8F4394FB471E8B1659AFFE787D1E3D1 +:15445500828B1E7F65D30363B8C4A6C50D7420DAB86991177966 +:15446A00E4B1DCC8FAC7D876D6E21F7B64E32C65CBC63CF69F69 +:15447F001F2B88FFC946FFD8A3E277C51F8B315AEC67F43BF207 +:15449400258177794725F7908CBD9E17E5050EDE696C16FA775A +:1544A900929CBB5F2F5CFBD414BC17CC84F7AE85A0B90BEF3177 +:1544BE008177A7BF6EFC936C2FBEDBC63FD67C30361CFC17BBB3 +:1544D300F0EF116B37167E7B6DFC164136D13BEC33BBF9DE2957 +:1544E800FF4B21FF2D9AA19C887B69D3C1C279FD14589E408C43 +:1544FD00AAA4D48273D5099237B954C72304C3A17B37EB15EBF0 +:154512009A34256789969773A7061EF693BC61AF376C3CF4031B +:154527007A776EAD569CF3592D3FE70FAC77D2CA8D6CCD3D1BF6 +:15453C0077C73C2D806B2170522ED6B603B9AA47CC8548473C72 +:1545510037C7A641FBD89BCA71E6687B9E403EF80E03AEB7C9AB +:15456600ECA43C99F1FE1A8D77CC5117D26905EB41D003684EA5 +:15457B000BBE6AE7FF163D57BC2BE35E7CD2EA77C1FF01EF9849 +:06459000C0E6B892000035 +:00000001FF diff --git a/drivers/atm/pca200e_ecd.data b/drivers/atm/pca200e_ecd.data new file mode 100644 index 000000000..eca84aa7e --- /dev/null +++ b/drivers/atm/pca200e_ecd.data @@ -0,0 +1,906 @@ +:150000001F8B0808AC5A10380203706361323030655F65636428 +:150015002E62696E327D00DC3A0D7054459AFD261333136278A4 +:15002A00192663E02479728060A10E9063213F64F0700F3DE05E +:15003F009E6CDC7B2F3514B35EF0A28B9A5A731E554B91474C5C +:1500540034E11AB6692618B7609D8404A2121CA8648D7551435D +:150069009DA578A56C8AF276A9AB829DF3AC92DD52CC5EB177A0 +:15007E00D4CA32F77DDD6F665E263FA25B775B7753D5E9F7BEA8 +:15009300FEFAFBEBEFFBFAEB7E79F4A91F6C270A21A1870849C1 +:1500A8007C974CFA8536C11F37B9A99FFEAD9C49302569258321 +:1500BD00D8EF4EEE6E14EF59E3B3EDFED3E3C735EC67E50822CC +:1500D200A9FE0FFD29BF7CEA97A26F4EC993D537AF13234A5E2D +:1500E7005EDE94F3BF245F4AFCF1F129E7CF9E866E0ADE2C3919 +:1500FC002BF0237F849F3240F688FEB5EC75792D39E3BCB43E9B +:15011100C9A9F54BDE24FFBC9C3C6987DDCD33F3938CB0674E4E +:1501260078D6F8D7D63FD9DC8CEEABDC4824B2F9DC949E391965 +:15013B00FED7BF11FF975E7267F17D1CFB4BE77E3625BFBC0C26 +:150150003F0FF9BFFF5372CB72671A1F3D3EF99DF51312ECCF0D +:15016500C070095C0E5FF8FFFE4B3A7E246851FDD31C5230FA46 +:15017A00FC0A35E009832F79ADB5E45140A3A4743C8CE3E39F62 +:15018F00C35BB09DEAFF05BD7A95BB3DADE6B56DADE538465425 +:1501A40052C90E11EF08B4773A8857FB013CB7112F090619CEAC +:1501B9005B125380AEB695F80197D874FE9A9022A5D554ADE572 +:1501CE002661CA73EE80B5F5F26AE22D7F9A78FC814838484AB5 +:1501E300E8B36DBD4D843D4C4930CE42B06FCC091861CFB9BDAD +:1501F8002621C3B438D010BE6DD7091AF29090DFEA334930C6AA +:15020D001187E86D9CB09E2EDF18033C8DD220A9BB6D57390DB4 +:1502220011D2D8B26F23C02CEA0FAC0EB76CBADB3C4F48F1BBF2 +:150237001157A5EBD25FC0FCCB804A3412ECA211D133EA167DD2 +:15024C003B8518510311A53A5FDD62226D9C4BD46AEA567ACCA9 +:15026100362DB78EE8A7683E21017F201E4E927EEAB6169944DB +:15027600AFE1ADE3AEBAC0C53534B0EE4194CF8AC2FE47C6065E +:15028B007960DD5253D1FA6834346000BC45C0D909BE0A681025 +:1502A000BDD7BA4BDBBA12ED8A7C09EB8EA79BDA6BF9816681AC +:1502B500F70EF3723259F4518D59F578B3AB0A66E7A3597F0E69 +:1502CA00BA90E04E5BEEC669E5765D2A33DD6762936427C1D5C0 +:1502DF005CDA40CA8A7AA03EA807AC0147BBA02E52A72974180E +:1502F4007B956F461DD851EB3EA14348C8A0EA9689F2332DA72B +:150309000E7B941FFB00D8FFD6801526637B69AB8FCC22A5F03C +:15031E00ACF65863355BCB4740B7F5A05B6A3CEC239954156CC1 +:15033300E7B09E9AA7F084F085DB760DD171378910B6285EA406 +:15034800F64A5F403DE05D8BB4C2F800BD8EE3418BAF06B8AA3D +:15035D00EE81F5E96393DE6D3B92E0385D564748698085091946 +:15037200A79EC256E0D34F49792B1D759310AC032BD6FBCDCEAF +:1503870038D845EFE5456A87F95932097ABB5B050D98BFE30F8A +:15039C009CDF2BE6B767E667E6C6EDC6D24DB7E7A56AA4888777 +:1503B1003626DE3B6D253EE5C5810BE19CD8095A7CFEB241D8BF +:1503C600765A663C6DAE8CBC4EF7B70D35420264F51833C16105 +:1503DB00A6438F32018C232C303A64E29A23DCADBDCAE604CE52 +:1503F000C2DAFC0BE48392B027D20C3E546386122FF0964DDB3D +:15040500C0A7BEC35A366D323B120AE8B357F8531ECA1ED46DF0 +:15041A007F6AE732A6800FFA49302E6321B8C48EB97E560BEFE0 +:15042F00458110CC6910FE9B84D825C10415992A67940623CBF7 +:15044400E9EC584E5DD1912DB4E84C9DA9C486689188ABB8F0F0 +:15045900BD43E494A124DEA49DE43503E75D87B4D6F9E7F81CCD +:15046E00E748EF05F296419A062866F84EF23AC04791363CBF24 +:150483000BCFC31CE5D213EF71C44759162BA4E81F2077148DF9 +:15049800DE677E1BF429501F117ABAB5A3E037FD527EFD21DE68 +:1504AD0072EB2653890C502FC844D803BC937403BD7E2113CE66 +:1504C20027FA51FE0EC4AAE7DCA04906DB38E62BF04FDB0E52E9 +:1504D700EFC24B09339A731CE3886F2C203A191CE0A344E0591A +:1504EC00183F514DC49F88258C471F213EC2FAAC68A8CFB85650 +:15050100D6535DAAB92A3CE7C0EFCB0728CC6BDC33EBBE3AF4E9 +:15051600E76BC964B19EF8949519FF64CE568E091F74150C995D +:15052B00885B1C83D82FEF43FCD0E167A306513B39C4E31CF4C7 +:150540000131A6FE965F4D26FD9E7387CD79E78E9AE46AAF90F1 +:1505550009FC2A0E7E2562E5D1C8C62AB40BFA87E7CCA98C1F9A +:15056A00E07CDB0F02E0079ED07A136DD5DEE892EB27D74DDAA8 +:15057F009075F0D47A1E222F1BA9F524FAABBC1763C2F6998923 +:15059400F69376FBD1FB4F007E4396CDFA85CD8A1BD166C3B678 +:1505A900CDE268B322323660755A03C6B5E64D2B053DCC1D2390 +:1505BE00D266445F1497ADAD0B68E03E15BF6D6448D8278AEB56 +:1505D300C80678BEF73EB0C30FE947E092E01FC585095735DAFE +:1505E800F671D7EE55CF245C958188AB5ADA037C046D01BEE121 +:1505FD00BAF4A9E9518E9B1D5AC626FE09B121732DAEABB48BBB +:150612008C15B459DAD7B3F32CC428FA34D7B6547ACE7D067369 +:15062700345B4F0631B39A266B102748855D9AEE95FAA9DD5677 +:15063C00D4EA35EAB4875792D2583897B499FE5D3F12FA91FA31 +:15065100A3343AFA18E487C7B823BF7489DC027E87B620FA20D5 +:150666004FD1F043DE9AE5B0C528F877AC664BD58D1BD21EFFFA +:15067B0059BA7B79AD423CD23EFF6EAE509A67B0CF7B609F6360 +:15069000FF23F63989F6D9BCD64CED8550E85072F557D21EB076 +:1506A5004745AD6EE339DB1EF3C922D37F7DA9B0478E5E629653 +:1506BA005AA5D57F827B8FBE9F46125FF04F66E1FE5412866761 +:1506CF0086F945D818ED469ECAF8A08A7BB46860BB6E87ED4EC3 +:1506E400F114BF6CDB45C1764D60BB8F6DDB5D00DB21FF8083E0 +:1506F9007F83CD7B22DFE3C67E6F5F26674C9F2BE638724555DF +:15070E001A0F7DDA111F0B20A778361F4BE710B11F8EC13CAB3F +:15072300CFB85A932B64C35C82792494788F611E51E60E9B4A3C +:1507380007E413987728E1C8273927219F0C603EF1E1B81893A8 +:15074D00F9A4D8B3F9A4F963E02D724A539F88D97980873AFBA5 +:150762001C3A37E59359CE5C33A1781D3BC1DC9B7BCDA235ED12 +:15077700A29E2C523E379B4988CE17BAF7F3909FE8EF821F7925 +:15078C000AB11608D25AE1474B445DF7FC5CCD20E5FB68A3A870 +:1507A100170E70A2DF010DFCFD7FBBF54429CA4C9ABEA016F86E +:1507B6008190DD315E0F7E5103E34F925FAF825A94A30ECFCD41 +:1507CB00EDC7BD45FA3FEA06F6167AA890B7BE6EEB8ED2E275F7 +:1507E0005F9819585F7C7324B932C5ABCC90B5C0CDF0B262939A +:1507F500695544DE16B4F419E647605EC90313E7DD13D9B652B6 +:15080A00AE1BE31B70DDEC7941C02DC8C25D1129B371352AEAA4 +:15081F003D7B5DDD02EF009F3F4EEA549887F684FAAA68452469 +:15083400AF42D45290DF570BFC56BA0BF015C4D73BF911F04B90 +:1508490037E243DE03FC62DCA7D1977CA206EDE5CEFA7063BDC6 +:15085E00A3BEDB4CC197290D617DA68BDC791A7B55055EA967AE +:150873000D7A477DD7EA98BF20E2AE48D57848C3FD00350F601C +:150888007C421EC69849CFB37FEA060FC6604F20B001CE496318 +:15089D00F45BB141FAE3B6A126DC2B99A8E7346641AFCCBD0C5D +:1508B200FC9F80B3D24E383761AD1C83FDE1320F41BEF0EFBA70 +:1508C7005F9C89FC501BE39EAAC2D98AE8F5D48775DE582DD4FD +:1508DC0079C130D653FB649EE04837404E899AD0B2CF592B7220 +:1508F10048F13F47DC707EFA7B13EB3699AF0DFBFCA4DB755C24 +:150906003B75477AA046AD605EF541B3E5D6BBCD36A0A978FFF8 +:15091B00C6DC8B750C9CBB3007DDB2E7553337827B40B7D80387 +:150930008A033190A792DF42FECCF4C379E3167106B1EBAEB1A5 +:150945001EEEC7F307D45D9DA1DE74BD05671CBE429CA18E43BC +:15095A00BE5B682CD0CC95E2ACA1F6C4DD381FFA828EE5E21D9F +:15096F00CF4F17DE36CBDB9B95EA476A72D279D11F53A6CF9FA5 +:150984002F7597077ACCF25BD6C49886A7633517D785EC80E7CC +:15099900C4DF12320AAD0BDA4E683AB425D008B40B301E87C6CB +:1509AE00A0E9625E4FDC6EB04FF43059BBFD16CF2CA13DDE56FB +:1509C30043BEDBB50EF83FC2317F3629F20C3409C7410F71268F +:1509D8008F2F88CBF60A4BF1D9381D5E9ADF82B8362D3FA475C3 +:1509ED00BA4BD293F8E3643ABE8067E39C2533D1CBD03A3C13A1 +:150A02009E8DD33425BF89326D9C964E46A68553D2C9D040BBF7 +:150A17007F55C31A995C3D2CF1C7A25CE40D8CB1E29881790360 +:150A2C00623586F12B629A58F412FA289C3F647C34424C9608E5 +:150A41007F9B2E4E5E8138715DFA8579CB9E939363247D66979D +:150A5600B181F1823501C620C60CC64E3A56ACA39958518FC96B +:150A6B00B3FA18D457D69F1A6B2156F09CCE223913E224153FF3 +:150A80001F431E9A8D7990EDA5175CF2ACFE817D7D38027114D6 +:150A950081380A7D8D38DA6CC751C3639938FA009E23DF07232E +:150AAA004223D0128F43850E8D416B8016825602ED1AE0753D49 +:150ABF0036318EC41D03C412CAEFD9DF938E27E09B965B03B992 +:150AD400F7BCFF8A21C70726C557AA05537E9F8DEBE047317E33 +:150AE900DEEF81F157441D23C75BE2B2C13A3649FEF5022F9BEF +:150AFE004E8B23CE5AE21F91E9F8B54C8AB35E320D3D874FEF6F +:150B13009A915E86969EC69B420F382B230E9D92DF4499668A69 +:150B28008D7A32959D60BE4D7FE194E3683F394E74A0F3154D74 +:150B3D00CE4DE17F988EBFD4BA8B38D4FBB846C8AC542C4EA83B +:150B520027713FDF91D98F156FABA86DB78CB65588BD1DFC5798 +:150B67007D286614EF1AA4BA479E078B77F5D28847D6AE88CF94 +:150B7C00B0C665526784B9B260E38E7DBC445B88674CB6E10A5C +:150B910021EE75DDA61F635A2DC718F12B780796AE33FA999E1D +:150BA60043484524B702756A8067E58101519721BC73FE108595 +:150BBB009862B92AE8AF77F3DBB513DC1D6B73DC635914F1AC84 +:150BD00087F12E56D25A75B3B4622F6768017E1CF67CBF1E338F +:150BE50015C85F985FE2F23B9EE0F375F4B11CFA743964B06EE9 +:150BFA00521FC48BD74A7D2C873E5F492B4B9FC12C7D06BFA10A +:150C0F003E71873E671D32C46F521FC44B7C47EA1377E8F3954C +:150C2400B4B2F419CED267F81BEAA35EC9E8B3E44A460684DF02 +:150C39008C3E88A7DAFAE0F3AA9BA595A5CF48963E230E7D4207 +:150C4E00F6FDA61A180DA77CBCCCA066BB897CA58FE0FB4EFBF0 +:150C63003D6EBF37D8EFC81FDF0DF11EA3C29781C7CE1CD1D360 +:150C780041FBBDDF7E1FB6DF2FD8EF23F6FB6AA0B3533BC6C47E +:150C8D007E0B63EDDA49BC1BE40C9EBBB49FE2F99F8FC273BFE6 +:150CA200F6160B698BA97DE6E61ACC2B857D695E24B73A10CB76 +:150CB700ADF62572AB3DB00E78DE451DCBB597059D7A98BB5EAC +:150CCC003B25E844E1B9567B83E1FC77A41C0C79D66B7B98A408 +:150CE1006BF18540B710724F0D394B4F6F3BB916715096422D36 +:150CF600B702613FD9F653011B75C0F66E7B4BC050A614EC99A4 +:150D0B006DCFAD4DD15FACC9F5433AF3C4733FABB7F9A34C0FC4 +:150D2000960DAC49D14CE122AD146E4A5694ADD4C645BAF768FE +:150D3500B9D5381EB56DAA3D216D1ABA22EF6F904789BD3FE19D +:150D4A00B8BEC3392EF9DD65D358286174F44989B3DEA681BC57 +:150D5F00FD4803C6C69FC88C55D9760CC3F846B01FDA8EC2739B +:150D7400583BC0F0DC392264BA2CE4DCA1BDC88E08FB76F1DBED +:150D8900AF0807F47DF7466E65D9853BCDCDA56F2C7F612C6631 +:150D9E007C7B2DCAD12E6C940F67B9556BDD952B4AF72C6730C3 +:150DB3007697188B0B79F363B915F3DE7257064A0F2CE7305641 +:150DC800B856CA8FF6CA8738B9F17B77E5EFE6BFB8FC208CFDBE +:150DDD0047756E753E9C577F7DF1F32AA4F9F17C5A85F3FFF557 +:150DF200C86015E29EBF78026AAD06C113E48F5BA22F113283A0 +:150E07009E715DF43B056D120CC555D1370A39E07C18C798B8BB +:150E1C00EDCC6553F93002F1F71A2D10DF7F625CCEBBCC6B45C5 +:150E31002F6D4482116E403F67DD5153D9F47DA8B3F6D15B712C +:150E4600AF04BB49BE31DE2AFA06DE2EFA2E61CFBC3D80BFEF5E +:150E5B0069C0BF9B16068280AF895C26F2ADE81BF9B0E8570B92 +:150E70009BCF3A03F81FFE10F037D1D9011DF0435CCA1DE37EDB +:150E8500E89F15EBB093975CC9EC6DA454033C43ACCD23B0367D +:150E9A008DDA7EA606C6007681AE96B6E141D15FE0E5D037AD30 +:150EAF00245E1674D52944A3FBAF277DE84B3B005EA01D83BA29 +:150EC400C112F6CB81B3F8ED77209E8C2BDC2B1FB171D1DE7613 +:150ED900BC517CDE0D3C55EF0766EB9A98FD6DB39F22BF48E2BF +:150EEE0067DCBF6B08EB5F529F789DC33BB340367FA8CF54BDFC +:150F0300782FF021776B43FC9315B63CDA1DF4C69792C76198CC +:150F1800AFDAF2305B1EAA65E4C1BDEEBC8D3BEA9067740679E9 +:150F2D0074873CB5200FBC3336853CB50E799EB4797C807164D6 +:150F4200CB336ACB73BD2C230FEE55F7D9B8E86F2979F0793A72 +:150F570079420E79D6833CF0CE6253C8F3CEF28C3C977E277943 +:150F6C002CBB827B9A940779A03C3B1CF2E05E735AE20A5E2E36 +:150F8100C8ADADD57DFC7A32994CE55867F917D10659443B01F6 +:150F960039BA96AA810DE1CE35FD14FF4FA873ECB821758973F1 +:150FAB00DDCE291BAFE0A505F1791CFB6658EB6539856F9A5A59 +:150FC00002CE58E939FD7C839D8F53B806E04521B67D901B9DD8 +:150FD500F3752DCA6A81BF017218DA61689FB1466D21DBA92DFB +:150FEA00039F2967ED5A15ACD57A56663C627272B07149A28F90 +:150FFF0046ADBEC62EC08F6923AC5FA3ACF3C8095A4C06CC398E +:151014005B8FD0F9173FA3AD5BEFA46DF397D2E7B62EA7CF1F57 +:151029005943DB2FAEA387E69FA6783FF357BFC8C198A6F8BFCB +:15103E00542F1C7993169CE9310F5CDC07F5C0BE554EB9CEDE5D +:1510530043BC85DAFAEA344C6FA1E5F712AFCF09130AB4D0C3DD +:15106800D3C06BAF2527C18D480BC37C89F6F12F9E621E6BA1D1 +:15107D00CBD64C01875AE093F9C4BB30D6C3704D312FD45EC9C3 +:15109200D405E99F3AC2884A995B13DF2FD855FCC78E2063D72D +:1510A70044DFC5AEBB64AD33EE92DF494812EAA2C23E336A0D67 +:1510BC0019F87D638EBBCF3C9433641C0A0D189DB0962F586F8B +:1510D100189E0F3E1777C9F825E280D561A81BA9897E90EF9079 +:1510E6000FCFF76E3A24E0CF440A2A3E49FD7B8D9D377E5E23CE +:1510FB00F7C7487A2F8D31947F01EC63F9B1DF97CF8BFD1DEE8E +:1511100023F65E382CEA18B97F0DCB5C073693FB1FB371BA04B5 +:151125004E43669F14F1F0A4CD6774129F5B27F091FBE5B0A8F2 +:15113A0087527CE2369FF5361F89D345651EEE67B171428E04DB +:15114F0095BABCFD7DA63FB4C83C06BAFA2277560560AFBA7A78 +:1511640043EA7B3E726FC56578F680FDCB0C3807E50E34C29EFD +:1511790055AD94F687550DBF8B04E9D8DB9027624A5DADF6326D +:15118E00DED9F9DCEADDB00F75B0D2D0BEAA0324DA48D43DD4DD +:1511A30055DA15762F851A4DFF0D5FA8FD86BB6C5B57691D3C31 +:1511B800A41DE0FE441F63B97D4DCBB46E8E79C51A053D12BD56 +:1511CD004C059A08276A94C281CBE3E4B9E527DDD5CEF965C6B7 +:1511E2004193DB34702E3E232D1D68B94B97844359F37D303FCA +:1511F700A4BDC8A186B0E747A79CAFFE23EE4D4BC2284B10C611 +:15120C0096419D11D43AC45D3427AD8D86F62B9EAB609E3B411A +:1512210039E96C74475AB90FF66017D6BB7A2FF744A2BC2032BB +:1512360022EE9C27FAF1B0EDC7D6043F4EFBEF689FA13AFCB79B +:15124B00106A85B48F821FE0FAA18FE6ED1F308BC92253EAB616 +:1512600044EA16EAAE76FAB35FEB608188BBD28DE768C2A807ED +:15127500D6A3E94EE2C5F7E7E7B61B259B89F7A5B93143D596FA +:15128A008AB5598FEB0073D9FAE876EC73578BFF21CABF23206C +:15129F0069AAAB3C61159E676A128F885E0BA4E4D620EECA880B +:1512B4005AB8CC6C752DDD9E6BC399CFDA9E1AC7FF6352430BCD +:1512C900BFE74ED10845BFE74B3DAFCBC0459C801EF81D11EF02 +:1512DE00CD0E6AEE3A96DE9BE4BDD916BCABB2EFA5314E08DEDD +:1512F300AFE9C75940AB2EC7B51570BD8F5DAFA95E29EEFB990A +:15130800BCE39FA37799F8BD016922CCA746CDB3C9A47F527EA9 +:15131D00B2F9D74EE2DF6EDF9D4B39EE127766BD71A4A3240E38 +:151332004BBA3A7E4790307C4E4C419FC571FF91F4D500F0620B +:1513470094E2BE68D3F4F9347FD50AADA02264E78D0AEDF66A05 +:15135C00A0C97C6A47FAEE1068B3A2ACF7F4B3CD8F8F1D355654 +:1513710068F757F8B4FBCB03DAA28AD47DEB0A6DBBA46DD35490 +:15138600BC8727D155DE9F19B638717B25D610F8EC4638D8F716 +:15139B00207ECF8950FC3E731ABFE72C4EB82B713D104791385F +:1513B000EC20E660C4D1FB38E2A0ACA501AC11A1B67B88903162 +:1513C5000236FE4BE255C5DD690CCF9BEA79D24FF15ED2F20E35 +:1513DA0088EF6B44AC7B4CE0FBD5D7E47730FBDC81304D1BA0C3 +:1513EF00E28CE280056D58A303B6CC8635E0D9B754F0E33B1C7E +:15140400E3E2FF0C865D648936C09D30DC971766C188CB4DCA55 +:1514190027C2583DF46A6488A910CBABB3C712CAF87016AC0146 +:15142E0060235930F7BF29E3A3593002B0771066AFF37F13F3E9 +:1514430084C1511569F6242F3203617CC0644C280C0F0C1AF656 +:15145800229960D0640871E2A297502C37025AEFB141264ADC60 +:15146D00E0A1CC4156D92DEE7CC144126CB07926122DDD9DB8D3 +:1514820099327844070F14B7425DEE8E73BD2D6A2B6559B7D497 +:151497009D52B355DE15578538BAE8B2559C73DFD7DD6FE6CDD5 +:1514AC006450F1F6EA7E4CBD37DDFDBEEFEBAFBFFEBEAFFBFBA7 +:1514C100BA31DE44D82DB80EE738919E4FBE9AF31B37FF6E8C0B +:1514D600D97D8E4A1BC19FE113CC3500EB7D15DAA8986B25E05C +:1514EB0087B471F62449D02133CEFDA473208FA0ED37A19F74B0 +:151500003663C7C458757D99E6E3144ABE9AA12F947C9BF50CD4 +:151515008CEBAB1D34234CD447180B4298111E57823AA4431D81 +:15152A006768C3D7CAB2AD92C6AD92463FE63CA91C16DF3FF7EC +:15153F00E1FF709CDAB90469291BFD5236446E9DE415D833C0CF +:151554000DBEEBAB6C10E61C105FC6F58DEC875B3ED5BCE799CF +:15156900AF3269B70EFEBE8AB2C2569792B0D97682E72DADE6FD +:15157E00717D5146D64D2F2B7296012DDCE704CDE492EFAB5527 +:15159300511E4ABE0134BEC1CA529CCF7E53D2C1CBC0E6F81BA9 +:1515A800C7A4FE495015BE293361DC608CF8337C825E8FF0D8F6 +:1515BD00B855A83D29D09E64DABF2DF80B65F06EEDC9F843208F +:1515D200770BC03B94FDC477DE271FD06EF709DE2FB9C6F8FCD9 +:1515E70009F8B2F5FBDAB2F576D9D305CA9475D3CB4A9C65796F +:1515FC00F1542EDF728EDAF3DFA91B7AF274033EA764DDD5BE7C +:15161100310B7C63D755E3F3FBD96FD1EE4ECD27B36CBD843CC7 +:1516260079CA9639785F78B6D748E4D5CF3A3766081863B4A142 +:15163B001CFCA948C92615F7A301D6853FCFEA38940F9C17769B +:15165000DD94B30E78E19670F8D301632C0F86CD032183A2CC22 +:15166500CC2F03787BED325FB6CC2C5036D39B5B867DEA73F4B0 +:15167A00D92EEB2D5056EC7596993451A9105621F9436214752A +:15168F0006CE4B1FC83CC6CA306EC2FFFBC7DACB1C6B51524A3A +:1516A400F89A13E5D7C7E5374E6D399F7910F72B13AC1DE6BA33 +:1516B9003F2474592118EA35C380BA700CDFB19DA53BD60968C7 +:1516CE001F501F6E475D02FFF1BB0315633A878FB2E223AC503C +:1516E300B9EA28A7CEF6E585CB5528EF92712E94FB7C7E617C84 +:1516F800B820BF7C85FB3AEB5CC21832C7A3072A123AD703DF1D +:15170D00866F7F4258D8CFAF1B037A2D747D6758B9E39A907AAE +:15172200DEB6FD421FE7F23A571F17A005BE11B48C51FE04D841 +:15173700D7233CF06F0AF2A1407B92699F4BDF1E87DCE1FC7519 +:15174C0079A7CF6FE29D3EBF8BBCD3E7322950B6DF337D7E97A8 +:1517610078A7CF6525AF0CDB3FE7FC36BB26E13ABB92CF716123 +:151776001B90A70B1DB60FE3E0DD72AF86386CA19A57A738EAD9 +:15178B007C79756E475D795E5DA9A36E812AED48204577F72309 +:1517A0005D268F1F667D8F380BDA7BE6DCDF88338C69E058640C +:1517B500FD8D98217C8BDCDC45A266737E547F75BBABAD8E9F57 +:1517CA0067C09C7AF516428A0E361AC9CFD31E5843EA53F054F3 +:1517DF00802798FB87FB643F03997A3EF6C77A726984BDD79F79 +:1517F4008DAFB70EFCFFFECEB7104F0DD0CA423DFAEA3B9555D3 +:1518090076EC09E339A4DB7C7312CFA274C7DE9CE2CF495CDB6C +:15181E00C033F9668A9F5101FFF25EB157E2F039A98B8C9F43E4 +:151833007E52807D39C4E339D2CEF6839D1D053B0BCFEF8FEA65 +:151848008277D59C77B6CD8D7D96F6106FAFCE3E93FC8BB8384D +:15185D00FF50FF35013C13CA3FBC53B903F1EDB957CC93DDF0B5 +:15187200447F12734E79CC08FEAFCFF137E36CCD771C7335E3A0 +:15188700FFA62CEC2BF024217992903C49489E249027C5B09E3B +:15189C00BE16FEE15CF26A4B0233B5BEC04BC58257A2EC562824 +:1518B1003B1018CB295B01654381E3765929969541D98D8149CF +:1518C6002CE3FBEE829F7A0AF8077C6C4D4DE7E3A53B89A721F4 +:1518DB00857CACBAE34FDD9FFE02F25024E5610FE03DDF9C4B45 +:1518F0006783423C473F853903B4BEF4E9745A5BE11BFA29D2CB +:151905005AF3AD69B5E391DF86DEED05E82D96F49E015A1B9ABF +:15191A00A7CBAF8939BE0564F7E38B694F11F4E3838BD3FB616C +:15192F00029CD317B11FBE6BEA47E63CEEB7EC4F5781FE28B23F +:151944003F5756114F17FCBE0BFEF73E813E69554CD56A18D73C +:15195900FDA0F35CCB09998472FCAF9056FA21BE0774AA017723 +:15196E00166886A56A2D2F22FE08E899B511DC0F8C51DC35426B +:151983009B98A262AD12DB0FB65831C11EF6F3FD2C0AEDCE4436 +:151998008E58A51DC7ACB512762F3CD3D79B74233C5DE2BFBBA6 +:1519AD00218F9E06D95687E746F0357D9AC04774810FF120BED8 +:1519C200E833B9F81640BBD28E23D65AC0F7E10501C327F17D8A +:1519D7007C41E083FF6E273F55C9CFA34D44D437919CFA39B6C6 +:1519EC00FE93F59756E6D6CF95F5DB65FD0779F5F364FD5A59A5 +:151A01007F9CD7A7A8EFD9ECF9A334F491913E1DF790DC68A32C +:151A1600F3CE1BF5833FC4F0CC47656C7333EE2F997D75959A13 +:151A2B0012D4A53E1BA838AF3787F6055B1DF1DCBD273B7E8D0B +:151A4000BC7ABCFBFDE680A3FCDC0BCF5CC1F2959B7FDDEC8CD9 +:151A5500FF9E7DEBA72F63F983FFF8AB665289B1C761DAFBDB56 +:151A6A00275A7C7E7373EC87C433761FF14CA3D391AF9B7A36C9 +:151A7F00D73E0B5F2365A10E7179C53A8C97A9B97DB3FD236C72 +:151A94003713647D3028721BB0ED40DBB83E33725F607F1BD7AA +:151AA900E5CCB47539D4719D0F3079591E3C5C6F52B02D5D5C15 +:151ABE0086ED35183306CD2A1DF7BDC16FF4F457C4F4BBC89216 +:151AD300A0972CA99BAFB98298233650C1F4756655F0BD0C5F2F +:151AE800C6F83EC46CCE0FB6177D9412F0F546F3EA3D8E7A059E +:151AFD00EA7BB37CED2F5248BF1BEA5DB5307EB2CD7C6ECFC40A +:151B1200B7D741FB8DB2FDF740FFFBB592805DE787BA0622E42F +:151B270009FF2F3C3B6254C3FFF98E360BCFC60D5F1E3DF7C0A8 +:151B3C0038252271CB0DBAB6FECBB4277625EDD9FA557A96EC0C +:151B5100DFAA49D0D3203F397AC527E574B491F079134A3E4B1F +:151B660093256416CA19FAC136EC27619E610C4775D0E5AA8842 +:151B7B0019C723DCFED2808C3FEF01B8D5C0FFDE45C493AA12E9 +:151B9000B27FB20160CB7D72226DF99364980E4E8EEA336F4273 +:151BA5009B1EA0C297D5E43E6D35C576459EB8F1AF8B7E50EF22 +:151BBA006B8CB1062BEB6F45E0BD669090283C1B9E23C484E70C +:151BCF0065F895C3FB65F885E0C79E13FB5D08A7F53FD29ED399 +:151BE400B82693FFDDE7D39EE3F89F8DB079303E181BA8E47B6F +:151BF9000929EBF4FD843C87B6818D58367FED75C669919FC22E +:151C0E0061281AC6285EC77C7A9ABA8F102FEA228C9B711FF33D +:151C230088E56AA306EE2763EC8AE7CAAB23B8B75AD6E4A0E3B9 +:151C3800AC9BCCC2D82AE2C7734FB857B100EAC73CD25E713CCB +:151C4D000798CA7535A326FC5FF05F609F501F89FC8B0C2D99AC +:151C6200B39958F63B570AF0F17D3CC5F18E7B97F63BEE59F2DD +:151C7700B80FFC1F73C4B96C783E76C4405D904A5FCFE71EC6BA +:151C8C004486FEF9282F23A9EB89EFDD51F10E7F701CB36D6341 +:151CA10016C65186268FEA650ADF43B1447C2566613CA5C94103 +:151CB600B7D8BF1CA60F4C3D30B5787234472E67A35C227D20D4 +:151CCB009BBB6F271E1EAF0C1F61E8F7EDD7560510861B73A2DD +:151CE00022A798163941FDFC9CD3179697E700279862EF075FF5 +:151CF50014F916FC5C82DAC3F74C791C397CCC7A5CCEC76BF51C +:151D0A00279B1CFCFA661A246E3CAB84F80BCC81F25560EBE5AC +:151D1F00FC60B8F7AC522E5764B288801D328662CA263C7B40E5 +:151D3400EFE5716FBFBD6E9B43460CD46BC85B2AE9C3EFCFDEF8 +:151D4900463CCAD45386FAFE53BA5347E2792466821EE76BBC5A +:151D5E007E9AFEBBD30AC626152EFBA6581F4D017FCCB87E3379 +:151D7300190DE299C5D496A3CDCE71B94EEA8BEE159C0779F150 +:151D8800175CBFD9704D0E374D4ED2CC99447594611CED7B66CF +:151D9D00BC20EC191276F90A92B38F9B858F79A4FD745FC5B0E0 +:151DB200CECFC7838E45FA63FCEC42DC5C8CEB03C0519C1C3729 +:151DC70095E409D35D1A37704F7026E09B1B66862B42E9A1A492 +:151DDC00B249D17AE90DEA2F8D33E9B4DF1B5382D9757098A279 +:151DF1005FBBDB85BAB015CAAAF9790D9EAE8B3EC3FD620D515C +:151E06008ECFCA06983B77BFC8D75A01ED4D727F017AC13E46AC +:151E1B000EA37D1CE6F6715FC549DD3BD9773BC737A5F4B2C6FC +:151E300031417B386E7AD1DF93E54591B8A9362678FF0E9103BC +:151E4500BA05F2EA5E07F38DC5AD9BC51955E68A8C67FA3737FD +:151E5A00341AB4BF15FA2AF33E8D9EF70E67F371F7817FE13540 +:151E6F00253DEC2AF440B90AFA176971E2748978EADE9C3334E2 +:151E8400A82741C648E549B18F20FD33E09DE08FC82DC8E5A33C +:151E9900DAF762CE7E3DCCBDC806EC036BC7791A4A1EDE5B29A3 +:151EAE00D681E683503E188EE96EAFD86B4B024DE78B4D3CA3AA +:151EC3003E0BEB03EB458E0CDAB0C572EDD8CA6564CCAC833ABB +:151ED8009B764E37B46F58CFFD6C1EC75F2BDB353ADAB5245FE1 +:151EED00DD0B3F13CBA3EB798CC4C43831F605D7AA48C7E05399 +:151F020071DD3729F704A1DCC6DB25E1FD5501BCBB1D78B7CB1C +:151F1700763F71B4BB0BF0623BD3D12E2ADBF514A0EFAEE41B6C +:151F2C0026CEB17E4EE3DF9B685FDC408B0AF43DCF65679CEF03 +:151F4100430FFE13D04AC4397EB783D66E097BA000ADCC41C374 +:151F56006ED9EE50015A871DEDF6C8762F7C0DAD38C636ADA5E6 +:151F6B00DF406BA983D6A484DDB1613AAD5D1BB2347C2CDB6D89 +:151F8000DB7095F1DC901D4FE52AE3A938F09EB7C7B300DEDD56 +:151F95000EBC17ECF1BC0ADED68D38BF2690074C75E2C5FECA8E +:151FAA00FB36B0DC96F935D0FE308967647E638990F92B2E21E2 +:151FBF00F3A18D59DCE11281BB65E3D7E006BC3E89D7C6E77309 +:151FD400F473A384D1561806C3396BEF7597E7EB3CD02FC75F90 +:151FE900CAEA3B3E9FF95D0A4719B767784F8E7A9CA11FE92EF7 +:151FFE00ED33F6815FAA826D53D79E32CAE909E32021739C3A1C +:15201300E86FA05F85748FFD9DDF15D70F9BE33ACA8B88271E8C +:15202800D0613DBC17D7BF77715859DBB01C6015815DC8E8D5B4 +:15203D00D0B8EE5E17E73A95EB53DB5E98A84FE35C9FAA6D40B2 +:152052003FE85197E33DA7BF9598AF31ACBB2A9881E7F178AE2F +:152067008CB0F9D23625047E26F5697848F8946063455F46F90A +:15207C00F9097E3E08ED52641CECD23B863B7682A26D2A684F28 +:152091005ECEAE1F193FC7D46BF8319C8E7B15F2FFA5747A5E1E +:1520A600FE5A52EC77F278BD359C02FDEA81B915AEA12CD41386 +:1520BB00455DEC2E163A59917E7C293CA37F486772FF588AE7B0 +:1520D000E79539F3C6944671EF4CABA31D5EF893DF0E6DC2F3A4 +:1520E5001A9E5B3AC910CE83987F510BFF8167E877BB2A13EDD1 +:1520FA00587F4368D4B821F40ECA8CD5CC7345C618C2C372FF1D +:15210F00E6B895FDFF8EC1CBFE3A8E3E0BF1B38421BE7F076D69 +:15212400BAAFC8DB631CFF324BD3608AFB4D0E9A12B4991C5B1C +:15213900E9D75C011B37DEBDC3F34230FF1ADAFB6FFCC2CABCBE +:15214E00AFFA228327B9F058535126EF07D6AB320F1BE92ABB9B +:15216300310E7EFE10B3F819D31A3A07F87D3BB24315B044DB21 +:152178003186FC07B368A9EAD330D6C7E19B414BD18E5BED0E8D +:15218D00BF12D6DDE411AD64E5844BAE8B0BE05983BE4B41D8DD +:1521A200555689FA16C09EA0840D594AEC94856704C4797E691E +:1521B700BB51BF15CBF98B396DF25C0091759305FD19915B88C8 +:1521CC0072746106D29560ED226798B9257D6E271D682B8B05AC +:1521E1005C7F30415522CF2AA8C72CA443FD6889C56D51868E26 +:1521F60014ED8A65E51BE11CBD4FC0194C09F8026E82F3A7EC3D +:15220B00A33EE68235223F8347C6753C138F3EB0F82661619B93 +:152220009C7900F03F8C65FD1FBBDF083F719FE89FC0339683D4 +:15223500C7DE73C0B69C8F49C1C71B36F75AFE7082D7259C38A8 +:15224A0033E7914354D0D24055CE975679875080BA653E202FCF +:15225F000F8FB28717A1EFFA0ACF4773D2E07B7909738E1DB4DE +:15227400B114F508C6FE992D27E80BE30D65CF935E9DDFD31477 +:15228900A69C2FFCAC05D42BD05FD660525C841797F61AECC022 +:15229E00ADC607FF96F690A911BEBEF7E118A96F1A8A768AF9BB +:1522B30023E24E017B0D535E3C7D1DD5D37624735E3EB39E9A77 +:1522C8003A66DD7EADEBA9F06B962D539847365C22D6BDB93243 +:1522DD002564086919967CE163128C7179E2EB5958C7A33D4393 +:1522F200794219E0BC32C51AFEA5AF44AE52A1F504CF1B0EC06E +:15230700DC6717E83C7FA01DF767BCDA92FAF7D19EC23AFC1118 +:15231C00EDD6E0659893CB93BE55DC36DE2FF37DEEC74B4F0E1C +:1523310070B9E3F960A2DCC2F2F7E4FA3622DB46F3DACA720B9E +:15234600CBEDF3B836FC5EF9CD60DE37B2DCC2F22E09BF5FB607 +:15235B008DE5B595E51696DBEBD4C512FE6AD916DBE1FB028718 +:15237000BE6975D4E13B9E6DC2334D6E90A362B0558A36622134 +:15238500BF1475BF81E31DD046F19EA9B9734343CD0AAC57CB16 +:15239A007A2E18A5DA116BBEF94993BFE55343891CB75E8E95C9 +:1523AF006C72C39A0BECF1BC9991192B95C805CB96D999A0DB1C +:1523C4009257709F2E3B077E0A3652E1E746D8B4F928E757464D +:1523D900AF200CF5E08831583CAA236D73375759F67CE632C014 +:1523EE00CFE58EF3BB8BF8592FA147ACFCF92CF2400127CC19EB +:15240300E73C796A76AF91F8ADD84754A54EFBA679F27480DF1E +:152418008D23E6C8C008CF89518BB3F98F8B31F7007C8D07F85F +:15242D00DE7E36AEB50EE4CD67CBCDFF36BEE9984FAD45FF072C +:152442003A3ACF9F086B23ACC4DBC7F9F912C06BFAD4E10B5CB6 +:15245700CCB3BB400BB611FB20A6C5F7472AC7DA4B0EC68D21C8 +:15246C009015B5294E93220662B9C57E29BF37096D33D66BB0B8 +:152481006E4FA17D97F0307EAB4716B1622FDE75D743272F66C3 +:1524960071AB05FC107704F0F23D0AD3C2F11A02BBAF4E8CD0AA +:1524AB00CB12278E6F0E4EA877E7E1CCED7F75FB4607FE900352 +:1524C000BF5600BFE2C0BFA000FEAA6BC48FFE456F6380DAB4A9 +:1524D500200D139F081A1600AE7CFCEAC4118E4B8B8CC0DA3C30 +:1524EA00D10E6B6F0B7D1F45E377CACC5B101961CF83DF833679 +:1524FF00ED92D3CFC1589F5A65F5B65103EF74BBF46455338FA4 +:152514002756DFB4B4AA6D6B50FB6143E366ED9EBF587FB7B6A6 +:15252900E127BBBA3B1FDDA5ADEFDCDED9B1AB33A8B56CB9679D +:15253E00C7CECE8D5D3B7EFCA3AEEE2DF5CB6E5B16D0AA1FD909 +:15255300D5B56DE7CE1D8F6DE978BC235457D75877DBD23F5BD6 +:15256800AE3DBC6D7BE72E2DD0585BD750DB7807BC04EB03C11A +:15257D00FADBB4AA4CFCCCC6575BBBB533BAA3BBF6A11D8F4646 +:152592006B3BB67644773D51FB68C7B6C76A77ED7CA8B6735700 +:1525A700B4F6E1276A3B3AB6F3B2ED3B764497EDBAA96E857601 +:1525BC00ABD6B9755BB7B6B5F3E18E1F6FEFD61EEAEA78EC478C +:1525D1009D5AF5EEEECEDDDD4B11CBB783BF75E7B6C73B77D624 +:1525E6003E0CDDDAD2D1FDE896AD3B1F5FF6D04D2B1AAE063F10 +:1525FB00039E9F6799E30FB7EFC77D42B58ACEF537B4576BF5C9 +:152610006C199EE5B1F3F423CACA85FA05E350E870B4880CD334 +:15262500F63FA63379FAEDDABDD67FFECEB552517F6054692D59 +:15263A00B40AE6DE39D0253E78BE85BA539ECBEEFA22ED797785 +:15264F009112DCA81D613550379F8C3787B401C6EBC3CAD30165 +:1526640028437DD3E428C3762AD8408069F56BA5AB6C9B500E21 +:15267900BA710611BE04FEBF02B0F7A9CF44D14F1CFE657A16F7 +:15268E00D2E5CC6B77E6B4C72E8B585C1F6F5F4DBBA03D513FA2 +:1526A300B77CF0CD04E68D39F0B328E1676797B9C85CA40FE9F8 +:1526B800F069C718F66106AC53317F8E4C2DC538ACCFDF72AB4E +:1526CD00817DC77B164BFEA1D1C02B54AA0096D8AF3A44C3DAC6 +:1526E2000BB4FE6DC00DFE940FBEB7F1E0391EBCB301CA2C2721 +:1526F700CE35E934C7C9EF6D04FFEA783A3DA732E2127B6AE153 +:15270C00017A1DD80584997C0BF3660350F60AA7AB04ECE521AB +:152721007E6FC47EDC972BB3C7CD3E6311FB038EDDE77CEC30F5 +:152736007EA36930EFD4BE845B5B6195B41C85F13EC061E33C5F +:15274B00C43958AABD6CD57CE56ACAFAAB620C6C7E3BC7C1F730 +:152760004EDAFD75F5574EA66739C703E951811E9F63BCA211D6 +:15277500378D257F65A920875A722431D7BF1BDA76515F7211DD +:15278A009B9D2CDEB43AB914E435DA8E776AE01D89782F0E0997 +:15279F00DF4DDF55709DA453F465947F79D0C07B36D662FC4621 +:1527B400C533BB61EE8B0E9ACBF5D74275ABD66845ABDE2F396E +:1527C9004FFDA15BF83E63EFEBE959975C765ED6009B9133FE04 +:1527DE006B29DE5D89EDDAA1DD19D92E906C01B8ADD66A11DF97 +:1527F30048F03B29E5B326B2860EF0BC9145D485F77F014FC4CC +:152808009D94B9CFBD2E71278EB8E76B047CE95AFD52B180EFB5 +:15281D00A523C603DAECE05C6D76DDEB8BCA82D6E21B83A7B1E3 +:152832000EE3BAE3E9598B355790D3A90E50DC8376C3BC3C0DA3 +:15284700F320137F9B7A45D8E7A957AC9F5754EB7CBF1874E630 +:15285C00A0840FDFF3BDD47E8065B7B5DB6D873607DBF0BEB4B9 +:1528710012DE07DCDFCDC7A57F21E6512B7CCFE358324E77F2F6 +:1528860028C233D982D251C3F7DF87190A4E6B12CF389FE7E720 +:15289B00A9ACD0ABFA10C09D5F5A632C07BEE2D9D81A729EF631 +:1528B00086DE88624C2D896B83B6A5860563751DC84EC99E710C +:1528C5008AB90441DCFF507F21C646CE65F4A915BE2ED380AECD +:1528DA00503BA75FFD85357129ED395A24FA79178C75538131D3 +:1528EF00857575597E9F7A2FA5790E09C2D92EBF9F0F73AE6456 +:15290400CA34F0BEBA2258A784928729FD4DDA637F8B730575F3 +:15291900E284E43BC66F911701E083DD6618EAF83B7B864652D2 +:15292E006911EF8436A54773798F325888569CC7E5C91EE6FB92 +:152943004CF0FC83BFCDFD6E02F98F72CE75C37E6AF37A1078EE +:15295800DD9A1CB1265E933E80B3DFB83724FB4D7F2FFA8D63CC +:15296D008FF0A200AF468E1997CD51219B788ED6D576B71186B2 +:15298200FA9B6DF9936321F89885D1F07B416B1464E2E3D78499 +:152997004CCC2FAD37FC23AEA02D1B78CC3B2AE2B952364EE849 +:1529AC00E8DF2D262756A15CF81A135C1E2C73B1EE1E386228C5 +:1529C100A073174B3910FB02B9E37E12F8EC575F0199EFA15EF8 +:1529D600900B5F4F9D91BA28F96DCF07C737181B2FC4EF6538A7 +:1529EB00DFA13DE7793E1E984F9837649F7FB9CE211BDD201B4B +:152A0000D13342365C781796940DCC8343DEF01C07CCEB782D44 +:152A15003B7E086F76B8CBD0FFFD2FEB41C759D5C936AB2AD9BA +:152A2A0062819EB3400FB202F909FC5E665CEF946A553CC61AE4 +:152A3F002BB00F06FA9BCEF00E1891728C1B8DB5A3DFE6F28C47 +:152A540018B89FA6CB73D6E8833FC0F79712FCAC18DFFF8275A5 +:152A69003B9E0FFB79C54958ABC6F95E981AEBB3300F7275EC6C +:152A7E0014F7FFCC581C65729EAAF559ABB553168367191B3372 +:152A93004E6BA29E2C8AD38FAFE21FBAC984E723A5B9F8B1A2B3 +:152AA800CF5D3F73FD4F7B4F1B1DC575DD9BD5AC342B0D627676 +:152ABD00D95D495848232C12C9519C5DB1C8922CC242A88FEC13 +:152AD20010654B9D744612F63AB603B19D84B634C7E784C42B00 +:152AE7005889058FF03015F65A266695480E6E209539909014D9 +:152AFC0092A5761C9152B2E1381C9AA4F638716C9AB8B6EC6293 +:152B110087A436DB7BEFCCAC56027F25ED39FDD13367CECCFB72 +:152B2600BEEFDEF7EEBBEFBDFBEEBB95BB86F37317D82FD98F5D +:152B3B00D9F7D9636C823DC40CB69D6D619BD917D84676275BBC +:152B5000CF6E6537B33EA6B04FB0B5ECE3EC63ECA3AC9B5DC784 +:152B650056B3556C255BC196C38CB29375B076D6C696B1085B45 +:152B7A00CA5A599885D887D8D5EC83AC059E0FB0AB58333C4D64 +:152B8F00ECFDF0BC8F2D81A7119E2BE1590C4F033C323CF5F4B3 +:152BA400D4C1B3889E5A7AAEA067A1FDD4D0536D3F558527687B +:152BB9003F81C2E32F7A16143DBE598F77CE235DF2CCBFE4A91D +:152BCE00BCEC33EF2D1FF16D9F8A777CCADFF5E379C747C0C3D7 +:152BE300535AF6BB963D6099CEB280EC52D7DE1F63F241F46BAC +:152BF800043FDDFE6F82FF9CFDDF02FF1207FFC863EA9A207EDC +:152C0D0054D359B7968349B2C4299A242F3E28C5E1CDC06B2E5B +:152C22003E487602C97E6C13D9BE9365DBCF63FB71E017B7FD26 +:152C3700CA6D3F17F8656CBF0ADBAF04FC303F2893CE264A2C4B +:152C4C0016B2F342BDE2909D07EA1187ECB4A8371C8234310E91 +:152C6100F768656DE3B751D0BA4A83D9F6A81BE41AF48BD1B952 +:152C7600FFB0EECB70ADC25433F081865161AA83EC1B26DE2674 +:152C8B006CF26DC2C81E0B84554218F81BE8CF9FE850A9EC5CF1 +:152CA000B3E1E0CEC139D62367C3983B4234D1659A8787749C89 +:152CB500F731AC27A509F5237E118792CB8A3F99B5C3813776CE +:152CCA00C98B0DDDC9E7B8E51F837831E49BD262831740067A12 +:152CDF008B6F8C9B89932BFA975C33FFBAED4FF8CFE6E7A36DBF +:152CF40009EB3CB7AC4D93FD5BD9D2E720DD4999743D4AED7F28 +:152D09003A37EB82B686F66043EDC03B5D2CE96A37CA609ECA75 +:152D1E00473BD4E9860E5A9F9BFEBE7B19E204DDB8469A857495 +:152D3300226B471D6CA30570018C5613E456A38C5D05B05F65E1 +:152D4800B883D1FEDC65FC24CEF263F2AB06F2DAA6B96B14217A +:152D5D0059273F6CDFF0BD49E65A79A099941868E571BE2C35E6 +:152D7200A03D4A18CFC35064BBDE42EB5061834908974CB0C425 +:152D87005CD55046B38EE5F353D5AA94688EE0574834B7E23778 +:152D9C008675CD8548A6C6B8D48ED15E6528A425A84FB46B511B +:152DB100D26D8AA27F3C3FBF1BE2C4C88E24CAD0D659D8B8163F +:152DC600A573001BAC33B1A18D961E14BBDBBE272065EB48E02C +:152DDB003AEF7C002A09F397A4AEB3A482FB3DE87E7505BF8CF3 +:152DF000E5B6E8A2CCB7B2D856FD3CD62B27EB96DD5C4B6FAAC7 +:152E0500C52C69A53C213F5A57C2FFD8889EAA49281CD9F31C8E +:152E1A00310A7A20B11FA4B17EB5F2FD3A2F9F30989E84791408 +:152E2F00BFEC9B377F13F27F328DFEE8D7027EA373FCAAC16F26 +:152E4400688EDFA6150097F47CFA7337BF1006815913E5A7F5FB +:152E5900BBD99456BBF205B5B7FE99F043EDE7ECB316093A3FF3 +:152E6E00BC287106EF0EA075B3452B4FA97C665C77C1B828CBA6 +:152E8300DF4A33FDBC21A44668AE836B6D4276775B10E7515087 +:152E98000ED3BF615CC1BDA0221ECAD933E1C99B5F6A031880EB +:152EAD00A64F035CA7744EDBA93EB4EE79ED8AA806ED68A70154 +:152EC200384B5C5CB13A2C6C87F2625B27D9BE52B42D3E2908A7 +:152ED70068EB74DBA8D0FD02F83F306AB9BF6EBBBF3D3A95CFC1 +:152EEC00073217E75CF311FB693AE99AD2116F77B3AC96F85E05 +:152F010069EB97BF5CDA8AFA10A3B9879485A71F504A4E3DA5BB +:152F16005EC7CE8417668FA964672DA4DB76067354D780F4F77E +:152F2B00EAF95B9E3616724F42F81943481C68C3392CE63D7D7E +:152F4000CB295DC894B61EBAA77419CA26C447A4B18349570694 +:152F5500E87C58C7BAFC61EF6024781CF2967EAD617D24843B52 +:152F6A00F6F8A4807B23D2B68312C1FFC383CF431F2C978753B1 +:152F7F0068DBBA4C1E4CEC4A680AD7A3411FFDA98E3657E38FD5 +:152F940031769F80FB095A6ABAE13503E2EE78496E591683F8DE +:152FA9009BE3AB5B518EA1BE251DD0F9CC578047BA5BE3D9FD8E +:152FBE00AD4C3FAC4F63DB8370EC3F6BC19FCF1C80F63348B612 +:152FD300299A6CDB31D4D7F461B20BDF44FD0C64DBCC30F4B3E3 +:152FE80084C6036D25A645F02B30AD15BFB85F266476431E596D +:152FFD00B2C55A9D49EA9C00380A65C9862AB643EC1FFBA6308D +:153012006CDC88A1CC9D491A572534F2CF803FBA512E9C6ED029 +:153027007431CEB77A4176C47E32DD306E2C0C66FA8F5E742F22 +:15303C00035C1A536FE40509E0E98232CE60BF0AA5B52CF0E088 +:153051002EC89765F6184F15CEF7A47411301002E09E1FD42243 +:153066004C3F9EA67929F0B3EDD153CAE9DB4B5BD36C504927FD +:15307B00762B171BF965E9E8B052951C51776DD5945D1D6749C3 +:15309000B694CCFBD39D4BEAAEA13DA3506212D762BD8B92B8B7 +:1530A50027A8D766A84ED69AB680F67513B466DDCEA32CFDBCA3 +:1530BA00CE75A38EE113C6AEACA6E07AA190D903E9B6219E69A5 +:1530CF006FAFDABCDFA8351F369A0037B550D75C298805108ECA +:1530E400FDB349DE46B63C280F49439B4E42B57C9F4E36F7D6B9 +:1530F900691AA4D39137F0F1437AC4FC1EC4DD66A00D4E616AB7 +:15310E008F8A79BA4E4E908E5AEC71C66A70BF3F74846C05F0F8 +:153123003D432AD469D4D5B3534D95B1D9FD23876BFB29ED8BE7 +:15313800FFC6FFF0618EE8427B1E7EF311D203A45B7670CD1FF4 +:15314D00FD5892F4B5B0CED6FE478AF63F8CEC88526D0EA543D0 +:15316200E6231969A5A60AD76B6AC91A4DE565CD1005DCD3DEE3 +:15317700A3354577B7E1B9B1C000B41F98B75627D07DD808DA47 +:15318C006E3CD36EF1FDDD86DF145BD18FEC8D16F643D2B4E610 +:1531A100EF42DCE446F446A28375C69963FB34D4CBB6CE365B69 +:1531B6007720FC02F2E2D6A0CE5E86E8C7A50EA8C14583C60317 +:1531CB0051EB5C2CAE9DBB7A2CDBCB3716D921E03EAA912D62AA +:1531E0000969AB7FED20D93284FAE33A346F022FCB9D277C7B31 +:1531F5004DBE57A4B9439AF6195CA46B6ADDB101F35C03ED4235 +:15320A0021BC9CF945ADC95C102EE6F1C8DB918EC4DF0BBC1DC8 +:15321F00F8FC86D25EBFF9BA4176DBFE11DBE190B1E5CD7CA012 +:15323400E54DECBB162D10D77E73A7EED246546FA7B5D7EF02FD +:153249001E81F7CB886C64A9086D65211B09231DB5A236AA591F +:15325E00F4D2D3A4F375AE9FDA18D00FDD3CB3F45F5336DD9182 +:15327300CE9806DD48D7B934251AD8F478271CBF5B5AFD4FD299 +:15328800A29C6891B6F7796668F28EB4281A6B1D3AE8DF477B45 +:15329D005995A1629AF8E2EF0F93DDEDD8C0E4857BDEDF26C538 +:1532B200CB605C1DD0D1B636F2AECD5F2C6D9DFA2F871F59FCB0 +:1532C700A31A68E65BA4191CF04DA421D6D5DAF3B1CAC0F230DC +:1532DC00EFC2B9A882BC64D1A5A688269B099E94657705C27175 +:1532F1005F5132771A9C9CA4F6846EA5C8BE40A4287DE4930561 +:153306007D5FD2134EB309D2DB6C42DA0F4C28A2EC26DE1C225F +:15331B003D404DAF895ABCA8D00FA1CEDC061C8FE17BFD29C2BE +:1533300001F45B7FEA0F567DCD39D76CA18DFBEA60AABF06645E +:153345000199650E8658F660949907AB7F9BF7C07712DC93E0AA +:15335A003FD96DA77FABF8CAB9D9F1ABEDF838AEEF7FBDA84C2E +:15336F00D4C780F947715AB2CF45771668FAC57BF8655DB87E3E +:153384002E1F4DDC37754C2985E9062F8FA4D04E49B9FC448ADD +:15339900EC86D37E5096CE544AF22198B72475D15CD27AE3FDB6 +:1533AE00790FE2417B30EF999B67316CA4770869BBE407F5F373 +:1533C300CF6A2023E96403C56A877F6750DBB56CAD4CEF0279DE +:1533D800B115E4A2F7D236A79F1DD193AE94CEF6F1BDD3CF6A0E +:1533ED0046D29536BAE45DC6EB17B17F24ECB9C980F11CCA42CA +:15340200407FDC5F95A18C629C5C787A363E717FD796672D5DEB +:15341700687D8F8EB23307FD0BEB086E63F5DF82BC188A914D54 +:15342C0074279FEC8F67F2697C2D2FD4E2D9A16035C8F103FAC1 +:153441004928F36E16D798194AE3BA986836E9A5C7C3EAB7121E +:15345600CDE1C1F6F659B26519C375E276EAF765DCADC067AE49 +:15346B00D765339666D22B862034A8B8D66CC9958BDBCA61EE8B +:15348000E2AA53A80CB4878769DC0361B5321A8E944399FBEB54 +:15349500AF6DAB3565181B9BF46A33A47362A73AF895B0E6CE17 +:1534AA00C23C31D76E387788A0EE07B374D041DE6C0CF3B8563E +:1534BF001DFBD424D36F191552B87FF857F43557B896CDACFF5A +:1534D40057DB7A174D363F0B013F6B5750AEF7C95C88E62A504F +:1534E9000FDEB11D937B64B226BB47ADB1EF6FF0C3388DE3317F +:1534FE00CB7DC7F072CFA9AD0D95D7B0BAA97EC6CE6912FB759A +:153513009B9F7B59DD29BB5B51560C01AFACE526D440F048BF54 +:1535280010FDF5D25AF8BA4EED26BBF4C827AB56A26EC011FBD2 +:15353D00BEA1843605E3BE2F7158F5D682DC52B0CFFCCE6F157A +:15355200C8E6F84DAF288BF8E2653067F98ECECC470E8E83CCE6 +:15356700556BDEAF23EFC276817BD85E18AF9FAA19591A05598C +:15357C0007C7A14FB875926FFEE9412DECC8346FBC997F4B99EA +:1535910026FDFBFC5BCA34ED6F25D3C45ED04CE77C39F21CC0B6 +:1535A60095D0707B5B39E93423DE8EB5F98FFF07E47F4C5B0B28 +:1535BB00B87BA05D776C76109E828943053C05CD2561E11CEEF2 +:1535D000296D99E44F1C437E1D5C68CE0B835BF79901FA969B53 +:1535E5008BE8AB035FBF5CFD619C8DB8BA5F564F5EC80B880779 +:1535FA00AC6B8B5D7766D7BDF63275C734E90BEFBDFE8B80EE1D +:15360F00D5C85763BBD2B1D7E7CC6FA08E747744113D5B8AE3A5 +:15362400C476EB37B0B47623C8F0CF3F35B254968F4F0297D654 +:153639007C1C8CB7D219C36FB74B1EF505A49F1B77B3B39A97FE +:15364E007B91EE4FB862E5CB6A28FBBDC8151D163EAF602F502E +:15366300DBC3FE7A05CE67426709A7D8E6703D17D784EB4C771E +:15367800AB13A7EAF8D305BC57415A491E48272A92BD18F72EE4 +:15368D005CB28D1D4AA32E4AC9D4310C1B759D3CA6EA799847E0 +:1536A2004178937C7B1B7E119EF32BCA966DBAF91990177FAEFD +:1536B7000BF263A32DF2BF1AD5E7ED3AC6862645D437CBACD512 +:1536CC00AC7F9C4B0D4D9E5B61A53F0278F3DB795D58B1BEED6D +:1536E1006AF6F5569A0B15C5C5B49847713AB4F7BEE5DE334AFE +:1536F60048FECBA5E88FE32588D21FC7FF0771CC8C0D65503E7B +:15370B00C5B4E5A8630FB8C4F361B5BBBE4A785D28838C60E796 +:153720005F39EBBF2AECB2FED3E5F2FC307C7557A525B763FE8C +:15373500AE8777A83437FA21F00A90BB8CE8238A144DAAD5302F +:15374A0096D079BD7761A31F5F1863525C6AAD8AFB984CDA4A08 +:15375F00E3901480F1C41E87684CC2B0F7301E3963913D2E5D94 +:15377400763CC2B108C7A408D9F4288C291A3B618D29563932C9 +:15378900AB965F3116A06C01E394206F37BA5FCD0BE5192D5589 +:15379E000E7047A2C956677E580DE31AC6697AD5A1F7A05EDB5A +:1537B3006ACD2B733FA0701DC343801F4CCF32CFE97417484EF5 +:1537C8008379654A2BCD24133E2847CA1C4A639F2B318F699847 +:1537DD0027B6356C734DF2B3A3D8A6CEBEE1C86B36CC00EBA1A5 +:1537F2005D5F813E3CA0D37959B439FA5D6B5CDDF3CA4CFFF2E4 +:1538070006ADF32F82BD5F3659C53C208B7AF62DB0DC719E794D +:15381C0036BB98670A5E4BCE6EB27993A523E2C6BB03FCCE58AA +:1538310098D136039EFCC73BD45520CFBA07C6D491DC98522753 +:15384600BB3B17CA1FFC30AE9D511AA9592D9C178D3540BBE016 +:15385B0086F87883EE96701D8E1B7A716F73849D1FD0CC1378F1 +:15387000B9D15C797276F9AB12CD4BFFA4722ED1BF09F53756D0 +:15388500B10A495AACA2BE2DEE75476A58855BFA06E9475E9528 +:15389A0079B30B75A7825F0AA3AC4B3A51645F00CFE5423CA71A +:1538AF003CF4EF02F78CCD6E9AEB94E3BEF81341B47DD3D4FF48 +:1538C4004610F36D253D9F5C35AB10E363C05797A8EF93B98E87 +:1538D90052482FC61B8C0BE0CF7F6940B7F412F921679DC02DFA +:1538EE006D517F0161685F6F04E340BD704F4F46DD29F0E3E3FC +:1539030063C651F487FF17618E7ED64E877B5BCF813F7EC78161 +:15391800C6783EF0A8CB3A53398234F74FA31D4656B60FEDE209 +:15392D00BDAC49A71F5450AFB51AE737D2214D100FA83D40DB6E +:153942000532DF5B66EE21BB48B5C00B8326C61FDEC26D1FA1AC +:15395700FBE170AE7355A66BA9245A672FD0F6C97CCA736254CD +:15396C0080388215C75F9DE19772FB2E4DCB6265A4EFAA03DE24 +:153981002201EB4C23EAB7A0DD41DCCF37C18F49C9C2FE1A2F08 +:153996009F37EE02BAF1801711FA66BCCABEA3720E7D437141CA +:1539AB008B9B3F3CC83F3DA0BEE177F2AD2DE49BB2F38DDBB65E +:1539C000677700AF385A86B695E47E964B18B4FE2E4534AEAEF2 +:1539D500BD9F379B0CC1443FA095D94EE5579BD306CA4392991B +:1539EA00813CE3FDB82EB9A3668342BCAA6E637FAD8967CCCFD0 +:1539FF00F6F3F2678DA341AB7D34429A263337DA02E923905F61 +:153A1400D702E609417A0BB63F4B236C68A77415CAA076FB725B +:153A2900D545FBA3E6EF8C1D3531254A792AFD317043FC83ABCF +:153A3E00E11B87BC4B614E70A3B9D7889A0FA4BB4D7D34065FA4 +:153A5300DCD38BC17F16C215282BE7B36DF1B20CE1009015D890 +:153A6800519351FACD8C711BE41B07D8FCD85E01572DF015E0BB +:153A7D008B362E6508AF85FFD590871FBE8D3077DB00FFE716D1 +:153A920060DB065C815F37F8F1C06F9E02BF50D0A2477C8E4D94 +:153AA7005FF7D30915DA5D854FE6979714D18B4378E47103D74A +:153ABC00A042F2B826E0FFE5F4E5E83C48448BB958C5D5995BCC +:153AD10022D86F4A3B642D4B3A81CD7A359E6991068C52DA2366 +:153AE600E6869C3C3250667D7A8CCE0570350975C67E4B14E2A1 +:153AFB00453406F90D215EFC4D05DEA69CC231AD5945BBE28BDE +:153B1000E5DEA56CD32B8353CF32E6E4C3360D68999FD8FB05AF +:153B25009BC63413FE51074328C0D3A12FC47105C39EB5F48CEF +:153B3A005B1CFE047ED99FA0AEDEB2E502C00A3207C1EDD09B26 +:153B4F00492097DBE9826CF972B6A983F277F46D310DE45551D0 +:153B6400C9BA280CF32A0B5E8A2FECDF7E6E461F5EC2BB96FCCD +:153B7900FB0A75ECFA31D6F1807A030C0DD29726F4F88F11604E +:153B8E00B44D64ADF7EBE0CEC03B096F16DE1CBC26BCD3787B99 +:153BA300758E0CAD3119DE50CE8ACB360D5A75B574E6C9CD7E81 +:153BB80039DB2DCF7147E7B8E373DC8939EECC1C77768EDB9CD5 +:153BCD00E366BF9A53FEAF8A74FA013FDDDC6CFB0393483BFFD1 +:153BE20064C16E531CEA161838AC56D2D9503B1F9873E3DCFA61 +:153BF70086F8BA48E0D8849ECE219D66F03605EEB3F09E83F799 +:153C0C0002BC02D0A71ADE2678DBE1ED86578177C34FACB8ECF6 +:153C2100D004E12DE3D01FDC8837BDC88D784B14B9116F1B8B77 +:153C3600DC88B778911BF1162B7223DEA2456EC45BA8C88D78AC +:153C4B00938BCBFFD58C5D442A1FDC818E8C816D1BF54BF97BFD +:153C6000D65DEB9C6B279C5DCE3E03E0576445F89D1BE74F0C29 +:153C750047DE7314E417908DF427E6310FEA1AC29CBA33CD31E8 +:153C8A008F00FFC0673A451823CBE545D73C05E3622DFC231DFB +:153C9F0079699B7A971778D67C5671076BEC8CCEB778DA4DF0DC +:153CB4001F996FF1B23AD6B8DCD11B91D1CE2F8CF93AE48138E6 +:153CC9009BAE84F11BD29FAB44D9E1D1193B0A20EF9DA91F80D0 +:153CDE0071793FCA08FAF40AF7F227208EECBDFCF8E48C73B8E8 +:153CF3009789E311A0D1531C4F8472B7DA67BC41DE597E16F2D1 +:153D0800F290FC3E9B8FD502BC9B251C0F51BED8AEEF88E3B99A +:153D1D009E47F52DD1FD547FCF87DCBD92DCAC23CF6F03B4794F +:153D320057EEC6B5306DE33C5CCF1FD399FEA81E80B97B271B90 +:153D4700A4F8839E0985AB6987B175CCC07B8078905BC9B66F83 +:153D5C006C587B6A3E8E637ABFE44D511E47459021218D203F57 +:153D7100AAF330167B2A715D6ECC401B0688E746C9923F10D617 +:153D86009C385BBEDB378F553C01F965E6E138D3A827696C6ACA +:153D9B00A2B109CF137235213A9F7EF662DE539E18E874C79ABA +:153DB00054596ED05F5CC12DBF0BD24CCDB76422070F3E5B5772 +:153DC5006B66FD43D6A7A7914F6D25BB6B98BF74FA030A9ED3D9 +:153DDA0040987DD1B1A53CC82A3CE4390D79F6824C85E7407863 +:153DEF00D265A57138407607A62D9BA17C7CC21065EBFED03C4A +:153E0400E9413FAA0580E7F3F26306C6AF043E4AF7A59780FC2C +:153E19008C770C16DDDF721EF2F8511CDA5E1C6D16587691BFD7 +:153E2E00CBC63A4570E33883B88C9633CFEBD0665F65039D0EF2 +:153E4300EC164EF6116FC23CE8CC045BD2E9C07D1EE046FD401A +:153E5800A04305DAF9C0B6C1A3DED985BCC7B1FB5D5CA7605144 +:153E6D009D9CF106EB45FBBCC0EF102E777618E039AA511DA462 +:153E8200319C7340BDB7CFD89D8D0F68231EE6B9016075D27CEB +:153E9700383AD8897BD4FF7CE0E7FB45B9C50890AEA70A7D760A +:153EAC00B5E1C0CECBFB691E86FF38C64B368ED6D8703A7A6FBD +:153EC100362E03B8BFD60261BE38BFDC5F32D337244FA36ADD4C +:153ED600E39AA6F28CE3E3CB5924827BD6796BEF219FFFF2F1E0 +:153EEB0008F82575BC5BC09BBB57F59EBE56918EAF54EB645735 +:153F000017E9B4E6B6A30E89C7533C6EDA70B6B225342E4F0ACC +:153F1500CCF334D4F167D0F6D8A6AF525E185F405E1F19A77B66 +:153F2A000BE8FC47570B9D7B00395CFF6662AC13CF44207E1FE7 +:153F3F00887374AF9C8D779FCF747756A1BC6E1ED3CFDFFC9DFD +:153F5400E53F0337D69937272EDFDE0047567BB3DA8F681ED6B2 +:153F6900779BEEDE60D7049587FDCCA2A74C3875F835DFB5043E +:153F7E00F729315CAFCB8E459CFAC6B8D9ED12F5122EC6B94E46 +:153F930084DBC1DB4BD971E201621C78825DCECF208F775BA70C +:153FA8003AD3BD3C543EBB2D76BF9EF7AC063A8AF1A2BAC88FA0 +:153FBD00E9A87F56A80BCC61ACFA3715EA8270F05D1FA4BA1001 +:153FD2009EE2636F8927B7D4A8DAEB1E79ACAF707C17E9FAE127 +:153FE700DC688FCBE6138003E0E99E82CDF1DC8076F2BF1C7DE8 +:153FFC00CB16AA13EACF3A696F837448EF34A429E63377BF6960 +:15401100B55751DEAFCBF171ED73D18930968D6D51DA7CD43A54 +:1540260057969B80F9C2A041F6E1A72D5EEEF415DE3C60489E81 +:15403B0009D50B3CF77E985B8926F215CDAEFF9199FA43BBA8E9 +:15405000EA3A46F5AF02BAD9F42D8C21E5C8EFA83F68AA6507E9 +:15406500DCEA0F17D1164AE4D0ACFEF09BEC21B28F82386BBD10 +:15407A00C53AEF8DE53CCC863BA12D5BFDA46BD06AC700EB5097 +:15408F0002CF30EBFDBBC9B6F9B139F4D62D7AD71F5D6E805B09 +:1540A4008C8F17D1F5908E6966E83A6ED72B45F5429EE3ED1A8C +:1540B900A63A2DCCF0CBB1ED3BB42CB45FF0E333686B3FA90FC2 +:1540CE0041FFB3ECEC5BF5F802B44FA72DFAD8D1CE4A281F618E +:1540E300B900B02C84B677A86C76DB3BF99FD0EEE422F8E200AC +:1540F8005FBC083ED981CFE24B84CFAE4182AF982F4C4F5B7B51 +:15410D00C8F8E5E3D69DB37A34B9B1B268CC49FCDE694B85B9DC +:15412200AB8F454608B768CB223D9DAF28B43D906D7E81BADD7A +:154137005FE5AF95E2D6FCDB17DDAF3E0969020D7CAFF7745A0A +:15414C007171CCBB00C3728774E97446E1610E7E10609570CC13 +:1541610081F683EB92828072A7A6058347FA65909112F78EF437 +:154176006E41FFD4EF90876F114E1EA37DF073F5C3CB58EEA8CC +:15418B006E84B85ECCA72E398C36C1FC5578BF10F827613ECE96 +:1541A000A4618387FC708F93DC502E4F7B2AC306A5C3B2F461E7 +:1541B500D4175D5097E13B07AC345B1230A7C77511618DA6D2CC +:1541CA00FDBCA87364CFE91156CC7F6BB7A694F49C5713F9BC33 +:1541DF006FE4239A8275E6214D5DF2C03A841FC74E840561C3C2 +:1541F4003D8476802170FA88521587BA9EF88AEA631AF0F08C51 +:15420900F22D1C17EC3CD1FE3CC8C03E4CE7D47D08F24FED3C5F +:15421E004CF7FE627BA1B8B1435B84EDBF534D840DEA8475C1C0 +:154233007B41912E8807A61FD3109F6DA83600E10E2ECE16F0E9 +:15424800609555C003AEBFE62C3C04BFCF77A67A70AF79421B7B +:15425D0000FF11EC2F8013F4C3B50D1C832D788F010E0E289865 +:154272007F49CF6BEA66C2C301C50BF5431C48782E05F74EF013 +:15428700CE0D280B6DDA86A0FCBAE0B97EC75EAD65DF04E6FFDB +:15429C00AF30B6A326A5BCCACE698B42ECD38D32FF61C79E62DB +:1542B100EE9364AF96ECCE74D31AC19251EB6C608AD245CD6D7D +:1542C6001AB46D0F7C711FCDC8BD36D3CEF13C18AE55611B6D33 +:1542DB00C1B934EA1E86DA35F61AE9B58DC2989B4D34B97B3965 +:1542F00021A2F289B0BA0760AD5726F19E385D977777D1FC14F6 +:15430500E248C03B44F9639D82FCD94E49FEC4723E26E3789DC3 +:15431A007D0EE461FCF6E35C2AF628D9BC0D74C886953FCA8CB7 +:15432F0063D91084B540FA2648DF08E9D1AF56FE44A79307B46F +:15434400A74E11C205087F6EC567293F91E666AF6C71E26CC493 +:154359007200267FC7B495B76EC18D388A60DF00385BE467BB1B +:15436E00F88E901183705C2FE882F934970AAB5202F7D2ACF8F1 +:15438300981FB481000FF9603CD2E77E0DCF015AF769601F6EDA +:1543980067F6FC1ADBBC346E97B3AF1F6D3254D3D97DCB0FE76F +:1543AD004CE8876D2260E9B05F325FE2388B9E057FC8BFD6990B +:1543C200FF901E1F944F7704650CF3B54BE75CD6D9C17D3A8668 +:1543D70021FF015E6B95057102B9AFA9FED35F53505EF5771D0F +:1543EC00B2EEE580303FCEFDD9611CDFB58FBF50C26AB387DBB4 +:1544010036C2B827DAF30C4B67D09273D066BC9038B0B40A64E3 +:154416004F3FE61BDA67C151E0932982CF1F4D46C83E04B8311D +:15442B00CFEAE8785B6D519E85B90BF05C4A6FF3CFDFD8ED19DF +:15444000EB81733B80CDF71CADE934CEA4293E8F48F76DDFA789 +:15445500FDF632E9F6CF4907ED5DBFDC7A52D4DCABFDFB65D2F4 +:15446A00DFF52ED2BF7C997491778477AF76EE32E9DE60EF5C67 +:15447F00DEF49B73F6D3707DA7B8FD01ADA65F9BBDBE31373CC9 +:15449400F1FADB874FBF53F8FF76FE73C2C5E2F6FF76EB03FFC6 +:1544A9001FFE47854B45F8F7CDE54BFF67E0B7DB47ECBDA5C765 +:1544BE00FEB580974916FB24D9B869EA1F94E2B7AD82AE287AF2 +:1544D3006F573508C7BB56C5EBB6AB74D607656EEF0675DEEA92 +:1544E800EDAA2CDFA9CDBB6E40F5F7688AC835A8FECA063509AF +:1544FD00728BDDA7D75D80B159F236A998DF1F9BD7DEEB35652F +:154512001275FF7A70EE12D7502389974B7A3F073C392036A83C +:15452700E53D2DEAC3D7372BF53DCD4A50BC4D1D2CF98082F66E +:15453C002017F17167AEE2C7F83C77A54A6B0FAB078877200F1F +:15455100A9AF4C2AA8DFE584FB28BC59757B1324DFD5DF9450C1 +:15456600697FC9BE2F7C2E0CAB6C182A0086BD0043A0A87C2C1D +:15457B00B70E60C078942FE45F5CF6053BDFE9A27CF3F967F20B +:15459000229E150FB3DEB578473AE49D28896B888F3CB3F2BAA4 +:1545A5009AB10555801B11CAF4AC69061C35288BC416B5F6430B +:1545BA007CAF9B0DF4D57F9EEFDD3B3F4934C0759110C0817BDE +:1545CF00705791DD9019D81126929358E21EAA1BC074D286E933 +:1545E40028D65DBC51ADDFB956E52A1DD8F2171DD83A01B66A62 +:1545F900B181FC1320203AF4F254B6A822C1B45D595499547755 +:15460E006DDD51680B88E73FE4F3360C8CEA893695ACFDE3E983 +:154623007BB0DC9C0D075793C2BBA784F99A05837767A3EA852E +:15463800F2B06EBDB62E3F2ABD115ECA66F0520F6DA7624D974C +:15464D001AE889103CDB4AB62BE580970A31A996B264DF0EBB47 +:154662006D2EA6BACF947B0ECAD221CC0BF802BAFB1C1890F65F +:15467700F5DD372A280BD5F7DCA8CCA53F74226F39ED1BCCF4C2 +:15468C00A7FAA93D148F3BD5A2066E8AAB3CBB539D07711FE630 +:1546A10058D06DFF1BF05FD10370427BA9A88CA8DAE31DCADEFE +:1546B600131D4AC5A9356A4003BF9DAB55ED233740DBBF41C1A6 +:1546CB003610009CD6AFB170C1C7B95E996DA0B60D729ADFCD92 +:1546E000DDA28AF112BCF7C4EFC1BD9ABAEEFE79DCADAAC8AF72 +:1546F50052C59550DE7577A8E2EA1BD4E192554A04D70156CE75 +:15470A00C42F0B5AE766287E326CC57FF233AAF844873ABC35B0 +:15471F00ACB861DCF53E7E9B52FFA1925EB48D2C24C27D9E6CDC +:1547340047DFFD684F4A0BABF5A76E51B9931DAA067139618691 +:15474900169BB08F07E99CCD3AB4A5220C40BAE31D7D34D76B64 +:15475E0067BDA5DE505F99B7BDAF3EB556D906BC4106FF21F8F1 +:154773007E1A79CE4FD6ABE250878A72B52CDF8AB29D20263FAF +:15478800A3726BEE5429ECC90E080FABC38033A43FB6719C93FD +:15479D0094FF03D75B7F0A70A80DA881539F512B4E6EA736B0B1 +:1547B2000BDAC03CA07D7954EB2BE64B4877A41DE928DB34C57B +:1547C70036791DC0D28BF0039EF16EBF1EF84F96DCA5CC837208 +:1547DC0010FEC1ADD6FFAA8BF900F225C78D71616C58B7278FDB +:1547F1006B3856DB36606A85F843BE0773AE054EBBBA1BE290E4 +:154806003E39C070D71CFD4AEFE3B54AFDC96AC06DB57AB97630 +:15481B00F4129B6947BF64563B421A94433B0A8A77115E1EB6C7 +:15483000DB12B6A380067E73DAD2F6C49FAF2F0F6E00FAC4FB9D +:15484500B7B35BD7CF0BC6FA39F10ED57157446F5D8F749A376F +:15485A00B0B68F9DE8ED73BEF52FBBE87E9DF2C4DABE8A6C6F1C +:15486F001FE7019A5FD9A0B9810E1781F688BFAB8916AEDE0ABE +:154884006D0BD0E10EA0C30EE2E9C5B428B16991B4EEF5F17365 +:15489900C29550766CDD14D105DB4D6CDDD13974019AF86EB218 +:1548AE00E9027CD7B7B6882EEF2BA2CBABA43339D3B7B742BF10 +:1548C3001E29A213D987863680FE9B6D5A9D063A39B4D9F01E37 +:1548D800E971A6881E3FB2E9817D3A60D3E2123A006D8A695101 +:1548ED0016FDD4FAD2E8DAF5EC6ED62B663FD5374FDAD057C62A +:15490200FE7A7D79E26FFAC4ECADE4AEFF3CF5579FC8C01DBD70 +:1549170093F0CE6F6ED05CC07B2F96C5B47207EFD04F2BC4AD95 +:15492C00C0FFFE42AD5873EF2CBC975F0EEFA9C548F322BCC7E7 +:1549410009EF4E7D8BF10F3CDF779D8D7F5C13C17EE2E0DF5732 +:15495600847F17AD6D58F81DB1F15B897C0AC2F0DEF0E23EE01F +:15496B00A47F89C6058B66988EECD3DB74B0701E9905CB97015C +:15498000CF6286EB7D12BE49E03DA59007DE9FBCF763B7A9F5A9 +:154995003D5D8A54B254292BB956C1362C02EF61273AFAF6FE68 +:1549AA000B849D5AA3F84A3EA2784A3E6A8571ABFAD8F537F4B0 +:1549BF006D8BBB7A11AEC5F69DF2D046BCA5B28BC648F4477B35 +:1549D40018CE1C05CB47BB9125CED86D8F1F180F75A511AEE79C +:1549E900F3793FC429F4FD27A1EFE3D87506A693B85E82F2017F +:1549FE008C75FE27ECF8DF82FFFA9779FCFA8E505E2975976B5E +:154A1300FC36D4D3629C7597298C2C795F74FC768369A4F38504 +:104A2800FEFE99F5D6F2FF06E2E5D1A4A89C0000A7 +:00000001FF diff --git a/drivers/atm/sba200e_ecd.data b/drivers/atm/sba200e_ecd.data new file mode 100644 index 000000000..d097e743b --- /dev/null +++ b/drivers/atm/sba200e_ecd.data @@ -0,0 +1,928 @@ +:150000001F8B0808AC5A10380203736261323030655F65636426 +:150015002E62696E327D00DC3A0D6C14D7996FD7B3F5AE71CCD4 +:15002A0078592F3F8DD70F0AA949E8DD022E07F61A1644AA40C3 +:15003F00012D88A433EE52268844E8924B571792229D1B0F8EB1 +:15005400013B7DD0C7608813E1640D5E58529C6C909D101DE4AC +:1500690016357749A4E4BA8A7227541DC9AA17295C4A2F76455E +:15007E00259438EC7DDF9B19EF7831C4A1524F772B8DDF9BF742 +:15009300BEF7FDBFEFFBDE1B3FFCD3BF7F88B808896E2484FED3 +:1500A8008890844A880EFD1CB4BBA00DB710128396439B8076CC +:1500BD0018DA4E68B51FC3036D16DA1DB8364E88026DE92FBA6D +:1500D2001EFE486452BF7C63D90D63AE825E0863FB54E1A984C2 +:1500E700782F999F6AB59F9E3C49B19D522690D8ED9FFB737D9F +:1500FC00FCD38F45DB66F353D2B6AD1433AEF2F2F209D77F491D +:15011100BE34E18787275C3FF52678EDF13693B20B7EE47FE17D +:15012600E71A20BB45FB4AA95D5E29DC72DD983C8589E52B4C68 +:15013B00927E7959B9A987A7DA6E4DCF24842D778E97CC7F63BA +:15015000F90B6D6DE8BEAEEBF97C299D49C95956A43F7A5BF4D5 +:150165005F7C512AA1FBB7D87EF4AFBF99905E79919E97FCDF83 +:15017A00FFB93C759E5BCDF3F48DEFDA29E89C2A8EA109DC0E0B +:15018F005FF8FFFE2B387E24ACB3FC6765A432BB6F911CF4C674 +:1501A400C1977CFA72F2308031121A8EE3BC3E026FE14E96FF67 +:1501B900025AF9AA21793BD46B5B3B1A708EC8A429FF1CF1557A +:1501CE003E4F7C81FDC4977802FA5DC447C2618EEBEA932EC057 +:1501E3004BB79000C012130F873C52EDEA50657DA14AB86BAFA6 +:1501F80014D4B75C5C467C1D4F126F20B8231E269759EF9EFE32 +:15020D009D846F61249CE1FA03844C0B6A716FD52F20EB9C6518 +:1502220035C1447C7AEB6916F59268404FA9249C341086C4F6C2 +:15023700182477ACC79FE300570FFC87E3FBC3A4657AEB6A1692 +:15024C0085F4D4BE7FB34AE4F5AC7D7DB3FA3C213546D2DD045F +:150261007C32C81F7230EF6A9E22B7A8B81EE7116EDFCCCB8A9D +:1502760067E549751FF5B490DC6C5641483010844C26EF66BEA1 +:15028B006067FCC3B9C4E721F3D53DC3EE1669F72655BAB04CF6 +:1502A00095B6AC654B008EF03EFD6EBA6531EA08F113F958A63E +:1502B500F8F4EB015853B966BE7AB950A8FEB04D8DB4FF933BA0 +:1502CA00021254BC2478DA75DB3C456FC2D306E429775C5F2546 +:1502DF0078A202FFB7626115F9D9AB95B5608BFC601B04DD5402 +:1502F4000575C0F90BA1C39DD5640A91FBF4DC8A2D0DE780D715 +:150309001DC0AB3D1FAB26E3C3487898BD07DA0F053964FC6180 +:15031E00B09F6E2C85F4EFDDC054B2B33F93978886ED30B49447 +:15033300768879E085CA723BCEF75CC37918AB1763BB718C8F81 +:15034800E218973A503F887F41CB78FCF545FC0256ACB3E8DA10 +:15035D0034052D8BEE84341DF8D924F1874DFC62BDC065D1B458 +:1503720069396575E2BF52823F5CC47F03AE9BF17F2BFD283F5C +:15038700BE7DFE1BC41863C362AC4325B1FE8C3D3EF66ED31296 +:15039C00F6BE39FF0257281DAF69ED17F8883C2F83386A5A1923 +:1503B1001BB5E418C30B73E3E48AF573539E9BF37F2BFCD76E07 +:1503C600827FCCEEB1FE1E1B7F838D9FA45929AE521C387FCD8B +:1503DB00E143B62C02A73CD433A10CE3F647A7B91FAAFA55D204 +:1503F00030CFB4AD06B685FE0DBED990327DD38903EC5BB9A572 +:15040500685F6F5587E09B3474B0AC44A2105B784D2CAD1ECE76 +:15041A00B85B80BE512D77A9570A85A0D33FD6FD99EB3BC4FAF6 +:15042F00CE09D78FAD053C57715DCCE12B18A2352F4BE4DF3E26 +:15044400A3E73F3562F9670D7FEEAC3AFD034D21B14BAC4EB966 +:15045900475D4C7FC5F6DC3B9020F2BF81EF26793FC4F5605035 +:15046E0089631EE0D00FC49222DEE3788D3E00FDB481E324B744 +:15048300A8470EEE8A93DC7B10B366C4F7CDDCA178E9E3ACFDEA +:15049800FD956A27C4B7F6F7D7837DE688787987152FBF0532CD +:1504AD00C87598AB92BC1BCF26E134E7D056692EE07F3ED0CF67 +:1504C20033CC96D2CAB56AA12CCB24D72A55EADDC8BAC949C5A3 +:1504D700A50DB0EEB2E30AC28C421A3D4C5E56C05E0CAB886E6F +:1504EC00F23A8C67712DF4FF45113C02DE68FE6D03E4309096C9 +:15050100DB45AABB203749D1BBD5BB80A7629CBF17F86C6701DD +:15051600E06D6788F8BC40FB933677C4BBE135950CFEDCC09CF9 +:15052B0087FC728B5FC455F5515EED2E3BA9A05ED65592181934 +:150540001C30B244C0E918E7BB519E705AC4FC2A42FC2496D294 +:1505550047B7F635873457A377C309F0B30106F089DD3F9C0F86 +:15056A00364FF16B85424D9DF26B359AFF9457B94EA8B1FCDB9D +:15057F009C84327177E57915E18379C83D202BD2385A0672CBE6 +:1505940003461053742C63CEC97F32C0F601EF8697D559078ED5 +:1505A900C3BE4D097EC0EE19B0BBD8136BE99A8829F3A21ECFAA +:1505BE00CAE3AAB013E634CB4601878D1EADB5725A02721ADA1A +:1505D30000748276C8A27FA15F800E9016D959D40FEAE5975DB2 +:1505E800DF079D844D9D583CD83A09002E874EAA854E56AC5F7D +:1505FD002CF0900C0BB60AF9C00FF764AC07F676126B984CB013 +:1506120055E82BFA3CD80FD619159837071F671F423DF547CC48 +:150627009D9ABBB94EF94FD5EDFED9920D9ABB2948DDCDE3ED05 +:15063C007B3FE4F1ACE201DD96CA8CF2A1DC1EB2006AA3679877 +:150651000CB2CABD9BD88E3B896FAFB6B1C9BBE105F0796ED6EE +:1506660014E1A5ACB002FD803221E3D52B26CFBC5F7F80DEBF28 +:15067B00988492F15AB2470D8C32C12FE9EF63DDD98560AF85B3 +:1506900006ECCF8CF5F4E05E053D0AD9486CD0C0F501D8C35394 +:1506A5001C72BD05754ABA6D6364519B29DBDD753F5B485DC4FE +:1506BA006BCAFA6BF53A79F216B2E641D6939396B5F5DBC477B6 +:1506CF004CC8FA30C8BAC39435047BBBE1F7A67CB1E3FA532095 +:1506E4005F6DF63BEAD4489390AD2C36430DE9A1E66F635D12CB +:1506F9003B20628096FFDC38EB2553A0E5B81F85AE5007644910 +:15070E00D12FE4BE8CF5801EFA8A7AC8BD6A209D523DF4801E4A +:1507230074D043D0D24325E80169074B68831F4E194FF38472E3 +:15073800C0972AEED189F7E6346B6F46C6E6D1C78027EC8760F4 +:15074D00EF3AF72BEE55C253FAB5151EC10BC417D8AF2761BF9D +:150762007ECADD9543AA6BE659D5D53524F6EC11C79EED297B45 +:15077700C5DEB37E9C3F52DCB335E8FFE8D7CE7D3B0BE05046FB +:15078C00BF4346AD9C4C71EEE7B1FC943BCDFDC1CBF1EA46B191 +:1507A1005788F48AD452BDAC53F4AB5DEB45BC8E06486C8EF056 +:1507B6005F6EE65EC88572F20A93D6ACC59C974940CE2B4C4D3A +:1507CB00B05EFDB8C2662694C06E880F77A4541FFA4FCCB0FC60 +:1507E00087C7671D931ABD55AB61BFC6581BD118FA4ADA05352E +:1507F50041586188A322F20CD3A03568598B1F7CEB04ACF36627 +:15080A008FA9011DF3FFEF0D51CBE01EF84BB6DB3E6764B09B53 +:15081F00E9E04BC89773FE51F0AD1524C1B6E9879693F065A3B1 +:150834001E6581396FB61DCE4A585F7C435A0F9AB4B278CE7380 +:15084900CCAD4A8E3621FE34B9357E5D33D7E74BD637265BC568 +:15085E00FAA513ACA7DA492677758B1C6DCF47110FCCDD958C37 +:1508730034A1FEEDB501FD984A61CE8BF0B1B9803B950925C1C8 +:15088800A6164C8305238BF5A9CC647C22F0A6D48CF11F7DAC82 +:15089D00167D35D76F94D64FEB1E76D43FA2AE642C8AB58F2916 +:1508B200DF196CCD7ACFEA53689DF58F63FD1C0D7D1060A1FEDC +:1508C700411CD21AA61EC43D0BF2E27E1A572BE3F1F93E2FEEED +:1508DC0053C31FCCC6F17C5BA75C51FF86BE06E7DDA19D24F6BF +:1508F10004C39C9E7B40D4893C8BF50E9C875D33CD9A270A7153 +:1509060003EB2B92DB8E7006C2C9C119702E7E5A9C8BA747FA68 +:15091B00C59938181D54B1CEC0F544AE15676212AA8F4F8F3447 +:150930008873309E89CB8066FBFEFBADF3F0BDEAF32EFB3CBC70 +:15094500D43C7BDE10C78B67CF89F2349E3DDFAA29397B62AE9C +:15095A00B6CFC3B992F33087986B3F373B0F7F4D8C7C4CDB1875 +:15096F00F11C3CA3BA601DC6BA3D10C776BF9B56BC55C7314647 +:150984008A5A40C43898C739A0853569CD9CA4A7C98449A13EBA +:15099900A222060A9B891858EDADFA15F8C48098DB4EACF36D2F +:1509AE0091DF1EC423D60B9D9B7024F62763F7BB19657A24259F +:1509C3006C00670103C726F7FCB3217C16EC1BA8492A585360D5 +:1509D8002C47BF7906F9224BD94BA843FB5EE0366C531F98D827 +:1509ED003613DD0B94C796AA28EB3EBC178056DC0B403BFE5E71 +:150A020060693CEEBAF15EE0EB6CD6FE17B0D944FAE413D8D15A +:150A17005B750FD830CA2C7939CAEB6D9D6DE290470CBF43DE6A +:150A2C00042153049FAD7D967D070C8499DC73613C3F729F6190 +:150A4100E39D01786D5BDBF1E9CE478AF1C5E5EB107ADA94DD30 +:150A5600D3689F51E58D49A5A67590C5800FAC0FF04CAA79CD1A +:150A6B003C8DF05CE80DFC0A748363EE92B161475C9A41E7F61F +:150A800060CCB93802B97A659F1AD0D07F1A18C81E708580C77E +:150A950031BED23C564648A3E66944597640DFB5C63C7FE1F838 +:150AAA00E1DA2106B508F7C82F412CEF33EEA4A70D29B9C7210B +:150ABF0097CE104EFF119EB74C5C4B268B2B79AA880BE087AD61 +:150AD40073A08BE8784634F0DDA6F34DE4D11DF2F43878D02783 +:150AE900290FC2651E30E5D11DF27C2DAE1279AE96C873F536FA +:150AFE00E5C938E479C7C1436692F2205CFE7E539E8C439EAFE6 +:150B1300C55522CFB51279AEDDA63CC991A23C67478A3CE0F891 +:150B280064E44138D99207FB4B268BAB449ED11279461DF2440C +:150B3D00ADFB0C19F3B9E5E3750A53EFFB09D2357D04DF975A45 +:150B5200EF19EBBDDE7A47FAF83E43BC2799F065A0B1AB4CB4FF +:150B6700ECAAF59EB6DEAF59EF17ADF751EBFD1DC0B38B9EE038 +:150B7C00D8D760AE93BECCC5BD03F47BE86B5CD403D04FD337E7 +:150B91007994DEC5CC73C5592303EBE05C51334BF33407939EC7 +:150BA600667FDED3EC053B606D8F3236D05302CF7658BB9ABEDF +:150BBB002AF074437F337D83E3FAB74C3E38D2DC4E777313AFA4 +:150BD0006E0C025EBC6B5841DE6167B6BEBC5CDC59004C15F5B9 +:150BE50034E2D80B5B5F136359C7D8335BDF1463C8933DF6E484 +:150BFA00D6BDCB6DFC7751D37E886796E8A7F9768B3EF2B4B65E +:150C0F006E60998DD386455C36ACCD2BF216B26011EF5F514FEF +:150C2400B3B84BB1743AFC88A9D39CF8EE61CA3EC3CE1F304F8C +:150C3900C7CD9BF4EEB6700C9A638CFF9D09F3A1850369071099 +:150C4E0007CC651F2DCE452C3DC6617E1DE80F75C7A01FA7072F +:150C6300399E8FCE099E2E0B3E1FA5CFF15EA1DF1EE3F48870DB +:150C780040FF03D73D4D7B67526543E88D85CFE692CA0F962315 +:150C8D001F9D424715509B2E592E352D0AED5EC861EE6E319754 +:150CA20011FC56243D8DB3DE949A82A1830B0D98AB5A6EF28FE3 +:150CB700FAAA807D72FD2BA9E98BDAE7161E82B93F367B9A2BEB +:150CCC00B4F2C6CF2EFD2182387F57CB22B8FEB7BD831184FDD0 +:150CE100E0D269C8FB3B044DE03FA38B7686E019E4CCC444BBDF +:150CF6004BE026E1682629DA84E0036A8E0CEE89E9172EABAEBD +:150D0B00F735D87FAFB0CA60268EFA31D75D36368BD6D41109F9 +:150D20006B8602EDB495C755D7FA47A0F6D9CFEEC05C097A3363 +:150D3500E9268D0ED1EE303A45DB23F4590EE705D7FEC701FEB1 +:150D4A007BAC2A1806782A6219C20F8A36619C15ED52A1F32969 +:150D5F001700FEFD7F10B5D5D4600CE0A386C977D2E887F6692B +:150D740061875D467AA498DB4808EAADB0226CB30D6C93A007C3 +:150D8900B81CCCC1D845B6B4CCBA2B17ED45A301DA9DDF273E14 +:150D9E001E76B7C0318F1D182DF8D1971E85F14A7A02EA055D0D +:150DB300E8AF0CCE160BBE8370E6BEC25CB9CD82457D5BFB8D79 +:150DC80061FF29A029FBDE533B9625AD6F6D507FC1B896FF8DAF +:150DDD0011681D62E8C0DBF3AF1BF0CE75E02D104DA9B20FCFF3 +:150DF20039EF1B121D323E69B0F8A1B3D9F52F4D1A4761BD6C70 +:150E0700F1C32D7E8ECE29F283B9EE030B36EBE0277B0B7E623A +:150E1C000E7E36033FF0CEF904FC6C76F0F39845E33DDC47160B +:150E31003F598B9F4A073F98AB5659B0E86F363FD8BF193F51AC +:150E4600073FAB811F78E7C909F8796B71919F8FBE30699C1BBB +:150E5B00C19C66F28334909FD6D9457E30D79C3161052D37C413 +:150E7000D68EE694310A676A3BC63A3F0F6874906BF434C4E84F +:150E8500CD4C0EDE173FBC2CCDF0FF560EE74E2AD65D9091B78B +:150E9A0062CA7F8CE0652EF17B1D79334EFB7959D57995E60779 +:150EAF0058714DDAB868C5631B5601B86ED8DB7E888DCEF53124 +:150EC400DACD37037D05F850E85178AEF0049DCB77D105E03353 +:150ED9000DBC9346C056AB799DB24D35C8A1447D3EC5BAF55427 +:150EEE00A207E093F41C4F53C60FF79E663564409DB6A597D514 +:150F03005EBAC23AB67C97EDA99DCFF66E59C8F6F52E639D97C5 +:150F180056B223B56718DED37CFCDB32DCD30CFFB7E7D9DEF32D +:150F2D00ACF2C231F5E0A5FD500FEC5FE2E4EB9D30F155D1D593 +:150F4200CD6363B176D6B090F8FCCE3121403B3B7A93F1CDD75E +:150F57000A378C2B5A3BC77889FA09D44FB08EB7B33B9B26184E +:150F6C00875AE06A1DF179434911ABC046F2DCE4318EF6C5F74D +:150F81004F46AC1A413EC789CCB844C51D2BBF8AFF6810E6FCBA +:150F96009A687BF8A8DBAC7586451B66A4007551554AEDD6878E +:150FAB00946EBD5F9926A5D4236543CA91E88072186CF9ACFEB4 +:150FC00086E27DEF0FAA8005E0837A9722AF632AFA4185833FB6 +:150FD500BC8390D890187F52AB6CFCC4FE770F2B6EFCFB0A33BF +:150FEA003F6A63B934C991E73990C72A925F35CC4A3E8179C4C6 +:150FFF00CA8567451D63E6AFB366AC039D99F98F5B303D026617 +:1510140047314F8AFDF09845277B039D3BC6D131F3E559510FD6 +:15102900D97432169D0F2D3A264C0F33E3709A87AF12D21B76BE +:15103E00B5941F48A981E83CBCDFF3FBB5EF468290ABAE5E372C +:15105300E5FD40FBEBC6CBD0F782FEEB14380779061290B39AFC +:151068005DA1745CA678DF1B66C92CC489A4AB65333D652C022E +:15107D001C92FC3DC8435D3C14DD1F3948BA13788676877AE21E +:15109200D23D50A3C5468CB974C4705BBA8ED02E234A0F1A8197 +:1510A7007C8A734F6AE702DA67605C895D0039F2FD5C069C38D8 +:1510BC000E276206072EAF93E6A617FA9A9DEBEB9443AA61E19E +:1510D100C0B5D8475C147049A1FA78B464BD1FD647E97306D4F3 +:1510E60010D6FAEE09D7E7FE1173537D1C7909C3DC02A833C232 +:1510FB00B48BE1DD96413A120AFD2FC3E3C238779A19E470422A +:15111000D23A0C3FE46037D6BBB17EC3AB751B95DA39718F365C +:15112500DE8FCF5A7EAC8FF3E331FFCDA614D9E1BF55502B8C04 +:15113A00F928F801DA0F7DB4FCC0805A43E6A9A66CF5A66CD11A +:15114F00BE66A73F0768170F6A529384E766C29917ECB1733E0C +:15116400F1E1FBBE999DCAC54DC4F7E2CCA422D3F9C236ABD16A +:151179000EB096AFEE7E085BCF52F13F2D15B383264E79893719 +:15118E002E43FF568F0947444B8336DF14F65D1D91AB16A81DE5 +:1511A300EEF90F79AC71EED71FB2E7F1FF6AE4E8DC07251B479E +:1511B800B4FB41BFDD5F591C17FB04E498438E36617E801A931D +:1511CD004E8BF5604D631CA2520BD51883B37A0061360998CB74 +:1511E200D6779F4EBCA3A0247692076973837DCF82DF034657E0 +:1511F700342F36BFD19B7797884F4E7633C487637EB95B7D077F +:15120C00713AE82F17B829C33B5949FE0CE87719B80EE95BEBFC +:1512210032B80EE89D71F62F3AF158BF83B9E39073F0FBEF1552 +:15123600568DF74FFC285B8BFB92DE1B09D2798DCC8A0F3FA1C4 +:15124B000F35EA629F778AEFE5BBA75C413ADC2F3F67DE75C28B +:1512600018E4AB1A1BBFA4CD6558B309D81F7EDE4272FD7C9ADA +:1512750003B6C2829520374F16EE10F0BA0AE2DD0B5A5D13D6FA +:15128A0008E677FE432A9C9E184473435AF339F8E46CD63B4C08 +:15129F00104FA67AF42893454EE83FF3BB42A11AEF06B789B5BD +:1512B40069B17681B69FD5C84FAB776AE759448333656C9E811D +:1512C900F489DC6F081EB09F4B19923C5745DC52FEA88DDBE4E5 +:1512DE0011F6DA589FA78C2CD058A44D6FACD2A6477EA04D6DF9 +:1512F30044BE376975CDB67C923C5B2D956F3273820F7BACC455 +:151308007E7C18BF7D9F03DB65E24B08A9C63AC6E53BA7BEE98E +:15131D00C2FBC734D64D747A10725E6CC8C0DA424A0E31D7BBE7 +:15133200E7D5FF065E7B5CC48BF6C77BF9465AD358456B227E15 +:151347007A47E366D0D32A5ADBB8CEB237E2A8965F1577D4E057 +:15135C000C34289F51CB80C60298AF86BE1BFA088773F6B90BB5 +:15137100E15DD638AE0F26E78571BD8CB2027D19F8284CA5ECCB +:1513860008E953189C8702AE3EF17DE059F17F5203D67D685A64 +:15139B009CD1719F797D57D4368823337C4755D7CC4EF57052CB +:1513B0006AA9B9705E9D23EE5933868EDF5E760E88EF34384755 +:1513C5008E0DB1CBE2FB0C65B3C8A9E508432C18F17DA56F880C +:1513DA00CDD2BE6A126B89398EDF4DF4248EFFBC89C883064DB6 +:1513EF00A6F03B8821AF1950A330EED79AC5B817DEA980AB6D72 +:1514040092F05E22F6BA7118FC026582FD5F8D7715B3A2A71B27 +:15141900C59D456ED038AC4942EF788FF70CC43C5BC6A0252368 +:15142E00CA11B1F27D7D01CF75FF43CC13064755A4D993BC91CC +:151443001988C3038611280C0F1CD6E045326894648038C168C9 +:151458002556E40688EE7B5CD089266EB450729055768B5B5FCA +:15146D003081041F5CF34C206BE1DE84CD94932B2203071A3D8B +:15148200ACCBDE79BB68A5AE721677C7D5B9DEECD69E4779615E +:151497008D6CDC65AB38E7BEAFBBDFCC9BC9A0E0DED5FD987AC3 +:1514AC006FBEEEF77D5F7FFDF5F77DDDFD7547F5F31B315A88AC +:1514C1001BB88ED10BB618607BCEF31C0253B2E941318E59B05A +:1514D600E751CCF18671A03F4CDCB28FC53814642D3F01387A39 +:1514EB00433155770FB3BC0699D9A328ABEF954FB03595493179 +:151500002F4698A20CB3BD8A291B2C2060E47206562A6057702E +:151515006D46C454576DDF30DD1B292025CAB0698761DCE8CF5F +:15152A00819102899467C3E8203CE5C8192A83AFA9C032D15E21 +:15153F00DC8F21F4769E6B22BEBFF4E59C7F70B1EFE3D4E291CB +:151554003FC5FFF019EAE881BE606BC0316AD10929C3F44592AE +:1515690030FAF4188BBB3F01BB07D1C3168CBB93E9B888CB7601 +:15157E00C1548AC935947C3DCD6728F916EDE819566B6CBC2309 +:151593004EF46F7DA14186B319437E5C0345D9C8C3B42F1C65B4 +:1515A800F07A019F12B1117B029F3EDC2F92193EA6035EFC1FE0 +:1515BD008E1956FFA7447F768BFE64BA60C90D6224A00FF3A197 +:1515D200D7696F826C29B2D96359B4C7259E72CEF3BD2FD3E9DE +:1515E700C559F685CBFB75B6CF555344C27ADD1915C74C0DDB68 +:1515FC0013E730B2613AACC00E2BC6711C376BC1E339C47B8D20 +:15161100CCE1A1E409E0F7049D3FC9E4EED3053F0C0636CD57B4 +:15162600191773BF8421C3372C8708FA8C3DC3678CD9888F0E7C +:15163B009BF9EA933CF549BAFE5B5CD600837773773ADE8E53ED +:151650006931CC3E443BF19DB5C90BBC5B6D82F729479CE97FDA +:15166500C09B29DF579729B7607BF3C0A40DD3614E3B2C67FFB1 +:15167A0091E9BB1863D6F8B58FED8E9CB18D4FE7C7710DCBAE50 +:15168F00F58D9EE71BABEC255B19C674ED8BC82CCBA6A03CAC55 +:1516A400727C5F72A1536BC8299F85B4EF47DA71A3028C776FB2 +:1516B900C4B945C6BD0EC0157E28639F5037702C5865E5F6325F +:1516CE0090834BE0614F1B8EA21C1C56FBB9FE71989E0B037C5D +:1516E3007B2C983703D3F3C0667AB261D8A62E5B9B2D58671E54 +:1516F80058A1C70ED38D4431D8B685423E246AA0FDC0F1E915CD +:15170D00FA1E4FEB3BC0D017D8D63A4811616B1AA8BF5EA6BF42 +:1517220031C3D2F39907713D3C418FC2B8F785B86DCB8743BE31 +:15173700611C5086397BF230D6331B6CF350B4EF681FB7A15DC2 +:15174C00C1B526F8EEC0C2B8CAF0839EC14490E683CB36B861D9 +:15176100AFBF203F5C0678AB43D8DF626E732D99615C500F659D +:1517760079E5E5CDDFD6591F27B43E7DB8EDC0C284CA7310AFE4 +:15178B00436EFF8BB8B09D5FD507C68DF0F58D7165F76B42D8B7 +:1517A0007BCB77737B9C2DEB6C7B9C8717F886F302710A3E0187 +:1517B500F76CC4C7F6C3F3C8214F7D92AE9FCDDF6E9BDEE11865 +:1517CA007678A68F71E2993EC60B3CD3C733C903DBEF9E3EC6AB +:1517DF009D9EE9E359CA8161FD57ECDF66E6BC221EC371CE7D03 +:1517F40003CA7489CDF7C15397785C62129B2F9473CA245B99AC +:1518090037A7CC652B5B905356642B5B2C0B3F129834E23DC8D7 +:15181E00972EF2CBAD582446838A3390893D6294E5EA425F6464 +:15183300628FA8C6E38C9CD853CEE4C8C8BE924647DD2AE853AA +:1518480098670742867C3B2105072B357D32E5763A3AD5367878 +:15185D004A20935E85AFC3FE0874EA70F4F7E5646A805EE941AA +:15187200044EC44576EDFFFFFDD5D610F7D86729370D75A835F8 +:15188700F749EBACBD4DDC2F24EDFA293667688F9E1A67CFD1D9 +:15189C00532CC7AA3D796A929DC989D2C446BE16678B410D07AF +:1518B10019FE18E539713F71ABF7F3BC65EE67BBC1CF0E829F2F +:1518C600051FC9E456C2E466F9EA1AE083783AD5F2CF84EC22A0 +:1518DB000E263BB47D51C0E307F847F749AB91D6D98D7C8C8CD2 +:1518F000C013D71B1D0A8B154DFCBF212BF68CD107BF617F17F3 +:15190500B179E0A4896D045924842C12421609218B04CAA2F079 +:15191A005E57A33D7EB95EF9E158F228CB033395AEC0D1422EFD +:15192F002B0EBB13600702F12CD83D00EB0B9CB66045089B0F62 +:15194400B05B03A30863FB3A5CA6572E810C4196172F4D9765C3 +:15195900C37AE2BE700965E95F7DBDEDBADEF69CCBA30F054261 +:15196E001F3EAA26EEDAEA6C3E2B24E2AE075E9CC0EBDA3CBC7E +:15198300C6A17E29E3B574F58DF4C1F5F27B3C0FBF8582DF525A +:15199800A0DD1F9AAEBFFA35F4B77322E52E8076B44F4C6F471A +:1519AD0012F0344F603BBCAB6F54976EA43DF13CED91447B1A71 +:1519C200818773F7417BBE01FDD6FF8236297E2A2BA594D97E0D +:1519D700B0798EBB0889001CFF4BA4D6D88DEF01D550403A8B99 +:1519EC0015CD9495EA57D91E33D899FA08AE37478DF001EE1352 +:151A010095837CAE32FE32F86249077FD8CDD64B0DA837161922 +:151A1600328B9A4E9A139F72DC7EC09B9AAD1B53F0DFC1FFBBA4 +:151A2B002E7C9ACDCF0551F70A3C1B20DEF42A9C1E51393DA4D7 +:151A400083F4D02BDBE92D867A454D43663DD0DB2D709CFE9440 +:151A5500D3EB14F4E0BFCB2E4F59C8B3086489E5ED5524AB7C94 +:151A6A008E65FFAA7879434EF95C513E26CACB73CAE789F2E328 +:151A7F00A2DCCBCA278D1A9A39CF92823652D2A5E2DE9D0B7DD7 +:151A940074CEF9956E888768D4B905E28CAD55B8AEA977AD2A29 +:151AA90056A4A02AE29A9E8517D5AAD0BE60AD2D5F60CF48D3BE +:151ABE000728ABE7DB3FAC0AD8E01FFFF0E5AB085FB3F5832A70 +:151AD3007B7EC18537BFFF1AC29FF8DB9F559162DCDBEE373A7F +:151AE800FFE5856AAF4FDF4A1E236E974ADCD3F8B4E58F2987E0 +:151AFD00B2FD338F35264DB4210E0F9FC331989CDD362B3EC2C4 +:151B12007A3341D7A7D6F2DC19ACDB5337ACCE8C3C12D85FC732 +:151B2700EC391DB5EC39945967724637E69FEF1B9FA7DCF14B5D +:151B3C002977661E46B55EDDAFE2BE0AC48DEEEE8551753D59D3 +:151B51001EF490E5AB16298EE0799045CF42AA6ED0FDC17369BF +:151B6600B9C4D99AC4CD4C1E740FC6284E88F50673CADDB672FB +:151B7B0009CA3B3372ED2E9048B70BCA1D65D07FA2CE22E6D307 +:151B9000F8B73741FD0651FF0EB0FF3EE1DFB0CC07651584EB9F +:151BA50013FE5F7261402B81FF8B6C75965C8869DE1C7E1E8494 +:151BBA007E4A4462A60B7C6CF96F53EEE8D594BBF9CBD42CD1C5 +:151BCF00BE7511B0D3A03F5976C52BF45442F9839E86927F6EF3 +:151BE400E84E320BF50CE3600B37AE5FE21EA16CE30B73854FA4 +:151BF90047980F360222BFA108F02E00F97B9712B7EEE7BABFE7 +:151C0E00600DE016FB3054F8F31749BFD13B3AA8BEB90CF7E984 +:151C230002068F654B0C561EA830D07717B863DA0F963E5CEE8D +:151C3800AD8CD2D65732F1168577A90F2255788EC2EF1CFC9498 +:151C4D005EB0AFF01B17BFD65EBEFE85F82EFE12D7BF94C6F455 +:151C6200BC4CC0A3FFC1E161012F009F5683EF7480CE837E2B7B +:151C770000FF50CCD618264DE9DB84BC823E830E9896DCADF9D7 +:151C8C000796596D9394037406B3ADD4083C4A48D17FA6DC93CD +:151CA100249BAEEE22B370AD1BF1FF33CC476702DD31A81376E8 +:151CB600733F65E191051EF932E76DF493947B90E7F5883A101A +:151CCB0007D1210DC7EC646A361B23B837D6F7F7C7198C4CCED0 +:151CE00026DE9F0EF277F883F2CED48D9AB89FD6377A5C9D2F99 +:151CF500B1F50E93EFB3454DDC575B6BA3C3D71DFB8DC7C61FD8 +:151D0A001B5F363A98A53F37A3FE209FA043814ADCA386B8203C +:151D1F003C443146DBAFAC0BB01C45CC8D8BBC4B95C819C3C77B +:151D340072E8BF303D7CED9BF68A7557BE8E3BC2F70C020ADF8D +:151D49002F40BA387EC227CDE7593FDC40FC373E8438D2F3B0B3 +:151D5E00AFE741D0065A69FA79F475DB3AF0CB69FB17A5E3B899 +:151D7300D62B1BEC9C14192D20E037D8FA3EE0A0631B591E841D +:151D8800CF9A67CD2103EC0C12CA784CD834FCBEFB5EE296C690 +:151D9D005FD2E40F5F52ED362D6D77D99C6CC448FDD57B923824 +:151DB2003324A32D66F3191AA37790C120E6EA4FFDFB7095BD05 +:151DC7006F6E1263BBA482E45D1FE56B9BBAC03B22F026742EFA +:151DDC003FC0ABC738DE25C7B3F0CE1078C757E7E0457B08F1E8 +:151DF100D5BE85FD2A3BAF0F3610F126393E7D19EEC9CB83B482 +:151E06003039AC4BC933BAAB28C6D6F966029DB961AA3922869F +:151E1B007128296D91944EE316F91D6D2C95F279A25230334FC2 +:151E30000D1B1877EE72A0ADAA6DB4CEDD635E358B4B587EE23F +:151E4500A4A9E2B3B8A291C80FBCCAE64201E554E8D13CED0713 +:151E5A00FF15E847FFD5CFFCD7BE8523AA67B4EB5E466F5CEA4B +:151E6F00A49571CE7B38A67B301E13F082484C972B13AC7D8726 +:151E8400C801D584B1ECDA30C8F6D1BE85361EFAC411194EB76D +:151E99006F6E6830687DCBED46FA7D1A3FFDFD997CEC7DE0FFB5 +:151EAE003DBAE0875E831F80CB601F91173B4D07DF4FDF9375AB +:151EC3002604ED1501BE8B47F83C5FC44F203B2E1F9E4F922D53 +:151ED80047B9EBD5ACFD0B186FC88303FA1AD73F43C9237B8A4E +:151EED00F95C4DFF25C07BC351D5E5116B64C0D3C5421DCF3873 +:151F0200CFC2F2B64D3C470A7DCC3231BFAB653A12D7FF14CA3C +:151F17002CDE19DF507FD7261607B33C8E7A51EF7BB67AD5C94A +:151F2C00D7F7C04F47786213DBD3D0314F00DB82F349E4A3F77A +:151F4100A598EA1DE5FC20DCA2DB2AF09DCC4377C446779BA8EC +:151F5600F7B6ADDE7AA08BF5466DF5DA44BD9FE4E16F7DF2845B +:151F6B008EE3EA1CE3F16F74F403B5789E06F83BCC746798AD4C +:151F800015F7FE1DF04A0619AFB5365EDB05EEF7F3F03A6EE3A1 +:151F95006197A8F78F7978BD60ABB75BD4FBD7AFE035BA39C326 +:151FAA006BFDD7F05A6FE33529700F6C9ECE6B7C7386875F8943 +:151FBF007A439BAFD19F9B33FD59738DFEACB1D1BD68F5671EA7 +:151FD400BA2336BA13567F5E836E77038EAFB328031AB6D3C5F7 +:151FE900F68AFB3F106EE9FC7EA87F84C4D23ADFE0E43A7FD59C +:151FFE00C1755E6FC8D00E3B39ED8E86AFA00D741B045D8B5E7B +:1520130083AD9D0D02474F7E1C14C7ACB516ADE6DA3C3C4FF630 +:152028005AC6DEB1F18CE771E5E394F92FBCB7473E4D31CE73E4 +:15203D00157569FB206E94C197C9F5EF6A0B8C33DA41DCA3B7F4 +:15205200D9A01F40BBF2D91EEB3B9F23A61ED18755D417BEF704 +:15206700774085F9EA1E9C9FAE67B832BEE12EC055007E216DFF +:15207C005743C3AA6B438CD954664F2D7FA1A33D8D317B2AD7C5 +:1520910001FF60471DB6F7ACF61663BE4EBFEA5848B514E65951 +:1520A600E0BAEF659EFBC57D5382D3A7C29E86FB786C07BE8FF4 +:1520BB00B765909DE791C3BA46D12F4586C12FBDADB9A2670C99 +:1520D000F44D79FDC98F32F33B9ECFD0A9F970BB1AD712C4FFBC +:1520E500A9546A5EEE5C8FAF47B2FD70B3640AECAB1BC656B88C +:1520FA00D4A0A18E36B4C5AE426E93252BCEC6F32DBF4BA57368 +:15210F003F9529969F39DF9E372855F27B70545B3DBC8028B73B +:152124001EFA84C30A9EA11AA188E7093C4355E6C0DBD558FC4D +:15213900EB284E3462F92DA141ED96D0DBA8336615D6C19800DF +:15214E00F3A901EEDB1A3333FFDFD618ECCF6218A3101F4D680E +:15216300FCFBB7D1A77B0B3C1DDA7BBFCDF0E49F6271928DA775 +:152178008451454EAEF1298E80451BEF02BA83D18C52ACEFBB81 +:15218D00F50B33FDBEEE8B349DE492936B0BD2795F309F147980 +:1521A200F8C8D7FC5B3127A28F9AEC2C5729CB19BA17C5217371 +:1521B7005CBC6E9CA2FCC12D9AB2BC17FAFA347CD36B4ACA69E7 +:1521CC00B3D1164F5E7C84906714E79AB30E316FCD43E7218C26 +:1521E1005DF2E2F69B4EF94DC07DD620B4CF94A2EF9A986F8196 +:1521F600EB9F69DF8DF38A42317E11EFB7C57D14A20CFFE7B9AD +:15220B00EF83E596A21E4DCC40BE127482E78C5397E0CF65E79A +:1522200003FA1BF945BCBE6082E51BB1BC0FF9A4897CC83F5F73 +:152235008EBC73DD13EBF1150319FD463C138F703CFE298E9FB9 +:15224A00E34D30F9CCFF791775C01C0EEFAFE823C32A9EA3C3D2 +:15225F0098977F9330B14ED63800FCC707ECF7C9F07623FEC926 +:152274004778FB389D78161D6B4D00EB323926B91C6FD9DA6987 +:15228900E23D116C4E63A7993E5F1B32382F1586CCE4526BF06A +:15229E009C8480E112F9A00C1E1EA44F2DC5D8F518CB47B4F334 +:1522B300E07D6D39B5F71DD431257908F7E6A9A5272CC606DB7A +:1522C8007A9874AAECDEA8B0C1E4827C61B904EDA515BA819379 +:1522DD00E4C2A24E8D1EB8533B7F21E526E3036CFEEDC53E92E8 +:1522F2004F6992F22EF545F8F9796BEEB2A070FAFCA9A36E8876 +:15230700CDE7B2E650E327CD7B6F740E15FE4BD3D229CC23ECDB +:15231C0077F2F969B64E711D425E4A845C589F04A33C7F4D1EC1 +:1523310030713E8DFE0CF5097580C94AE773E9A35FA6E6D8F47E +:15234600384B9F59DE7800C63E9D30E6F9028DB87EE2519697DC +:15235B007F88FE14E6E9CF287706AFC098BC2BE965E7B07B1FA4 +:15237000E5F4E38FE2251B0798DE610E97809B083F27E6B551F3 +:152385005137915357C04D841F15E3DDC2FF9EF8E67CCE37023B +:15239A006E22BC55E03F27EA2673EA0AB889F0B502FF3281BF77 +:1523AF0053D4C57AF8BED8666FBA6D65F88E67DBF04C9B0BF426 +:1523C400A8107C95A40C98282F49DEAFA19F092883788676EE70 +:1523D900DC505F9504F3D3F91D135A9132642ED22FADF5557FB6 +:1523EE00A64991D3E66B51E71617CFFB9C373332638D14993002 +:152403002D9D9D09B62D7915D7D13263E0FBE02325766E884EE9 +:152418001B8F627CA5ED0AE2900F0E68BD85832AF23677ABDF7C +:15242D00B4C633D301B409101B3892EFB2FD46FEFD88993B9E8E +:1524420079FE24D08431631F272FDDDCA925FE89AFF3C9C2A6AC +:152457007DDD38D98BB9A2D618E91960392BB2F0A7385696619D +:15246C006E00C41A8FB1B5F7CCDED306C51910E7A9FEF0FD47F0 +:15248100DB78AA2DF83FB0D139F1445819A04E4F17936729E02E +:15249600ABFF2CE377E9E7397E1778C13A44EEC03326265B170D +:1524AB00298E373A0FC6B43ED015796D8CDFCF00B8703D05C6F8 +:1524C000E33C764700F8662CC77BC33087D8F2BFB8BFAA46965F +:1524D500D2420FDEBDD7618CFF3A435BCE1387B8224097AF4988 +:1524EA0098D85F7DE0F7E5B303C6154113FB378B2694BB7268E4 +:1524FF0066B7BFA4B1C1463F6CA3AFE4A12FD9E82FCE43DF7F80 +:1525140083F431BEE8AC0C18162FC8C3D825CEC362A0954B5FF5 +:152529003E3BC46829910103EF4082B9B789B18FA4F03B8F16DC +:15253E004706E861887BD0A74DD9E31C5C7393FD66679DA1E108 +:152553005D60532FFAABD87E5FC96D2BFC75CD41E54F2A2AB7BB +:152568002A0FFEF1A60794CDDFDBD9DEF2EC4E6553CBB696A616 +:15257D009D2D41A5FAF107B7EF686968DDFEDDEFB4B63F5EBE5C +:15259200F2EE9501A5E4999DAD4FEFD8B1FDB9C79B9E6F0AADAF +:1525A7005A55B9EAEE157F7497F2D4D3DB5A762A81CAB255156B +:1525BC006595ABE125581E0896DFADF8D3FB5B16BDB2B2E696EB +:1525D100B6EDED654F6E7FB6ADACA9B9A96DE70B65CF363DFDA7 +:1525E6005CD9CE1D4F96B5EC6C2B7BEA85B2A6A66D0CB66DFB24 +:1525FB00F6B6953B6F5B758F72A7D2D2FC74BBD2DCF254D3775B +:15261000B7B52B4FB6363DF79D16A564577BCBAEF61548E5FA76 +:15262500F037EF78FAF9961D654F41B31E6F6A7FF6F1E61DCF95 +:15263A00AF7CF2B67B2AAE853F8D9E9D679AE30B37EE67F71A4D +:15264F00F88DB9BE8AC612A59CAEC4B35CD6398D88B406EFD1B8 +:1526640038143AD25640FA8DC6DFA7D2E7341A958DE627BF703B +:15267900AC91E48735BF526DF861EC7D0CB6C40BCF37D176E26F +:15268E003E09DD6FB47E9172FF74A9146C50866829942D22C3C6 +:1526A3005521A587B2F2B0B4370030B4376B6D30AC27830F04B5 +:1526B8009C66B752B4CEF2090BC036CE203C96C0FF5701F73E78 +:1526CD00F9E5368C13CFFD756A16F2653FD7603FD310BDC2F71F +:1526E200CABA58FD12A31FEA13F9B2E9856FCE027D3B4FB48D99 +:1526F700B0B3D32B1D642EF2877C78959314DB3003E6A998E3FD +:15270C0046C657E03EA9D7577DA7866DEF02393A7F52A9E1B5D5 +:152721006A7EC0C5D7AB0E1961E58746CD08D08678CA0BDF5BC8 +:1527360074F01C97B77A850630D34EF3A1548AD1EC62FD72CC9E +:15274B003C9D4ACDC1FBC4F8BA738F7113F805C439F916AEE733 +:152760000700768CF1E5047F7908F90AEFC775B9F956BF5967CC +:152775006CA2BFC3BEBBCCFA0EF7571405C69DDC957029F7980F +:15278A00CEEAE3D0DF07186E1C8738068B94D7CCD22F1D6BED4A +:15279F00EBBF28734BDEF67EA87927E5FAAAF2D27752B3ECFD49 +:1527B40081FCC8C08FD7D65F6D1197114DFEEC556C93121D4848 +:1527C900CCC13BE7E8622314ED4890E2B6464F926CF14697828B +:1527DE003F3EC7EEC3F3F96AA1ED0F18787F29CE1DDF9470BE3A +:1527F300A41A18D348EF3FA3E11D51F5B8CF12C6B3DB611693D4 +:15280800F6EA41D50C55AEDBA414ACFBD079D1F0856E67EB8DA0 +:15281D00462235EB23B12F128AF6D09BB2F4A01EF3BFE763BD01 +:1528320066A8773ABDAF1231F07EEE40B49A12F915EA666D83D9 +:15284700793795F63ADCEB35DC4767F617BEDFE3C0F58C8BFC2C +:15285C00CEAAE601889DCB204E78925E29242ECFD880F69872A0 +:152871007370AE72F3AA3796CE0FBEBAECD6E018C091DED4894A +:15288600D4AC658A23C8F8917B0C5C7376C1383C0F7A9FDE0F44 +:15289B001B3FC6FDF1F831F32F1696A86C7D186CE4D142116F97 +:1528B000290EB6761A075C565DAB5E3BD4395837A0E29DA7C812 +:1528C5002FAEE7E6D2C2F18BDFB7C2F7EF39385FB8A679E10D71 +:1528DA001C3F7BE9E2A241CDFBDF47282A4A6D14CFB45F64E72D +:1528EF00E7CCD0EB6A1FE05D5454AADD8577C28E47D55272D174 +:15290400E80C9D68C33D2E05FBA96E8566429FA0AE38770F1B8D +:15291900B8B71FC4F58EF08F791F88B18B31B4C4E6610AF015FA +:15292E006A64FC877F6C8E4DA5DCA70B783BD7439FAECDD37719 +:15294300308F9E9FDBA6DEA914CBE9403CEDE2FB4530C69CE3B3 +:152958003A8C83FD4601CC4B42C923863196725BDFCE80B1811F +:15296D0036F0AC903BEEA7A22CC22007AB4E3F94B1F7F1970D63 +:15298200CCA762FB8F50A7F48D6CD95F0539E6E315C7ED82680B +:1529970007F57FCE653E359CFD1D933FEA33B305FB0D4BD6BDC7 +:1529AC0020EBDAE88079F5B8F0F9F676A34E8A761FFD0D6F378E +:1529C100F63DE2DB05F84A599F458C5D2C6E133AFA2BAEA378CF +:1529D6007EDA51F780867B86DFB2F450F40997670657E8379C5D +:1529EB00E736D00DE083E9C6A2A2B59AEF178EA0A523783CBFC9 +:152A00008DEFB30A1D39A3625CB78C9C5987FAE1AD4C30BD3021 +:152A1500F565AAEBFD214D025BBB4CE8035F0FC8EEFF1190B788 +:152A2A004F3EC6E29DD9A01F5EB0BF577E2DE46E8D0BDB37B8AA +:152A3F00679D4FEE2B717C437D94FD343A30AE7A218EAC17FDA3 +:152A54003EC3A623EDA023AD1F701D71809C25A123E597B99C53 +:152A690059EE01F6FFF14C3F223E4FB84D6BFDB7B672B0676627 +:152A7E0049B4CEF447FFA7BDEF8F8EE2B8F3AC1EF54833D22015 +:152A93005AC3CC20B0905A443892A33833625024598481B05E2D +:152AA8009910769673B2DD92B0C7B1BD109B64B93B6E1FEF85E7 +:152ABD00C42318890137B8E913589615337224AF7C0B398507C9 +:152AD200397C4F24E2C239B021DC2C211C9764F1388FD8BAACE3 +:152AE700CF283E62E3C466EEFBA9EE1E8D846CECDDBDF7EE8F21 +:152AFC009B7EF3BAEBF7B7BEDF6F557DABEA5BDF5A69AC4D3DC0 +:152B110064AC4ED519D4075AF65353DC2E34E6371EB9869F2B10 +:152B26000ACEB2EE45FDB55654BA5B0DDE817DA2914EC869824F +:152B3B007B50C5FAD98475AE1E32F7037C3D69949F0DE4EB5DA3 +:152B5000B09131CED8A10527686E3ACCD7BEA454B701BDC4D514 +:152B6500A9935CDE8BA786C193F324B9DB582D9F34747AFBF5F8 +:152B7A0011F5B46C86B3EA61EDEA07C8832E36E6FE07F17305BB +:152B8F005F77BC253C273C2C7C56F00937D8AFD97F633F64DFE9 +:152BA40063C3EC5966B0DD6C07DBCEFE9A6D618FB38DEC61F62A +:152BB90020EB600AFB125BCFFE8C7D917D81B5B17BD96AB68A61 +:152BCE00AD642BD8729A41B6B066D6C41AD93216664B59030BD8 +:152BE300B120FB0CBB9B7D9AD5D3F3297617ABA3A7967D929E0F +:152BF8003BD9127A6AE8F9043D8BE9A9A647A6A78A3F95F42CC7 +:152C0D00E24F057FEEE0CF42EB59C09F72EB999F7B02D6E3CFE1 +:152C22003DBEBC675EDEE39DF694CD78A45B9EB9B73CA5B33E15 +:152C3700733EF0F17CE85372DBA7F8233FEEDB3E2E6E3B338E52 +:152C4C00F3B1C15A4DE6674B4856A96CEA8C32F928FC6AC84FD6 +:152C6100B7BE6BE93B6D7DD7D3B724D037FA96CA5A8A1FD17442 +:152C7600D6A6A569522C098A26C98B8F4A31FAA7E89F597C1419 +:152C8B00E598B6496BB90D3659B6FCDC969F407E31CBAFD8F202 +:152CA00073905FCAF22BB1FC0AC80FF95199FC2CAAC4A2412BC1 +:152CB5002FE8F906AD3CA0D71BB4D2428F374869A202F66465D7 +:152CCA002D880E49BE4BA3D975BF93E469F845B99D8790EE4D6B +:152CDF00090DAE3375D4FEABFB5D679A558E9F0F091BFD90302C +:152CF4006E7F87C24A298CFC0DF88B679B555E76BACEB07167CF +:152D0900E31CF5485B30EA2F719AE8329F770775CCF318EAC994 +:152D1E00D3043B815FE0507298F1E3A7AC70EA135BE5C5866EE7 +:152D3300E593FA2FA67F94E245D15F4A8B0DD105BBA3B3BFA3AF +:152D4800C2549C74DEB7E498FAD62D7F8EFFF1EC5CE82698E770 +:152D5D00F7656DD2B4C76AEA6D705D4699EB74145ADFFC9CB4E6 +:152D720083788DD11C34D8447DA783251C4D4611ECA1469AD5B9 +:152D8700C9EA66BE1E37F943E732E0046EAC898E533A0F6B8218 +:152D9C004EB4514FB8A08E5673C90D4611BB8B60BFCB700622DC +:152DB1009DE959FC24C1F463F25B06FADADA996B124159E77EE0 +:152DC600E0EF029CCB151A44A29914EF6A10313F96AAF537A019 +:152DDB003B2F85A8C826BD9EAF3BC17E6C33D7C9803BEA28A727 +:152DF00032EA74942F9E2957A5785D186F57BCAE01EF28EA9AFF +:152E05000E72191A71391FC3DE6230A8C5799B68D2225CD728D1 +:152E1A0002FF58766E1BC58972FB879095CD33CF312DC2F5F20E +:152E2F0037F133A82CB8C53C03CDB659F714242D5D08ACEBCEA1 +:152E440025A012345F49E83A4B28D8DF81FBAD15E23296DEA113 +:152E59007B64B1814577C2AE9C8BA565DDB4FF6AEA31D5670A9B +:152E6E001A789E941F5F47C277B4574F2E882B42AA17DF464EDC +:152E8300CF23FA5FFB50BF0AF9A02ECA670DA62768DE242EFB76 +:152E9800EE83DFA5FC5FEE833FFCEAC9AF7F865F39F9F5CCF080 +:152EAD00DBBA82E0925EEBFBFA83AF874860D63CF2157D1B3BFC +:152EC200A355AC7C5D6DAF7A25F46CD3045FB75814BF44F57999 +:152ED7004A5BB4F2BCEABA4FE336CACB2DBBF3934F88CBC4D496 +:152EEC0090EEA0F15196BFDFC7F4EB862B69DAE3E476D4C70FBC +:152F01003406307FA2F298FEB7C61DC2EB2AF051CC5E098D3CFA +:152F1600F86623C142B4BD42F09DD7056D9FFAEC86D7B43B22A6 +:152F2B005486B4CF20DCC56FAE581D72ED46F93B47D94821CDB2 +:152F4000E3BE33EA725DA3F05DFDAEB6D7C9FFE97ED3FD3796FB +:152F5500FB3FF59FC966FD7DF679C0E8CFFB128E333AF0B68DCF +:152F6A008D6BF11F14367CEB5B850DD07FE84F3FAB2CBCF0B4B0 +:152F7F005270FEA2BA865D0A2D1C3FA9422748F8C900F4F5CCDC +:152F94003A120D70EED52FFD07F5FA43578C85C2CB14E792E1D4 +:152FA9008A1F69C4BC15F94F3E745E77A50A1B469F285CC6F5AF +:152FBE00645FE26BDE47138E14D1FAB88E7AFCE1507738708AB3 +:152FD300F2977EA3A12E12608EFE68D485FD1069D75189C3FEC9 +:152FE800E3A3AF513B2C96F726B3244F16C9DDF1FD714D11D6BF +:152FFD0069D44E7FAEC36E288D00EC2917F610B4E464F5EF0D02 +:153012008ABBE74DB97E5994E26F8FAD6EE0EBAF05E6594D31D5 +:15302700F56DEA279D0DB1F1C30D4C3FAE4F82FFB0BE47E1EB7B +:15303C00C95F4C1D211EEAE6F6486A2D7B41BCBDE97BB9DDF0EB +:153051005ADED648AE4DEDA5B616D744A2ABC4B430DE2EA635C4 +:15306600E08D3D3257EA00EC1D733BA2E5A9842EB85EC63C93F4 +:15307B00DB0B052FA28DB8CE216CC88842EE4E258CBBE21AF7B7 +:153090007FEF27541EB921134ED2D4D013131BCA486E445B997A +:1530A500AC1E321606529D63379DCB0897C6E9F7B22E89E06916 +:1530BA00A5322EA16D05FB349DFAE156CA97A5068C8BBC7E4946 +:1530CF009DDAA91424C0DEEED6C24C3F053BDAA3E82F7747CE85 +:1530E4002BBF7EB4B0A18F752B7DF1034AE91271595F64AF3217 +:1530F9003FD1ABEEDFA929FB9B2F73D952CA1CEC5BB3A4F2B3DC +:15310E007C8F28181FC5DA6BD9A204F600F58A14AF8FB986EDC6 +:1531230032EDF5E3BB4D24193AF39A2EB411EFEAA78DFDE39A1A +:1531380082F541576A80D2ED028EF95E5E79E6A0519179CEA8B5 +:15314D0025BC54503D338524165038DA67ADBC8BDB6EE1794811 +:153162009A7191E6A1E5F2533AB7B1B841D3289D8EBE418C1DA2 +:15317700D3C3991F50DC5DD4467A699C1B509167762EF4786000 +:15318C004B80BAFC7327D583F15EC5BBB257756843AA6B7CB87A +:1531A10011E7E87DA78E98F6BC4F33B6003A00D029A39FB8AE2A +:1531B60047A57AF73BD6ED53134579776CA4B1D69FD4BEF10F46 +:1531CB00E28F0F0A9C667C0FC4977981EB03F25B806033057EB2 +:1531E0002CC1F5B78013733F24C9F7438CF15EA53CD3D317CC90 +:1531F500BC9092566ABC0F2958ABA9A2AC191E17F6B807B4DAA8 +:15320A00C881469CF3F277116FD1BCB63C0EF7712360B985B33F +:15321F0003AA392E1C307C194F03FCB0B6EFCAED8FF4F13D009A +:15323400077097EED56B389DCCF3C9021BD1A0476D9E4B1EE5BE +:153249007DE9AF282F612DFAB214A7AF903CA20616751B4F47B0 +:15325E00CC73AC584B17BEA071BBBA12A7B3693B5AE23CFF9D4E +:15327300A35761D392EA8DF56831437D5BFA3AA7435946C4B92C +:15328800E57980A79CDB5F4A76DA773430FD4903F6C100A7902A +:15329D00F986569B9917CAEFFBD1E783BEBCDFCFF5F9D4FF6FB5 +:1532B2002A6CF765DEC638C06DAB48991EE3B1F7B37EDFFBE0EC +:1532C700779306C0B12FB34F7768BD6A598BB9E7EFA07E03F7AF +:1532DC00DE7858EF520FF1D042D61B02FDCE7D798A77CF59B649 +:1532F1007F2F73DDAF894ECE7B4437B845BEDF11E7FB58A037C4 +:15330600E8CB6D5EA19D133D67D292E3DEA2C3ED70FB9169045F +:15331B001AE4E3DEA6C7C7A04131A7419FB5CF33458BDBD220BD +:153330006FECB5F11F1B87BDB4D2603E2DBCB14F86605F8345EF +:15334500BB466F3CF1C946295644E36C972E901FFAB1CDDF28C2 +:15335A006C38F147FB3CA0D99F9413ADBC8B3443A03A8176A8A8 +:15336F00A3B9E7639681F290B77DBE7D4A7E32E9B1208F16DB67 +:15338400393C49D3EE0E85635F51CAEC3304EBBE1BB8953CFDD8 +:15339900E3AD79E9B77E39A7E7CBF583FBD830D7DBDC049A7748 +:1533AE000D2B1ED9C9FBE92D5C0F50D31744CCBE29D7EEA8CE2A +:1533C300C2268CCBF4BEEF3CC701B553DFB63F98F5CDCCB8F661 +:1533D8000BF6DCCB03C9CE052413C82C7534C8C68F4658E668BC +:1533ED00F93F66DDF41E25F728F98F3659E93F28BE32313DBE77 +:15340200CB8A8F717EE0EDBC32B1DF48F391FCB4A80F9F7B51F9 +:153417007D6E92FCD28AF573792CFED499934A2189F6A2DC9BBD +:15342C00849D9A62F97412679ECDFDA0717EE651928FD13C2606 +:15344100A17B324B1A4E1FC8BA81878167B3EE9979E6C3C6F7CB +:1534560031296DABFC8C7EFD558D64259C19485A7CF8EF0DCEEC +:15346B00BB416EB37E723FC98F0D241F7D1CDE9C7CB5574F3836 +:15348000481E1D11DB275FD58C84A3CF6895F71B6FDF44FB88C7 +:153495005B73952EE32A6422A23FF657652A231F2737AE4CC7E0 +:1534AA0027F6772DF9D6D47FD60774C8D202B52FD491DC46F8DA +:1534BF00DF91FC188C72BBDF763E727A2A1FDFEFB3AE0A9CED31 +:1534D4000994C32EB47E91CADC06BBF91968DC46344FA6562FE1 +:1534E9003C15527F10AF0B753735F13EAB88D1DC287D9F562434 +:1534FE003C4C7DCB9A19B2A6639928DFA7CB99681FEC1CBB5C2A +:15351300D514DE66C9998B1B8B694EE3A8547859B08B0879DDE3 +:15352800D915524B23A17031953D54754F634546A631B3562FB7 +:15353D00CF0475C1D3A2767F3BA439C769FE986E326C7BD4D0FD +:1535520001E132BFD445F2674D4874134CD1AF8C32FDA17E5706 +:1535670012FB88FF9ABF332B1CCB6ED5BF29B7F4306AAD7E2D55 +:15357C0048FD5A9302B9DF2B0B413E9709364DD94049BF30BA8B +:15359100607C405D60DD59E0A3711C63314BBF64940957D55FDC +:1535A60057977E96914CCED88426B1DF34FA846B6A69B5B301F8 +:1535BB0072648464F60A6158D593DD4A39E618D46FA29F14DD49 +:1535D000AF73FB344CDA31FA00FBEF212ECBC1760CB91792FC9F +:1535E5008DB7FD5F2817B5E7DC83669A8FF23F9CCD06642ABF7B +:1535FA00D1CA9FDBF69F257FFB1F4F4DE57DA7FCA73C0DEC3F98 +:15360F0049B566F92E8259B6E250BF1E58287F32945F1FF84BF5 +:15362400DC864D11CDA95ED259E685A33E6AE7C998735945E6DD +:15363900A08EFE14BC8A7DF5329219DA16F42E8D903C8631F194 +:15364E004B4E9DCB608DCF68215BEEDAF47EF603E52ECFBBD91D +:153663000F94BB9A6691BB1CE78EA890BD206FD9F2574EEE8AAB +:153678000C37E28CBB6F25CEBABFAE35DD9CDE1FF23E9368DB97 +:15368D0056FD686331D7C99ED03CEC64A3EFD4FF22584E6A8B1D +:1536A200334B7278704D38DB6D3CC006D104E1E9DECC1C93BEB6 +:1536B700382B6386EB62F2B87A37A1A1006E2B0C7E080B4085CD +:1536CC006486DF091AAF3E088F243B841D6DD7D41BEF645DC0D6 +:1536E1002770566FE1B0E63D138715B3E010694EBFF32F8B4708 +:1536F6003FE457C2E3A2C089CECBC063747F5FECF733AE95B49A +:15370B007065F3FFEDDCF2CCF4D103FA1AD6A7DD4FF39DEFFF58 +:15372000AC77A92C9F1AA5514CF30A24A74A970C9FD54E45E8FD +:153735005348BF34B6B1CB5A99F0867AC7CA6BEA216A87341F91 +:15374A006FC01AB85466A898FBB2F401CD357E90DE07B53B5395 +:15375F00628397E6805EF6BAEA3D754515F8BD15A3DCBE14B79D +:15377400AFF4438C1B716D60FC07E13B28DE1D142F30DE13B21D +:153789006D3F4994066D54A638B63F6C3FC11FEDAB32736F4889 +:15379E009A28E434E736A7CE5EE16D0AF76905327786A6EC5777 +:1537B3005DE1FD43F0D5D2507EF9F2AB81696EE9D5CA696EE8E9 +:1537C8005BCDA7B2E673B8BAF3E03A990757771E5C272DB8FEA1 +:1537DD0084E072E6C175320FAE25A19976B582164FE7E0CAF8FC +:1537F200A7C3955934CD0D9EA9A0B1B531833E90DF11C9F8DC00 +:153807004700EF8C111DC61AE711CFCC3F457C263F63283769B9 +:15381C009E9E7E5E0F73FB865D7DF192443BDCDBF85D55C7FA7E +:15383100A00F5570866091BBFA1DE7BECD797284AFDD3CAF0766 +:15384600E5471BCDB897B5EB2B8A96791E7885E629BFD45DF29A +:15385B00F7FAEBE5FF61C47F37939F7A463DD07F4CADD7CC6F34 +:15387000CCF37B46275698F98C52BE3E2BCF1B2B3636DECDFE86 +:15388500A681CFD3F3E2222DF2C84F778EE2EC78F2921294FFC4 +:15389A006229FC21BFD134EECFF0FD0C64B8684F0AF323A42D33 +:1538AF00C6990FE25D9C27ACD8FF3CE763F4AFA2957FE9B4EFA6 +:1538C400F92187F9DD572CCF0DD15B7770BD769DE7EF786E8FEB +:1538D900CA714CF3761FC9FF46E405458A24D472C23F3FDF2953 +:1538EE009936FF6FF72799272924D7ABD85767D24E2E1749FE99 +:15390300B862CB455C4642D8C7908F6CD9C8929366958F201BEC +:1539180041460A731B30391947D3CF99328E598ECCCAE5DF195D +:15392D00F320EB92DCE492771B23D7B2AEE294962C26B8C3914D +:153942004483BD76514E7216E224AF8166DD3AAB15DBB75F33B8 +:15395700E5AEF11FF3701DE141C20FD2B3D4555D583041E3BBD3 +:15396C00466D21A915A612712F9523A58EF5A19F04DF214FCC1D +:15398100DFC17FB5F2ABFDE6BC7E265FF7F2FE653EC9C5DE53D5 +:153996007B492619D3C08315046BEB1FF3E55FAB8E54B7792958 +:1539AB00677BE6CDACBF96E4DD6DBF356556BE1741F09D79D3A5 +:1539C0004C531630CF6FB9ACFDDFD1F9CC4D7329F7C83CD38DB4 +:1539D500F3A3DB1DCC7D86FEE6FCB0D6B28F62EA383953423B4C +:1539EA00F33569F6D962CF4F894F4E35ABAB683EE6EC1A547BD6 +:1539FF00D3834AA5EC6C59287FFA73580BE669A43A35771E3916 +:153A14005A4D7C24F488B16ADD29615D59E879E3505D985DEFCD +:153A2900D2B6FC149750CD9C0F4D2F7F55BC6EE93FAB9C5BF459 +:153A3E00C7829D35F35989242D56A12F0E5D0DD843724A7FCB73 +:153A5300F57BEF4ABDDF0ADDBFC03743E8C3B84E1FB761111D23 +:153A680036D6523CBB3CF8B7927BEACE013E472F96024D9DA766 +:153A7D0003B0AF54DBF95E00F936987A72E5ACC4131BA4B1734E +:153A9200897AA72C34632FD513AB366E90BFF8CD2EDDD4AB1599 +:153AA7007B2E5AF32BA7B443FD1585C13E682FE250BDB0372D1B +:153ABC0043F78FFCC4D8A031067FFA7EA390B92F5BE98AC87D98 +:153AD10095FCF11E221AC35ED698C33CB3DB0B9AFB26614796E4 +:153AE600158DC02EE7354DBAF08C02BDEC729C75938E692ECFE7 +:153AFB0011751DD1769E2CB6176506349CF3A8A07E349041FC40 +:153B1000BD3B30C60996EDC0BB52AD4B258F797608B675E6F2B3 +:153B25003C87FB711F93CB8CE32B4F894B85915BD3B26811D7DC +:153B3A00D7D6096F61BF797616FA59B09B0A3D948C1F77C324AA +:153B4F0072F73188F2756333D14D24BC78A82DC7E89BCDB21F0F +:153B64001B8CB9B458E6C747C52B5DEA7B3E3BDF8A5CBE492BCA +:153B7900DF98653B7B0FF52D63458C9F1966E9B8C1F793A4B0E2 +:153B8E00265436758A995AC395811FD12AD3C4CB2FCF4C92FB54 +:153BA3004CA79449519EB14EACB3EF59B049E17D5BE596CE8A23 +:153BB8000C6C185CEE14E5AF196301933F6A284D6D26DD5F4F2A +:153BCD00E9C3945FEB3CE60E527A13B63FE9036CB0B3BC0A7361 +:153BE20028669F5B8E744632EF187B16449508CF53E98C929B8F +:153BF700E21F5D4DEF18E55D4873DAFB33878C48E6E9BEB68CD8 +:153C0C00DE1FA537F6A8A3F43D4EE10A9595F65AB6C4598AE365 +:153C210000F64B61F3B13393321EA17C63049B0FFC4AB8AAA7B5 +:153C3600B78BDEB0D12B5378057DAFA63C7CF4AEA1F9DA26FA1D +:153C4B009E9807DE265C915F1BF989D4D75C24BF60C0A4476CD9 +:153C6000864D72E795B84A7C57E295C5E50579F412008F3C64E5 +:153C7500604D35280F515F3764CC464FF33C53588B3A58C9DDD8 +:153C8A00A987C2683785CDB216E53AAD757A39BF43A8CB30756C +:153C9F001D841E3B8F149559D537C8CFB5080BE2EA947DA00895 +:153CB400C50B6B8CF2EB015E7CB5B9BE6DE2EF3106D6A9B8178D +:153CC90061B1DCBE946DFD5DB7F21BC6EC7CD8D62E2DF8736B0E +:153CDE00FF6BEBA0B685BE7B6467BB2B074FB3BE10E310C27EAD +:153CF30063EAC9D7DBFD13F9457F0E5DD365CB5D046B8C997058 +:153D0800DBF4E6772A5AE9026CF972B6B599E76FEB8B230DE54F +:153D1D005552CA5A7918F22A0ADC8A2FB46F9F30759E439A7424 +:153D3200501D4772753C7701753CA2AE8149D46F0EEB9317007C +:153D4700306C5F99FB57F2CF281AFD23F48FD23F46FF2DF48FD5 +:153D5C00D35FA77F8AFEA3F41FFF9919976DED36EB6A9EF9E018 +:153D71006E7D867B74863B3DC33D39C32DBD36DD1D9CE18ECEF0 +:153D8600706F99E1D667B8475FCB3B9342F86913A6DBB78880A5 +:153D9B0076BED19C5DB049AA97BFEBB85ACACF365BF9548E74A6 +:153DB000626D684D6C43D87F7258AFBD083A4DE14D21F726FA49 +:153DC5006FA37F92FE7DF41FA1FF09FA9FA1FF65FA4FD0FFC613 +:153DDA0045332E3B36CCF196B2E94F6EE04DCF73036FF13C37CD +:153DEF00F0B625CF0DBCC5F2DCC05B34CF0DBC45F2DCC05B3084 +:153E0400CF0DBCC9F9E5BF36657F93974F6E7F73CA006F433FFD +:153E19005A7C62C33DB67D048EB3D9EC7F107E3D2C0FBF33E3C5 +:153E2E00FC33C3D1F78C91FC42B2947E7A0E734357B658165B92 +:153E4300FA04E676D137F5332D1E1A238BE5459FBD48E36205B5 +:153E58007D838EA2B44BDD5C467DD65C56F218AB6989CC35FBFF +:153E6D00B407E83B3CD7ECCB2A59CD725BFF49869D72DCFB4582 +:153E820079006793A5347E53FA8952C80E2F4ED9E92019F152A8 +:153E970055178DCB872123E8932B9CCB4F531CB96CF6F1C91EC9 +:153EAC00E7B0378FF1689299363AEC781E2A77A7659780E49DE9 +:153EC100E597292F3797F7A7F7631504EF7609E321E48BDDFA81 +:153ED6009E18CEA5BDA8EF881CE6F5777FC6D92EC9753AFA7C2A +:153EEB009C112A5B79006BB9DA9639D89F1AD499FEA2EE178621 +:153F0000D516D6CDE377BB87156141138DAD83460DD54D243929 +:153F150097DB268FEED52ECEC538A6774A65499EC7988764486F +:153F2A004AE3925FD4451A8BDDA558571EA4BEFC450378AE91FA +:153F3F004CF903B0A63DD3E5BB9139ACE434E5979A8371A6469B +:153F54004FF0B1A9968F4D380F2B2C08727B0A976F66DDC5F1B1 +:153F6900AE1667B45695E56AFD8D15C2F2CD94E6CC5C5326B23D +:153F7E00F1E0B5740FA7F477653D4EBC29A57772BB7EC85FBA96 +:153F9300F02905E78C00B33732B854245945A43C2729CF769297 +:153FA800A9708E49E4BAD87C1C862D490379A0BD8BB161C323AE +:153FBD009BF7BA66B91EFF8B9A9FFA7C51FE9E81F8B8FB976419 +:153FD200B00D1305243FE3CEC7BCFBA71294C7DFC588F762B02A +:153FE700B561DA75FFCF6CB0C5436E8C33C065A498B9DF269E84 +:153FFC007D8B75B5D8B09B3819E17D13F2E0677ED892161BEE59 +:15401100EB0437F45D890E25B02303DE100907176F64DDF6BD19 +:1540260005F9750AE4D5C91E6F502FAEB740FD1DE0728ED39C6C +:15403B00233AA6F13A4883FD34F7A07AEF9EB2731CEBD27ADD53 +:15405000CCBD8660B5D37C2ED2DD029D8B9F1CF9E5618F5C6F8D +:15406500F8B9AEB24A6D76B561C32ECA87F9BC0DDF18E3250BE4 +:15407A00476B2D386D3D4E0B977EEC15D7539837262EF7154C5C +:15408F00B50DC95DA39AF7EBF6F1F28C5343CB59380C1D8CAC5D +:1540A400B96796CD7EEB5498FC123AEE46294B3FA9965DB84765 +:1540B900914EAD542B65472BD7C94EEF864E94DB9D3F6E5A70DC +:1540CE0036B0257C5C1E7531F715AAE32F88F7D8D6E7795E88FB +:1540E300EF425F1F1EE2F7AEF0F34BADF5FCDC0EC9E1FA77E3C0 +:1540F800832D38D303FC3E8D7B0B49A6B5F0EEF5669C2DF321EE +:15410D00AF674EEAD71F7C69F92FC88D3A8B99E1D9F98D706485 +:15412200F29BC93F9ECC71FD40C6D91E681DE6E5A19D99F4946F +:15413700394EEDFE5A6C5D82B51884EB95E38361BBBE51613A5F +:15414C005F42CFE6664C6801DC36DEDE1C1FE27D8027467D8299 +:1541610055CE2F288F8F5AA7CA8C7379B0783A2FB6BD9D75AFA9 +:15417600263A7A62797591BFA7439F3257179AC398F5AFCDD556 +:15418B00057088AD9FE675E1788A0D7E209E9C528D6AAD9364C6 +:1541A000515FD7A9FD5C671573A30187D54F100EA84F77E7EEE2 +:1541B5004C487769E7FE68EB0FD7F33A411FDC4EFB08A503BD44 +:1541CA00FB284D7E3FB3ED7D935F3DF2615D8E0D695F8F0C8732 +:1541DF0050367851DA3E669E8B4C0FD37CA11BFB9D567D877409 +:1541F400BBAD88992386E41E56CBA8CF3D48732B4F06FD8A6685 +:15420900D5FFC454FD892FE6B79EE4F59F4F74B3E89B1B438A6B +:15421E00D1DFF1F6A0C1DE7FAE3DDC840D9FF0B169EDE1B7E3CD +:15423300C7B85D1FE0ACE121D35E01CA798EED6D215E36DB49B7 +:154248006BB7C9C7046B4F1C67F0F5CE03B8B3217A7206BD7508 +:15425D0093DE5563CB0D727B624379743DA623CD145D87AC7ADB +:154272002579BDD0E794B5EEE5755A98129783F76D5AE6F89743 +:15428700FCC414EE0A49E83DD4FECC7B42CC7AFC35F1A7CD8B26 +:15429C005E36D6524AE503961B04CB42E2BD6345D379EFDCFF00 +:1542B10026BE93F3E08B117CB13CF8641B3EB35FE2F86CEDE6C9 +:1542C600F0E5F70BF1EBA6CE03DE62CCBC07588F24B694E68D22 +:1542DB0039F1776D5ECACD5DBD2CDCCB710B5B2C7D93D9921C44 +:1542F000EF916CF32B9C55785EBC478A99F36F6FE4B0FA32A58C +:15430500F1578BED6517FA1487C0CAE6212C7D4C972EA414DCF3 +:15431A00F17094609530E610FF6C06AFBA20776A5A2070A253C4 +:15432F00261929FE646FFB0EF827DF411FBEC375EE24D7DB9887 +:15434400A8DABB8CA5C7742328B4239FCAC45ED89CF3CDC7FD16 +:1543590068E49FC07AB5B4D710293FECCD7337952BF23DC1BDA2 +:15436E00064F87B2F4BDD07F9E87BB95BBCC343BE234A7C7BA03 +:15438300886BAD063D0E3FD7A1B3E6F412BF4F604CDFD9A6299D +:1543980005EBAEABF16CD6DBFB794D419D454A539938B201F0C4 +:1543AD0063EC042C80CD4F75692218FC174E28F36354D7B3DF2C +:1543C20056BD4CA33E3CA57C1FE38295A77876402519D88B7446 +:1543D70076DD7B28FFE4BEE3FC1E66F00B8F1B3DB6C3B5FB1DAF +:1543EC003503D8A84EA80BBB3EA0812EC003D34F6AC06723D44E +:154401005C28DCC6C5E51C1ECCB27278C07A6DDAC443E08762E3 +:154416004B721D742486B52EF2EF457B219CC00F6B1B18834D1B +:15442B00784F120E8E28C8BF60DDEFD5ED1C0F479432AA1F70F9 +:1544400020E15C15D5DB853B83A82CD84C0E52F99581894EDBE9 +:154455001EB2699F27AEE9C4837B162495B7D884B628C8FEB2C2 +:15446A0046163F97B3D7F917DC1E32B79BD4C6D70896F49B67EE +:15447F005B933C5D24B30B7756B8E98D7D6023F6EE149FE33C0E +:1544940023D6AAC0A3F5984B439736D8A4E937B89E663F8DB948 +:1544A900E3F15A67BBE00AAB623CA40E10AC55CA28EEB9D475D6 +:1544BE00F9402B9F9F521C89FA0E8FFCC51697FCB51649FED26B +:1544D30072312A63BC1EBF4AF230DE9D984B455FE43695FDCD24 +:1544E800B261E60F9971703C4861F594BE96D2D7507AF855C8F3 +:1544FD005F6AB1F3207E6AF150B88BC2AFAEF81ACFCFC3E766D2 +:15451200BFDB61C7D9827208265FF3A499B76EC20D1C85D136AC +:1545270008CE7AF9D556B1396864281CEB05AD349F1692215583 +:15453C008A630FD88C8FFC8807FC22E58378FC7C020EA4C7CC33 +:15455100FB80D0869B9835BF06CF4B435639239DB02952CE6D45 +:154566004F987E9833C18FEB1B9A67316E992F098249CF9C3FD4 +:15457B00E55F61CF7FB85E2A95CFEF384B195BDEBD75CE659ECD +:154590007D1DD11186FE07772CF8ADFEC69FFE8EEABBF01D0521 +:1545A500F2AAAFF59879AF1085F930F767C731BE6BAFFCB680E3 +:1545BA00558C1F6FDC42E39EC79A67983AB0A69C833B095CF13E +:1545CF00234BE793ECE943BEC111138E5C3F99E4F0F9228930CA +:1545E400B76F426EE4591E196AACC8CB333777A13E97A7B7FA20 +:1545F900CFDF5AFC8C7A606E47B079AFF2359D9AA934F9E76932 +:15460E00F9FDE74F69FF384BBAC333D211BFEBB3AD27453287BE +:15462300B4FF394BFACD1F21FDB559D2856F0BEF216D6296747F +:15463800EFB1DB9737F9FE8CFD27ACEFE4F31FD6FCDF9DBEBE22 +:15464D0031335CFAC38787C76F17FE7F3BFF19E19E7CFEFFB008 +:15466200F581FF1FFE4F0A97F2F0EF9DD92FFD3F03BFC51FD198 +:154677008F971EED6B9E287359ECCBDC46536D67B7147B641541 +:15468C0035454FD9A3AA46E1B82BDA73EF6E15ED14E3A4A76CC6 +:1546A100933A67F56E55961FD7E6DCDBA5FAD6698A47A8567DC5 +:1546B600A5D56A82E416AB4D6FB84163B35456AB22BF7F6A5E9C +:1546CB0087EED314EC110BEB30778969D0A813E582F6AF539F69 +:1546E000ECF754ABC5EBEAD5E7EEAB53AAD6D52901CF236A774F +:1546F500C1A714DCC5B8488CD973151FE28BC22754BEF6B0BABF +:15470A008BF71DE843AA4A130AF413ED702F0FAF539D65712E7A +:15471F00DF553D1057F9FE1264E459605865C15042301C22180D +:15473400FC79E5A3DC4A8201F178BE947F7ED937AC7C27F3F2CE +:15474900CD665FC97A60EB20C4DAD7331640DEF18298067C644E +:15475E009999D7DD8CCD9B4FB8F15099EEB57584A36A6591A745 +:154773005EADF88CD8EE645D1D557F25B61F9A9BE034C0BA4825 +:1547880090E0C01EDC5DDC76DA14EC5EAE07833DB8F813BC6EA9 +:15479D0004D3390BA631D4DD73BF5AB56FBD2A94DAB0656FDA01 +:1547B200B0B5106CE59E6AEE1F2701D1A697BBB45EF5709876A1 +:1547C7002B8B4A13EAFE9D7B72BC003CFF219BB56060BC9EB026 +:1547DC000966EE374F3E8172D3161CB81FEC0C7DCFD54C18CA91 +:1547F100F6D5A865541EEAD66E9D4D81D226C74BD1145EAA8851 +:15480600774AD6B6AAFE75610ECFAE82DD4A31E1A5C493500B35 +:15481B0059A2638FC59B8B79DDA7CA9DA0B2740A2B237C11DDC4 +:15483000BD360CA07D55DBFD0A64A1AA75F72B33E94F8DA8AC8E +:1548450098EF1B4CB5A7AA33033C9E70BE5EF53F105345F6B844 +:15485A003A87E23E27B080D3FA36E8BB641DC149FC52521A56D0 +:15486F00B51F352B87CE362B25E7D7AA7E8DFCF6AD56B5CFAF8A +:1548840021DE5FA38007FC84D3AAB5262EC498D02EB34D9CB7E4 +:15489900494EF3398587544FAC0077EBF8DCD8ABA96CEB9C2374 +:1548AE003CAC7AC455AA67259577EF63AA67F51A756FC12A05F2 +:1548C300FA1EE2CAA9F84501F31C188F9F0899F15FFEAAEA3924 +:1548D800DDACEEDD19529C34EE96FDE811A5EA3305EDB0BDEDB4 +:1548ED008A873ADCE3CD1D07610F4D0BA955E71F528573CDAA2E +:15490200467105D7142DB6A28D07F8B9B10DB005E4EAA274A731 +:154917009A3BF85CAF89B51796053B8ACA9A3AAA92EB955DD473 +:15492C0037C8E4DF43EFBF449FF3F71B554F4FB30AB95A961F63 +:15494100866CE7F224BEAA0A6B1F5779D8CBCD141E52F712CEDB +:15495600407FF038E624C5FF5168AF3A4F38D4BA54FFF9AFAA3B +:15496B0025E776731ED84F3C3087685F1CD13AF2FB25D01DB469 +:15498000E33AF5164DC193F7122CED809FF08CBB49D7D177A2D7 +:1549950060B33287CA01FCDD3BCDEF5537B37EF44BB61B7169FF +:1549AA006CD83090C51A8EC9DB064DAD803FF47B34E79A67F3A6 +:1549BF00D5368AC3CF47100C9B67E80797FDA842A93A574EB8AA +:1549D4002D5767E3A337D9141FFD9A997C041A14131F053C9B2E +:1549E900395E9EB378097CE4D7C86F062FED8EFFF9C6E2C026AC +:1549FE00A24FAC73377B78E39C40B453F03CA6DAEE92C8C31BD2 +:154A130041A7395DEB3BD8D9F60EFB5D75CDC1EF702A8EAFEF25 +:154A280028196FEF10DC44F34F546B4EA2C34DA23DF07737A785 +:154A3D0085A3BD44DB4174788CE8B087F7E9F9B428B0689130FA +:154A5200EF8EF209AE4F50D9D10D67385DC037D10D6333E84242 +:154A670034F13E60D185FA5DEFFA3CBADC994797B7B8CEEF5418 +:154A7C00DBDE49EDBA378F4EDCFE38F100FCB75BB4BA803BFF2F +:154A91002CDA6CFA98F4B894478FBFB3E88136EDB768710B1D40 +:154AA6008836F9B4288A7C65636164FD46B68DB57BC6BFD23197 +:154ABB0047DAD451C4FECDC6E2F8BFEDF08C3FCCDD557FC5DBED +:154AD000ABD7C3C81D799CE35DDC5EAD39A8EFBD5914D58A6DA5 +:154AE500BC533B2DF1ECA4FEEF5FA9256B9F9C86F7E2D9F09E3E +:154AFA005C0C9AE7E13DC6F16ED7371FFFD4E77BEFB5F08F35C1 +:154B0F0011B4131BFFDE3CFC3BF8DA8689DF5E0BBFA5E8A7280A +:154B2400AC92E65AF96DC04EFF261F174C9A211DE8A658743081 +:154B3900711E9E06CBB708CF9E94D0FE32BD13D4F714521EB8D2 +:154B4E00FFFDD0171F51ABD6B52A52C152A5A8E01E053CECA121 +:154B6300BE879D6DEE38F4530A3BBF56F1167C5E71177CC10C75 +:154B7800135675B0FBD674EC8A39DA01D762E084CA261E292BCC +:154B8D00941D7C8C843FECB9D87314940FBBA705F6D86D8D1FA2 +:154BA20088075D7FC0F55A36EBA338B9B6FF32B57D8C5D9768CE +:154BB7003A89F512C80734D6F94E5BF1BF4FDF55D744BCBD27B6 +:154BCC00785E4975BF63E8117EC65230EF62A69125EB8D0C3DF1 +:154BE1006A308DEB88C1DF37B5DE5AFC7F00E871AED038A00037 +:014BF60000BE +:00000001FF diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index 11cd3e6ca..26c8c9d90 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -636,12 +636,12 @@ printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]); event_dump(); } if (!size) { - kfree_skb(skb); + dev_kfree_skb_irq(skb); if (vcc) vcc->stats->rx_err++; continue; } if (!atm_charge(vcc,skb->truesize)) { - kfree_skb(skb); + dev_kfree_skb_irq(skb); continue; } skb->len = size; @@ -854,7 +854,7 @@ printk("NONONONOO!!!!\n"); uPD98401_TXBD_SIZE*ATM_SKB(skb)->iovcnt,GFP_ATOMIC); if (!dsc) { if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); + else dev_kfree_skb_irq(skb); return -EAGAIN; } /* @@@ should check alignment */ @@ -908,7 +908,7 @@ if (*ZATM_PRV_DSC(skb) != (uPD98401_TXPD_V | uPD98401_TXPD_DP | *ZATM_PRV_DSC(skb) = 0; /* mark as invalid */ zatm_vcc->txing--; if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); + else dev_kfree_skb_irq(skb); while ((skb = skb_dequeue(&zatm_vcc->backlog))) if (do_tx(skb) == RING_BUSY) { skb_queue_head(&zatm_vcc->backlog,skb); @@ -1395,7 +1395,7 @@ static int __init zatm_init(struct atm_dev *dev) command | PCI_COMMAND_IO | PCI_COMMAND_MASTER))) { printk(KERN_ERR DEV_LABEL "(itf %d): can't enable IO (0x%02x)" "\n",dev->number,error); - return error; + return -EIO; } eprom_get_esi(dev); printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%x,irq=%d,", @@ -1741,7 +1741,6 @@ static int zatm_send(struct atm_vcc *vcc,struct sk_buff *skb) if (!skb) { printk(KERN_CRIT "!skb in zatm_send ?\n"); if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); return -EINVAL; } ATM_SKB(skb)->vcc = vcc; diff --git a/drivers/block/Config.in b/drivers/block/Config.in index 01fc28943..d4ba3f06b 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -44,6 +44,7 @@ else bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 bool ' Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then + bool ' Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO @@ -54,38 +55,43 @@ else define_bool CONFIG_IDEDMA_PCI_EXPERIMENTAL n fi fi + if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then + bool ' ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP + fi bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 - if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_AEC6210" = "y" ]; then - bool ' AEC6210 Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_AEC6210_TUNING + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_AEC6210" = "y" ]; then + bool ' AEC6210 Tuning support (WIP)' CONFIG_AEC6210_TUNING fi if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then bool ' ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 - if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then - bool ' AMD Viper support (EXPERIMENTAL)' CONFIG_BLK_DEV_AMD7409 + bool ' AMD Viper support' CONFIG_BLK_DEV_AMD7409 + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_AMD7409" = "y" ]; then + bool ' AMD Viper ATA-66 Override (WIP)' CONFIG_AMD7409_OVERRIDE fi fi bool ' CMD64X chipset support' CONFIG_BLK_DEV_CMD64X - if [ "$CONFIG_BLK_DEV_CMD64X" = "y" -a "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then - bool ' CMD64X chipset RAID support (EXPERIMENTAL) (WIP)' CONFIG_BLK_DEV_CMD64X_RAID + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_CMD64X" = "y" ]; then + bool ' CMD64X chipset RAID (WIP)' CONFIG_CMD64X_RAID fi if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 fi + bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X - if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then - bool ' HPT34X DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT34X_DMA + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then + bool ' HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA fi bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366 - if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT366" = "y" ]; then - bool ' HPT366 Fast Interrupt support (EXPERIMENTAL) (WIP)' CONFIG_HPT366_FAST_IRQ_PREDICTION - bool ' HPT366 mode three unsupported (EXPERIMENTAL) (WIP)' CONFIG_HPT366_MODE3 + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_HPT366" = "y" ]; then + bool ' HPT366 Fast Interrupts (WIP)' CONFIG_HPT366_FIP + bool ' HPT366 mode Three (WIP)' CONFIG_HPT366_MODE3 fi - if [ "$CONFIG_X86" = "y" ]; then + if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX if [ "$CONFIG_BLK_DEV_PIIX" = "y" -a "$CONFIG_IDEDMA_PCI_AUTO" = "y" ]; then - bool ' PIIXn Tuning support' CONFIG_BLK_DEV_PIIX_TUNING + bool ' PIIXn Tuning support' CONFIG_PIIX_TUNING fi fi fi @@ -98,21 +104,18 @@ else if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX if [ "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then - bool ' Special UDMA Feature' CONFIG_PDC202XX_FORCE_BURST_BIT - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' Special Mode Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_MASTER_MODE + bool ' Special UDMA Feature' CONFIG_PDC202XX_BURST + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" ]; then + bool ' Special Mode Feature (WIP)' CONFIG_PDC202XX_MASTER fi fi if [ "$CONFIG_X86" = "y" ]; then bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 fi - bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 fi if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 - if [ "$CONFIG_X86" = "y" ]; then - bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX - fi + bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX fi fi if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then @@ -232,6 +235,7 @@ if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ "$CONFIG_BLK_DEV_AMD7409" = "y" -o \ "$CONFIG_BLK_DEV_CMD640" = "y" -o \ "$CONFIG_BLK_DEV_CMD64X" = "y" -o \ + "$CONFIG_BLK_DEV_CS5530" = "y" -o \ "$CONFIG_BLK_DEV_CY82C693" = "y" -o \ "$CONFIG_BLK_DEV_HPT34X" = "y" -o \ "$CONFIG_BLK_DEV_HPT366" = "y" -o \ @@ -240,7 +244,6 @@ if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \ "$CONFIG_BLK_DEV_PIIX" = "y" -o \ "$CONFIG_BLK_DEV_SIS5513" = "y" -o \ - "$CONFIG_BLK_DEV_CS5530" = "y" -o \ "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then define_bool CONFIG_BLK_DEV_IDE_MODES y else diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 9f313de8f..be158ca1a 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -130,6 +130,10 @@ ifeq ($(CONFIG_BLK_DEV_CMD64X),y) IDE_OBJS += cmd64x.o endif +ifeq ($(CONFIG_BLK_DEV_CS5530),y) +IDE_OBJS += cs5530.o +endif + ifeq ($(CONFIG_BLK_DEV_CY82C693),y) IDE_OBJS += cy82c693.o endif @@ -198,10 +202,6 @@ ifeq ($(CONFIG_BLK_DEV_PDC202XX),y) IDE_OBJS += pdc202xx.o endif -ifeq ($(CONFIG_BLK_DEV_CS5530),y) -IDE_OBJS += cs5530.o -endif - ifeq ($(CONFIG_BLK_DEV_PDC4030),y) IDE_OBJS += pdc4030.o endif diff --git a/drivers/block/README.buddha b/drivers/block/README.buddha deleted file mode 100644 index d3b7bc73f..000000000 --- a/drivers/block/README.buddha +++ /dev/null @@ -1,210 +0,0 @@ - -The Amiga Buddha and Catweasel IDE Driver (part of ide.c) was written by -Geert Uytterhoeven based on the following specifications: - ------------------------------------------------------------------------- - -Register map of the Buddha IDE controller and the -Buddha-part of the Catweasel Zorro-II version - -The Autoconfiguration has been implemented just as Commodore -described in their manuals, no tricks have been used (for -example leaving some address lines out of the equations...). -If you want to configure the board yourself (for example let -a Linux kernel configure the card), look at the Commodore -Docs. Reading the nibbles should give this information: - -Vendor number: 4626 ($1212) -product number: 0 (42 for Catweasel Z-II) -Serial number: 0 -Rom-vector: $1000 - -The card should be a Z-II board, size 64K, not for freemem -list, Rom-Vektor is valid, no second Autoconfig-board on the -same card, no space preferrence, supports "Shutup_forever". - -Setting the base address should be done in two steps, just -as the Amiga Kickstart does: The lower nibble of the 8-Bit -address is written to $4a, then the whole Byte is written to -$48, while it doesn't matter how often you're writing to $4a -as long as $48 is not touched. After $48 has been written, -the whole card disappears from $e8 and is mapped to the new -addrress just written. Make shure $4a is written befor $48, -otherwise your chance is only 1:16 to find the board :-). - -The local memory-map is even active when mapped to $e8: - -$0-$7e Autokonfig-space, see Z-II docs. - -$80-$7fd reserved - -$7fe Speed-select Register: Read & Write - (description see further down) - -$800-$8ff IDE-Select 0 (Port 0, Register set 0) - -$900-$9ff IDE-Select 1 (Port 0, Register set 1) - -$a00-$aff IDE-Select 2 (Port 1, Register set 0) - -$b00-$bff IDE-Select 3 (Port 1, Register set 1) - -$c00-$cff IDE-Select 4 (Port 2, Register set 0, - Catweasel only!) - -$d00-$dff IDE-Select 5 (Port 3, Register set 1, - Catweasel only!) - -$e00-$eff local expansion port, on Catweasel Z-II the - Catweasel registers are also mapped here. - Never touch, use multidisk.device! - -$f00 read only, Byte-access: Bit 7 shows the - level of the IRQ-line of IDE port 0. - -$f01-$f3f mirror of $f00 - -$f40 read only, Byte-access: Bit 7 shows the - level of the IRQ-line of IDE port 1. - -$f41-$f7f mirror of $f40 - -$f80 read only, Byte-access: Bit 7 shows the - level of the IRQ-line of IDE port 2. - (Catweasel only!) - -$f81-$fbf mirror of $f80 - -$fc0 write-only: Writing any value to this - register enables IRQs to be passed from the - IDE ports to the Zorro bus. This mechanism - has been implemented to be compatible with - harddisks that are either defective or have - a buggy firmware and pull the IRQ line up - while starting up. If interrupts would - always be passed to the bus, the computer - might not start up. Once enabled, this flag - can not be disabled again. The level of the - flag can not be determined by software - (what for? Write to me if it's necessary!). - -$fc1-$fff mirror of $fc0 - -$1000-$ffff Buddha-Rom with offset $1000 in the rom - chip. The addresses $0 to $fff of the rom - chip cannot be read. Rom is Byte-wide and - mapped to even addresses. - -The IDE ports issue an INT2. You can read the level of the -IRQ-lines of the IDE-ports by reading from the three (two -for Buddha-only) registers $f00, $f40 and $f80. This way -more than one I/O request can be handled and you can easily -determine what driver has to serve the INT2. Buddha and -Catweasel expansion boards can issue an INT6. A seperate -memory map is available for the I/O module and the sysop's -I/O module. - -The IDE ports are fed by the address lines A2 to A4, just as -the Amiga 1200 and Amiga 4000 IDE ports are. This way -existing drivers can be easily ported to Buddha. A move.l -polls two words out of the same address of IDE port since -every word is mirrored once. movem is not possible, but -it's not necessary either, because you can only speedup -68000 systems with this technique. A 68020 system with -fastmem is faster with move.l. - -If you're using the mirrored registers of the IDE-ports with -A6=1, the Buddha doesn't care about the speed that you have -selected in the speed register (see further down). With -A6=1 (for example $840 for port 0, register set 0), a 780ns -access is being made. These registers should be used for a -command access to the harddisk/CD-Rom, since command -accesses are Byte-wide and have to be made slower according -to the ATA-X3T9 manual. - -Now for the speed-register: The register is byte-wide, and -only the upper three bits are used (Bits 7 to 5). Bit 4 -must always be set to 1 to be compatible with later Buddha -versions (if I'll ever update this one). I presume that -I'll never use the lower four bits, but they have to be set -to 1 by definition. - The values in this table have to be shifted 5 bits to the -left and or'd with $1f (this sets the lower 5 bits). - -All the timings have in common: Select and IOR/IOW rise at -the same time. IOR and IOW have a propagation delay of -about 30ns to the clocks on the Zorro bus, that's why the -values are no multiple of 71. One clock-cycle is 71ns long -(exactly 70,5 at 14,18 Mhz on PAL systems). - -value 0 (Default after reset) - -497ns Select (7 clock cycles) , IOR/IOW after 172ns (2 clock cycles) -(same timing as the Amiga 1200 does on it's IDE port without -accelerator card) - -value 1 - -639ns Select (9 clock cycles), IOR/IOW after 243ns (3 clock cycles) - -value 2 - -781ns Select (11 clock cycles), IOR/IOW after 314ns (4 clock cycles) - -value 3 - -355ns Select (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) - -value 4 - -355ns Select (5 clock cycles), IOR/IOW after 172ns (2 clock cycles) - -value 5 - -355ns Select (5 clock cycles), IOR/IOW after 243ns (3 clock cycles) - -value 6 - -1065ns Select (15 clock cycles), IOR/IOW after 314ns (4 clock cycles) - -value 7 - -355ns Select, (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) - -When accessing IDE registers with A6=1 (for example $84x), -the timing will always be mode 0 8-bit compatible, no matter -what you have selected in the speed register: - -781ns select, IOR/IOW after 4 clock cycles (=314ns) aktive. - -All the timings with a very short select-signal (the 355ns -fast accesses) depend on the accelerator card used in the -system: Sometimes two more clock cycles are inserted by the -bus interface, making the whole access 497ns long. This -doesn't affect the reliability of the controller nor the -performance of the card, since this doesn't happen very -often. - -All the timings are calculated and only confirmed by -measurements that allowed me to count the clock cycles. If -the system is clocked by an oscillator other than 28,37516 -Mhz (for example the NTSC-frequency 28,63636 Mhz), each -clock cycle is shortened to a bit less than 70ns (not worth -mentioning). You could think of a small performance boost -by overclocking the system, but you would either need a -multisync monitor, or a graphics card, and your internal -diskdrive would go crazy, that's why you shouldn't tune your -Amiga this way. - -Giving you the possibility to write software that is -compatible with both the Buddha and the Catweasel Z-II, The -Buddha acts just like a Catweasel Z-II with no device -connected to the third IDE-port. The IRQ-register $f80 -always shows a "no IRQ here" on the Buddha, and accesses to -the third IDE port are going into data's Nirwana on the -Buddha. - - Jens Schönfeld february 19th, 1997 - updated may 27th, 1997 - eMail: sysop@nostlgic.tng.oche.de - diff --git a/drivers/block/README.fd b/drivers/block/README.fd deleted file mode 100644 index 38f0b85a5..000000000 --- a/drivers/block/README.fd +++ /dev/null @@ -1,222 +0,0 @@ -This Readme file describes the floppy driver. - -FAQ list: -========= - - A FAQ list may be found in the fdutils package (see below), and also -at http://fdutils.linux.lu/FAQ.html - - -LILO configuration options (Thinkpad users, read this) -====================================================== - - The floppy driver is configured using the 'floppy=' option in -lilo. This option can be typed at the boot prompt, or entered in the -lilo configuration file. - Example: If your kernel is called linux-2.2.13, type the following line -at the lilo boot prompt (if you have a thinkpad): - linux-2.2.13 floppy=thinkpad -You may also enter the following line in /etc/lilo.conf, in the description -of linux-2.2.13: - append = "floppy=thinkpad" - - Several floppy related options may be given, example: - linux-2.2.13 floppy=daring floppy=two_fdc - append = "floppy=daring floppy=two_fdc" - - If you give options both in the lilo config file and on the boot -prompt, the option strings of both places are concatenated, the boot -prompt options coming last. That's why there are also options to -restore the default behavior. - - If you use the floppy driver as a module, use the following syntax: - insmod floppy <options> - -Example: - insmod floppy daring two_fdc - - Some versions of insmod are buggy in one way or another. If you have -any problems (options not being passed correctly, segfaults during -insmod), first check whether there is a more recent version. - - The floppy related options include: - - floppy=asus_pci - Sets the bit mask to allow only units 0 and 1. (default) - - floppy=daring - Tells the floppy driver that you have a well behaved floppy controller. - This allows more efficient and smoother operation, but may fail on - certain controllers. This may speed up certain operations. - - floppy=0,daring - Tells the floppy driver that your floppy controller should be used - with caution. - - floppy=one_fdc - Tells the floppy driver that you have only one floppy controller. - (default) - - floppy=two_fdc - floppy=<address>,two_fdc - Tells the floppy driver that you have two floppy controllers. - The second floppy controller is assumed to be at <address>. - This option is not needed if the second controller is at address - 0x370, and if you use the 'cmos' option. - - floppy=thinkpad - Tells the floppy driver that you have a Thinkpad. Thinkpads use an - inverted convention for the disk change line. - - floppy=0,thinkpad - Tells the floppy driver that you don't have a Thinkpad. - - floppy=omnibook - floppy=nodma - Tells the floppy driver not to use Dma for data transfers. - This is needed on HP Omnibooks, which don't have a workable - DMA channel for the floppy driver. This option is also useful - if you frequently get "Unable to allocate DMA memory" messages. - Indeed, dma memory needs to be continuous in physical memory, - and is thus harder to find, whereas non-dma buffers may be - allocated in virtual memory. However, I advise against this if - you have an FDC without a FIFO (8272A or 82072). 82072A and - later are OK. You also need at least a 486 to use nodma. - If you use nodma mode, I suggest you also set the FIFO - threshold to 10 or lower, in order to limit the number of data - transfer interrupts. - - If you have a FIFO-able FDC, the floppy driver automatically - falls back on non DMA mode if no DMA-able memory can be found. - If you want to avoid this, explicitely ask for 'yesdma'. - - floppy=yesdma - Tells the floppy driver that a workable DMA channel is available. - (default) - - floppy=nofifo - Disables the FIFO entirely. This is needed if you get "Bus - master arbitration error" messages from your Ethernet card (or - from other devices) while accessing the floppy. - - floppy=fifo - Enables the FIFO. (default) - - floppy=<threshold>,fifo_depth - Sets the FIFO threshold. This is mostly relevant in DMA - mode. If this is higher, the floppy driver tolerates more - interrupt latency, but it triggers more interrupts (i.e. it - imposes more load on the rest of the system). If this is - lower, the interrupt latency should be lower too (faster - processor). The benefit of a lower threshold is less - interrupts. - To tune the fifo threshold, switch on over/underrun messages - using 'floppycontrol --messages'. Then access a floppy - disk. If you get a huge amount of "Over/Underrun - retrying" - messages, then the fifo threshold is too low. Try with a - higher value, until you only get an occasional Over/Underrun. - It is a good idea to compile the floppy driver as a module - when doing this tuning. Indeed, it allows to try different - fifo values without rebooting the machine for each test. Note - that you need to do 'floppycontrol --messages' every time you - re-insert the module. - Usually, tuning the fifo threshold should not be needed, as - the default (0xa) is reasonable. - - floppy=<drive>,<type>,cmos - Sets the CMOS type of <drive> to <type>. This is mandatory if - you have more than two floppy drives (only two can be - described in the physical CMOS), or if your BIOS uses - non-standard CMOS types. The CMOS types are: - 0 - Use the value of the physical CMOS - 1 - 5 1/4 DD - 2 - 5 1/4 HD - 3 - 3 1/2 DD - 4 - 3 1/2 HD - 5 - 3 1/2 ED - 6 - 3 1/2 ED - 16 - unknown or not installed - (Note: there are two valid types for ED drives. This is because 5 was - initially chosen to represent floppy *tapes*, and 6 for ED drives. - AMI ignored this, and used 5 for ED drives. That's why the floppy - driver handles both.) - - floppy=unexpected_interrupts - Print a warning message when an unexpected interrupt is received. - (default) - - floppy=no_unexpected_interrupts - floppy=L40SX - Don't print a message when an unexpected interrupt is received. This - is needed on IBM L40SX laptops in certain video modes. (There seems - to be an interaction between video and floppy. The unexpected - interrupts affect only performance, and can be safely ignored.) - - floppy=broken_dcl - Don't use the disk change line, but assume that the disk was - changed whenever the device node is reopened. Needed on some - boxes where the disk change line is broken or unsupported. - This should be regarded as a stopgap measure, indeed it makes - floppy operation less efficient due to unneeded cache - flushings, and slightly more unreliable. Please verify your - cable, connection and jumper settings if you have any DCL - problems. However, some older drives, and also some laptops - are known not to have a DCL. - - floppy=debug - Print debugging messages. - - floppy=messages - Print informational messages for some operations (disk change - notifications, warnings about over and underruns, and about - autodetection). - - floppy=silent_dcl_clear - Uses a less noisy way to clear the disk change line (which - doesn't involve seeks). Implied by 'daring' option. - - floppy=<nr>,irq - Sets the floppy IRQ to <nr> instead of 6. - - floppy=<nr>,dma - Sets the floppy DMA channel to <nr> instead of 2. - - floppy=slow - Use PS/2 stepping rate: - " PS/2 floppies have much slower step rates than regular floppies. - It's been recommended that take about 1/4 of the default speed - in some more extreme cases." - - - -Supporting utilities and additional documentation: -================================================== - - Additional parameters of the floppy driver can be configured at -runtime. Utilities which do this can be found in the fdutils package. -This package also contains a new version of mtools which allows to -access high capacity disks (up to 1992K on a high density 3 1/2 disk!). -It also contains additional documentation about the floppy driver. - -The latest version can be found at fdutils homepage: - http://fdutils.linux.lu - -The fdutils-5.3 release can be found at: - http://fdutils.linux.lu/fdutils-5.3.src.tar.gz - http://www.tux.org/pub/knaff/fdutils/fdutils-5.3.src.tar.gz - ftp://tsx-11.mit.edu/pub/linux/sources/sbin/fdutils-5.3.src.tar.gz - ftp://metalab.unc.edu/pub/Linux/utils/disk-management/fdutils-5.3.src.tar.gz - -Reporting problems about the floppy driver -========================================== - - If you have a question or a bug report about the floppy driver, mail -me at Alain.Knaff@poboxes.com . If you post to Usenet, preferably use -comp.os.linux.hardware. As the volume in these groups is rather high, -be sure to include the word "floppy" (or "FLOPPY") in the subject -line. If the reported problem happens when mounting floppy disks, be -sure to mention also the type of the filesystem in the subject line. - - Be sure to read the FAQ before mailing/posting any bug reports! - - Alain diff --git a/drivers/block/README.lvm b/drivers/block/README.lvm deleted file mode 100644 index 3d652457f..000000000 --- a/drivers/block/README.lvm +++ /dev/null @@ -1,8 +0,0 @@ - -This is the Logical Volume Manager driver for Linux, - -Tools, library that manage logical volumes can be found -at <http://linux.msede.com/lvm>. - -There you can obtain actual driver versions too. - diff --git a/drivers/block/README.md b/drivers/block/README.md deleted file mode 100644 index 6ad19ac99..000000000 --- a/drivers/block/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Tools that manage md devices can be found at sweet-smoke.ufr-info-p7.ibp.fr -in public/Linux/md035.tar.gz. - - Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr> diff --git a/drivers/block/aec6210.c b/drivers/block/aec6210.c index f74103d9a..30be6a7cc 100644 --- a/drivers/block/aec6210.c +++ b/drivers/block/aec6210.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/aec6210.c Version 0.04 Dec. 13, 1999 + * linux/drivers/block/aec6210.c Version 0.05 Feb. 10, 2000 * - * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * pio 0 :: 40: 00 07 00 00 00 00 00 00 02 07 a6 04 00 02 00 02 @@ -56,7 +56,52 @@ #define ACARD_DEBUG_DRIVE_INFO 1 -#ifdef CONFIG_BLK_DEV_AEC6210_TUNING +#define DISPLAY_AEC6210_TIMINGS + +#if defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS) +#include <linux/stat.h> +#include <linux/proc_fs.h> + +static int aec6210_get_info(char *, char **, off_t, int); +extern int (*aec6210_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int aec6210_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + p += sprintf(p, "\n AEC6210 Chipset.\n"); + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + return p-buffer;/* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte aec6210_proc = 0; + +#ifdef CONFIG_AEC6210_TUNING struct chipset_bus_clock_list_entry { byte xfer_speed; @@ -269,7 +314,7 @@ int aec6210_dmaproc (ide_dma_action_t func, ide_drive_t *drive) } return ide_dmaproc(func, drive); /* use standard DMA stuff */ } -#endif /* CONFIG_BLK_DEV_AEC6210_TUNING */ +#endif /* CONFIG_AEC6210_TUNING */ unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name) { @@ -277,12 +322,19 @@ unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name) pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); } + +#if defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS) + aec6210_proc = 1; + bmide_dev = dev; + aec6210_display_info = &aec6210_get_info; +#endif /* DISPLAY_AEC6210_TIMINGS && CONFIG_PROC_FS */ + return dev->irq; } void __init ide_init_aec6210 (ide_hwif_t *hwif) { -#ifdef CONFIG_BLK_DEV_AEC6210_TUNING +#ifdef CONFIG_AEC6210_TUNING hwif->tuneproc = &aec6210_tune_drive; if (hwif->dma_base) { @@ -291,7 +343,7 @@ void __init ide_init_aec6210 (ide_hwif_t *hwif) hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } -#endif /* CONFIG_BLK_DEV_AEC6210_TUNING */ +#endif /* CONFIG_AEC6210_TUNING */ } void __init ide_dmacapable_aec6210 (ide_hwif_t *hwif, unsigned long dmabase) diff --git a/drivers/block/ali14xx.c b/drivers/block/ali14xx.c index e86fe61db..e7fd203b4 100644 --- a/drivers/block/ali14xx.c +++ b/drivers/block/ali14xx.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ali14xx.c Version 0.03 Feb 09, 1996 + * linux/drivers/block/ali14xx.c Version 0.03 Feb 09, 1996 * * Copyright (C) 1996 Linus Torvalds & author (see below) */ @@ -55,12 +55,12 @@ /* port addresses for auto-detection */ #define ALI_NUM_PORTS 4 -static int ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4}; +static int __init ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4}; /* register initialization data */ typedef struct { byte reg, data; } RegInitializer; -static RegInitializer initData[] = { +static RegInitializer __init initData[] = { {0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00}, @@ -150,7 +150,7 @@ static void ali14xx_tune_drive (ide_drive_t *drive, byte pio) /* * Auto-detect the IDE controller port. */ -static int findPort (void) +static int __init findPort (void) { int i; byte t; @@ -183,7 +183,7 @@ static int findPort (void) /* * Initialize controller registers with default values. */ -static int initRegisters (void) { +static int __init initRegisters (void) { RegInitializer *p; byte t; unsigned long flags; @@ -200,7 +200,7 @@ static int initRegisters (void) { return t; } -void init_ali14xx (void) +void __init init_ali14xx (void) { /* auto-detect IDE controller port */ if (!findPort()) { diff --git a/drivers/block/alim15x3.c b/drivers/block/alim15x3.c index 4b9b28e3b..bc3d2b9e3 100644 --- a/drivers/block/alim15x3.c +++ b/drivers/block/alim15x3.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/alim15x3.c Version 0.08 Jan. 14, 2000 + * linux/drivers/block/alim15x3.c Version 0.08 Jan. 14, 2000 * * Copyright (C) 1998-2000 Michel Aubry, Maintainer * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer @@ -493,7 +493,6 @@ static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive) default: break; } - return ide_dmaproc(func, drive); /* use standard DMA stuff */ } @@ -518,6 +517,13 @@ unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name) if (inb(fixdma_base+2) & 0x80) printk("%s: simplex device: DMA will fail!!\n", name); } + +#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) + ali_proc = 1; + bmide_dev = dev; + ali_display_info = &ali_get_info; +#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ + return 0; } @@ -666,22 +672,11 @@ void __init ide_init_ali15x3 (ide_hwif_t *hwif) */ hwif->dmaproc = &ali15x3_dmaproc; hwif->autodma = 1; - hwif->drives[0].autotune = 0; - hwif->drives[1].autotune = 0; } else { hwif->autodma = 0; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } - -#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) - if (!ali_proc) { - ali_proc = 1; - bmide_dev = hwif->pci_dev; - ali_display_info = &ali_get_info; - } -#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ - return; } diff --git a/drivers/block/amd7409.c b/drivers/block/amd7409.c index 46d5f36af..b12847843 100644 --- a/drivers/block/amd7409.c +++ b/drivers/block/amd7409.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/amd7409.c Version 0.01 Jan. 10, 2000 + * linux/drivers/block/amd7409.c Version 0.03 Feb. 10, 2000 * * Copyright (C) 2000 Andre Hedrick <andre@suse.com> * May be copied or modified under the terms of the GNU General Public License @@ -24,6 +24,51 @@ #include "ide_modes.h" +#define DISPLAY_VIPER_TIMINGS + +#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) +#include <linux/stat.h> +#include <linux/proc_fs.h> + +static int amd7409_get_info(char *, char **, off_t, int); +extern int (*amd7409_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int amd7409_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + p += sprintf(p, "\n AMD 7409 VIPER Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte amd7409_proc = 0; + +extern char *ide_xfer_verbose (byte xfer_rate); + /* * Here is where all the hard work goes to program the chipset. * @@ -33,11 +78,13 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed) ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; int err = 0; - int drive_number = ((HWIF(drive)->channel ? 2 : 0) + - (drive->select.b.unit & 0x01)); + byte unit = (drive->select.b.unit & 0x01); + int drive_number = ((HWIF(drive)->channel ? 2 : 0) + unit); + unsigned long dma_base = hwif->dma_base; byte drive_pci = 0x00; byte drive_pci2 = 0x00; - byte drive_timing = 0x00; + byte ultra_timing = 0x00; + byte dma_pio_timing = 0x00; byte pio_timing = 0x00; switch (drive_number) { @@ -49,54 +96,99 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed) return ((int) ide_dma_off_quietly); } - pci_read_config_byte(dev, drive_pci, &drive_timing); - pci_read_config_byte(dev, drive_pci2, &pio_timing); + pci_read_config_byte(dev, drive_pci, &ultra_timing); + pci_read_config_byte(dev, drive_pci2, &dma_pio_timing); + pci_read_config_byte(dev, 0x4c, &pio_timing); - printk("%s: UDMA 0x%02x PIO 0x%02x ", - drive->name, drive_timing, pio_timing); +#ifdef DEBUG + printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ", + drive->name, ultra_timing, dma_pio_timing, pio_timing); +#endif + + ultra_timing &= ~0xC7; + dma_pio_timing &= ~0xFF; + pio_timing &= ~(0x03 << drive_number); + +#ifdef DEBUG + printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ", + ultra_timing, dma_pio_timing, pio_timing); +#endif switch(speed) { case XFER_UDMA_4: - drive_timing &= ~0xC7; - drive_timing |= 0x45; - pci_write_config_byte(dev, drive_pci, drive_timing); + ultra_timing |= 0x45; + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); break; case XFER_UDMA_3: - drive_timing &= ~0xC7; - drive_timing |= 0x44; - pci_write_config_byte(dev, drive_pci, drive_timing); + ultra_timing |= 0x44; + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); break; case XFER_UDMA_2: - drive_timing &= ~0xC7; - drive_timing |= 0x40; - pci_write_config_byte(dev, drive_pci, drive_timing); + ultra_timing |= 0x40; + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); break; case XFER_UDMA_1: - drive_timing &= ~0xC7; - drive_timing |= 0x41; - pci_write_config_byte(dev, drive_pci, drive_timing); + ultra_timing |= 0x41; + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); break; case XFER_UDMA_0: - drive_timing &= ~0xC7; - drive_timing |= 0x42; - pci_write_config_byte(dev, drive_pci, drive_timing); + ultra_timing |= 0x42; + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); + break; + case XFER_MW_DMA_2: + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); + break; + case XFER_MW_DMA_1: + dma_pio_timing |= 0x21; + pio_timing |= (0x03 << drive_number); + break; + case XFER_MW_DMA_0: + dma_pio_timing |= 0x77; + pio_timing |= (0x03 << drive_number); + break; + case XFER_PIO_4: + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); + break; + case XFER_PIO_3: + dma_pio_timing |= 0x22; + pio_timing |= (0x03 << drive_number); + break; + case XFER_PIO_2: + dma_pio_timing |= 0x42; + pio_timing |= (0x03 << drive_number); + break; + case XFER_PIO_1: + dma_pio_timing |= 0x65; + pio_timing |= (0x03 << drive_number); + break; + case XFER_PIO_0: + default: + dma_pio_timing |= 0xA8; + pio_timing |= (0x03 << drive_number); break; - case XFER_MW_DMA_2:break; - case XFER_MW_DMA_1:break; - case XFER_MW_DMA_0:break; - case XFER_SW_DMA_2:break; - case XFER_SW_DMA_1:break; - case XFER_SW_DMA_0:break; - case XFER_PIO_4:break; - case XFER_PIO_3:break; - case XFER_PIO_2:break; - case XFER_PIO_1:break; - case XFER_PIO_0:break; - default: break; } - printk(":: UDMA 0x%02x PIO 0x%02x\n", drive_timing, pio_timing); + pci_write_config_byte(dev, drive_pci, ultra_timing); + pci_write_config_byte(dev, drive_pci2, dma_pio_timing); + pci_write_config_byte(dev, 0x4c, pio_timing); + +#ifdef DEBUG + printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n", + ultra_timing, dma_pio_timing, pio_timing); +#endif + if (speed > XFER_PIO_4) { + outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); + } else { + outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); + } err = ide_config_drive_speed(drive, speed); return (err); } @@ -109,12 +201,14 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed) static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; + byte udma_66 = ((id->hw_config & 0x2000) && + (HWIF(drive)->udma_four)) ? 1 : 0; byte speed = 0x00; int rval; - if ((id->dma_ultra & 0x0010) && (HWIF(drive)->udma_four)) { + if ((id->dma_ultra & 0x0010) && (udma_66)) { speed = XFER_UDMA_4; - } else if ((id->dma_ultra & 0x0008) && (HWIF(drive)->udma_four)) { + } else if ((id->dma_ultra & 0x0008) && (udma_66)) { speed = XFER_UDMA_3; } else if (id->dma_ultra & 0x0004) { speed = XFER_UDMA_2; @@ -128,12 +222,6 @@ static int config_chipset_for_dma (ide_drive_t *drive) speed = XFER_MW_DMA_1; } else if (id->dma_mword & 0x0001) { speed = XFER_MW_DMA_0; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else if (id->dma_1word & 0x0002) { - speed = XFER_SW_DMA_1; - } else if (id->dma_1word & 0x0001) { - speed = XFER_SW_DMA_0; } else { return ((int) ide_dma_off_quietly); } @@ -143,7 +231,6 @@ static int config_chipset_for_dma (ide_drive_t *drive) rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); return rval; @@ -222,8 +309,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive) } } else if (id->field_valid & 2) { try_dma_modes: - if ((id->dma_mword & 0x0007) || - (id->dma_1word & 0x0007)) { + if (id->dma_mword & 0x0007) { /* Force if Capable regular DMA modes */ dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) @@ -265,16 +351,45 @@ int amd7409_dmaproc (ide_dma_action_t func, ide_drive_t *drive) return ide_dmaproc(func, drive); /* use standard DMA stuff */ } +unsigned int __init pci_init_amd7409 (struct pci_dev *dev, const char *name) +{ + unsigned long fixdma_base = dev->resource[4].start; + + if (!fixdma_base || fixdma_base == PCI_BASE_ADDRESS_IO_MASK) { + /* + * + */ + } else { + /* + * enable DMA capable bit, and "not" simplex only + */ + outb(inb(fixdma_base+2) & 0x60, fixdma_base+2); + + if (inb(fixdma_base+2) & 0x80) + printk("%s: simplex device: DMA will fail!!\n", name); + } +#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) + amd7409_proc = 1; + bmide_dev = dev; + amd7409_display_info = &amd7409_get_info; +#endif /* DISPLAY_VIPER_TIMINGS && CONFIG_PROC_FS */ + + return 0; +} + unsigned int __init ata66_amd7409 (ide_hwif_t *hwif) { -#if 0 +#ifdef CONFIG_AMD7409_OVERRIDE + byte ata66 = 1; +#else byte ata66 = 0; +#endif /* CONFIG_AMD7409_OVERRIDE */ +#if 0 pci_read_config_byte(hwif->pci_dev, 0x48, &ata66); return ((ata66 & 0x02) ? 0 : 1); -#else - return 0; #endif + return ata66; } void __init ide_init_amd7409 (ide_hwif_t *hwif) @@ -288,3 +403,8 @@ void __init ide_init_amd7409 (ide_hwif_t *hwif) hwif->drives[1].autotune = 1; } } + +void ide_dmacapable_amd7409 (ide_hwif_t *hwif, unsigned long dmabase) +{ + ide_setup_dma(hwif, dmabase, 8); +} diff --git a/drivers/block/buddha.c b/drivers/block/buddha.c index e5862cd31..3e1cfcd33 100644 --- a/drivers/block/buddha.c +++ b/drivers/block/buddha.c @@ -42,7 +42,7 @@ #define BUDDHA_BASE2 0xa00 #define BUDDHA_BASE3 0xc00 -static const u_int buddha_bases[CATWEASEL_NUM_HWIFS] = { +static const u_int __init buddha_bases[CATWEASEL_NUM_HWIFS] = { BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3 }; @@ -61,7 +61,7 @@ static const u_int buddha_bases[CATWEASEL_NUM_HWIFS] = { #define BUDDHA_STATUS 0x1e /* see status-bits */ #define BUDDHA_CONTROL 0x11a -static int buddha_offsets[IDE_NR_PORTS] = { +static int __init buddha_offsets[IDE_NR_PORTS] = { BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL, BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL }; @@ -75,7 +75,7 @@ static int buddha_offsets[IDE_NR_PORTS] = { #define BUDDHA_IRQ2 0xf40 /* interrupt */ #define BUDDHA_IRQ3 0xf80 -static const int buddha_irqports[CATWEASEL_NUM_HWIFS] = { +static const int __init buddha_irqports[CATWEASEL_NUM_HWIFS] = { BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3 }; @@ -109,7 +109,7 @@ static int buddha_ack_intr(ide_hwif_t *hwif) * Any Buddha or Catweasel boards present? */ -static int find_buddha(void) +static int __init find_buddha(void) { struct zorro_dev *z = NULL; @@ -143,7 +143,7 @@ static int find_buddha(void) * We support only _one_ of them, no multiple boards! */ -void buddha_init(void) +void __init buddha_init(void) { hw_regs_t hw; int i, index; diff --git a/drivers/block/cmd640.c b/drivers/block/cmd640.c index 3e5f56cec..b2077df6d 100644 --- a/drivers/block/cmd640.c +++ b/drivers/block/cmd640.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/cmd640.c Version 1.02 Sep 01, 1996 + * linux/drivers/block/cmd640.c Version 1.02 Sep 01, 1996 * * Copyright (C) 1995-1996 Linus Torvalds & authors (see below) */ @@ -290,7 +290,7 @@ static byte get_cmd640_reg_vlb (unsigned short reg) return b; } -static int match_pci_cmd640_device (void) +static int __init match_pci_cmd640_device (void) { const byte ven_dev[4] = {0x95, 0x10, 0x40, 0x06}; unsigned int i; @@ -310,7 +310,7 @@ static int match_pci_cmd640_device (void) /* * Probe for CMD640x -- pci method 1 */ -static int probe_for_cmd640_pci1 (void) +static int __init probe_for_cmd640_pci1 (void) { get_cmd640_reg = get_cmd640_reg_pci1; put_cmd640_reg = put_cmd640_reg_pci1; @@ -324,7 +324,7 @@ static int probe_for_cmd640_pci1 (void) /* * Probe for CMD640x -- pci method 2 */ -static int probe_for_cmd640_pci2 (void) +static int __init probe_for_cmd640_pci2 (void) { get_cmd640_reg = get_cmd640_reg_pci2; put_cmd640_reg = put_cmd640_reg_pci2; @@ -338,7 +338,7 @@ static int probe_for_cmd640_pci2 (void) /* * Probe for CMD640x -- vlb */ -static int probe_for_cmd640_vlb (void) +static int __init probe_for_cmd640_vlb (void) { byte b; @@ -359,7 +359,7 @@ static int probe_for_cmd640_vlb (void) * Returns 1 if an IDE interface/drive exists at 0x170, * Returns 0 otherwise. */ -static int secondary_port_responding (void) +static int __init secondary_port_responding (void) { unsigned long flags; @@ -403,7 +403,7 @@ void cmd640_dump_regs (void) * Check whether prefetch is on for a drive, * and initialize the unmask flags for safe operation. */ -static void check_prefetch (unsigned int index) +static void __init check_prefetch (unsigned int index) { ide_drive_t *drive = cmd_drives[index]; byte b = get_cmd640_reg(prefetch_regs[index]); @@ -424,7 +424,7 @@ static void check_prefetch (unsigned int index) /* * Figure out which devices we control */ -static void setup_device_ptrs (void) +static void __init setup_device_ptrs (void) { unsigned int i; @@ -507,7 +507,7 @@ inline static byte pack_nibbles (byte upper, byte lower) /* * This routine retrieves the initial drive timings from the chipset. */ -static void retrieve_drive_counts (unsigned int index) +static void __init retrieve_drive_counts (unsigned int index) { byte b; @@ -694,7 +694,7 @@ static void cmd640_tune_drive (ide_drive_t *drive, byte mode_wanted) /* * Probe for a cmd640 chipset, and initialize it if found. Called from ide.c */ -int ide_probe_for_cmd640x (void) +int __init ide_probe_for_cmd640x (void) { #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED int second_port_toggled = 0; diff --git a/drivers/block/cmd64x.c b/drivers/block/cmd64x.c index 8f5f04aea..4e98893ec 100644 --- a/drivers/block/cmd64x.c +++ b/drivers/block/cmd64x.c @@ -1,4 +1,4 @@ -/* $Id: cmd64x.c,v 1.20 1999/12/30 03:48:37 +/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16 * * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines. * Note, this driver is not used at all on other systems because @@ -8,7 +8,7 @@ * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1998 David S. Miller (davem@redhat.com) - * Copyright (C) 1999 Andre Hedrick (andre@suse.com) + * Copyright (C) 1999-2000 Andre Hedrick (andre@suse.com) */ #include <linux/types.h> @@ -18,8 +18,10 @@ #include <linux/ide.h> #include <asm/io.h> +#include "ide_modes.h" #define CMD_DEBUG 0 +#undef NO_WRITE #if CMD_DEBUG #define cmdprintk(x...) printk(##x) @@ -27,6 +29,235 @@ #define cmdprintk(x...) #endif +/* + * CMD64x specific registers definition. + */ + +#define CNTRL 0x51 +#define CNTRL_DIS_RA0 0x40 +#define CNTRL_DIS_RA1 0x80 +#define CNTRL_ENA_2ND 0x08 + +#define CMDTIM 0x52 +#define ARTTIM0 0x53 +#define DRWTIM0 0x54 +#define ARTTIM1 0x55 +#define DRWTIM1 0x56 +#define ARTTIM23 0x57 +#define ARTTIM23_DIS_RA2 0x04 +#define ARTTIM23_DIS_RA3 0x08 +#define DRWTIM23 0x58 +#define DRWTIM2 0x58 +#define BRST 0x59 +#define DRWTIM3 0x5b + +#define MRDMODE 0x71 + +#define DISPLAY_CMD64X_TIMINGS + +#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) +#include <linux/stat.h> +#include <linux/proc_fs.h> + +static int cmd64x_get_info(char *, char **, off_t, int); +extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + switch(bmide_dev->device) { + case PCI_DEVICE_ID_CMD_648: + p += sprintf(p, "\n CMD648 Chipset.\n"); + break; + case PCI_DEVICE_ID_CMD_646: + p += sprintf(p, "\n CMD646 Chipset.\n"); + break; + case PCI_DEVICE_ID_CMD_643: + p += sprintf(p, "\n CMD643 Chipset.\n"); + break; + default: + p += sprintf(p, "\n CMD64? Chipse.\n"); + break; + } + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte cmd64x_proc = 0; + +/* + * Registers and masks for easy access by drive index: + */ +#if 0 +static byte prefetch_regs[4] = {CNTRL, CNTRL, ARTTIM23, ARTTIM23}; +static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3}; +#endif + +/* + * This routine writes the prepared setup/active/recovery counts + * for a drive into the cmd646 chipset registers to active them. + */ +static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count) +{ + unsigned long flags; + ide_drive_t *drives = HWIF(drive)->drives; + byte temp_b; + static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; + static const byte recovery_counts[] = + {15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0}; + static const byte arttim_regs[2][2] = { + { ARTTIM0, ARTTIM1 }, + { ARTTIM23, ARTTIM23 } + }; + static const byte drwtim_regs[2][2] = { + { DRWTIM0, DRWTIM1 }, + { DRWTIM2, DRWTIM3 } + }; + int channel = (int) HWIF(drive)->channel; + int slave = (drives != drive); /* Is this really the best way to determine this?? */ + + cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n", setup_count, + active_count, recovery_count, drive->present); + /* + * Set up address setup count registers. + * Primary interface has individual count/timing registers for + * each drive. Secondary interface has one common set of registers, + * for address setup so we merge these timings, using the slowest + * value. + */ + if (channel) { + drive->drive_data = setup_count; + setup_count = IDE_MAX(drives[0].drive_data, drives[1].drive_data); + cmdprintk("Secondary interface, setup_count = %d\n", setup_count); + } + + /* + * Convert values to internal chipset representation + */ + setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count]; + active_count &= 0xf; /* Remember, max value is 16 */ + recovery_count = (int) recovery_counts[recovery_count]; + + cmdprintk("Final values = %d,%d,%d\n", setup_count, active_count, recovery_count); + + /* + * Now that everything is ready, program the new timings + */ + __save_flags (flags); + __cli(); + /* + * Program the address_setup clocks into ARTTIM reg, + * and then the active/recovery counts into the DRWTIM reg + */ + (void) pci_read_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], &temp_b); +#ifndef NO_WRITE + (void) pci_write_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], + ((byte) setup_count) | (temp_b & 0x3f)); + (void) pci_write_config_byte(HWIF(drive)->pci_dev, drwtim_regs[channel][slave], + (byte) ((active_count << 4) | recovery_count)); +#endif + cmdprintk ("Write %x to %x\n", ((byte) setup_count) | (temp_b & 0x3f), arttim_regs[channel][slave]); + cmdprintk ("Write %x to %x\n", (byte) ((active_count << 4) | recovery_count), drwtim_regs[channel][slave]); + __restore_flags(flags); +} + +/* + * Attempts to set the interface PIO mode. + * The preferred method of selecting PIO modes (e.g. mode 4) is + * "echo 'piomode:4' > /proc/ide/hdx/settings". Special cases are + * 8: prefetch off, 9: prefetch on, 255: auto-select best mode. + * Called with 255 at boot time. + */ +static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted) +{ + int setup_time, active_time, recovery_time, clock_time, pio_mode, cycle_time; + byte recovery_count2, cycle_count; + int setup_count, active_count, recovery_count; + int bus_speed = ide_system_bus_speed(); + /*byte b;*/ + ide_pio_data_t d; + + switch (mode_wanted) { + case 8: /* set prefetch off */ + case 9: /* set prefetch on */ + mode_wanted &= 1; + /*set_prefetch_mode(index, mode_wanted);*/ + cmdprintk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis"); + return; + } + + (void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d); + pio_mode = d.pio_mode; + cycle_time = d.cycle_time; + + /* + * I copied all this complicated stuff from cmd640.c and made a few minor changes. + * For now I am just going to pray that it is correct. + */ + if (pio_mode > 5) + pio_mode = 5; + setup_time = ide_pio_timings[pio_mode].setup_time; + active_time = ide_pio_timings[pio_mode].active_time; + recovery_time = cycle_time - (setup_time + active_time); + clock_time = 1000 / bus_speed; + cycle_count = (cycle_time + clock_time - 1) / clock_time; + + setup_count = (setup_time + clock_time - 1) / clock_time; + + active_count = (active_time + clock_time - 1) / clock_time; + + recovery_count = (recovery_time + clock_time - 1) / clock_time; + recovery_count2 = cycle_count - (setup_count + active_count); + if (recovery_count2 > recovery_count) + recovery_count = recovery_count2; + if (recovery_count > 16) { + active_count += recovery_count - 16; + recovery_count = 16; + } + if (active_count > 16) + active_count = 16; /* maximum allowed by cmd646 */ + + /* + * In a perfect world, we might set the drive pio mode here + * (using WIN_SETFEATURE) before continuing. + * + * But we do not, because: + * 1) this is the wrong place to do it (proper is do_special() in ide.c) + * 2) in practice this is rarely, if ever, necessary + */ + program_drive_counts (drive, setup_count, active_count, recovery_count); + + printk ("%s: selected cmd646 PIO mode%d (%dns)%s, clocks=%d/%d/%d\n", + drive->name, pio_mode, cycle_time, + d.overridden ? " (overriding vendor mode)" : "", + setup_count, active_count, recovery_count); +} + static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66) { struct hd_driveid *id = drive->id; @@ -123,7 +354,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul static void config_chipset_for_pio (ide_drive_t *drive, unsigned int rev) { - /* FIXME!! figure out some PIOing junk.... */ + cmd64x_tuneproc(drive, 5); } static int cmd64x_config_drive_for_dma (ide_drive_t *drive) @@ -198,7 +429,7 @@ fast_ata_pio: no_dma_set: config_chipset_for_pio(drive, class_rev); } - return hwif->dmaproc(dma_func, drive); + return HWIF(drive)->dmaproc(dma_func, drive); } static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) @@ -277,9 +508,9 @@ unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name) #endif /* Setup interrupts. */ - (void) pci_read_config_byte(dev, 0x71, &mrdmode); + (void) pci_read_config_byte(dev, MRDMODE, &mrdmode); mrdmode &= ~(0x30); - (void) pci_write_config_byte(dev, 0x71, mrdmode); + (void) pci_write_config_byte(dev, MRDMODE, mrdmode); /* Use MEMORY READ LINE for reads. * NOTE: Although not mentioned in the PCI0646U specs, @@ -287,16 +518,26 @@ unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name) * back as set or not. The PCI0646U2 specs clarify * this point. */ - (void) pci_write_config_byte(dev, 0x71, mrdmode | 0x02); - + (void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02); +#if 0 /* Set reasonable active/recovery/address-setup values. */ - (void) pci_write_config_byte(dev, 0x53, 0x40); - (void) pci_write_config_byte(dev, 0x54, 0x3f); - (void) pci_write_config_byte(dev, 0x55, 0x40); - (void) pci_write_config_byte(dev, 0x56, 0x3f); - (void) pci_write_config_byte(dev, 0x57, 0x5c); - (void) pci_write_config_byte(dev, 0x58, 0x3f); - (void) pci_write_config_byte(dev, 0x5b, 0x3f); + (void) pci_write_config_byte(dev, ARTTIM0, 0x40); + (void) pci_write_config_byte(dev, DRWTIM0, 0x3f); + (void) pci_write_config_byte(dev, ARTTIM1, 0x40); + (void) pci_write_config_byte(dev, DRWTIM1, 0x3f); + (void) pci_write_config_byte(dev, ARTTIM23, 0x5c); + (void) pci_write_config_byte(dev, DRWTIM23, 0x3f); + (void) pci_write_config_byte(dev, DRWTIM3, 0x3f); +#else + (void) pci_write_config_byte(dev, ARTTIM23, 0x1c); +#endif + +#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) + cmd64x_proc = 1; + bmide_dev = dev; + cmd64x_display_info = &cmd64x_get_info; +#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */ + return 0; } @@ -317,8 +558,13 @@ void __init ide_init_cmd64x (ide_hwif_t *hwif) pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; - if (!hwif->dma_base) + hwif->tuneproc = &cmd64x_tuneproc; + + if (!hwif->dma_base) { + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; return; + } switch(dev->device) { case PCI_DEVICE_ID_CMD_643: diff --git a/drivers/block/cs5530.c b/drivers/block/cs5530.c index 3e26b8006..0f2f04990 100644 --- a/drivers/block/cs5530.c +++ b/drivers/block/cs5530.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/cs5530.c Version 0.5 Feb 13, 2000 + * linux/drivers/block/cs5530.c Version 0.5 Feb 13, 2000 * * Copyright (C) 2000 Mark Lord <mlord@pobox.com> * May be copied or modified under the terms of the GNU General Public License @@ -24,130 +24,63 @@ #include <asm/irq.h> #include "ide_modes.h" -/* - * Return the mode name for a drive transfer mode value: - */ -static const char *strmode (byte mode) +#define DISPLAY_CS5530_TIMINGS + +#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS) +#include <linux/stat.h> +#include <linux/proc_fs.h> + +static int cs5530_get_info(char *, char **, off_t, int); +extern int (*cs5530_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count) { - switch (mode) { - case XFER_UDMA_4: return("UDMA4"); - case XFER_UDMA_3: return("UDMA3"); - case XFER_UDMA_2: return("UDMA2"); - case XFER_UDMA_1: return("UDMA1"); - case XFER_UDMA_0: return("UDMA0"); - case XFER_MW_DMA_2: return("MDMA2"); - case XFER_MW_DMA_1: return("MDMA1"); - case XFER_MW_DMA_0: return("MDMA0"); - case XFER_SW_DMA_2: return("SDMA2"); - case XFER_SW_DMA_1: return("SDMA1"); - case XFER_SW_DMA_0: return("SDMA0"); - case XFER_PIO_4: return("PIO4"); - case XFER_PIO_3: return("PIO3"); - case XFER_PIO_2: return("PIO2"); - case XFER_PIO_1: return("PIO1"); - case XFER_PIO_0: return("PIO0"); - default: return("???"); - } + char *p = buffer; + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + p += sprintf(p, "\n Cyrix 5530 Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; } +#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */ + +byte cs5530_proc = 0; + +extern char *ide_xfer_verbose (byte xfer_rate); /* * Set a new transfer mode at the drive */ int cs5530_set_xfer_mode (ide_drive_t *drive, byte mode) { - int i, error = 1; - byte stat; - ide_hwif_t *hwif = HWIF(drive); - - printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, strmode(mode)); - /* - * If this is a DMA mode setting, then turn off all DMA bits. - * We will set one of them back on afterwards, if all goes well. - * - * Not sure why this is needed (it looks very silly), - * but other IDE chipset drivers also do this fiddling. ???? -ml - */ - switch (mode) { - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - case XFER_SW_DMA_2: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } + int error = 0; - /* - * Select the drive, and issue the SETFEATURES command - */ - disable_irq(hwif->irq); - udelay(1); - SELECT_DRIVE(HWIF(drive), drive); - udelay(1); - if (IDE_CONTROL_REG) - OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); - OUT_BYTE(mode, IDE_NSECTOR_REG); - OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); - OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); - udelay(1); /* spec allows drive 400ns to assert "BUSY" */ + printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode)); + error = ide_config_drive_speed(drive, mode); - /* - * Wait for drive to become non-BUSY - */ - if ((stat = GET_STAT()) & BUSY_STAT) { - unsigned long flags, timeout; - __save_flags(flags); /* local CPU only */ - ide__sti(); /* local CPU only -- for jiffies */ - timeout = jiffies + WAIT_CMD; - while ((stat = GET_STAT()) & BUSY_STAT) { - if (0 < (signed long)(jiffies - timeout)) - break; - } - __restore_flags(flags); /* local CPU only */ - } - - /* - * Allow status to settle, then read it again. - * A few rare drives vastly violate the 400ns spec here, - * so we'll wait up to 10usec for a "good" status - * rather than expensively fail things immediately. - */ - for (i = 0; i < 10; i++) { - udelay(1); - if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) { - error = 0; - break; - } - } - enable_irq(hwif->irq); - - /* - * Turn dma bit on if all is okay - */ - if (error) { - (void) ide_dump_status(drive, "cs5530_set_xfer_mode", stat); - } else { - switch (mode) { - case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break; - case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break; - case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break; - case XFER_UDMA_1: drive->id->dma_ultra |= 0x0202; break; - case XFER_UDMA_0: drive->id->dma_ultra |= 0x0101; break; - case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break; - case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break; - case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break; - case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break; - case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break; - case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break; - } - } return error; } @@ -302,8 +235,10 @@ int cs5530_dmaproc (ide_dma_action_t func, ide_drive_t *drive) case ide_dma_check: return cs5530_config_dma(drive); default: - return ide_dmaproc(func, drive); + break; } + /* Other cases are done by generic IDE-DMA code. */ + return ide_dmaproc(func, drive); } /* @@ -384,6 +319,13 @@ unsigned int __init pci_init_cs5530 (struct pci_dev *dev, const char *name) pci_write_config_byte(master_0, 0x43, 0xc1); restore_flags(flags); + +#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS) + cs5530_proc = 1; + bmide_dev = dev; + cs5530_display_info = &cs5530_get_info; +#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */ + return 0; } diff --git a/drivers/block/cy82c693.c b/drivers/block/cy82c693.c index 412f403c3..cfff0381c 100644 --- a/drivers/block/cy82c693.c +++ b/drivers/block/cy82c693.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/cy82c693.c Version 0.34 Dec. 13, 1999 + * linux/drivers/block/cy82c693.c Version 0.34 Dec. 13, 1999 * * Copyright (C) 1998-99 Andreas S. Krebs (akrebs@altavista.net), Maintainer * Copyright (C) 1998-99 Andre Hedrick, Integrater @@ -54,7 +54,7 @@ #include "ide_modes.h" /* the current version */ -#define CY82_VERSION "CY82C693U driver v0.34 99-09-03 Andreas S. Krebs (akrebs@altavista.net)" +#define CY82_VERSION "CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)" /* * The following are used to debug the driver. @@ -439,4 +439,3 @@ void __init ide_init_cy82c693(ide_hwif_t *hwif) hwif->drives[1].autotune = 1; } } - diff --git a/drivers/block/dtc2278.c b/drivers/block/dtc2278.c index d805dec75..d8838e111 100644 --- a/drivers/block/dtc2278.c +++ b/drivers/block/dtc2278.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/dtc2278.c Version 0.02 Feb 10, 1996 + * linux/drivers/block/dtc2278.c Version 0.02 Feb 10, 1996 * * Copyright (C) 1996 Linus Torvalds & author (see below) */ @@ -95,7 +95,7 @@ static void tune_dtc2278 (ide_drive_t *drive, byte pio) HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1; } -void init_dtc2278 (void) +void __init init_dtc2278 (void) { unsigned long flags; diff --git a/drivers/block/falconide.c b/drivers/block/falconide.c index 321569eb1..7bce07517 100644 --- a/drivers/block/falconide.c +++ b/drivers/block/falconide.c @@ -40,7 +40,7 @@ #define ATA_HD_STATUS 0x1d /* see status-bits */ #define ATA_HD_CONTROL 0x39 -static int falconide_offsets[IDE_NR_PORTS] = { +static int __init falconide_offsets[IDE_NR_PORTS] = { ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL, ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1 }; @@ -50,7 +50,7 @@ static int falconide_offsets[IDE_NR_PORTS] = { * Probe for a Falcon IDE interface */ -void falconide_init(void) +void __init falconide_init(void) { if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) { hw_regs_t hw; diff --git a/drivers/block/gayle.c b/drivers/block/gayle.c index 920f2ee0a..29cceb20e 100644 --- a/drivers/block/gayle.c +++ b/drivers/block/gayle.c @@ -41,7 +41,7 @@ #define GAYLE_STATUS 0x1e /* see status-bits */ #define GAYLE_CONTROL 0x101a -static int gayle_offsets[IDE_NR_PORTS] = { +static int __init gayle_offsets[IDE_NR_PORTS] = { GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL, GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1 }; @@ -105,7 +105,7 @@ static int gayle_ack_intr_a1200(ide_hwif_t *hwif) * Probe for a Gayle IDE interface (and optionally for an IDE doubler) */ -void gayle_init(void) +void __init gayle_init(void) { int a4000, i; diff --git a/drivers/block/hpt34x.c b/drivers/block/hpt34x.c index 10fe3ebc1..7a077368e 100644 --- a/drivers/block/hpt34x.c +++ b/drivers/block/hpt34x.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/hpt34x.c Version 0.28 Dec. 13, 1999 + * linux/drivers/block/hpt34x.c Version 0.29 Feb. 10, 2000 * - * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * @@ -16,6 +16,12 @@ * hdg: DMA 1 (0x0012 0x0052) (0x0030 0x0070) * hdh: DMA 1 (0x0052 0x0252) (0x0070 0x00f0) * + * ide-pci.c reference + * + * Since there are two cards that report almost identically, + * the only discernable difference is the values reported in pcicmd. + * Booting-BIOS card or HPT363 :: pcicmd == 0x07 + * Non-bootable card or HPT343 :: pcicmd == 0x05 */ #include <linux/config.h> @@ -27,7 +33,6 @@ #include <linux/ioport.h> #include <linux/blkdev.h> #include <linux/hdreg.h> - #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/init.h> @@ -35,16 +40,56 @@ #include <asm/io.h> #include <asm/irq.h> - #include "ide_modes.h" #ifndef SPLIT_BYTE #define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) #endif -#define HPT343_DEBUG_DRIVE_INFO 0 -#define HPT343_DISABLE_ALL_DMAING 0 -#define HPT343_DMA_DISK_ONLY 0 +#define HPT343_DEBUG_DRIVE_INFO 1 + +#define DISPLAY_HPT34X_TIMINGS +#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) +#include <linux/stat.h> +#include <linux/proc_fs.h> + +static int hpt34x_get_info(char *, char **, off_t, int); +extern int (*hpt34x_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + p += sprintf(p, "\n HPT34X Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte hpt34x_proc = 0; extern char *ide_xfer_verbose (byte xfer_rate); @@ -109,12 +154,8 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) struct hd_driveid *id = drive->id; byte speed = 0x00; -#if HPT343_DISABLE_ALL_DMAING - return ((int) ide_dma_off); -#elif HPT343_DMA_DISK_ONLY if (drive->media != ide_disk) return ((int) ide_dma_off_quietly); -#endif /* HPT343_DISABLE_ALL_DMAING */ hpt34x_clear_chipset(drive); @@ -249,14 +290,13 @@ try_dma_modes: fast_ata_pio: dma_func = ide_dma_off_quietly; no_dma_set: - config_chipset_for_pio(drive); } -#if 0 +#ifndef CONFIG_HPT34X_AUTODMA if (dma_func == ide_dma_on) dma_func = ide_dma_off; -#endif +#endif /* CONFIG_HPT34X_AUTODMA */ return HWIF(drive)->dmaproc(dma_func, drive); } @@ -273,18 +313,10 @@ int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); unsigned long dma_base = hwif->dma_base; - byte unit = (drive->select.b.unit & 0x01); unsigned int count, reading = 0; byte dma_stat; switch (func) { - case ide_dma_off: - case ide_dma_off_quietly: - outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); - break; - case ide_dma_on: - outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); - break; case ide_dma_check: return config_drive_xfer_rate(drive); case ide_dma_read: @@ -357,11 +389,16 @@ unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name) pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start); pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start); pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start); - pci_write_config_word(dev, PCI_COMMAND, cmd); __restore_flags(flags); /* local CPU only */ +#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) + hpt34x_proc = 1; + bmide_dev = dev; + hpt34x_display_info = &hpt34x_get_info; +#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */ + return dev->irq; } @@ -372,11 +409,7 @@ void __init ide_init_hpt34x (ide_hwif_t *hwif) unsigned short pcicmd = 0; pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd); -#ifdef CONFIG_BLK_DEV_HPT34X_DMA -#if 0 hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; -#endif -#endif /* CONFIG_BLK_DEV_HPT34X_DMA */ hwif->dmaproc = &hpt34x_dmaproc; } else { hwif->drives[0].autotune = 1; diff --git a/drivers/block/hpt366.c b/drivers/block/hpt366.c index 7328ea7b8..02c9c16dd 100644 --- a/drivers/block/hpt366.c +++ b/drivers/block/hpt366.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/hpt366.c Version 0.15 Dec. 22, 1999 + * linux/drivers/block/hpt366.c Version 0.16 Feb. 10, 2000 * - * Copyright (C) 1999 Andre Hedrick <andre@suse.com> + * Copyright (C) 1999-2000 Andre Hedrick <andre@suse.com> * May be copied or modified under the terms of the GNU General Public License * * Thanks to HighPoint Technologies for their assistance, and hardware. @@ -30,6 +30,13 @@ #include "ide_modes.h" +#define DISPLAY_HPT366_TIMINGS + +#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) +#include <linux/stat.h> +#include <linux/proc_fs.h> +#endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */ + const char *bad_ata66_4[] = { "WDC AC310200R", NULL @@ -120,6 +127,48 @@ struct chipset_bus_clock_list_entry twenty_five_base [] = { #define HPT366_ALLOW_ATA66_4 1 #define HPT366_ALLOW_ATA66_3 1 +#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) +static int hpt366_get_info(char *, char **, off_t, int); +extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; +static struct pci_dev *bmide2_dev; + +static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + u32 bibma = bmide_dev->resource[4].start; + u32 bibma2 = bmide2_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + if (bmide2_dev) + c1 = inb_p((unsigned short)bibma2 + 0x02); + + p += sprintf(p, "\n HPT366 Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer;/* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte hpt366_proc = 0; + extern char *ide_xfer_verbose (byte xfer_rate); byte hpt363_shared_irq = 0; byte hpt363_shared_pin = 0; @@ -263,20 +312,20 @@ static int config_chipset_for_dma (ide_drive_t *drive) pci_read_config_byte(HWIF(drive)->pci_dev, 0x51, ®51h); -#ifdef CONFIG_HPT366_FAST_IRQ_PREDICTION +#ifdef CONFIG_HPT366_FIP /* * Some drives prefer/allow for the method of handling interrupts. */ if (!(reg51h & 0x80)) pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h|0x80); -#else /* ! CONFIG_HPT366_FAST_IRQ_PREDICTION */ +#else /* ! CONFIG_HPT366_FIP */ /* * Disable the "fast interrupt" prediction. * Instead, always wait for the real interrupt from the drive! */ if (reg51h & 0x80) pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h & ~0x80); -#endif /* CONFIG_HPT366_FAST_IRQ_PREDICTION */ +#endif /* CONFIG_HPT366_FIP */ /* * Preserve existing PIO settings: @@ -420,7 +469,6 @@ no_dma_set: * This is specific to the HPT366 UDMA bios chipset * by HighPoint|Triones Technologies, Inc. */ - int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { byte reg50h = 0; @@ -434,7 +482,6 @@ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive) pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); /* ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); */ case ide_dma_timeout: - break; default: break; } @@ -464,6 +511,17 @@ unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name) if (test != 0x08) pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); +#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) + if (!hpt366_proc) { + hpt366_proc = 1; + bmide_dev = dev; + hpt366_display_info = &hpt366_get_info; + } + if ((hpt366_proc) && ((dev->devfn - bmide_dev->devfn) == 1)) { + bmide2_dev = dev; + } +#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */ + return dev->irq; } @@ -482,18 +540,6 @@ unsigned int __init ata66_hpt366 (ide_hwif_t *hwif) void __init ide_init_hpt366 (ide_hwif_t *hwif) { -#if 0 - if ((PCI_FUNC(hwif->pci_dev->devfn) & 1) && (hpt363_shared_irq)) { - hwif->mate = &ide_hwifs[hwif->index-1]; - hwif->mate->mate = hwif; - hwif->serialized = hwif->mate->serialized = 1; - } - - if ((PCI_FUNC(hwif->pci_dev->devfn) & 1) && (hpt363_shared_pin)) { - - } -#endif - hwif->tuneproc = &hpt366_tune_drive; if (hwif->dma_base) { hwif->dmaproc = &hpt366_dmaproc; diff --git a/drivers/block/ht6560b.c b/drivers/block/ht6560b.c index d9fb885c2..6b7d5af72 100644 --- a/drivers/block/ht6560b.c +++ b/drivers/block/ht6560b.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/ht6580.c Version 0.04 Mar 19, 1996 + * linux/drivers/block/ht6560b.c Version 0.07 Feb 1, 2000 * - * Copyright (C) 1995-1996 Linus Torvalds & author (see below) + * Copyright (C) 1995-2000 Linus Torvalds & author (see below) */ /* @@ -12,42 +12,31 @@ * * Version 0.03 Some cleanups * - * I reviewed some assembler source listings of htide drivers and found - * out how they setup those cycle time interfacing values, as they at Holtek - * call them. IDESETUP.COM that is supplied with the drivers figures out - * optimal values and fetches those values to drivers. I found out that - * they use IDE_SELECT_REG to fetch timings to the ide board right after - * interface switching. After that it was quite easy to add code to - * ht6560b.c. + * Version 0.05 PIO mode cycle timings auto-tune using bus-speed * - * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine - * for hda and hdc. But hdb needed higher values to work, so I guess - * that sometimes it is necessary to give higher value than IDESETUP - * gives. [see cmd640.c for an extreme example of this. -ml] + * Version 0.06 Prefetch mode now defaults no OFF. To set + * prefetch mode OFF/ON use "hdparm -p8/-p9". + * Unmask irq is disabled when prefetch mode + * is enabled. * - * Perhaps I should explain something about these timing values: - * The higher nibble of value is the Recovery Time (rt) and the lower nibble - * of the value is the Active Time (at). Minimum value 2 is the fastest and - * the maximum value 15 is the slowest. Default values should be 15 for both. - * So 0x24 means 2 for rt and 4 for at. Each of the drives should have - * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or - * similar. If value is too small there will be all sorts of failures. - * - * Port 0x3e6 bit 0x20 sets these timings on/off. If 0x20 bit is set - * these timings are disabled. + * Version 0.07 Trying to fix CD-ROM detection problem. + * "Prefetch" mode bit OFF for ide disks and + * ON for anything else. * - * Mikko Ala-Fossi * - * More notes: + * HT-6560B EIDE-controller support + * To activate controller support use kernel parameter "ide0=ht6560b". + * Use hdparm utility to enable PIO mode support. * - * There's something still missing from the initialization code, though. - * If I have booted to dos sometime after power on, I can get smaller - * timing values working. Perhaps I could soft-ice the initialization. + * Author: Mikko Ala-Fossi <maf@iki.fi> + * Jan Evert van Grootheest <janevert@iae.nl> * - * -=- malafoss@snakemail.hut.fi -=- searching the marvels of universe -=- + * Try: http://www.maf.iki.fi/~maf/ht6560b/ */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ +#define HT6560B_VERSION "v0.07" + +#undef REALLY_SLOW_IO /* most systems can safely undef this */ #include <linux/types.h> #include <linux/kernel.h> @@ -63,175 +52,291 @@ #include "ide_modes.h" -/* - * This routine handles interface switching for the peculiar hardware design - * on the F.G.I./Holtek HT-6560B VLB IDE interface. - * The HT-6560B can only enable one IDE port at a time, and requires a - * silly sequence (below) whenever we switch between primary and secondary. - * - * This stuff is courtesy of malafoss@snakemail.hut.fi - * (or maf@nemesis.tky.hut.fi) - * - * At least one user has reported that this code can confuse the floppy - * controller and/or driver -- perhaps this should be changed to use - * a read-modify-write sequence, so as not to disturb other bits in the reg? - */ +/* #define DEBUG */ /* remove comments for DEBUG messages */ /* - * The special i/o-port that HT-6560B uses to select interfaces: + * The special i/o-port that HT-6560B uses to configuration: + * bit0 (0x01): "1" selects secondary interface + * bit2 (0x04): "1" enables FIFO function + * bit5 (0x20): "1" enables prefetched data read function (???) + * + * The special i/o-port that HT-6560A uses to configuration: + * bit0 (0x01): "1" selects secondary interface + * bit1 (0x02): "1" enables prefetched data read function + * bit2 (0x04): "0" enables multi-master system (?) + * bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time (?) */ -#define HT_SELECT_PORT 0x3e6 - +#define HT_CONFIG_PORT 0x3e6 +#define HT_CONFIG(drivea) (byte)(((drivea)->drive_data & 0xff00) >> 8) /* - * We don't know what all of the bits are for, but we *do* know about these: - * bit5 (0x20): "1" selects slower speed by disabling use of timing values - * bit0 (0x01): "1" selects second interface + * FIFO + PREFETCH (both a/b-model) */ -static byte ht6560b_selects [2][MAX_DRIVES] = {{0x3c,0x3c}, {0x3d,0x3d}}; +#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */ +/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */ +#define HT_SECONDARY_IF 0x01 +#define HT_PREFETCH_MODE 0x20 /* - * VLB ht6560b Timing values: + * ht6560b Timing values: + * + * I reviewed some assembler source listings of htide drivers and found + * out how they setup those cycle time interfacing values, as they at Holtek + * call them. IDESETUP.COM that is supplied with the drivers figures out + * optimal values and fetches those values to drivers. I found out that + * they use IDE_SELECT_REG to fetch timings to the ide board right after + * interface switching. After that it was quite easy to add code to + * ht6560b.c. + * + * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine + * for hda and hdc. But hdb needed higher values to work, so I guess + * that sometimes it is necessary to give higher value than IDESETUP + * gives. [see cmd640.c for an extreme example of this. -ml] + * + * Perhaps I should explain something about these timing values: + * The higher nibble of value is the Recovery Time (rt) and the lower nibble + * of the value is the Active Time (at). Minimum value 2 is the fastest and + * the maximum value 15 is the slowest. Default values should be 15 for both. + * So 0x24 means 2 for rt and 4 for at. Each of the drives should have + * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or + * similar. If value is too small there will be all sorts of failures. * * Timing byte consists of - * High nibble: Recovery Time (rt) - * The valid values range from 2 to 15. The default is 15. + * High nibble: Recovery Cycle Time (rt) + * The valid values range from 2 to 15. The default is 15. * - * Low nibble: Active Time (at) - * The valid values range from 2 to 15. The default is 15. + * Low nibble: Active Cycle Time (at) + * The valid values range from 2 to 15. The default is 15. * * You can obtain optimized timing values by running Holtek IDESETUP.COM * for DOS. DOS drivers get their timing values from command line, where * the first value is the Recovery Time and the second value is the * Active Time for each drive. Smaller value gives higher speed. * In case of failures you should probably fall back to a higher value. - * - * Here's an example to make it clearer: - * - * DOS: DEVICE=C:\bin\HTIDE\HTIDE.SYS /D0=2,4 /D1=4,5 /D2=10,10 /D3=15,15 - * Linux: byte ht6560b_timings [][] = {{0x24, 0x45}, {0xaa, 0xff}}; - * - * Note: There are no ioctls to change these values directly, - * but settings can be approximated as PIO modes, using "hdparm": - * - * rc.local: hdparm -p3 /dev/hda -p2 /dev/hdb -p1 /dev/hdc -p0 /dev/hdd */ +#define HT_TIMING(drivea) (byte)((drivea)->drive_data & 0x00ff) +#define HT_TIMING_DEFAULT 0xff -static byte ht6560b_timings [2][MAX_DRIVES] = {{0xff,0xff}, {0xff,0xff}}; - -static byte pio_to_timings[6] = {0xff, 0xaa, 0x45, 0x24, 0x13, 0x12}; +/* + * This routine handles interface switching for the peculiar hardware design + * on the F.G.I./Holtek HT-6560B VLB IDE interface. + * The HT-6560B can only enable one IDE port at a time, and requires a + * silly sequence (below) whenever we switch between primary and secondary. + */ /* * This routine is invoked from ide.c to prepare for access to a given drive. */ static void ht6560b_selectproc (ide_drive_t *drive) { - byte t; unsigned long flags; static byte current_select = 0; static byte current_timing = 0; - byte select = ht6560b_selects[HWIF(drive)->index][drive->select.b.unit]; - byte timing = ht6560b_timings[HWIF(drive)->index][drive->select.b.unit]; - + byte select, timing; + + __save_flags (flags); /* local CPU only */ + __cli(); /* local CPU only */ + + select = HT_CONFIG(drive); + timing = HT_TIMING(drive); + if (select != current_select || timing != current_timing) { current_select = select; current_timing = timing; - __save_flags (flags); /* local CPU only */ - __cli(); /* local CPU only */ - (void) inb(HT_SELECT_PORT); - (void) inb(HT_SELECT_PORT); - (void) inb(HT_SELECT_PORT); + if (drive->media != ide_disk || !drive->present) + select |= HT_PREFETCH_MODE; + (void) inb(HT_CONFIG_PORT); + (void) inb(HT_CONFIG_PORT); + (void) inb(HT_CONFIG_PORT); + (void) inb(HT_CONFIG_PORT); + outb(select, HT_CONFIG_PORT); /* - * Note: input bits are reversed to output bits!! + * Set timing for this drive: */ - t = inb(HT_SELECT_PORT) ^ 0x3f; - t &= (~0x21); - t |= (current_select & 0x21); - outb(t, HT_SELECT_PORT); - /* - * Set timing for this drive: - */ - outb (timing, IDE_SELECT_REG); - (void) inb (IDE_STATUS_REG); - __restore_flags (flags); /* local CPU only */ + outb(timing, IDE_SELECT_REG); + (void) inb(IDE_STATUS_REG); #ifdef DEBUG - printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, t, timing); + printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing); #endif } + __restore_flags (flags); /* local CPU only */ } /* * Autodetection and initialization of ht6560b */ -int try_to_init_ht6560b(void) +static int __init try_to_init_ht6560b(void) { byte orig_value; int i; - + /* Autodetect ht6560b */ - if ((orig_value=inb(HT_SELECT_PORT)) == 0xff) + if ((orig_value=inb(HT_CONFIG_PORT)) == 0xff) return 0; - + for (i=3;i>0;i--) { - outb(0x00, HT_SELECT_PORT); - if (!( (~inb(HT_SELECT_PORT)) & 0x3f )) { - outb(orig_value, HT_SELECT_PORT); - return 0; + outb(0x00, HT_CONFIG_PORT); + if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) { + outb(orig_value, HT_CONFIG_PORT); + return 0; } } - outb(0x00, HT_SELECT_PORT); - if ((~inb(HT_SELECT_PORT))& 0x3f) { - outb(orig_value, HT_SELECT_PORT); + outb(0x00, HT_CONFIG_PORT); + if ((~inb(HT_CONFIG_PORT))& 0x3f) { + outb(orig_value, HT_CONFIG_PORT); return 0; } /* - * Ht6560b autodetected: - * reverse input bits to output bits - * initialize bit1 to 0 + * Ht6560b autodetected */ - outb((orig_value ^ 0x3f) & 0xfd, HT_SELECT_PORT); - - printk("\nht6560b: detected and initialized"); + outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT); + outb(HT_TIMING_DEFAULT, 0x1f6); /* IDE_SELECT_REG */ + (void) inb(0x1f7); /* IDE_STATUS_REG */ + + printk("\nht6560b " HT6560B_VERSION + ": chipset detected and initialized" +#ifdef DEBUG + " with debug enabled" +#endif + ); return 1; } -static void tune_ht6560b (ide_drive_t *drive, byte pio) +static byte ht_pio2timings(ide_drive_t *drive, byte pio) { - unsigned int hwif, unit; + int bus_speed, active_time, recovery_time; + int active_cycles, recovery_cycles; + ide_pio_data_t d; + + if (pio) { + pio = ide_get_best_pio_mode(drive, pio, 5, &d); + + /* + * Just like opti621.c we try to calculate the + * actual cycle time for recovery and activity + * according system bus speed. + */ + bus_speed = ide_system_bus_speed(); + active_time = ide_pio_timings[pio].active_time; + recovery_time = d.cycle_time + - active_time + - ide_pio_timings[pio].setup_time; + /* + * Cycle times should be Vesa bus cycles + */ + active_cycles = (active_time * bus_speed + 999) / 1000; + recovery_cycles = (recovery_time * bus_speed + 999) / 1000; + /* + * Upper and lower limits + */ + if (active_cycles < 2) active_cycles = 2; + if (recovery_cycles < 2) recovery_cycles = 2; + if (active_cycles > 15) active_cycles = 15; + if (recovery_cycles > 15) recovery_cycles = 0; /* 0==16 */ + +#ifdef DEBUG + printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time); +#endif + + return (byte)((recovery_cycles << 4) | active_cycles); + } else { + +#ifdef DEBUG + printk("ht6560b: drive %s setting pio=0\n", drive->name); +#endif + + return HT_TIMING_DEFAULT; /* default setting */ + } +} + +/* + * Enable/Disable so called prefetch mode + */ +static void ht_set_prefetch(ide_drive_t *drive, byte state) +{ + unsigned long flags; + int t = HT_PREFETCH_MODE << 8; + + save_flags (flags); /* all CPUs */ + cli(); /* all CPUs */ + + /* + * Prefetch mode and unmask irq seems to conflict + */ + if (state) { + drive->drive_data |= t; /* enable prefetch mode */ + drive->no_unmask = 1; + drive->unmask = 0; + } else { + drive->drive_data &= ~t; /* disable prefetch mode */ + drive->no_unmask = 0; + } + + restore_flags (flags); /* all CPUs */ + +#ifdef DEBUG + printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis")); +#endif +} - if (pio == 255) { /* auto-tune */ - if (drive->media != ide_disk) - pio = 0; /* some CDROMs don't like fast modes (?) */ - else - pio = ide_get_best_pio_mode(drive, pio, 5, NULL); +static void tune_ht6560b (ide_drive_t *drive, byte pio) +{ + unsigned long flags; + byte timing; + + switch (pio) { + case 8: /* set prefetch off */ + case 9: /* set prefetch on */ + ht_set_prefetch(drive, pio & 1); + return; } - unit = drive->select.b.unit; - hwif = HWIF(drive)->index; - ht6560b_timings[hwif][unit] = pio_to_timings[pio]; - if (pio == 0) - ht6560b_selects[hwif][unit] |= 0x20; - else - ht6560b_selects[hwif][unit] &= ~0x20; + + timing = ht_pio2timings(drive, pio); + + save_flags (flags); /* all CPUs */ + cli(); /* all CPUs */ + + drive->drive_data &= 0xff00; + drive->drive_data |= timing; + + restore_flags (flags); /* all CPUs */ + +#ifdef DEBUG + printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing); +#endif } -void init_ht6560b (void) +void __init init_ht6560b (void) { - if (check_region(HT_SELECT_PORT,1)) { - printk("\nht6560b: PORT 0x3e6 ALREADY IN USE\n"); + int t; + + if (check_region(HT_CONFIG_PORT,1)) { + printk(KERN_ERR "ht6560b: PORT %#x ALREADY IN USE\n", HT_CONFIG_PORT); } else { if (try_to_init_ht6560b()) { - request_region(HT_SELECT_PORT, 1, ide_hwifs[0].name); + request_region(HT_CONFIG_PORT, 1, ide_hwifs[0].name); ide_hwifs[0].chipset = ide_ht6560b; ide_hwifs[1].chipset = ide_ht6560b; ide_hwifs[0].selectproc = &ht6560b_selectproc; ide_hwifs[1].selectproc = &ht6560b_selectproc; ide_hwifs[0].tuneproc = &tune_ht6560b; ide_hwifs[1].tuneproc = &tune_ht6560b; - ide_hwifs[0].serialized = 1; - ide_hwifs[1].serialized = 1; + ide_hwifs[0].serialized = 1; /* is this needed? */ + ide_hwifs[1].serialized = 1; /* is this needed? */ ide_hwifs[0].mate = &ide_hwifs[1]; ide_hwifs[1].mate = &ide_hwifs[0]; ide_hwifs[1].channel = 1; + + /* + * Setting default configurations for drives + */ + t = (HT_CONFIG_DEFAULT << 8); + t |= HT_TIMING_DEFAULT; + ide_hwifs[0].drives[0].drive_data = t; + ide_hwifs[0].drives[1].drive_data = t; + t |= (HT_SECONDARY_IF << 8); + ide_hwifs[1].drives[0].drive_data = t; + ide_hwifs[1].drives[1].drive_data = t; } else - printk("\nht6560b: not found\n"); + printk(KERN_ERR "ht6560b: not found\n"); } } diff --git a/drivers/block/ide-cd.h b/drivers/block/ide-cd.h index 8891205ed..1eb48ef6c 100644 --- a/drivers/block/ide-cd.h +++ b/drivers/block/ide-cd.h @@ -1,11 +1,11 @@ -#ifndef _IDE_CD_H -#define _IDE_CD_H /* * linux/drivers/block/ide_cd.h * - * Copyright (C) 1996, 1997, 1998 Erik Andersen - * Copyright (C) 1998, 1999 Jens Axboe + * Copyright (C) 1996-98 Erik Andersen + * Copyright (C) 1998-2000 Jens Axboe */ +#ifndef _IDE_CD_H +#define _IDE_CD_H #include <linux/cdrom.h> #include <asm/byteorder.h> diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c index e62295241..f766605bc 100644 --- a/drivers/block/ide-disk.c +++ b/drivers/block/ide-disk.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-disk.c Version 1.09 April 23, 1999 + * linux/drivers/block/ide-disk.c Version 1.09 April 23, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c index 3b6f5e56a..751424831 100644 --- a/drivers/block/ide-dma.c +++ b/drivers/block/ide-dma.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999 + * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999 * * Copyright (c) 1999 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License @@ -91,6 +91,8 @@ #include <asm/io.h> #include <asm/irq.h> +extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc); + #ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS struct drive_list_entry { @@ -401,6 +403,7 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); unsigned long dma_base = hwif->dma_base; + byte unit = (drive->select.b.unit & 0x01); unsigned int count, reading = 0; byte dma_stat; @@ -408,8 +411,11 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) case ide_dma_off: printk("%s: DMA disabled\n", drive->name); case ide_dma_off_quietly: + outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); case ide_dma_on: drive->using_dma = (func == ide_dma_on); + if (drive->using_dma) + outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); return 0; case ide_dma_check: return config_drive_for_dma (drive); @@ -424,7 +430,7 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);/* issue cmd to drive */ + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); case ide_dma_begin: /* Note that this is done *after* the cmd has @@ -449,12 +455,10 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) return check_drive_lists(drive, (func == ide_dma_good_drive)); case ide_dma_lostirq: case ide_dma_timeout: - /* - * printk("ide_dmaproc: chipset supported func only: %d\n", func); - */ + printk("ide_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func), func); return 1; default: - printk("ide_dmaproc: unsupported func: %d\n", func); + printk("ide_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func); return 1; } } @@ -541,14 +545,15 @@ unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const } } if (dma_base) { - if (extra) /* PDC20246, PDC20262, & HPT343 */ + if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */ request_region(dma_base+16, extra, name); dma_base += hwif->channel ? 8 : 0; hwif->dma_extra = extra; switch(dev->device) { - case PCI_DEVICE_ID_CMD_643: case PCI_DEVICE_ID_AL_M5219: + case PCI_DEVICE_ID_AMD_VIPER_7409: + case PCI_DEVICE_ID_CMD_643: outb(inb(dma_base+2) & 0x60, dma_base+2); if (inb(dma_base+2) & 0x80) { printk("%s: simplex device: DMA forced\n", name); diff --git a/drivers/block/ide-features.c b/drivers/block/ide-features.c index 87b7cacb4..3f29ed591 100644 --- a/drivers/block/ide-features.c +++ b/drivers/block/ide-features.c @@ -1,16 +1,15 @@ /* - * linux/drivers/block/ide-features.c + * linux/drivers/block/ide-features.c Version 0.03 Feb. 10, 2000 * - * Copyright (C) 1999 Linus Torvalds & authors (see below) + * Copyright (C) 1999-2000 Linus Torvalds & authors (see below) * - * Andre Hedrick <andre@suse.com> + * Copyright (C) 1999-2000 Andre Hedrick <andre@suse.com> * * Extracts if ide.c to address the evolving transfer rate code for - * the SETFEATURES_XFER callouts. Below are original authors of some or - * various parts of any given function below. + * the SETFEATURES_XFER callouts. Various parts of any given function + * are credited to previous ATA-IDE maintainers. * - * Mark Lord <mlord@pobox.com> - * Gadi Oxman <gadio@netvision.net.il> + * May be copied or modified under the terms of the GNU General Public License */ #define __NO_VERSION__ @@ -36,12 +35,15 @@ #include <asm/io.h> #include <asm/bitops.h> +#define SETFEATURES_CONTROL_REG (0) /* some arch's may need */ + /* - * + * A Verbose noise maker for debugging on the attempted transfer rates. */ char *ide_xfer_verbose (byte xfer_rate) { switch(xfer_rate) { + case XFER_UDMA_7: return("UDMA 7"); case XFER_UDMA_6: return("UDMA 6"); case XFER_UDMA_5: return("UDMA 5"); case XFER_UDMA_4: return("UDMA 4"); @@ -71,14 +73,42 @@ char *ide_xfer_verbose (byte xfer_rate) char *ide_media_verbose (ide_drive_t *drive) { switch (drive->media) { - case ide_disk: return("disk "); - case ide_cdrom: return("cdrom "); - case ide_tape: return("tape "); - case ide_floppy: return("floppy"); - default: return("??????"); + case ide_scsi: return("scsi "); + case ide_disk: return("disk "); + case ide_optical: return("optical"); + case ide_cdrom: return("cdrom "); + case ide_tape: return("tape "); + case ide_floppy: return("floppy "); + default: return("???????"); } } +/* + * A Verbose noise maker for debugging on the attempted dmaing calls. + */ +char *ide_dmafunc_verbose (ide_dma_action_t dmafunc) +{ + switch (dmafunc) { + case ide_dma_read: return("ide_dma_read"); + case ide_dma_write: return("ide_dma_write"); + case ide_dma_begin: return("ide_dma_begin"); + case ide_dma_end: return("ide_dma_end:"); + case ide_dma_check: return("ide_dma_check"); + case ide_dma_on: return("ide_dma_on"); + case ide_dma_off: return("ide_dma_off"); + case ide_dma_off_quietly: return("ide_dma_off_quietly"); + case ide_dma_test_irq: return("ide_dma_test_irq"); + case ide_dma_bad_drive: return("ide_dma_bad_drive"); + case ide_dma_good_drive: return("ide_dma_good_drive"); + case ide_dma_lostirq: return("ide_dma_lostirq"); + case ide_dma_timeout: return("ide_dma_timeout"); + default: return("unknown"); + } +} + +/* + * Update the + */ int ide_driveid_update (ide_drive_t *drive) { /* @@ -129,50 +159,6 @@ int ide_driveid_update (ide_drive_t *drive) } /* - * Similar to ide_wait_stat(), except it never calls ide_error internally. - * This is a kludge to handle the new ide_config_drive_speed() function, - * and should not otherwise be used anywhere. Eventually, the tuneproc's - * should be updated to return ide_startstop_t, in which case we can get - * rid of this abomination again. :) -ml - */ -int ide_wait_noerr (ide_drive_t *drive, byte good, byte bad, unsigned long timeout) -{ - byte stat; - int i; - unsigned long flags; - - udelay(1); /* spec allows drive 400ns to assert "BUSY" */ - if ((stat = GET_STAT()) & BUSY_STAT) { - __save_flags(flags); /* local CPU only */ - ide__sti(); /* local CPU only */ - timeout += jiffies; - while ((stat = GET_STAT()) & BUSY_STAT) { - if (0 < (signed long)(jiffies - timeout)) { - __restore_flags(flags); /* local CPU only */ - (void)ide_dump_status(drive, "ide_wait_noerr", stat); - return 1; - } - } - __restore_flags(flags); /* local CPU only */ - } - /* - * Allow status to settle, then read it again. - * A few rare drives vastly violate the 400ns spec here, - * so we'll wait up to 10usec for a "good" status - * rather than expensively fail things immediately. - * This fix courtesy of Matthew Faupel & Niccolo Rigacci. - */ - for (i = 0; i < 10; i++) { - udelay(1); - if (OK_STAT((stat = GET_STAT()), good, bad)) - return 0; - } - (void)ide_dump_status(drive, "ide_wait_noerr", stat); - return 1; -} - - -/* * Verify that we are doing an approved SETFEATURES_XFER with respect * to the hardware being able to support request. Since some hardware * can improperly report capabilties, we check to see if the host adapter @@ -213,70 +199,96 @@ int set_transfer (ide_drive_t *drive, int cmd, int nsect, int feature) return 0; } -#if 0 -ide_startstop_t set_drive_speed_intr (ide_drive_t *drive) -{ - byte stat; - - if (!OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) /* - * if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,BAD_STAT)) - * if (stat != DRIVE_READY) + * Similar to ide_wait_stat(), except it never calls ide_error internally. + * This is a kludge to handle the new ide_config_drive_speed() function, + * and should not otherwise be used anywhere. Eventually, the tuneproc's + * should be updated to return ide_startstop_t, in which case we can get + * rid of this abomination again. :) -ml + * + * It is gone.......... + * + * const char *msg == consider adding for verbose errors. */ - (void) ide_dump_status(drive, "set_drive_speed_status", stat); - - return ide_stopped; -} -#endif - int ide_config_drive_speed (ide_drive_t *drive, byte speed) { - unsigned long flags; - int err; + ide_hwif_t *hwif = HWIF(drive); + int i, error = 1; + byte unit = (drive->select.b.unit & 0x01); byte stat; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ - /* * Don't use ide_wait_cmd here - it will * attempt to set_geometry and recalibrate, * but for some reason these don't work at * this point (lost interrupt). */ + /* + * Select the drive, and issue the SETFEATURES command + */ + disable_irq(hwif->irq); /* disable_irq_nosync ?? */ + udelay(1); SELECT_DRIVE(HWIF(drive), drive); + udelay(1); if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); OUT_BYTE(speed, IDE_NSECTOR_REG); OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); - - err = ide_wait_noerr(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD); - -#if 0 - if (IDE_CONTROL_REG) + if ((IDE_CONTROL_REG) && (SETFEATURES_CONTROL_REG)) OUT_BYTE(drive->ctl, IDE_CONTROL_REG); -#endif + udelay(1); + /* + * Wait for drive to become non-BUSY + */ + if ((stat = GET_STAT()) & BUSY_STAT) { + unsigned long flags, timeout; + __save_flags(flags); /* local CPU only */ + ide__sti(); /* local CPU only -- for jiffies */ + timeout = jiffies + WAIT_CMD; + while ((stat = GET_STAT()) & BUSY_STAT) { + if (0 < (signed long)(jiffies - timeout)) + break; + } + __restore_flags(flags); /* local CPU only */ + } - __restore_flags(flags); /* local CPU only */ + /* + * Allow status to settle, then read it again. + * A few rare drives vastly violate the 400ns spec here, + * so we'll wait up to 10usec for a "good" status + * rather than expensively fail things immediately. + * This fix courtesy of Matthew Faupel & Niccolo Rigacci. + */ + for (i = 0; i < 10; i++) { + udelay(1); + if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) { + error = 0; + break; + } + } -#if 0 - ide_set_handler(drive, &set_drive_speed_intr, WAIT_CMD, NULL); -#endif + enable_irq(hwif->irq); - stat = GET_STAT(); - if (stat != DRIVE_READY) + if (error) { (void) ide_dump_status(drive, "set_drive_speed_status", stat); + return error; + } drive->id->dma_ultra &= ~0xFF00; drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; + if (speed > XFER_PIO_4) { + outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2); + } else { + outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); + } + switch(speed) { -#if 0 - case XFER_UDMA_6: drive->id->dma_ultra |= 0x1010; break; - case XFER_UDMA_5: drive->id->dma_ultra |= 0x1010; break; -#endif + case XFER_UDMA_7: drive->id->dma_ultra |= 0x8080; break; + case XFER_UDMA_6: drive->id->dma_ultra |= 0x4040; break; + case XFER_UDMA_5: drive->id->dma_ultra |= 0x2020; break; case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break; case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break; case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break; @@ -290,11 +302,10 @@ int ide_config_drive_speed (ide_drive_t *drive, byte speed) case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break; default: break; } - return(err); + return error; } EXPORT_SYMBOL(ide_driveid_update); -EXPORT_SYMBOL(ide_wait_noerr); EXPORT_SYMBOL(ide_ata66_check); EXPORT_SYMBOL(set_transfer); EXPORT_SYMBOL(ide_config_drive_speed); diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c index e2977c754..bee6a4c6c 100644 --- a/drivers/block/ide-floppy.c +++ b/drivers/block/ide-floppy.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-floppy.c Version 0.9 Jul 4, 1999 + * linux/drivers/block/ide-floppy.c Version 0.9 Jul 4, 1999 * * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il> */ @@ -1264,8 +1264,11 @@ static int idefloppy_get_capacity (ide_drive_t *drive) blocks = descriptor->blocks = ntohl (descriptor->blocks); length = descriptor->length = ntohs (descriptor->length); if (!i && descriptor->dc == CAPACITY_CURRENT) { - if (memcmp (descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t))) - printk (KERN_INFO "%s: %dkB, %d blocks, %d sector size\n", drive->name, blocks * length / 1024, blocks, length); + if (memcmp (descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t))) { + printk (KERN_INFO "%s: %dkB, %d blocks, %d sector size, %s \n", + drive->name, blocks * length / 1024, blocks, length, + drive->using_dma ? ", DMA":""); + } floppy->capacity = *descriptor; if (!length || length % 512) printk (KERN_ERR "%s: %d bytes block size not supported\n", drive->name, length); diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c index a5593dffb..2ddbbc8bd 100644 --- a/drivers/block/ide-pci.c +++ b/drivers/block/ide-pci.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-pci.c Version 1.04 July 27, 1999 + * linux/drivers/block/ide-pci.c Version 1.04 July 27, 1999 * * Copyright (c) 1998-1999 Andre Hedrick * @@ -31,6 +31,7 @@ #define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB}) #define DEVID_PIIX4E ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1}) #define DEVID_PIIX4U ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1}) +#define DEVID_PIIX4U2 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1}) #define DEVID_VIA_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561}) #define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1}) #define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246}) @@ -95,13 +96,19 @@ extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long); #endif #ifdef CONFIG_BLK_DEV_AMD7409 +extern unsigned int pci_init_amd7409(struct pci_dev *, const char *); extern unsigned int ata66_amd7409(ide_hwif_t *); extern void ide_init_amd7409(ide_hwif_t *); +extern void ide_dmacapable_amd7409(ide_hwif_t *, unsigned long); +#define PCI_AMD7409 &pci_init_amd7409 #define ATA66_AMD7409 &ata66_amd7409 #define INIT_AMD7409 &ide_init_amd7409 +#define DMA_AMD7409 &ide_dmacapable_amd7409 #else +#define PCI_AMD7409 NULL #define ATA66_AMD7409 NULL #define INIT_AMD7409 NULL +#define DMA_AMD7409 NULL #endif #ifdef CONFIG_BLK_DEV_CMD64X @@ -135,11 +142,11 @@ extern void ide_init_cy82c693(ide_hwif_t *); #ifdef CONFIG_BLK_DEV_CS5530 extern unsigned int pci_init_cs5530(struct pci_dev *, const char *); extern void ide_init_cs5530(ide_hwif_t *); -#define INIT_CS5530 &ide_init_cs5530 #define PCI_CS5530 &pci_init_cs5530 +#define INIT_CS5530 &ide_init_cs5530 #else -#define INIT_CS5530 NULL #define PCI_CS5530 NULL +#define INIT_CS5530 NULL #endif #ifdef CONFIG_BLK_DEV_HPT34X @@ -149,7 +156,7 @@ extern void ide_init_hpt34x(ide_hwif_t *); #define INIT_HPT34X &ide_init_hpt34x #else #define PCI_HPT34X NULL -#define INIT_HPT34X NULL +#define INIT_HPT34X IDE_IGNORE #endif #ifdef CONFIG_BLK_DEV_HPT366 @@ -289,6 +296,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = { {DEVID_PIIX4, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX4E, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX4U, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4U2, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_VP_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, @@ -318,7 +326,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = { {DEVID_CY82C693,"CY82C693", PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_CS5530, "CS5530", PCI_CS5530, NULL, INIT_CS5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_AMD7409, "AMD7409", NULL, ATA66_AMD7409, INIT_AMD7409, NULL, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, + {DEVID_AMD7409, "AMD7409", PCI_AMD7409, ATA66_AMD7409, INIT_AMD7409, DMA_AMD7409, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; /* @@ -329,27 +337,6 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = { static unsigned int __init ide_special_settings (struct pci_dev *dev, const char *name) { switch(dev->device) { - case PCI_DEVICE_ID_TTI_HPT343: - { - int i; - unsigned long hpt34xIoBase = dev->resource[4].start; - unsigned short pcicmd = 0; - - pci_write_config_byte(dev, 0x80, 0x00); - pci_read_config_word(dev, PCI_COMMAND, &pcicmd); - if (!(pcicmd & PCI_COMMAND_MEMORY)) { - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); - } else { - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); - } - - dev->resource[0].start = (hpt34xIoBase + 0x20); - dev->resource[1].start = (hpt34xIoBase + 0x34); - dev->resource[2].start = (hpt34xIoBase + 0x28); - dev->resource[3].start = (hpt34xIoBase + 0x3c); - for(i=0; i<4; i++) - dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; - } case PCI_DEVICE_ID_TTI_HPT366: case PCI_DEVICE_ID_PROMISE_20246: case PCI_DEVICE_ID_PROMISE_20262: @@ -535,17 +522,8 @@ check_if_enabled: #endif } if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) { - /* - * Since there are two cards that report almost identically, - * the only discernable difference is the values - * reported in pcicmd. - * Booting-BIOS card or HPT363 :: pcicmd == 0x07 - * Non-bootable card or HPT343 :: pcicmd == 0x05 - */ - if (pcicmd & PCI_COMMAND_MEMORY) { - printk("%s: is IDE Express HPT363.\n", d->name); - d->bootable = OFF_BOARD; - } + /* see comments in hpt34x.c on why..... */ + d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD; } /* * Set up the IDE ports @@ -618,9 +596,7 @@ check_if_enabled: if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) || -#ifdef CONFIG_BLK_DEV_HPT34X IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) || -#endif /* CONFIG_BLK_DEV_HPT34X */ IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) || diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c index b57fa28da..24eef80b7 100644 --- a/drivers/block/ide-probe.c +++ b/drivers/block/ide-probe.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-probe.c Version 1.05 July 3, 1999 + * linux/drivers/block/ide-probe.c Version 1.05 July 3, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -57,7 +57,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd) ide__sti(); /* local CPU only */ ide_fix_driveid(id); if (!drive->forced_lun) - drive->last_lun = id->word126 & 0x7; + drive->last_lun = id->last_lun & 0x7; #if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA) /* * EATA SCSI controllers do a hardware ATA emulation: @@ -395,6 +395,56 @@ static inline byte probe_for_drive (ide_drive_t *drive) } /* + * Calculate the region that this interface occupies, + * handling interfaces where the registers may not be + * ordered sanely. We deal with the CONTROL register + * separately. + */ +static int hwif_check_regions (ide_hwif_t *hwif) +{ + int region_errors = 0; + + region_errors = ide_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_ERROR_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_LCYL_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_HCYL_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_SELECT_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_STATUS_OFFSET], 1); + if (hwif->io_ports[IDE_CONTROL_OFFSET]) + region_errors += ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); + if (hwif->io_ports[IDE_IRQ_OFFSET]) + region_errors += ide_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1); + + return(region_errors); +} + +static void hwif_register (ide_hwif_t *hwif) +{ + if (hwif->io_ports[IDE_DATA_OFFSET]) + ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_ERROR_OFFSET]) + ide_request_region(hwif->io_ports[IDE_ERROR_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_NSECTOR_OFFSET]) + ide_request_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_SECTOR_OFFSET]) + ide_request_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_LCYL_OFFSET]) + ide_request_region(hwif->io_ports[IDE_LCYL_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_HCYL_OFFSET]) + ide_request_region(hwif->io_ports[IDE_HCYL_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_SELECT_OFFSET]) + ide_request_region(hwif->io_ports[IDE_SELECT_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_STATUS_OFFSET]) + ide_request_region(hwif->io_ports[IDE_STATUS_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_CONTROL_OFFSET]) + ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_IRQ_OFFSET]) + ide_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name); +} + +/* * This routine only knows how to look for drive units 0 and 1 * on an interface, so any setting of MAX_DRIVES > 2 won't work here. */ @@ -403,12 +453,6 @@ static void probe_hwif (ide_hwif_t *hwif) unsigned int unit; unsigned long flags; - ide_ioreg_t ide_control_reg = hwif->io_ports[IDE_CONTROL_OFFSET]; - ide_ioreg_t region_low = hwif->io_ports[IDE_DATA_OFFSET]; - ide_ioreg_t region_high = region_low; - unsigned int region_request = 8; - int i; - if (hwif->noprobe) return; if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) { @@ -417,30 +461,11 @@ static void probe_hwif (ide_hwif_t *hwif) probe_cmos_for_drives (hwif); } - /* - * Calculate the region that this interface occupies, - * handling interfaces where the registers may not be - * ordered sanely. We deal with the CONTROL register - * separately. - */ - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - if (hwif->io_ports[i]) { - if (hwif->io_ports[i] < region_low) - region_low = hwif->io_ports[i]; - if (hwif->io_ports[i] > region_high) - region_high = hwif->io_ports[i]; - } - } - region_request = (region_high - region_low); - if (region_request == 0x0007) - region_request++; if ((hwif->chipset != ide_4drives || !hwif->mate->present) && #if CONFIG_BLK_DEV_PDC4030 (hwif->chipset != ide_pdc4030 || hwif->channel == 0) && #endif /* CONFIG_BLK_DEV_PDC4030 */ - (ide_check_region(region_low, region_request) || - (ide_control_reg && ide_check_region(ide_control_reg,1)))) - { + (hwif_check_regions(hwif))) { int msgout = 0; for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; @@ -467,20 +492,18 @@ static void probe_hwif (ide_hwif_t *hwif) if (drive->present && !hwif->present) { hwif->present = 1; if (hwif->chipset != ide_4drives || !hwif->mate->present) { - ide_request_region(region_low, region_request, hwif->name); - if (ide_control_reg) - ide_request_region(ide_control_reg, 1, hwif->name); + hwif_register(hwif); } } } - if (ide_control_reg && hwif->reset) { + if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) { unsigned long timeout = jiffies + WAIT_WORSTCASE; byte stat; printk("%s: reset\n", hwif->name); - OUT_BYTE(12, ide_control_reg); + OUT_BYTE(12, hwif->io_ports[IDE_CONTROL_OFFSET]); udelay(10); - OUT_BYTE(8, ide_control_reg); + OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]); do { ide_delay_50ms(); stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); @@ -594,7 +617,11 @@ static int init_irq (ide_hwif_t *hwif) * Allocate the irq, if not already obtained for another hwif */ if (!match || match->irq != hwif->irq) { +#ifdef CONFIG_IDEPCI_SHARE_IRQ + int sa = (hwif->chipset == ide_pci) ? SA_SHIRQ : SA_INTERRUPT; +#else /* !CONFIG_IDEPCI_SHARE_IRQ */ int sa = (hwif->chipset == ide_pci) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT; +#endif /* CONFIG_IDEPCI_SHARE_IRQ */ if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) { if (!match) kfree(hwgroup); @@ -784,20 +811,18 @@ static int hwif_init (ide_hwif_t *hwif) return (hwif->present = 0); } - if (init_irq (hwif)) { + if (init_irq(hwif)) { int i = hwif->irq; /* * It failed to initialise. Find the default IRQ for * this port and try that. */ - if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) - { + if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) { printk("%s: Disabled unable to get IRQ %d.\n", hwif->name, i); (void) unregister_blkdev (hwif->major, hwif->name); return (hwif->present = 0); } - if(init_irq (hwif)) - { + if (init_irq(hwif)) { printk("%s: probed IRQ %d and default IRQ %d failed.\n", hwif->name, i, hwif->irq); (void) unregister_blkdev (hwif->major, hwif->name); @@ -863,7 +888,8 @@ int ideprobe_init (void) for (index = 0; index < MAX_HWIFS; ++index) if (probe[index]) hwif_init(&ide_hwifs[index]); - ide_register_module(&ideprobe_module); + if (!ide_probe) + ide_probe = &ideprobe_module; MOD_DEC_USE_COUNT; return 0; } @@ -882,6 +908,6 @@ int init_module (void) void cleanup_module (void) { - ide_unregister_module(&ideprobe_module); + ide_probe = NULL; } #endif /* MODULE */ diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c index 66e45001c..90977c959 100644 --- a/drivers/block/ide-proc.c +++ b/drivers/block/ide-proc.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-proc.c Version 1.03 January 2, 1998 + * linux/drivers/block/ide-proc.c Version 1.03 January 2, 1998 * * Copyright (C) 1997-1998 Mark Lord */ @@ -73,21 +73,46 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif +#ifdef CONFIG_BLK_DEV_AEC6210 +extern byte aec6210_proc; +int (*aec6210_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_AEC6210 */ #ifdef CONFIG_BLK_DEV_ALI15X3 extern byte ali_proc; int (*ali_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_ALI15X3 */ - +#ifdef CONFIG_BLK_DEV_AMD7409 +extern byte amd7409_proc; +int (*amd7409_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_AMD7409 */ +#ifdef CONFIG_BLK_DEV_CMD64X +extern byte cmd64x_proc; +int (*cmd64x_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_CMD64X */ +#ifdef CONFIG_BLK_DEV_CS5530 +extern byte cs5530_proc; +int (*cs5530_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_CS5530 */ +#ifdef CONFIG_BLK_DEV_HPT34X +extern byte hpt34x_proc; +int (*hpt34x_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_HPT34X */ +#ifdef CONFIG_BLK_DEV_HPT366 +extern byte hpt366_proc; +int (*hpt366_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_HPT366 */ +#ifdef CONFIG_BLK_DEV_PDC202XX +extern byte pdc202xx_proc; +int (*pdc202xx_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_PDC202XX */ #ifdef CONFIG_BLK_DEV_PIIX extern byte piix_proc; int (*piix_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_PIIX */ - #ifdef CONFIG_BLK_DEV_SIS5513 extern byte sis_proc; int (*sis_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_SIS5513 */ - #ifdef CONFIG_BLK_DEV_VIA82CXXX extern byte via_proc; int (*via_display_info)(char *, char **, off_t, int) = NULL; @@ -229,7 +254,7 @@ static int proc_ide_write_config #endif /* CONFIG_BLK_DEV_IDEPCI */ if (for_real) { #if 0 - printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? 'PCI' : 'non-PCI', reg, val, digits); + printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? "PCI" : "non-PCI", reg, val, digits); #endif if (is_pci) { #ifdef CONFIG_BLK_DEV_IDEPCI @@ -349,7 +374,7 @@ static int proc_ide_read_drivers while (p) { driver = (ide_driver_t *) p->info; - if (p->type == IDE_DRIVER_MODULE && driver) + if (driver) out += sprintf(out, "%s version %s\n", driver->name, driver->version); p = p->next; } @@ -775,10 +800,38 @@ void proc_ide_create(void) create_proc_read_entry("drivers",0,proc_ide_root, proc_ide_read_drivers, NULL); +#ifdef CONFIG_BLK_DEV_AEC6210 + if ((aec6210_display_info) && (aec6210_proc)) + create_proc_info_entry("aec6210", 0, proc_ide_root, aec6210_display_info); +#endif /* CONFIG_BLK_DEV_AEC6210 */ #ifdef CONFIG_BLK_DEV_ALI15X3 if ((ali_display_info) && (ali_proc)) create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info); #endif /* CONFIG_BLK_DEV_ALI15X3 */ +#ifdef CONFIG_BLK_DEV_AMD7409 + if ((amd7409_display_info) && (amd7409_proc)) + create_proc_info_entry("amd7409", 0, proc_ide_root, amd7409_display_info); +#endif /* CONFIG_BLK_DEV_AMD7409 */ +#ifdef CONFIG_BLK_DEV_CMD64X + if ((cmd64x_display_info) && (cmd64x_proc)) + create_proc_info_entry("cmd64x", 0, proc_ide_root, cmd64x_display_info); +#endif /* CONFIG_BLK_DEV_CMD64X */ +#ifdef CONFIG_BLK_DEV_CS5530 + if ((cs5530_display_info) && (cs5530_proc)) + create_proc_info_entry("cs5530", 0, proc_ide_root, cs5530_display_info); +#endif /* CONFIG_BLK_DEV_CS5530 */ +#ifdef CONFIG_BLK_DEV_HPT34X + if ((hpt34x_display_info) && (hpt34x_proc)) + create_proc_info_entry("", 0, proc_ide_root, hpt34x_display_info); +#endif /* CONFIG_BLK_DEV_HPT34X */ +#ifdef CONFIG_BLK_DEV_HPT366 + if ((hpt366_display_info) && (hpt366_proc)) + create_proc_info_entry("", 0, proc_ide_root, hpt366_display_info); +#endif /* CONFIG_BLK_DEV_HPT366 */ +#ifdef CONFIG_BLK_DEV_PDC202XX + if ((pdc202xx_display_info) && (pdc202xx_proc)) + create_proc_info_entry("pdc202xx", 0, proc_ide_root, pdc202xx_display_info); +#endif /* CONFIG_BLK_DEV_PDC202XX */ #ifdef CONFIG_BLK_DEV_PIIX if ((piix_display_info) && (piix_proc)) create_proc_info_entry("piix", 0, proc_ide_root, piix_display_info); @@ -799,10 +852,38 @@ void proc_ide_destroy(void) * Mmmm.. does this free up all resources, * or do we need to do a more proper cleanup here ?? */ +#ifdef CONFIG_BLK_DEV_AEC6210 + if ((aec6210_display_info) && (aec6210_proc)) + remove_proc_entry("ide/aec6210",0); +#endif /* CONFIG_BLK_DEV_AEC6210 */ #ifdef CONFIG_BLK_DEV_ALI15X3 if ((ali_display_info) && (ali_proc)) remove_proc_entry("ide/ali",0); #endif /* CONFIG_BLK_DEV_ALI15X3 */ +#ifdef CONFIG_BLK_DEV_AMD7409 + if ((amd7409_display_info) && (amd7409_proc)) + remove_proc_entry("ide/amd7409",0); +#endif /* CONFIG_BLK_DEV_AMD7409 */ +#ifdef CONFIG_BLK_DEV_CMD64X + if ((cmd64x_display_info) && (cmd64x_proc)) + remove_proc_entry("ide/cmd64x",0); +#endif /* CONFIG_BLK_DEV_CMD64X */ +#ifdef CONFIG_BLK_DEV_CS5530 + if ((cs5530_display_info) && (cs5530_proc)) + remove_proc_entry("ide/cs5530",0); +#endif /* CONFIG_BLK_DEV_CS5530 */ +#ifdef CONFIG_BLK_DEV_HPT34X + if ((hpt34x_display_info) && (hpt34x_proc)) + remove_proc_entry("ide/hpt34x",0); +#endif /* CONFIG_BLK_DEV_HPT34X */ +#ifdef CONFIG_BLK_DEV_HPT366 + if ((hpt366_display_info) && (hpt366_proc)) + remove_proc_entry("ide/hpt366",0); +#endif /* CONFIG_BLK_DEV_HPT366 */ +#ifdef CONFIG_BLK_DEV_PDC202XX + if ((pdc202xx_display_info) && (pdc202xx_proc)) + remove_proc_entry("ide/pdc202xx",0); +#endif /* CONFIG_BLK_DEV_PDC202XX */ #ifdef CONFIG_BLK_DEV_PIIX if ((piix_display_info) && (piix_proc)) remove_proc_entry("ide/piix",0); diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c index 1e1b6e44e..95e780abf 100644 --- a/drivers/block/ide-tape.c +++ b/drivers/block/ide-tape.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-tape.c Version 1.16f Dec 15, 1999 + * linux/drivers/block/ide-tape.c Version 1.16f Dec 15, 1999 * * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il> * @@ -411,12 +411,12 @@ #include <asm/bitops.h> -#define NO_LONGER_REQUIRE (1) +#define NO_LONGER_REQUIRED (1) /* * OnStream support */ -#define ONSTREAM_DEBUG (1) +#define ONSTREAM_DEBUG (0) #define OS_CONFIG_PARTITION (0xff) #define OS_DATA_PARTITION (0) #define OS_PARTITION_VERSION (1) @@ -543,6 +543,7 @@ typedef struct os_header_s { /* * The following are used to debug the driver: * + * Setting IDETAPE_DEBUG_INFO to 1 will report device capabilities. * Setting IDETAPE_DEBUG_LOG to 1 will log driver flow control. * Setting IDETAPE_DEBUG_BUGS to 1 will enable self-sanity checks in * some places. @@ -557,7 +558,9 @@ typedef struct os_header_s { * is verified to be stable enough. This will make it much more * esthetic. */ +#define IDETAPE_DEBUG_INFO 0 #define IDETAPE_DEBUG_LOG 1 +#define IDETAPE_DEBUG_LOG_VERBOSE 0 #define IDETAPE_DEBUG_BUGS 1 /* @@ -700,9 +703,10 @@ typedef struct idetape_packet_command_s { */ typedef struct { unsigned page_code :6; /* Page code - Should be 0x2a */ - unsigned reserved1_67 :2; - u8 page_length; /* Page Length - Should be 0x12 */ - u8 reserved2, reserved3; + __u8 reserved0_6 :1; + __u8 ps :1; /* parameters saveable */ + __u8 page_length; /* Page Length - Should be 0x12 */ + __u8 reserved2, reserved3; unsigned ro :1; /* Read Only Mode */ unsigned reserved4_1234 :4; unsigned sprev :1; /* Supports SPACE in the reverse direction */ @@ -716,7 +720,8 @@ typedef struct { unsigned locked :1; /* The volume is locked */ unsigned prevent :1; /* The device defaults in the prevent state after power up */ unsigned eject :1; /* The device can eject the volume */ - unsigned reserved6_45 :2; /* Reserved */ + __u8 disconnect :1; /* The device can break request > ctl */ + __u8 reserved6_5 :1; unsigned ecc :1; /* Supports error correction */ unsigned cmprs :1; /* Supports data compression */ unsigned reserved7_0 :1; @@ -726,12 +731,12 @@ typedef struct { unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */ /* transfers for slow buffer memory ??? */ /* Also 32768 block size in some cases */ - u16 max_speed; /* Maximum speed supported in KBps */ - u8 reserved10, reserved11; - u16 ctl; /* Continuous Transfer Limit in blocks */ - u16 speed; /* Current Speed, in KBps */ - u16 buffer_size; /* Buffer Size, in 512 bytes */ - u8 reserved18, reserved19; + __u16 max_speed; /* Maximum speed supported in KBps */ + __u8 reserved10, reserved11; + __u16 ctl; /* Continuous Transfer Limit in blocks */ + __u16 speed; /* Current Speed, in KBps */ + __u16 buffer_size; /* Buffer Size, in 512 bytes */ + __u8 reserved18, reserved19; } idetape_capabilities_page_t; /* @@ -741,8 +746,8 @@ typedef struct { unsigned page_code :6; /* Page code - Should be 0x30 */ unsigned reserved1_6 :1; unsigned ps :1; - u8 page_length; /* Page Length - Should be 2 */ - u8 reserved2; + __u8 page_length; /* Page Length - Should be 2 */ + __u8 reserved2; unsigned play32 :1; unsigned play32_5 :1; unsigned reserved2_23 :2; @@ -768,23 +773,23 @@ typedef struct idetape_stage_s { typedef struct { unsigned error_code :7; /* Current of deferred errors */ unsigned valid :1; /* The information field conforms to QIC-157C */ - u8 reserved1 :8; /* Segment Number - Reserved */ + __u8 reserved1 :8; /* Segment Number - Reserved */ unsigned sense_key :4; /* Sense Key */ unsigned reserved2_4 :1; /* Reserved */ unsigned ili :1; /* Incorrect Length Indicator */ unsigned eom :1; /* End Of Medium */ unsigned filemark :1; /* Filemark */ - u32 information __attribute__ ((packed)); - u8 asl; /* Additional sense length (n-7) */ - u32 command_specific; /* Additional command specific information */ - u8 asc; /* Additional Sense Code */ - u8 ascq; /* Additional Sense Code Qualifier */ - u8 replaceable_unit_code; /* Field Replaceable Unit Code */ + __u32 information __attribute__ ((packed)); + __u8 asl; /* Additional sense length (n-7) */ + __u32 command_specific; /* Additional command specific information */ + __u8 asc; /* Additional Sense Code */ + __u8 ascq; /* Additional Sense Code Qualifier */ + __u8 replaceable_unit_code; /* Field Replaceable Unit Code */ unsigned sk_specific1 :7; /* Sense Key Specific */ unsigned sksv :1; /* Sense Key Specific information is valid */ - u8 sk_specific2; /* Sense Key Specific */ - u8 sk_specific3; /* Sense Key Specific */ - u8 pad[2]; /* Padding to 20 bytes */ + __u8 sk_specific2; /* Sense Key Specific */ + __u8 sk_specific3; /* Sense Key Specific */ + __u8 pad[2]; /* Padding to 20 bytes */ } idetape_request_sense_result_t; @@ -1247,13 +1252,13 @@ typedef struct { unsigned reserved3_45 :2; /* Reserved */ unsigned reserved3_6 :1; /* TrmIOP - Reserved */ unsigned reserved3_7 :1; /* AENC - Reserved */ - u8 additional_length; /* Additional Length (total_length-4) */ - u8 rsv5, rsv6, rsv7; /* Reserved */ - u8 vendor_id[8]; /* Vendor Identification */ - u8 product_id[16]; /* Product Identification */ - u8 revision_level[4]; /* Revision Level */ - u8 vendor_specific[20]; /* Vendor Specific - Optional */ - u8 reserved56t95[40]; /* Reserved - Optional */ + __u8 additional_length; /* Additional Length (total_length-4) */ + __u8 rsv5, rsv6, rsv7; /* Reserved */ + __u8 vendor_id[8]; /* Vendor Identification */ + __u8 product_id[16]; /* Product Identification */ + __u8 revision_level[4]; /* Revision Level */ + __u8 vendor_specific[20]; /* Vendor Specific - Optional */ + __u8 reserved56t95[40]; /* Reserved - Optional */ /* Additional information may be returned */ } idetape_inquiry_result_t; @@ -1287,10 +1292,25 @@ typedef struct { * Mode Parameter Header for the MODE SENSE packet command */ typedef struct { - u8 mode_data_length; /* Length of the following data transfer */ - u8 medium_type; /* Medium Type */ - u8 dsp; /* Device Specific Parameter */ - u8 bdl; /* Block Descriptor Length */ + __u8 mode_data_length; /* Length of the following data transfer */ + __u8 medium_type; /* Medium Type */ + __u8 dsp; /* Device Specific Parameter */ + __u8 bdl; /* Block Descriptor Length */ +#if 0 + /* data transfer page */ + __u8 page_code :6; + __u8 reserved0_6 :1; + __u8 ps :1; /* parameters saveable */ + __u8 page_length; /* page Length == 0x02 */ + __u8 reserved2; + __u8 read32k :1; /* 32k blk size (data only) */ + __u8 read32k5 :1; /* 32.5k blk size (data&AUX) */ + __u8 reserved3_23 :2; + __u8 write32k :1; /* 32k blk size (data only) */ + __u8 write32k5 :1; /* 32.5k blk size (data&AUX) */ + __u8 reserved3_6 :1; + __u8 streaming :1; /* streaming mode enable */ +#endif } idetape_mode_parameter_header_t; /* @@ -1299,10 +1319,10 @@ typedef struct { * Support for block descriptors is optional. */ typedef struct { - u8 density_code; /* Medium density code */ - u8 blocks[3]; /* Number of blocks */ - u8 reserved4; /* Reserved */ - u8 length[3]; /* Block Length */ + __u8 density_code; /* Medium density code */ + __u8 blocks[3]; /* Number of blocks */ + __u8 reserved4; /* Reserved */ + __u8 length[3]; /* Block Length */ } idetape_parameter_block_descriptor_t; /* @@ -1312,16 +1332,16 @@ typedef struct { unsigned page_code :6; /* Page Code - Should be 0xf */ unsigned reserved0 :1; /* Reserved */ unsigned ps :1; - u8 page_length; /* Page Length - Should be 14 */ + __u8 page_length; /* Page Length - Should be 14 */ unsigned reserved2 :6; /* Reserved */ unsigned dcc :1; /* Data Compression Capable */ unsigned dce :1; /* Data Compression Enable */ unsigned reserved3 :5; /* Reserved */ unsigned red :2; /* Report Exception on Decompression */ unsigned dde :1; /* Data Decompression Enable */ - u32 ca; /* Compression Algorithm */ - u32 da; /* Decompression Algorithm */ - u8 reserved[4]; /* Reserved */ + __u32 ca; /* Compression Algorithm */ + __u32 da; /* Decompression Algorithm */ + __u8 reserved[4]; /* Reserved */ } idetape_data_compression_page_t; /* @@ -1331,16 +1351,16 @@ typedef struct { unsigned page_code :6; /* Page Code - Should be 0x11 */ unsigned reserved1_6 :1; /* Reserved */ unsigned ps :1; - u8 page_length; /* Page Length - Should be 6 */ - u8 map; /* Maximum Additional Partitions - Should be 0 */ - u8 apd; /* Additional Partitions Defined - Should be 0 */ + __u8 page_length; /* Page Length - Should be 6 */ + __u8 map; /* Maximum Additional Partitions - Should be 0 */ + __u8 apd; /* Additional Partitions Defined - Should be 0 */ unsigned reserved4_012 :3; /* Reserved */ unsigned psum :2; /* Should be 0 */ unsigned idp :1; /* Should be 0 */ unsigned sdp :1; /* Should be 0 */ unsigned fdp :1; /* Fixed Data Partitions */ - u8 mfr; /* Medium Format Recognition */ - u8 reserved[2]; /* Reserved */ + __u8 mfr; /* Medium Format Recognition */ + __u8 reserved[2]; /* Reserved */ } idetape_medium_partition_page_t; /* @@ -1359,6 +1379,53 @@ typedef struct { static idetape_chrdev_t idetape_chrdevs[MAX_HWIFS * MAX_DRIVES]; static int idetape_chrdev_present = 0; +#if IDETAPE_DEBUG_LOG_VERBOSE + +/* + * DO NOT REMOVE, BUILDING A VERBOSE DEBUG SCHEME FOR ATAPI + */ + +char *idetape_sense_key_verbose (byte idetape_sense_key) +{ + switch (idetape_sense_key) { + default: { + char buf[22]; + sprintf(buf, "IDETAPE_SENSE (0x%02x)", idetape_sense_key); + return(buf); + } + + } +} + +char *idetape_command_key_verbose (byte idetape_command_key) +{ + switch (idetape_command_key) { + case IDETAPE_TEST_UNIT_READY_CMD: return("TEST_UNIT_READY_CMD"); + case IDETAPE_REWIND_CMD: return("REWIND_CMD"); + case IDETAPE_REQUEST_SENSE_CMD: return("REQUEST_SENSE_CMD"); + case IDETAPE_READ_CMD: return("READ_CMD"); + case IDETAPE_WRITE_CMD: return("WRITE_CMD"); + case IDETAPE_WRITE_FILEMARK_CMD: return("WRITE_FILEMARK_CMD"); + case IDETAPE_SPACE_CMD: return("SPACE_CMD"); + case IDETAPE_INQUIRY_CMD: return("INQUIRY_CMD"); + case IDETAPE_ERASE_CMD: return("ERASE_CMD") + case IDETAPE_MODE_SENSE_CMD: return("MODE_SENSE_CMD"); + case IDETAPE_MODE_SELECT_CMD: return("MODE_SELECT_CMD"); + case IDETAPE_LOAD_UNLOAD_CMD: return("LOAD_UNLOAD_CMD"); + case IDETAPE_PREVENT_CMD: return("PREVENT_CMD"); + case IDETAPE_LOCATE_CMD: return("LOCATE_CMD"); + case IDETAPE_READ_POSITION_CMD: return("READ_POSITION_CMD"); + case IDETAPE_READ_BUFFER_CMD: return("READ_BUFFER_CMD"); + case IDETAPE_SET_SPEED_CMD: return("SET_SPEED_CMD"); + default: { + char buf[20]; + sprintf(buf, "CMD (0x%02x)", idetape_command_key); + return(buf); + } + } +} +#endif /* IDETAPE_DEBUG_LOG_VERBOSE */ + /* * Too bad. The drive wants to send us data which we are not ready to accept. * Just throw it away. @@ -1523,6 +1590,14 @@ static void idetape_analyze_error (ide_drive_t *drive,idetape_request_sense_resu */ if (tape->debug_level >= 1) printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",pc->c[0],result->sense_key,result->asc,result->ascq); +#if IDETAPE_DEBUG_LOG_VERBOSE + if (tape->debug_level >= 1) + printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, asc = %x, ascq = %x\n", + idetape_command_key_verbose((byte) pc->c[0]), + result->sense_key, + result->asc, + result->ascq); +#endif /* IDETAPE_DEBUG_LOG_VERBOSE */ #endif /* IDETAPE_DEBUG_LOG */ if (tape->onstream && result->sense_key == 2 && result->asc == 0x53 && result->ascq == 2) { @@ -3833,7 +3908,7 @@ static int idetape_get_logical_blk (ide_drive_t *drive, int logical_blk_num, int if (tape->onstream) { #if ONSTREAM_DEBUG if (tape->debug_level >= 1) - printk(KERN_INFO "ide-tape: %s: first_stage == NULL, pipeline error %d\n", tape->name, test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags)); + printk(KERN_INFO "ide-tape: %s: first_stage == NULL, pipeline error %ld\n", tape->name, (long)test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags)); #endif clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); position = idetape_read_position(drive); @@ -5280,16 +5355,16 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp) static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id) { struct idetape_id_gcw gcw; -#if IDETAPE_DEBUG_LOG +#if IDETAPE_DEBUG_INFO unsigned short mask,i; -#endif /* IDETAPE_DEBUG_LOG */ +#endif /* IDETAPE_DEBUG_INFO */ if (!id) return 0; *((unsigned short *) &gcw) = id->config; -#if IDETAPE_DEBUG_LOG +#if IDETAPE_DEBUG_INFO printk (KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n"); printk (KERN_INFO "ide-tape: Protocol Type: "); switch (gcw.protocol) { @@ -5377,7 +5452,7 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id) } else printk (KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n"); -#endif /* IDETAPE_DEBUG_LOG */ +#endif /* IDETAPE_DEBUG_INFO */ /* Check that we can support this device */ @@ -5462,12 +5537,12 @@ static void idetape_onstream_configure_block_size (ide_drive_t *drive) header = (idetape_mode_parameter_header_t *) pc.buffer; bs = (idetape_block_size_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl); -#if IDETAPE_DEBUG_LOG +#if IDETAPE_DEBUG_INFO printk(KERN_INFO "ide-tape: 32KB play back: %s\n", bs->play32 ? "Yes" : "No"); printk(KERN_INFO "ide-tape: 32.5KB play back: %s\n", bs->play32_5 ? "Yes" : "No"); printk(KERN_INFO "ide-tape: 32KB record: %s\n", bs->record32 ? "Yes" : "No"); printk(KERN_INFO "ide-tape: 32.5KB record: %s\n", bs->record32_5 ? "Yes" : "No"); -#endif +#endif /* IDETAPE_DEBUG_INFO */ /* * Configure default auto columns mode, 32.5KB block size @@ -5587,7 +5662,7 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive) else if (tape->onstream && capabilities->blk32768) tape->tape_block_size = 32768; -#if IDETAPE_DEBUG_LOG +#if IDETAPE_DEBUG_INFO printk (KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n"); printk (KERN_INFO "ide-tape: Mode Parameter Header:\n"); printk (KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length); @@ -5615,7 +5690,7 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive) printk (KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl); printk (KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed); printk (KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512); -#endif /* IDETAPE_DEBUG_LOG */ +#endif /* IDETAPE_DEBUG_INFO */ } static void idetape_add_settings (ide_drive_t *drive) diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 93da9bea2..b82092452 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -186,6 +186,7 @@ static int ide_lock = 0; * ide_modules keeps track of the available IDE chipset/probe/driver modules. */ ide_module_t *ide_modules = NULL; +ide_module_t *ide_probe = NULL; /* * This is declared extern in ide.h, for access by other IDE modules: @@ -281,7 +282,7 @@ static void init_hwif_data (unsigned int index) * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them. */ #define MAGIC_COOKIE 0x12345678 -static void init_ide_data (void) +static void __init init_ide_data (void) { unsigned int index; static unsigned long magic_cookie = MAGIC_COOKIE; @@ -1093,13 +1094,18 @@ static ide_startstop_t start_request (ide_drive_t *drive) #endif block = rq->sector; blockend = block + rq->nr_sectors; - if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) { - printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name, - (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors); - goto kill_rq; +#if 0 + if ((rq->cmd == READ || rq->cmd == WRITE) && + (drive->media == ide_disk || drive->media == ide_floppy)) +#endif + { + if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) { + printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name, + (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors); + goto kill_rq; + } + block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0; } - block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0; - /* Yecch - this will shift the entire interval, possibly killing some innocent following sector */ if (block == 0 && drive->remap_0_to_1 == 1) @@ -1409,9 +1415,9 @@ void ide_timer_expiry (unsigned long data) } } else { ide_drive_t *drive = hwgroup->drive; - hwgroup->handler = NULL; if (!drive) { printk("ide_timer_expiry: hwgroup->drive was NULL\n"); + hwgroup->handler = NULL; } else { ide_hwif_t *hwif; ide_startstop_t startstop; @@ -1429,6 +1435,7 @@ void ide_timer_expiry (unsigned long data) return; } } + hwgroup->handler = NULL; /* * We need to simulate a real interrupt when invoking * the handler() function, which means we need to globally @@ -1436,7 +1443,7 @@ void ide_timer_expiry (unsigned long data) */ spin_unlock(&io_request_lock); hwif = HWIF(drive); - disable_irq(hwif->irq); + disable_irq(hwif->irq); /* disable_irq_nosync ?? */ __cli(); /* local CPU only, as if we were handling an interrupt */ if (hwgroup->poll_timeout != 0) { startstop = handler(drive); @@ -1802,23 +1809,33 @@ static void revalidate_drives (void) } } -static void ide_init_module (int type) +static void ide_probe_module (void) +{ + if (!ide_probe) { +#ifdef CONFIG_KMOD + (void) request_module("ide-probe-mod"); +#endif /* CONFIG_KMOD */ + } else { + (void) ide_probe->init(); + } + revalidate_drives(); +} + +static void ide_driver_module (void) { - int found = 0; + int index; ide_module_t *module = ide_modules; - + + for (index = 0; index < MAX_HWIFS; ++index) + if (ide_hwifs[index].present) + goto search; + ide_probe_module(); +search: while (module) { - if (module->type == type) { - found = 1; - (void) module->init(); - } + (void) module->init(); module = module->next; } revalidate_drives(); -#ifdef CONFIG_KMOD - if (!found && type == IDE_PROBE_MODULE) - (void) request_module("ide-probe-mod"); -#endif /* CONFIG_KMOD */ } static int ide_open (struct inode * inode, struct file * filp) @@ -1830,7 +1847,7 @@ static int ide_open (struct inode * inode, struct file * filp) return -ENXIO; MOD_INC_USE_COUNT; if (drive->driver == NULL) - ide_init_module(IDE_DRIVER_MODULE); + ide_driver_module(); #ifdef CONFIG_KMOD if (drive->driver == NULL) { if (drive->media == ide_disk) @@ -1881,9 +1898,9 @@ int ide_replace_subdriver (ide_drive_t *drive, const char *driver) if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) goto abort; strncpy(drive->driver_req, driver, 9); - ide_init_module(IDE_DRIVER_MODULE); + ide_driver_module(); drive->driver_req[0] = 0; - ide_init_module(IDE_DRIVER_MODULE); + ide_driver_module(); if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver)) return 0; abort: @@ -1897,6 +1914,35 @@ ide_proc_entry_t generic_subdriver_entries[] = { }; #endif +/* + * Note that we only release the standard ports, + * and do not even try to handle any extra ports + * allocated for weird IDE interface chipsets. + */ +void hwif_unregister (ide_hwif_t *hwif) +{ + if (hwif->io_ports[IDE_DATA_OFFSET]) + ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1); + if (hwif->io_ports[IDE_ERROR_OFFSET]) + ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1); + if (hwif->io_ports[IDE_NSECTOR_OFFSET]) + ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1); + if (hwif->io_ports[IDE_SECTOR_OFFSET]) + ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1); + if (hwif->io_ports[IDE_LCYL_OFFSET]) + ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1); + if (hwif->io_ports[IDE_HCYL_OFFSET]) + ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1); + if (hwif->io_ports[IDE_SELECT_OFFSET]) + ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1); + if (hwif->io_ports[IDE_STATUS_OFFSET]) + ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1); + if (hwif->io_ports[IDE_CONTROL_OFFSET]) + ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); + if (hwif->io_ports[IDE_IRQ_OFFSET]) + ide_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1); +} + void ide_unregister (unsigned int index) { struct gendisk *gd, **gdp; @@ -1967,9 +2013,7 @@ void ide_unregister (unsigned int index) * and do not even try to handle any extra ports * allocated for weird IDE interface chipsets. */ - ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8); - if (hwif->io_ports[IDE_CONTROL_OFFSET]) - ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); + hwif_unregister(hwif); /* * Remove us from the hwgroup, and free @@ -2036,23 +2080,28 @@ void ide_unregister (unsigned int index) kfree (gd->flags); kfree(gd); } - old_hwif = *hwif; + old_hwif = *hwif; init_hwif_data (index); /* restore hwif data to pristine status */ - hwif->hwgroup = old_hwif.hwgroup; - hwif->tuneproc = old_hwif.tuneproc; - hwif->resetproc = old_hwif.resetproc; - hwif->dmaproc = old_hwif.dmaproc; - hwif->dma_base = old_hwif.dma_base; - hwif->dma_extra = old_hwif.dma_extra; - hwif->config_data = old_hwif.config_data; - hwif->select_data = old_hwif.select_data; - hwif->irq = old_hwif.irq; - hwif->major = old_hwif.major; - hwif->proc = old_hwif.proc; - hwif->udma_four = old_hwif.udma_four; - hwif->chipset = old_hwif.chipset; - hwif->pci_dev = old_hwif.pci_dev; - hwif->pci_devid = old_hwif.pci_devid; + hwif->hwgroup = old_hwif.hwgroup; + hwif->tuneproc = old_hwif.tuneproc; + hwif->selectproc = old_hwif.selectproc; + hwif->resetproc = old_hwif.resetproc; + hwif->dmaproc = old_hwif.dmaproc; + hwif->dma_base = old_hwif.dma_base; + hwif->dma_extra = old_hwif.dma_extra; + hwif->config_data = old_hwif.config_data; + hwif->select_data = old_hwif.select_data; + hwif->proc = old_hwif.proc; + hwif->irq = old_hwif.irq; + hwif->major = old_hwif.major; + hwif->chipset = old_hwif.chipset; + hwif->autodma = old_hwif.autodma; + hwif->udma_four = old_hwif.udma_four; +#ifdef CONFIG_BLK_DEV_IDEPCI + hwif->pci_dev = old_hwif.pci_dev; + hwif->pci_devid = old_hwif.pci_devid; +#endif /* CONFIG_BLK_DEV_IDEPCI */ + abort: restore_flags(flags); /* all CPUs */ } @@ -2087,6 +2136,7 @@ void ide_setup_ports ( hw_regs_t *hw, } } hw->irq = irq; + hw->dma = NO_DMA; hw->ack_intr = ack_intr; } @@ -2126,11 +2176,11 @@ found: hwif->noprobe = 0; if (!initializing) { - ide_init_module(IDE_PROBE_MODULE); + ide_probe_module(); #ifdef CONFIG_PROC_FS create_proc_ide_interfaces(); #endif - ide_init_module(IDE_DRIVER_MODULE); + ide_driver_module(); } if (hwifp) @@ -2750,7 +2800,7 @@ int __init ide_setup (char *s) if (!strcmp(s, "ide=doubler")) { extern int ide_doubler; - printk("ide: Enabled support for IDE doublers\n"); + printk(" : Enabled support for IDE doublers\n"); ide_doubler = 1; return 0; } @@ -2759,12 +2809,14 @@ int __init ide_setup (char *s) #ifdef CONFIG_BLK_DEV_IDEPCI if (!strcmp(s, "ide=reverse")) { ide_scan_direction = 1; - printk("ide: Enabled support for IDE inverse scan order.\n"); + printk(" : Enabled support for IDE inverse scan order.\n"); return 0; } #endif /* CONFIG_BLK_DEV_IDEPCI */ +#ifndef CONFIG_BLK_DEV_IDEPCI init_ide_data (); +#endif /* CONFIG_BLK_DEV_IDEPCI */ /* * Look for drive options: "hdx=" @@ -3176,7 +3228,7 @@ void __init ide_init_builtin_drivers (void) #if defined(__mc68000__) || defined(CONFIG_APUS) if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) { ide_get_lock(&ide_lock, NULL, NULL); /* for atari only */ - disable_irq(ide_hwifs[0].irq); + disable_irq(ide_hwifs[0].irq); /* disable_irq_nosync ?? */ } #endif /* __mc68000__ || CONFIG_APUS */ @@ -3293,10 +3345,6 @@ ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *drive { unsigned int unit, index, i; - for (index = 0; index < MAX_HWIFS; ++index) - if (ide_hwifs[index].present) goto search; - ide_init_module(IDE_PROBE_MODULE); -search: for (index = 0, i = 0; index < MAX_HWIFS; ++index) { ide_hwif_t *hwif = &ide_hwifs[index]; if (!hwif->present) @@ -3327,8 +3375,16 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio setup_driver_defaults(drive); restore_flags(flags); /* all CPUs */ if (drive->autotune != 2) { - if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) + if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) { + /* + * Force DMAing for the beginning of the check. + * Some chipsets appear to do interesting things, + * if not checked and cleared. + * PARANOIA!!! + */ + (void) (HWIF(drive)->dmaproc(ide_dma_off_quietly, drive)); (void) (HWIF(drive)->dmaproc(ide_dma_check, drive)); + } drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap); drive->nice1 = 1; } @@ -3400,6 +3456,7 @@ EXPORT_SYMBOL(ide_spin_wait_hwgroup); /* * Probe module */ +EXPORT_SYMBOL(ide_probe); EXPORT_SYMBOL(drive_is_flashcard); EXPORT_SYMBOL(ide_timer_expiry); EXPORT_SYMBOL(ide_intr); @@ -3474,7 +3531,7 @@ EXPORT_SYMBOL(ide_register_hw); EXPORT_SYMBOL(ide_register); EXPORT_SYMBOL(ide_unregister); EXPORT_SYMBOL(ide_setup_ports); - +EXPORT_SYMBOL(hwif_unregister); EXPORT_SYMBOL(get_info_ptr); EXPORT_SYMBOL(current_capacity); @@ -3539,13 +3596,9 @@ void cleanup_module (void) { int index; - for (index = 0; index < MAX_HWIFS; ++index) { + for (index = 0; index < MAX_HWIFS; ++index) ide_unregister(index); -#ifdef CONFIG_BLK_DEV_IDEDMA - if (ide_hwifs[index].dma_base) - (void) ide_release_dma(&ide_hwifs[index]); -#endif /* CONFIG_BLK_DEV_IDEDMA */ - } + #ifdef CONFIG_PROC_FS proc_ide_destroy(); #endif diff --git a/drivers/block/ide_modes.h b/drivers/block/ide_modes.h index d8c8a7144..b6c28e6ab 100644 --- a/drivers/block/ide_modes.h +++ b/drivers/block/ide_modes.h @@ -1,11 +1,12 @@ -#ifndef _IDE_MODES_H -#define _IDE_MODES_H /* * linux/drivers/block/ide_modes.h * * Copyright (C) 1996 Linus Torvalds, Igor Abramov, and Mark Lord */ +#ifndef _IDE_MODES_H +#define _IDE_MODES_H + #include <linux/config.h> /* diff --git a/drivers/block/linear.c b/drivers/block/linear.c index 1c3305bae..978d75b80 100644 --- a/drivers/block/linear.c +++ b/drivers/block/linear.c @@ -121,14 +121,15 @@ static int linear_stop (mddev_t *mddev) return 0; } -static int linear_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) +static int linear_make_request (request_queue_t *q, mddev_t *mddev, + int rw, struct buffer_head * bh) { linear_conf_t *conf = mddev_to_conf(mddev); struct linear_hash *hash; dev_info_t *tmp_dev; long block; - block = bh->b_blocknr * (bh->b_size >> 10); + block = bh->b_rsector >> 1; hash = conf->hash_table + (block / conf->smallest->size); if (block >= (hash->dev0->size + hash->dev0->offset)) { @@ -149,8 +150,7 @@ static int linear_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) bh->b_rdev = tmp_dev->dev; bh->b_rsector = (block - tmp_dev->offset) << 1; - generic_make_request(rw, bh); - return 0; + return 1; } static int linear_status (char *page, mddev_t *mddev) diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 808878b3e..a0ac26a49 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -952,96 +952,122 @@ end_io: bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); } -void generic_make_request(int rw, struct buffer_head * bh) +static inline void buffer_IO_error(struct buffer_head * bh) +{ + mark_buffer_clean(bh); + /* + * b_end_io has to clear the BH_Uptodate bitflag in the error case! + */ + bh->b_end_io(bh, 0); +} + +int generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh) { - request_queue_t * q; unsigned long flags; + int ret; - q = blk_get_queue(bh->b_rdev); + /* + * Resolve the mapping until finished. (drivers are + * still free to implement/resolve their own stacking + * by explicitly returning 0) + */ + while (q->make_request_fn) { + ret = q->make_request_fn(q, rw, bh); + if (ret > 0) { + q = blk_get_queue(bh->b_rdev); + continue; + } + return ret; + } + /* + * Does the block device want us to queue + * the IO request? (normal case) + */ __make_request(q, rw, bh); - spin_lock_irqsave(&io_request_lock,flags); if (q && !q->plugged) (q->request_fn)(q); spin_unlock_irqrestore(&io_request_lock,flags); -} + return 0; +} /* This function can be used to request a number of buffers from a block device. Currently the only restriction is that all buffers must belong to the same device */ -static void __ll_rw_block(int rw, int nr, struct buffer_head * bh[],int haslock) +static void __ll_rw_block(int rw, int nr, struct buffer_head * bhs[], + int haslock) { + struct buffer_head *bh; + request_queue_t *q; unsigned int major; int correct_size; - request_queue_t *q; int i; - major = MAJOR(bh[0]->b_dev); - q = blk_get_queue(bh[0]->b_dev); + major = MAJOR(bhs[0]->b_dev); + q = blk_get_queue(bhs[0]->b_dev); if (!q) { printk(KERN_ERR "ll_rw_block: Trying to read nonexistent block-device %s (%ld)\n", - kdevname(bh[0]->b_dev), bh[0]->b_blocknr); + kdevname(bhs[0]->b_dev), bhs[0]->b_blocknr); goto sorry; } /* Determine correct block size for this device. */ correct_size = BLOCK_SIZE; if (blksize_size[major]) { - i = blksize_size[major][MINOR(bh[0]->b_dev)]; + i = blksize_size[major][MINOR(bhs[0]->b_dev)]; if (i) correct_size = i; } /* Verify requested block sizes. */ for (i = 0; i < nr; i++) { - if (bh[i]->b_size != correct_size) { + bh = bhs[i]; + if (bh->b_size != correct_size) { printk(KERN_NOTICE "ll_rw_block: device %s: " "only %d-char blocks implemented (%u)\n", - kdevname(bh[0]->b_dev), - correct_size, bh[i]->b_size); + kdevname(bhs[0]->b_dev), + correct_size, bh->b_size); goto sorry; } } - if ((rw & WRITE) && is_read_only(bh[0]->b_dev)) { + if ((rw & WRITE) && is_read_only(bhs[0]->b_dev)) { printk(KERN_NOTICE "Can't write to read-only device %s\n", - kdevname(bh[0]->b_dev)); + kdevname(bhs[0]->b_dev)); goto sorry; } for (i = 0; i < nr; i++) { + bh = bhs[i]; + /* Only one thread can actually submit the I/O. */ if (haslock) { - if (!buffer_locked(bh[i])) + if (!buffer_locked(bh)) BUG(); } else { - if (test_and_set_bit(BH_Lock, &bh[i]->b_state)) + if (test_and_set_bit(BH_Lock, &bh->b_state)) continue; } - set_bit(BH_Req, &bh[i]->b_state); + set_bit(BH_Req, &bh->b_state); - if (q->make_request_fn) - q->make_request_fn(rw, bh[i]); - else { - bh[i]->b_rdev = bh[i]->b_dev; - bh[i]->b_rsector = bh[i]->b_blocknr*(bh[i]->b_size>>9); + /* + * First step, 'identity mapping' - RAID or LVM might + * further remap this. + */ + bh->b_rdev = bh->b_dev; + bh->b_rsector = bh->b_blocknr * (bh->b_size>>9); - generic_make_request(rw, bh[i]); - } + generic_make_request(q, rw, bh); } - return; sorry: - for (i = 0; i < nr; i++) { - mark_buffer_clean(bh[i]); /* remeber to refile it */ - clear_bit(BH_Uptodate, &bh[i]->b_state); - bh[i]->b_end_io(bh[i], 0); - } + for (i = 0; i < nr; i++) + buffer_IO_error(bhs[i]); return; } @@ -1176,10 +1202,7 @@ int __init blk_dev_init(void) #ifdef CONFIG_BLK_DEV_FD floppy_init(); #else -#if !defined(CONFIG_SGI_IP22) && !defined(CONFIG_SGI_IP27) && \ - !defined (__mc68000__) && !defined(CONFIG_PPC) && !defined(__sparc__) && \ - !defined(CONFIG_APUS) && !defined(CONFIG_DECSTATION) && \ - !defined(CONFIG_BAGET_MIPS) && !defined(__sh__) && !defined(__ia64__) +#if defined(__i386__) /* Do we even need this? */ outb_p(0xc, 0x3f2); #endif #endif diff --git a/drivers/block/lvm.c b/drivers/block/lvm.c index 6d2f2743e..9f58a48d5 100644 --- a/drivers/block/lvm.c +++ b/drivers/block/lvm.c @@ -192,7 +192,7 @@ extern int lvm_init(void); static void lvm_dummy_device_request(request_queue_t *); #define DEVICE_REQUEST lvm_dummy_device_request -static void lvm_make_request_fn(int, struct buffer_head*); +static int lvm_make_request_fn(request_queue_t *, int, struct buffer_head*); static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong); static int lvm_blk_open(struct inode *, struct file *); @@ -1292,14 +1292,14 @@ static int lvm_proc_get_info(char *page, char **start, off_t pos, int count) */ static int lvm_map(struct buffer_head *bh, int rw) { - int minor = MINOR(bh->b_dev); + int minor = MINOR(bh->b_rdev); int ret = 0; ulong index; ulong pe_start; ulong size = bh->b_size >> 9; - ulong rsector_tmp = bh->b_blocknr * size; + ulong rsector_tmp = bh->b_rsector; ulong rsector_sav; - kdev_t rdev_tmp = bh->b_dev; + kdev_t rdev_tmp = bh->b_rdev; kdev_t rdev_sav; lv_t *lv = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]; @@ -1513,11 +1513,10 @@ static void lvm_dummy_device_request(request_queue_t * t) /* * make request function */ -static void lvm_make_request_fn(int rw, struct buffer_head *bh) +static int lvm_make_request_fn(request_queue_t *q, int rw, struct buffer_head *bh) { lvm_map(bh, rw); - if (bh->b_rdev != MD_MAJOR) generic_make_request(rw, bh); - return; + return 1; } diff --git a/drivers/block/macide.c b/drivers/block/macide.c index 4f6febd28..46a14ba19 100644 --- a/drivers/block/macide.c +++ b/drivers/block/macide.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/macide.c -- Macintosh IDE Driver + * linux/drivers/ide/macide.c -- Macintosh IDE Driver * * Copyright (C) 1998 by Michael Schmitz * @@ -43,7 +43,7 @@ #define MAC_HD_STATUS 0x1c /* see status-bits */ #define MAC_HD_CONTROL 0x38 /* control/altstatus */ -static int macide_offsets[IDE_NR_PORTS] = { +static int __init macide_offsets[IDE_NR_PORTS] = { MAC_HD_DATA, MAC_HD_ERROR, MAC_HD_NSECTOR, MAC_HD_SECTOR, MAC_HD_LCYL, MAC_HD_HCYL, MAC_HD_SELECT, MAC_HD_STATUS, MAC_HD_CONTROL }; @@ -84,7 +84,7 @@ static int mac_ack_intr(ide_hwif_t* hwif) * Probe for a Macintosh IDE interface */ -void macide_init(void) +void __init macide_init(void) { hw_regs_t hw; int index = -1; diff --git a/drivers/block/md.c b/drivers/block/md.c index b258fc6c5..171b3b659 100644 --- a/drivers/block/md.c +++ b/drivers/block/md.c @@ -75,16 +75,16 @@ static devfs_handle_t devfs_handle = NULL; static struct gendisk md_gendisk= { - MD_MAJOR, - "md", - 0, - 1, - md_hd_struct, - md_size, - MAX_MD_DEVS, - NULL, - NULL, - &md_fops, + major: MD_MAJOR, + major_name: "md", + minor_shift: 0, + max_p: 1, + part: md_hd_struct, + sizes: md_size, + nr_real: MAX_MD_DEVS, + real_devices: NULL, + next: NULL, + fops: &md_fops, }; void md_plug_device (request_queue_t *mdqueue, kdev_t dev) @@ -178,17 +178,16 @@ static void do_md_request (request_queue_t * q) return; } -void md_make_request (int rw, struct buffer_head * bh) +static int md_make_request (request_queue_t *q, int rw, struct buffer_head * bh) { - mddev_t *mddev = kdev_to_mddev(bh->b_dev); + mddev_t *mddev = kdev_to_mddev(bh->b_rdev); - if (!mddev || !mddev->pers) - bh->b_end_io(bh, 0); + if (mddev && mddev->pers) + return mddev->pers->make_request(q, mddev, rw, bh); else { - if ((rw == READ || rw == READA) && buffer_uptodate(bh)) - bh->b_end_io(bh, 1); - else - mddev->pers->make_request(mddev, rw, bh); + mark_buffer_clean(bh); + bh->b_end_io(bh, 0); + return -1; } } @@ -234,28 +233,6 @@ static mddev_t * alloc_mddev (kdev_t dev) return mddev; } -static void free_mddev (mddev_t *mddev) -{ - if (!mddev) { - MD_BUG(); - return; - } - - /* - * Make sure nobody else is using this mddev - * (careful, we rely on the global kernel lock here) - */ - while (md_atomic_read(&mddev->resync_sem.count) != 1) - schedule(); - while (md_atomic_read(&mddev->recovery_sem.count) != 1) - schedule(); - - del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev))); - md_list_del(&mddev->all_mddevs); - MD_INIT_LIST_HEAD(&mddev->all_mddevs); - kfree(mddev); -} - struct gendisk * find_gendisk (kdev_t dev) { struct gendisk *tmp = gendisk_head; @@ -757,6 +734,32 @@ static void export_array (mddev_t *mddev) MD_BUG(); } +static void free_mddev (mddev_t *mddev) +{ + if (!mddev) { + MD_BUG(); + return; + } + + export_array(mddev); + md_size[mdidx(mddev)] = 0; + md_hd_struct[mdidx(mddev)].nr_sects = 0; + + /* + * Make sure nobody else is using this mddev + * (careful, we rely on the global kernel lock here) + */ + while (md_atomic_read(&mddev->resync_sem.count) != 1) + schedule(); + while (md_atomic_read(&mddev->recovery_sem.count) != 1) + schedule(); + + del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev))); + md_list_del(&mddev->all_mddevs); + MD_INIT_LIST_HEAD(&mddev->all_mddevs); + kfree(mddev); +} + #undef BAD_CSUM #undef BAD_MAGIC #undef OUT_OF_MEM @@ -1723,13 +1726,7 @@ static int do_md_stop (mddev_t * mddev, int ro) printk (STILL_MOUNTED, mdidx(mddev)); OUT(-EBUSY); } - - /* - * complain if it's already stopped - */ - if (!mddev->nb_dev) - OUT(-ENXIO); - + if (mddev->pers) { /* * It is safe to call stop here, it only frees private @@ -1796,9 +1793,6 @@ static int do_md_stop (mddev_t * mddev, int ro) * Free resources if final stop */ if (!ro) { - export_array(mddev); - md_size[mdidx(mddev)] = 0; - md_hd_struct[mdidx(mddev)].nr_sects = 0; free_mddev(mddev); printk (KERN_INFO "md%d stopped.\n", mdidx(mddev)); @@ -3279,15 +3273,15 @@ static void md_geninit (void) { int i; - blksize_size[MD_MAJOR] = md_blocksizes; - max_readahead[MD_MAJOR] = md_maxreadahead; - for(i = 0; i < MAX_MD_DEVS; i++) { md_blocksizes[i] = 1024; + md_size[i] = 0; md_maxreadahead[i] = MD_READAHEAD; register_disk(&md_gendisk, MKDEV(MAJOR_NR,i), 1, &md_fops, 0); - } + blksize_size[MD_MAJOR] = md_blocksizes; + blk_size[MAJOR_NR] = md_size; + max_readahead[MD_MAJOR] = md_maxreadahead; printk("md.c: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t)); diff --git a/drivers/block/ns87415.c b/drivers/block/ns87415.c index 8b8bb3f60..0e5675fde 100644 --- a/drivers/block/ns87415.c +++ b/drivers/block/ns87415.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ns87415.c Version 1.00 December 7, 1997 + * linux/drivers/block/ns87415.c Version 1.00 December 7, 1997 * * Copyright (C) 1997-1998 Mark Lord * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) diff --git a/drivers/block/opti621.c b/drivers/block/opti621.c index 0885ed49e..cc2aa567c 100644 --- a/drivers/block/opti621.c +++ b/drivers/block/opti621.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/opti621.c Version 0.6 Jan 02, 1999 + * linux/drivers/block/opti621.c Version 0.6 Jan 02, 1999 * * Copyright (C) 1996-1998 Linus Torvalds & authors (see below) */ diff --git a/drivers/block/pdc202xx.c b/drivers/block/pdc202xx.c index c5a0c4924..bce80650c 100644 --- a/drivers/block/pdc202xx.c +++ b/drivers/block/pdc202xx.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/pdc202xx.c Version 0.28 Dec. 13, 1999 + * linux/drivers/block/pdc202xx.c Version 0.29 Feb. 10, 2000 * - * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this @@ -14,7 +14,7 @@ * 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word. * The 8/4 ratio is a BIOS code limit by promise. * - * UNLESS you enable "CONFIG_PDC202XX_FORCE_BURST_BIT" + * UNLESS you enable "CONFIG_PDC202XX_BURST" * * There is only one BIOS in the three contollers. * @@ -100,6 +100,61 @@ #define PDC202XX_DEBUG_DRIVE_INFO 0 #define PDC202XX_DECODE_REGISTER_INFO 0 +#define DISPLAY_PDC202XX_TIMINGS +#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) +#include <linux/stat.h> +#include <linux/proc_fs.h> + +static int pdc202xx_get_info(char *, char **, off_t, int); +extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + switch(bmide_dev->device) { + case PCI_DEVICE_ID_PROMISE_20262: + p += sprintf(p, "\n PDC20262 Chipset.\n"); + break; + case PCI_DEVICE_ID_PROMISE_20246: + p += sprintf(p, "\n PDC20246 Chipset.\n"); + break; + default: + p += sprintf(p, "\n PDC202XX Chipset.\n"); + break; + } + + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte pdc202xx_proc = 0; + extern char *ide_xfer_verbose (byte xfer_rate); /* A Register */ @@ -620,15 +675,15 @@ unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) (primary_mode & 1) ? "MASTER" : "PCI", (secondary_mode & 1) ? "MASTER" : "PCI" ); -#ifdef CONFIG_PDC202XX_FORCE_BURST_BIT +#ifdef CONFIG_PDC202XX_BURST if (!(udma_speed_flag & 1)) { printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1)); outb(udma_speed_flag|1, high_16 + 0x001f); printk("%sCTIVE\n", (inb(high_16 + 0x001f) & 1) ? "A" : "INA"); } -#endif /* CONFIG_PDC202XX_FORCE_BURST_BIT */ +#endif /* CONFIG_PDC202XX_BURST */ -#ifdef CONFIG_PDC202XX_FORCE_MASTER_MODE +#ifdef CONFIG_PDC202XX_MASTER if (!(primary_mode & 1)) { printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ", name, primary_mode, (primary_mode|1)); @@ -642,7 +697,14 @@ unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) outb(secondary_mode|1, high_16 + 0x001b); printk("%s\n", (inb(high_16 + 0x001b) & 1) ? "MASTER" : "PCI"); } -#endif /* CONFIG_PDC202XX_FORCE_MASTER_MODE */ +#endif /* CONFIG_PDC202XX_MASTER */ + +#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) + pdc202xx_proc = 1; + bmide_dev = dev; + pdc202xx_display_info = &pdc202xx_get_info; +#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */ + return dev->irq; } diff --git a/drivers/block/pdc4030.c b/drivers/block/pdc4030.c index 0b682645c..f42c4946f 100644 --- a/drivers/block/pdc4030.c +++ b/drivers/block/pdc4030.c @@ -1,5 +1,5 @@ /* -*- linux-c -*- - * linux/drivers/block/pdc4030.c Version 0.90 May 27, 1999 + * linux/drivers/ide/pdc4030.c Version 0.90 May 27, 1999 * * Copyright (C) 1995-1999 Linus Torvalds & authors (see below) */ diff --git a/drivers/block/pdc4030.h b/drivers/block/pdc4030.h index 9f08da5aa..551785c36 100644 --- a/drivers/block/pdc4030.h +++ b/drivers/block/pdc4030.h @@ -1,5 +1,5 @@ /* - * linux/drivers/block/pdc4030.h + * linux/drivers/ide/pdc4030.h * * Copyright (C) 1995-1998 Linus Torvalds & authors */ diff --git a/drivers/block/piix.c b/drivers/block/piix.c index 64cf45853..4c2d94c99 100644 --- a/drivers/block/piix.c +++ b/drivers/block/piix.c @@ -1,8 +1,8 @@ /* - * linux/drivers/block/piix.c Version 0.28 Dec. 13, 1999 + * linux/drivers/block/piix.c Version 0.30 Feb. 26, 2000 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer - * Copyright (C) 1998-1999 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * PIO mode setting function for Intel chipsets. @@ -49,13 +49,33 @@ * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, ®44); * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, ®48); * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a); + * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, ®54); + * + * 00:1f.1 IDE interface: Intel Corporation: + * Unknown device 2411 (rev 01) (prog-if 80 [Master]) + * Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- + * ParErr- Stepping- SERR- FastB2B- + * Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- + * <TAbort- <MAbort- >SERR- <PERR- + * Latency: 0 set + * Region 4: I/O ports at ffa0 + * 00: 86 80 11 24 05 00 80 02 01 80 01 01 00 00 00 00 + * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 20: a1 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 40: 07 a3 03 a3 00 00 00 00 05 00 02 02 00 00 00 00 + * 50: 00 00 00 00 11 04 00 00 00 00 00 00 00 00 00 00 + * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * f0: 00 00 00 00 00 00 00 00 3a 0f 00 00 00 00 00 00 * - * #if 0 - * int err; - * err = ide_config_drive_speed(drive, speed); - * (void) ide_config_drive_speed(drive, speed); - * #else - * #endif */ #include <linux/config.h> @@ -86,16 +106,88 @@ static struct pci_dev *bmide_dev; static int piix_get_info (char *buffer, char **addr, off_t offset, int count) { - /* int rc; */ - int piix_who = ((bmide_dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) || - (bmide_dev->device == PCI_DEVICE_ID_INTEL_82801AB_1) || - (bmide_dev->device == PCI_DEVICE_ID_INTEL_82371AB)) ? 4 : 3; char *p = buffer; - p += sprintf(p, "\n Intel PIIX%d Chipset.\n", piix_who); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n\n"); + u32 bibma = bmide_dev->resource[4].start; + u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0; + u8 c0 = 0, c1 = 0; + u8 reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0, reg54 = 0; + + pci_read_config_word(bmide_dev, 0x40, ®40); + pci_read_config_word(bmide_dev, 0x42, ®42); + pci_read_config_byte(bmide_dev, 0x44, ®44); + pci_read_config_byte(bmide_dev, 0x48, ®48); + pci_read_config_byte(bmide_dev, 0x4a, ®4a); + pci_read_config_byte(bmide_dev, 0x4b, ®4b); + pci_read_config_byte(bmide_dev, 0x54, ®54); + + psitre = (reg40 & 0x4000) ? 1 : 0; + ssitre = (reg42 & 0x4000) ? 1 : 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + switch(bmide_dev->device) { + case PCI_DEVICE_ID_INTEL_82372FB_1: + case PCI_DEVICE_ID_INTEL_82801AA_1: + p += sprintf(p, "\n Intel PIIX4 Ultra 66 Chipset.\n"); + break; + case PCI_DEVICE_ID_INTEL_82801AB_1: + case PCI_DEVICE_ID_INTEL_82371AB: + p += sprintf(p, "\n Intel PIIX4 Ultra 33 Chipset.\n"); + break; + case PCI_DEVICE_ID_INTEL_82371SB_1: + p += sprintf(p, "\n Intel PIIX3 Chipset.\n"); + break; + case PCI_DEVICE_ID_INTEL_82371FB_1: + case PCI_DEVICE_ID_INTEL_82371FB_0: + default: + p += sprintf(p, "\n Intel PIIX Chipset.\n"); + break; + } + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "\n"); - p += sprintf(p, "\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", + (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", + (c1&0x40) ? "yes" : "no " ); + p += sprintf(p, "UDMA enabled: %s %s %s %s\n", + (reg48&0x01) ? "yes" : "no ", + (reg48&0x02) ? "yes" : "no ", + (reg48&0x04) ? "yes" : "no ", + (reg48&0x08) ? "yes" : "no " ); + p += sprintf(p, "UDMA enabled: %s %s %s %s\n", + ((reg54&0x11) && (reg4a&0x02)) ? "4" : + ((reg54&0x11) && (reg4a&0x01)) ? "3" : + (reg4a&0x02) ? "2" : + (reg4a&0x01) ? "1" : + (reg4a&0x00) ? "0" : "X", + ((reg54&0x22) && (reg4a&0x20)) ? "4" : + ((reg54&0x22) && (reg4a&0x10)) ? "3" : + (reg4a&0x20) ? "2" : + (reg4a&0x10) ? "1" : + (reg4a&0x00) ? "0" : "X", + ((reg54&0x44) && (reg4b&0x02)) ? "4" : + ((reg54&0x44) && (reg4b&0x01)) ? "3" : + (reg4b&0x02) ? "2" : + (reg4b&0x01) ? "1" : + (reg4b&0x00) ? "0" : "X", + ((reg54&0x88) && (reg4b&0x20)) ? "4" : + ((reg54&0x88) && (reg4b&0x10)) ? "3" : + (reg4b&0x20) ? "2" : + (reg4b&0x10) ? "1" : + (reg4b&0x00) ? "0" : "X"); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); /* * FIXME.... Add configuration junk data....blah blah...... @@ -113,7 +205,6 @@ byte piix_proc = 0; extern char *ide_xfer_verbose (byte xfer_rate); -#ifdef CONFIG_BLK_DEV_PIIX_TUNING /* * */ @@ -143,7 +234,6 @@ static byte piix_dma_2_pio (byte xfer_rate) { return 0; } } -#endif /* CONFIG_BLK_DEV_PIIX_TUNING */ /* * Based on settings done by AMI BIOS @@ -191,8 +281,6 @@ static void piix_tune_drive (ide_drive_t *drive, byte pio) restore_flags(flags); } -#ifdef CONFIG_BLK_DEV_PIIX_TUNING - static int piix_config_drive_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -205,12 +293,15 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) byte maslave = hwif->channel ? 0x42 : 0x40; byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; - int ultra = ((dev->device == PCI_DEVICE_ID_INTEL_82371AB) || + int ultra66 = ((dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) || + (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0; + int ultra = ((ultra66) || + (dev->device == PCI_DEVICE_ID_INTEL_82371AB) || (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0; - int ultra66 = (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) ? 1 : 0; int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); int a_speed = 2 << (drive_number * 4); int u_flag = 1 << drive_number; + int v_flag = 0x10 << drive_number; int u_speed = 0; pci_read_config_word(dev, maslave, ®4042); @@ -245,10 +336,6 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); } - /* - * This is !@#$% ugly and stupid............. - * But ugly harware generates ugly code......... - */ if (speed >= XFER_UDMA_0) { if (!(reg48 & u_flag)) pci_write_config_word(dev, 0x48, reg48|u_flag); @@ -256,10 +343,12 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); pci_write_config_word(dev, 0x4a, reg4a|u_speed); } - if ((speed > XFER_UDMA_2) && (!(reg54 & u_flag))) { - pci_write_config_word(dev, 0x54, reg54|u_flag); + if (speed > XFER_UDMA_2) { + if (!(reg54 & v_flag)) { + pci_write_config_word(dev, 0x54, reg54|v_flag); + } } else { - pci_write_config_word(dev, 0x54, reg54 & ~u_flag); + pci_write_config_word(dev, 0x54, reg54 & ~v_flag); } } @@ -268,8 +357,8 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) pci_write_config_word(dev, 0x48, reg48 & ~u_flag); if (reg4a & a_speed) pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - if (reg54 & u_flag) - pci_write_config_word(dev, 0x54, reg54 & ~u_flag); + if (reg54 & v_flag) + pci_write_config_word(dev, 0x54, reg54 & ~v_flag); } piix_tune_drive(drive, piix_dma_2_pio(speed)); @@ -277,8 +366,7 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) (void) ide_config_drive_speed(drive, speed); #if PIIX_DEBUG_DRIVE_INFO - printk("%s: %s drive%d ", drive->name, ide_xfer_verbose(speed), drive_number); - printk("\n"); + printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive_number); #endif /* PIIX_DEBUG_DRIVE_INFO */ return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : @@ -299,16 +387,13 @@ static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive) /* Other cases are done by generic IDE-DMA code. */ return ide_dmaproc(func, drive); } -#endif /* CONFIG_BLK_DEV_PIIX_TUNING */ unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name) { #if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) - if (!piix_proc) { - piix_proc = 1; - bmide_dev = dev; - piix_display_info = &piix_get_info; - } + piix_proc = 1; + bmide_dev = dev; + piix_display_info = &piix_get_info; #endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */ return 0; } @@ -325,7 +410,7 @@ unsigned int __init ata66_piix (ide_hwif_t *hwif) pci_read_config_byte(hwif->pci_dev, 0x54, ®54h); pci_read_config_byte(hwif->pci_dev, 0x55, ®55h); - ata66 = (reg54h & mask) ? 0 : 1; + ata66 = (reg54h & mask) ? 1 : 0; return ata66; } @@ -335,9 +420,9 @@ void __init ide_init_piix (ide_hwif_t *hwif) hwif->tuneproc = &piix_tune_drive; if (hwif->dma_base) { -#ifdef CONFIG_BLK_DEV_PIIX_TUNING +#ifdef CONFIG_PIIX_TUNING hwif->dmaproc = &piix_dmaproc; -#endif /* CONFIG_BLK_DEV_PIIX_TUNING */ +#endif /* CONFIG_PIIX_TUNING */ hwif->drives[0].autotune = 0; hwif->drives[1].autotune = 0; } else { diff --git a/drivers/block/qd6580.c b/drivers/block/qd6580.c index d7b2784d1..31781a9f0 100644 --- a/drivers/block/qd6580.c +++ b/drivers/block/qd6580.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/qd6580.c Version 0.02 Feb 09, 1996 + * linux/drivers/block/qd6580.c Version 0.02 Feb 09, 1996 * * Copyright (C) 1996 Linus Torvalds & author (see below) */ @@ -60,7 +60,7 @@ static void tune_qd6580 (ide_drive_t *drive, byte pio) restore_flags(flags); /* all CPUs */ } -void init_qd6580 (void) +void __init init_qd6580 (void) { ide_hwifs[0].chipset = ide_qd6580; ide_hwifs[1].chipset = ide_qd6580; diff --git a/drivers/block/raid0.c b/drivers/block/raid0.c index 661855a18..0e075277a 100644 --- a/drivers/block/raid0.c +++ b/drivers/block/raid0.c @@ -223,23 +223,23 @@ static int raid0_stop (mddev_t *mddev) * Of course, those facts may not be valid anymore (and surely won't...) * Hey guys, there's some work out there ;-) */ -static int raid0_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) +static int raid0_make_request (request_queue_t *q, mddev_t *mddev, + int rw, struct buffer_head * bh) { - unsigned long size = bh->b_size >> 10; + int blk_in_chunk, chunksize_bits, chunk, chunk_size; raid0_conf_t *conf = mddev_to_conf(mddev); struct raid0_hash *hash; struct strip_zone *zone; mdk_rdev_t *tmp_dev; - int blk_in_chunk, chunksize_bits, chunk, chunk_size; long block, rblock; chunk_size = mddev->param.chunk_size >> 10; chunksize_bits = ffz(~chunk_size); - block = bh->b_blocknr * size; + block = bh->b_rsector >> 1; hash = conf->hash_table + block / conf->smallest->size; /* Sanity check */ - if (chunk_size < (block % chunk_size) + size) + if (chunk_size < (block % chunk_size) + (bh->b_size >> 10)) goto bad_map; if (!hash) @@ -261,20 +261,19 @@ static int raid0_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) rblock = (chunk << chunksize_bits) + blk_in_chunk + zone->dev_offset; /* - * Important, at this point we are not guaranteed to be the only - * CPU modifying b_rdev and b_rsector! Only __make_request() later - * on serializes the IO. So in 2.4 we must never write temporary - * values to bh->b_rdev, like 2.2 and 2.0 did. + * The new BH_Lock semantics in ll_rw_blk.c guarantee that this + * is the only IO operation happening on this bh. */ bh->b_rdev = tmp_dev->dev; bh->b_rsector = rblock << 1; - generic_make_request(rw, bh); - - return 0; + /* + * Let the main block layer submit the IO and resolve recursion: + */ + return 1; bad_map: - printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %ld %ld\n", chunk_size, bh->b_rsector, size); + printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %ld %d\n", chunk_size, bh->b_rsector, bh->b_size >> 10); return -1; bad_hash: printk("raid0_make_request bug: hash==NULL for block %ld\n", block); diff --git a/drivers/block/rapide.c b/drivers/block/rapide.c index 468f2e3b1..5905aca41 100644 --- a/drivers/block/rapide.c +++ b/drivers/block/rapide.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/drivers/block/ide-rapide.c + * linux/drivers/block/rapide.c * * Copyright (c) 1996-1998 Russell King. * @@ -16,7 +16,7 @@ #include <asm/ecard.h> -static const card_ids rapide_cids[] = { +static const card_ids __init rapide_cids[] = { { MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 }, { 0xffff, 0xffff } }; @@ -43,7 +43,7 @@ static inline int rapide_register(struct expansion_card *ec) return ide_register_hw(&hw, NULL); } -int rapide_init(void) +int __init rapide_init(void) { int i; diff --git a/drivers/block/rz1000.c b/drivers/block/rz1000.c index 811e1665f..455641c1d 100644 --- a/drivers/block/rz1000.c +++ b/drivers/block/rz1000.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/rz1000.c Version 0.05 December 8, 1997 + * linux/drivers/block/rz1000.c Version 0.05 December 8, 1997 * * Copyright (C) 1995-1998 Linus Torvalds & author (see below) */ diff --git a/drivers/block/sis5513.c b/drivers/block/sis5513.c index d255bbdf8..942187900 100644 --- a/drivers/block/sis5513.c +++ b/drivers/block/sis5513.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/sis5513.c Version 0.08 Dec. 13, 1999 + * linux/drivers/block/sis5513.c Version 0.09 Feb. 10, 2000 * - * Copyright (C) 1999 Andre Hedrick (andre@suse.com) + * Copyright (C) 1999-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * Thanks to SIS Taiwan for direct support and hardware. @@ -50,6 +50,7 @@ static const struct { { "SiS540", PCI_DEVICE_ID_SI_540, SIS5513_FLAG_ATA_66, }, { "SiS620", PCI_DEVICE_ID_SI_620, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, { "SiS630", PCI_DEVICE_ID_SI_630, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, + { "SiS5591", PCI_DEVICE_ID_SI_5591, SIS5513_FLAG_ATA_33, }, { "SiS5597", PCI_DEVICE_ID_SI_5597, SIS5513_FLAG_ATA_33, }, { "SiS5600", PCI_DEVICE_ID_SI_5600, SIS5513_FLAG_ATA_33, }, { "SiS5511", PCI_DEVICE_ID_SI_5511, SIS5513_FLAG_ATA_16, }, @@ -233,8 +234,10 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) byte drive_pci, test1, test2, mask; int err; + unsigned long dma_base = hwif->dma_base; + byte unit = (drive->select.b.unit & 0x01); byte speed = 0x00, unmask = 0xE0, four_two = 0x00; - int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + int drive_number = ((hwif->channel ? 2 : 0) + unit); byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; if (host_dev) { @@ -314,6 +317,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) return ((int) ide_dma_off_quietly); } + outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); err = ide_config_drive_speed(drive, speed); #if SIS5513_DEBUG_DRIVE_INFO @@ -532,6 +536,7 @@ void __init ide_init_sis5513 (ide_hwif_t *hwif) case PCI_DEVICE_ID_SI_630: case PCI_DEVICE_ID_SI_5600: case PCI_DEVICE_ID_SI_5597: + case PCI_DEVICE_ID_SI_5591: hwif->autodma = 1; hwif->dmaproc = &sis5513_dmaproc; break; diff --git a/drivers/block/sl82c105.c b/drivers/block/sl82c105.c index 9ab90f0df..29f006682 100644 --- a/drivers/block/sl82c105.c +++ b/drivers/block/sl82c105.c @@ -1,5 +1,5 @@ /* - * drivers/block/sl82c105.c + * linux/drivers/block/sl82c105.c * * SL82C105/Winbond 553 IDE driver * diff --git a/drivers/block/trm290.c b/drivers/block/trm290.c index 4ec1d09c6..fb5e8d1af 100644 --- a/drivers/block/trm290.c +++ b/drivers/block/trm290.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/trm290.c Version 1.01 December 5, 1997 + * linux/drivers/block/trm290.c Version 1.01 December 5, 1997 * * Copyright (c) 1997-1998 Mark Lord * May be copied or modified under the terms of the GNU General Public License diff --git a/drivers/block/umc8672.c b/drivers/block/umc8672.c index 13f5f39a7..02b581a28 100644 --- a/drivers/block/umc8672.c +++ b/drivers/block/umc8672.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/umc8672.c Version 0.05 Jul 31, 1996 + * linux/drivers/block/umc8672.c Version 0.05 Jul 31, 1996 * * Copyright (C) 1995-1996 Linus Torvalds & author (see below) */ @@ -76,7 +76,7 @@ static void out_umc (char port,char wert) outb_p (wert,0x109); } -static byte in_umc (char port) +static inline byte in_umc (char port) { outb_p (port,0x108); return inb_p (0x109); @@ -125,7 +125,7 @@ static void tune_umc (ide_drive_t *drive, byte pio) restore_flags(flags); /* all CPUs */ } -void init_umc8672 (void) /* called from ide.c */ +void __init init_umc8672 (void) /* called from ide.c */ { unsigned long flags; diff --git a/drivers/block/via82cxxx.c b/drivers/block/via82cxxx.c index 09c4a86a7..54681f38c 100644 --- a/drivers/block/via82cxxx.c +++ b/drivers/block/via82cxxx.c @@ -1,9 +1,10 @@ /* - * linux/drivers/block/via82cxxx.c Version 0.06 Dec. 13, 1999 + * linux/drivers/block/via82cxxx.c Version 0.07 Feb. 10, 2000 * - * Copyright (C) 1998-99 Michel Aubry, Maintainer - * Copyright (C) 1999 Jeff Garzik, MVP4 Support (jgarzik@mandrakesoft.com) - * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-99 Michel Aubry, Maintainer + * Copyright (C) 1999 Jeff Garzik, MVP4 Support + * (jgarzik@mandrakesoft.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * The VIA MVP-4 is reported OK with UDMA. @@ -473,12 +474,6 @@ static int via_set_fifoconfig(ide_hwif_t *hwif) !(newfifo & 0x03) ? "1" : (!(newfifo & 0x02) ? "3/4" : (newfifo & 0x01) ? "1/4" : "1/2")); - -#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) - via_proc = 1; - bmide_dev = hwif->pci_dev; - via_display_info = &via_get_info; -#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/ return 0; } @@ -530,6 +525,12 @@ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name) printk("\n"); } +#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) + via_proc = 1; + bmide_dev = dev; + via_display_info = &via_get_info; +#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/ + return 0; } @@ -555,7 +556,7 @@ void __init ide_init_via82cxxx (ide_hwif_t *hwif) } /* - * ide_dmacapable_via82c568(ide_hwif_t *, unsigned long) + * ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long) * checks if channel "channel" of if hwif is dma * capable or not, according to kernel command line, * and the new fifo settings. diff --git a/drivers/char/Config.in b/drivers/char/Config.in index c34978479..97e1f1f58 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -122,7 +122,8 @@ endmenu tristate '/dev/nvram support' CONFIG_NVRAM tristate 'Enhanced Real Time Clock Support' CONFIG_RTC -if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then +bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC +if [ "$CONFIG_OBSOLETE" = "y" -a "$CONFIG_ALPHA_BOOK1" = "y" ]; then bool 'Tadpole ANA H8 Support' CONFIG_H8 fi diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 4667e1fa3..7f3c6133b 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -158,13 +158,17 @@ obj-$(CONFIG_ADBMOUSE) += adbmouse.o busmouse.o obj-$(CONFIG_PC110_PAD) += pc110pad.o obj-$(CONFIG_WDT) += wdt.o obj-$(CONFIG_RTC) += rtc.o +obj-$(CONFIG_EFI_RTC) += efirtc.o ifeq ($(CONFIG_PPC),) obj-$(CONFIG_NVRAM) += nvram.o endif -obj-$(CONFIG_I810_RNG) += i810_rng.o obj-$(CONFIG_VIDEO_DEV) += videodev.o +obj-$(CONFIG_21825_WATCHDOG) += wdt285.o +obj-$(CONFIG_977_WATCHDOG) += wdt977.o +obj-$(CONFIG_DS1620) += ds1620.o + # # for external dependencies in arm/config.in and video/config.in # @@ -205,7 +209,7 @@ ifeq ($(CONFIG_I2C_PARPORT),y) L_I2C = y else ifeq ($(CONFIG_I2C_PARPORT),m) - M_I2C = y + L_I2C = m endif endif @@ -277,6 +281,13 @@ ifeq ($(CONFIG_DZ),y) L_OBJS += dz.o endif +obj-$(CONFIG_NWBUTTON) += nwbutton.o +obj-$(CONFIG_NWFLASH) += nwflash.o + +ifeq ($(CONFIG_DZ),y) + L_OBJS += dz.o +endif + ifeq ($(CONFIG_DRM),y) SUB_DIRS += drm ALL_SUB_DIRS += drm diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c index a21556a2b..c478395f8 100644 --- a/drivers/char/agp/agpgart_be.c +++ b/drivers/char/agp/agpgart_be.c @@ -1397,8 +1397,6 @@ static int __init sis_generic_setup (struct pci_dev *pdev) agp_bridge.free_by_type = agp_generic_free_by_type; return 0; - - (void) pdev; /* unused */ } #endif /* CONFIG_AGP_SIS */ diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c new file mode 100644 index 000000000..e3a37611d --- /dev/null +++ b/drivers/char/ds1620.c @@ -0,0 +1,436 @@ +/* + * linux/drivers/char/ds1620.c: Dallas Semiconductors DS1620 + * thermometer driver (as used in the Rebel.com NetWinder) + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/miscdevice.h> +#include <linux/smp_lock.h> +#include <linux/delay.h> +#include <linux/proc_fs.h> +#include <linux/capability.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/uaccess.h> +#include <asm/therm.h> + +#ifdef CONFIG_PROC_FS +/* define for /proc interface */ +#define THERM_USE_PROC +#endif + +/* Definitions for DS1620 chip */ +#define THERM_START_CONVERT 0xee +#define THERM_RESET 0xaf +#define THERM_READ_CONFIG 0xac +#define THERM_READ_TEMP 0xaa +#define THERM_READ_TL 0xa2 +#define THERM_READ_TH 0xa1 +#define THERM_WRITE_CONFIG 0x0c +#define THERM_WRITE_TL 0x02 +#define THERM_WRITE_TH 0x01 + +#define CFG_CPU 2 +#define CFG_1SHOT 1 + +static const char *fan_state[] = { "off", "on", "on (hardwired)" }; + +/* + * Start of NetWinder specifics + * Note! We have to hold the gpio lock with IRQs disabled over the + * whole of our transaction to the Dallas chip, since there is a + * chance that the WaveArtist driver could touch these bits to + * enable or disable the speaker. + */ +extern spinlock_t gpio_lock; +extern unsigned int system_rev; + +static inline void netwinder_ds1620_set_clk(int clk) +{ + gpio_modify_op(GPIO_DSCLK, clk ? GPIO_DSCLK : 0); +} + +static inline void netwinder_ds1620_set_data(int dat) +{ + gpio_modify_op(GPIO_DATA, dat ? GPIO_DATA : 0); +} + +static inline int netwinder_ds1620_get_data(void) +{ + return gpio_read() & GPIO_DATA; +} + +static inline void netwinder_ds1620_set_data_dir(int dir) +{ + gpio_modify_io(GPIO_DATA, dir ? GPIO_DATA : 0); +} + +static inline void netwinder_ds1620_reset(void) +{ + cpld_modify(CPLD_DS_ENABLE, 0); + cpld_modify(CPLD_DS_ENABLE, CPLD_DS_ENABLE); +} + +static inline void netwinder_lock(unsigned long *flags) +{ + spin_lock_irqsave(&gpio_lock, *flags); +} + +static inline void netwinder_unlock(unsigned long *flags) +{ + spin_unlock_irqrestore(&gpio_lock, *flags); +} + +static inline void netwinder_set_fan(int i) +{ + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + gpio_modify_op(GPIO_FAN, i ? GPIO_FAN : 0); + spin_unlock_irqrestore(&gpio_lock, flags); +} + +static inline int netwinder_get_fan(void) +{ + if ((system_rev & 0xf000) == 0x4000) + return FAN_ALWAYS_ON; + + return (gpio_read() & GPIO_FAN) ? FAN_ON : FAN_OFF; +} + +/* + * End of NetWinder specifics + */ + +static void ds1620_send_bits(int nr, int value) +{ + int i; + + for (i = 0; i < nr; i++) { + netwinder_ds1620_set_data(value & 1); + netwinder_ds1620_set_clk(0); + udelay(1); + netwinder_ds1620_set_clk(1); + udelay(1); + + value >>= 1; + } +} + +static unsigned int ds1620_recv_bits(int nr) +{ + unsigned int value = 0, mask = 1; + int i; + + netwinder_ds1620_set_data(0); + + for (i = 0; i < nr; i++) { + netwinder_ds1620_set_clk(0); + udelay(1); + + if (netwinder_ds1620_get_data()) + value |= mask; + + mask <<= 1; + + netwinder_ds1620_set_clk(1); + udelay(1); + } + + return value; +} + +static void ds1620_out(int cmd, int bits, int value) +{ + unsigned long flags; + + netwinder_lock(&flags); + netwinder_ds1620_set_clk(1); + netwinder_ds1620_set_data_dir(0); + netwinder_ds1620_reset(); + + udelay(1); + + ds1620_send_bits(8, cmd); + if (bits) + ds1620_send_bits(bits, value); + + udelay(1); + + netwinder_ds1620_reset(); + netwinder_unlock(&flags); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(2); +} + +static unsigned int ds1620_in(int cmd, int bits) +{ + unsigned long flags; + unsigned int value; + + netwinder_lock(&flags); + netwinder_ds1620_set_clk(1); + netwinder_ds1620_set_data_dir(0); + netwinder_ds1620_reset(); + + udelay(1); + + ds1620_send_bits(8, cmd); + + netwinder_ds1620_set_data_dir(1); + value = ds1620_recv_bits(bits); + + netwinder_ds1620_reset(); + netwinder_unlock(&flags); + + return value; +} + +static int cvt_9_to_int(unsigned int val) +{ + if (val & 0x100) + val |= 0xfffffe00; + + return val; +} + +static void ds1620_write_state(struct therm *therm) +{ + ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU); + ds1620_out(THERM_WRITE_TL, 9, therm->lo); + ds1620_out(THERM_WRITE_TH, 9, therm->hi); + ds1620_out(THERM_START_CONVERT, 0, 0); +} + +static void ds1620_read_state(struct therm *therm) +{ + therm->lo = cvt_9_to_int(ds1620_in(THERM_READ_TL, 9)); + therm->hi = cvt_9_to_int(ds1620_in(THERM_READ_TH, 9)); +} + +static ssize_t +ds1620_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + signed int cur_temp; + signed char cur_temp_degF; + + /* Can't seek (pread) on this device */ + if (ptr != &file->f_pos) + return -ESPIPE; + + cur_temp = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)) >> 1; + + /* convert to Fahrenheit, as per wdt.c */ + cur_temp_degF = (cur_temp * 9) / 5 + 32; + + if (copy_to_user(buf, &cur_temp_degF, 1)) + return -EFAULT; + + return 1; +} + +static int +ds1620_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct therm therm; + int i; + + switch(cmd) { + case CMD_SET_THERMOSTATE: + case CMD_SET_THERMOSTATE2: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (cmd == CMD_SET_THERMOSTATE) { + if (get_user(therm.hi, (int *)arg)) + return -EFAULT; + therm.lo = therm.hi - 3; + } else { + if (copy_from_user(&therm, (void *)arg, sizeof(therm))) + return -EFAULT; + } + + therm.lo <<= 1; + therm.hi <<= 1; + + ds1620_write_state(&therm); + break; + + case CMD_GET_THERMOSTATE: + case CMD_GET_THERMOSTATE2: + ds1620_read_state(&therm); + + therm.lo >>= 1; + therm.hi >>= 1; + + if (cmd == CMD_GET_THERMOSTATE) { + if (put_user(therm.hi, (int *)arg)) + return -EFAULT; + } else { + if (copy_to_user((void *)arg, &therm, sizeof(therm))) + return -EFAULT; + } + break; + + case CMD_GET_TEMPERATURE: + case CMD_GET_TEMPERATURE2: + i = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)); + + if (cmd == CMD_GET_TEMPERATURE) + i >>= 1; + + return put_user(i, (int *)arg) ? -EFAULT : 0; + + case CMD_GET_STATUS: + i = ds1620_in(THERM_READ_CONFIG, 8) & 0xe3; + + return put_user(i, (int *)arg) ? -EFAULT : 0; + + case CMD_GET_FAN: + i = netwinder_get_fan(); + + return put_user(i, (int *)arg) ? -EFAULT : 0; + + case CMD_SET_FAN: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (get_user(i, (int *)arg)) + return -EFAULT; + + netwinder_set_fan(i); + break; + + default: + return -ENOIOCTLCMD; + } + + return 0; +} + +static int +ds1620_open(struct inode *inode, struct file *file) +{ + MOD_INC_USE_COUNT; + + return 0; +} + +static int +ds1620_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + + return 0; +} + +#ifdef THERM_USE_PROC +static int +proc_therm_ds1620_read(char *buf, char **start, off_t offset, + int len, int *eof, void *unused) +{ + struct therm th; + int temp; + + ds1620_read_state(&th); + temp = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)); + + len = sprintf(buf, "Thermostat: HI %i.%i, LOW %i.%i; " + "temperature: %i.%i C, fan %s\n", + th.hi >> 1, th.hi & 1 ? 5 : 0, + th.lo >> 1, th.lo & 1 ? 5 : 0, + temp >> 1, temp & 1 ? 5 : 0, + fan_state[netwinder_get_fan()]); + + return len; +} + +static struct proc_dir_entry *proc_therm_ds1620; +#endif + +static struct file_operations ds1620_fops = { + NULL, /* lseek */ + ds1620_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + ds1620_ioctl, /* ioctl */ + NULL, /* mmap */ + ds1620_open, /* open */ + NULL, /* flush */ + ds1620_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ +}; + +static struct miscdevice ds1620_miscdev = { + TEMP_MINOR, + "temp", + &ds1620_fops +}; + +int __init ds1620_init(void) +{ + int ret; + struct therm th, th_start; + + if (!machine_is_netwinder()) + return -ENODEV; + + ds1620_out(THERM_RESET, 0, 0); + ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU); + ds1620_out(THERM_START_CONVERT, 0, 0); + + /* + * Trigger the fan to start by setting + * temperature high point low. This kicks + * the fan into action. + */ + ds1620_read_state(&th); + th_start.lo = 0; + th_start.hi = 1; + ds1620_write_state(&th_start); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(2*HZ); + + ds1620_write_state(&th); + + ret = misc_register(&ds1620_miscdev); + if (ret < 0) + return ret; + +#ifdef THERM_USE_PROC + proc_therm_ds1620 = create_proc_entry("therm", 0, 0); + if (proc_therm_ds1620) + proc_therm_ds1620->read_proc = proc_therm_ds1620_read; + else + printk(KERN_ERR "therm: unable to register /proc/therm\n"); +#endif + + ds1620_read_state(&th); + ret = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)); + + printk(KERN_INFO "Thermostat: high %i.%i, low %i.%i, " + "current %i.%i C, fan %s.\n", + th.hi >> 1, th.hi & 1 ? 5 : 0, + th.lo >> 1, th.lo & 1 ? 5 : 0, + ret >> 1, ret & 1 ? 5 : 0, + fan_state[netwinder_get_fan()]); + + return 0; +} + +void __exit ds1620_exit(void) +{ +#ifdef THERM_USE_PROC + remove_proc_entry("therm", NULL); +#endif + misc_deregister(&ds1620_miscdev); +} + +module_init(ds1620_init); +module_exit(ds1620_exit); diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c index 391cfcfc0..0f26dedd9 100644 --- a/drivers/char/efirtc.c +++ b/drivers/char/efirtc.c @@ -334,6 +334,7 @@ efi_rtc_read_proc(char *page, char **start, off_t off, if (len<0) len = 0; return len; } + static int __init efi_rtc_init(void) { @@ -345,6 +346,7 @@ efi_rtc_init(void) return 0; } + static int __exit efi_rtc_exit(void) { diff --git a/drivers/char/h8.c b/drivers/char/h8.c index 0583923d9..acc898cb8 100644 --- a/drivers/char/h8.c +++ b/drivers/char/h8.c @@ -6,6 +6,8 @@ * * Fixes: * June 1999, AV added releasing /proc/driver/h8 + * Feb 2000, Borislav Deianov + * changed queues to use list.h instead of lists.h */ #include <linux/config.h> @@ -23,7 +25,7 @@ #include <linux/stat.h> #include <linux/proc_fs.h> #include <linux/miscdevice.h> -#include <linux/lists.h> +#include <linux/list.h> #include <linux/ioport.h> #include <linux/poll.h> #include <linux/init.h> @@ -52,18 +54,13 @@ /* * Forward declarations. */ -int h8_init(void); +static int h8_init(void); int h8_display_blank(void); int h8_display_unblank(void); static void h8_intr(int irq, void *dev_id, struct pt_regs *regs); -#ifdef CONFIG_PROC_FS static int h8_get_info(char *, char **, off_t, int); -#else -static int h8_get_info(char *, char **, off_t, int) {} -#error "Somebody needs to learn C. Badly." -#endif /* * Support Routines. @@ -141,7 +138,9 @@ unsigned int h8_state = H8_IDLE; unsigned int h8_index = -1; unsigned int h8_enabled = 0; -queue_head_t h8_actq, h8_cmdq, h8_freeq; +LIST_HEAD(h8_actq); +LIST_HEAD(h8_cmdq); +LIST_HEAD(h8_freeq); /* * Globals used in thermal control of Alphabook1. @@ -170,7 +169,7 @@ int speed_tab[6] = {230, 153, 115, 57, 28, 14}; static void h8_intr(int irq, void *dev_id, struct pt_regs *regs) { u_char stat_reg, data_reg; - h8_cmd_q_t *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link); + h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link); stat_reg = H8_GET_STATUS; data_reg = H8_READ_DATA; @@ -260,7 +259,7 @@ static void h8_intr(int irq, void *dev_id, struct pt_regs *regs) return; } else if (data_reg == H8_SYNC_BYTE) { h8_state = H8_IDLE; - if (!QUEUE_IS_EMPTY(&h8_actq, link)) + if (!list_empty(&h8_actq)) h8_send_next_cmd_byte(); } else { Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg); @@ -276,10 +275,10 @@ static void h8_intr(int irq, void *dev_id, struct pt_regs *regs) /* If command reception finished. */ if (qp->cnt == qp->nrsp) { h8_state = H8_IDLE; - QUEUE_REMOVE(&h8_actq, qp, link); + list_del(&qp->link); h8_cmd_done (qp); /* More commands to send over? */ - if (!QUEUE_IS_EMPTY(&h8_cmdq, link)) + if (!list_empty(&h8_cmdq)) h8_start_new_cmd(); } return; @@ -317,9 +316,6 @@ static int __init h8_init(void) misc_register(&h8_device); request_region(h8_base, 8, "h8"); - QUEUE_INIT(&h8_actq, link, h8_cmd_q_t *); - QUEUE_INIT(&h8_cmdq, link, h8_cmd_q_t *); - QUEUE_INIT(&h8_freeq, link, h8_cmd_q_t *); h8_alloc_queues(); h8_hw_init(); @@ -364,9 +360,9 @@ static void __init h8_hw_init(void) return; } -#ifdef CONFIG_PROC_FS static int h8_get_info(char *buf, char **start, off_t fpos, int length) { +#ifdef CONFIG_PROC_FS char *p; if (!h8_enabled) @@ -387,8 +383,10 @@ static int h8_get_info(char *buf, char **start, off_t fpos, int length) ); return p - buf; -} +#else + return 0; #endif +} /* Called from console driver -- must make sure h8_enabled. */ int h8_display_blank(void) @@ -440,7 +438,7 @@ h8_alloc_queues(void) save_flags(flags); cli(); for (i = 0; i < H8_Q_ALLOC_AMOUNT; i++) { /* place each at front of freeq */ - QUEUE_ENTER(&h8_freeq, &qp[i], link, h8_cmd_q_t *); + list_add(&qp[i].link, &h8_freeq); } restore_flags(flags); return (1); @@ -458,15 +456,15 @@ h8_q_cmd(u_char *cmd, int cmd_size, int resp_size) /* get cmd buf */ save_flags(flags); cli(); - while (QUEUE_IS_EMPTY(&h8_freeq, link)) { + while (list_empty(&h8_freeq)) { Dprintk("H8: need to allocate more cmd buffers\n"); restore_flags(flags); h8_alloc_queues(); save_flags(flags); cli(); } /* get first element from queue */ - qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_freeq, link); - QUEUE_REMOVE(&h8_freeq, qp, link); + qp = list_entry(h8_freeq.next, h8_cmd_q_t, link); + list_del(&qp->link); restore_flags(flags); @@ -479,7 +477,8 @@ h8_q_cmd(u_char *cmd, int cmd_size, int resp_size) /* queue it at the end of the cmd queue */ save_flags(flags); cli(); - QUEUE_ENTER(&h8_cmdq, qp, link, h8_cmd_q_t *); + /* XXX this actually puts it at the start of cmd queue, bug? */ + list_add(&qp->link, &h8_cmdq); restore_flags(flags); @@ -500,13 +499,13 @@ h8_start_new_cmd(void) return; } - if (!QUEUE_IS_EMPTY(&h8_actq, link)) { + if (!list_empty(&h8_actq)) { Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!\n"); restore_flags(flags); return; } - if (QUEUE_IS_EMPTY(&h8_cmdq, link)) { + if (list_empty(&h8_cmdq)) { Dprintk("h8_start_new_cmd: no command to dequeue\n"); restore_flags(flags); return; @@ -515,9 +514,10 @@ h8_start_new_cmd(void) * Take first command off of the command queue and put * it on the active queue. */ - qp = (h8_cmd_q_t *) QUEUE_FIRST(&h8_cmdq, link); - QUEUE_REMOVE(&h8_cmdq, qp, link); - QUEUE_ENTER(&h8_actq, qp, link, h8_cmd_q_t *); + qp = list_entry(h8_cmdq.next, h8_cmd_q_t, link); + list_del(&qp->link); + /* XXX should this go to the end of the active queue? */ + list_add(&qp->link, &h8_actq); h8_state = H8_XMIT; if (h8_debug & 0x1) Dprintk("h8_start_new_cmd: Starting a command\n"); @@ -532,7 +532,7 @@ h8_start_new_cmd(void) void h8_send_next_cmd_byte(void) { - h8_cmd_q_t *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link); + h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link); int cnt; cnt = qp->cnt; @@ -689,7 +689,7 @@ h8_cmd_done(h8_cmd_q_t *qp) if (h8_debug & 0x40000) printk("H8: Sync command done - byte returned was 0x%x\n", qp->rcvbuf[0]); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_SN: @@ -697,7 +697,7 @@ h8_cmd_done(h8_cmd_q_t *qp) printk("H8: read Ethernet address: command done - address: %x - %x - %x - %x - %x - %x \n", qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2], qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_HW_VER: @@ -705,13 +705,13 @@ h8_cmd_done(h8_cmd_q_t *qp) case H8_RD_MAX_TEMP: printk("H8: Max recorded CPU temp %d, Sys temp %d\n", qp->rcvbuf[0], qp->rcvbuf[1]); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_MIN_TEMP: printk("H8: Min recorded CPU temp %d, Sys temp %d\n", qp->rcvbuf[0], qp->rcvbuf[1]); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_CURR_TEMP: @@ -719,7 +719,7 @@ h8_cmd_done(h8_cmd_q_t *qp) xx.byte[0] = qp->rcvbuf[0]; xx.byte[1] = qp->rcvbuf[1]; wake_up(&h8_sync_wait); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_SYS_VARIENT: @@ -740,7 +740,7 @@ h8_cmd_done(h8_cmd_q_t *qp) xx.byte[0] = qp->rcvbuf[1]; h8_sync_channel |= H8_GET_EXT_STATUS; wake_up(&h8_sync_wait); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_USER_CFG: @@ -755,7 +755,7 @@ h8_cmd_done(h8_cmd_q_t *qp) case H8_RD_INT_BATT_STATUS: printk("H8: Read int batt status cmd done - returned was %x %x %x\n", qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_EXT_BATT_STATUS: @@ -767,7 +767,7 @@ h8_cmd_done(h8_cmd_q_t *qp) printk("H8: Device control cmd done - byte returned was 0x%x\n", qp->rcvbuf[0]); } - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_CTL_TFT_BRT_DC: @@ -788,7 +788,7 @@ h8_cmd_done(h8_cmd_q_t *qp) XDprintk("H8: ctl upper thermal thresh cmd done - returned was %d\n", qp->rcvbuf[0]); } - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_CTL_LOWER_TEMP: diff --git a/drivers/char/h8.h b/drivers/char/h8.h index b59aadea8..986eef591 100644 --- a/drivers/char/h8.h +++ b/drivers/char/h8.h @@ -229,7 +229,7 @@ struct h8_data { * H8 command buffers */ typedef struct h8_cmd_q { - DLNODE(struct h8_cmd_q) link; /* double linked list */ + struct list_head link; /* double linked list */ int ncmd; /* number of bytes in command */ int nrsp; /* number of bytes in response */ int cnt; /* number of bytes sent/received */ @@ -238,10 +238,6 @@ typedef struct h8_cmd_q { u_char rcvbuf[H8_MAX_CMD_SIZE]; /* buffer to store response */ } h8_cmd_q_t; -typedef struct __queue_head { - DLNODE(struct h8_cmd_q) link; -} queue_head_t; - union intr_buf { u_char byte[2]; u_int word; diff --git a/drivers/char/lp.c b/drivers/char/lp.c index bb00a32fa..fcf0644ff 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -783,13 +783,13 @@ int __init lp_init (void) return -EIO; } + devfs_handle = devfs_mk_dir (NULL, "printers", 0, NULL); + if (parport_register_driver (&lp_driver)) { printk ("lp: unable to register with parport\n"); return -EIO; } - devfs_handle = devfs_mk_dir (NULL, "printers", 0, NULL); - if (!lp_count) { printk (KERN_INFO "lp: driver loaded but no devices found\n"); #ifndef CONFIG_PARPORT_1284 diff --git a/drivers/char/mem.c b/drivers/char/mem.c index e70860ea9..824ef94e4 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -5,6 +5,7 @@ * * Added devfs support. * Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu> + * Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com> */ #include <linux/config.h> @@ -285,8 +286,7 @@ static ssize_t write_kmem(struct file * file, const char * buf, return do_write_mem(file, (void*)p, p, buf, count, ppos); } -#if (!defined(CONFIG_PPC) && !defined(__mc68000__) && !defined(__mips__)) || \ - defined(CONFIG_HAVE_IO_PORTS) +#if (!defined(__mc68000__) && !defined(__mips__)) || defined(CONFIG_HAVE_IO_PORTS) static ssize_t read_port(struct file * file, char * buf, size_t count, loff_t *ppos) { @@ -435,7 +435,7 @@ out: static int mmap_zero(struct file * file, struct vm_area_struct * vma) { if (vma->vm_flags & VM_SHARED) - return -EINVAL; + return map_zero_setup(vma); if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; return 0; @@ -515,8 +515,7 @@ static struct file_operations null_fops = { write: write_null, }; -#if (!defined(CONFIG_PPC) && !defined(__mc68000__) && !defined(__mips__)) || \ - defined(CONFIG_HAVE_IO_PORTS) +#if (!defined(__mc68000__) && !defined(__mips__)) || defined(CONFIG_HAVE_IO_PORTS) static struct file_operations port_fops = { llseek: memory_lseek, read: read_port, @@ -550,8 +549,7 @@ static int memory_open(struct inode * inode, struct file * filp) case 3: filp->f_op = &null_fops; break; -#if (!defined(CONFIG_PPC) && !defined(__mc68000__) && !defined(__mips__)) || \ - defined(CONFIG_HAVE_IO_PORTS) +#if (!defined(__mc68000__) && !defined(__mips__)) || defined(CONFIG_HAVE_IO_PORTS) case 4: filp->f_op = &port_fops; break; diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c new file mode 100644 index 000000000..7c9bafc3b --- /dev/null +++ b/drivers/char/nwbutton.c @@ -0,0 +1,276 @@ +/* + * NetWinder Button Driver- + * Copyright (C) Alex Holden <alex@linuxhacker.org> 1998, 1999. + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/time.h> +#include <linux/timer.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/init.h> + +#include <asm/uaccess.h> +#include <asm/irq.h> +#define __NWBUTTON_C /* Tell the header file who we are */ +#include "nwbutton.h" + +static int button_press_count = 0; /* The count of button presses */ +static struct timer_list button_timer; /* Times for the end of a sequence */ +static DECLARE_WAIT_QUEUE_HEAD(button_wait_queue); /* Used for blocking read */ +static char button_output_buffer[32]; /* Stores data to write out of device */ +static int bcount = 0; /* The number of bytes in the buffer */ +static int bdelay = BUTTON_DELAY; /* The delay, in jiffies */ +static struct button_callback button_callback_list[32]; /* The callback list */ +static int callback_count = 0; /* The number of callbacks registered */ +static int reboot_count = NUM_PRESSES_REBOOT; /* Number of presses to reboot */ + +/* + * This function is called by other drivers to register a callback function + * to be called when a particular number of button presses occurs. + * The callback list is a static array of 32 entries (I somehow doubt many + * people are ever going to want to register more than 32 different actions + * to be performed by the kernel on different numbers of button presses ;). + * However, if an attempt to register a 33rd entry (perhaps a stuck loop + * somewhere registering the same entry over and over?) it will fail to + * do so and return -ENOMEM. If an attempt is made to register a null pointer, + * it will fail to do so and return -EINVAL. + * Because callbacks can be unregistered at random the list can become + * fragmented, so we need to search through the list until we find the first + * free entry. + */ + +int button_add_callback (void (*callback) (void), int count) +{ + int lp = 0; + if (callback_count == 32) { + return -ENOMEM; + } + if (!callback) { + return -EINVAL; + } + callback_count++; + for (; (button_callback_list [lp].callback); lp++); + button_callback_list [lp].callback = callback; + button_callback_list [lp].count = count; + return 0; +} + +/* + * This function is called by other drivers to deregister a callback function. + * If you attempt to unregister a callback which does not exist, it will fail + * with -EINVAL. If there is more than one entry with the same address, + * because it searches the list from end to beginning, it will unregister the + * last one to be registered first (FILO- First In Last Out). + * Note that this is not neccessarily true if the entries are not submitted + * at the same time, because another driver could have unregistered a callback + * between the submissions creating a gap earlier in the list, which would + * be filled first at submission time. + */ + +int button_del_callback (void (*callback) (void)) +{ + int lp = 31; + if (!callback) { + return -EINVAL; + } + while (lp >= 0) { + if ((button_callback_list [lp].callback) == callback) { + button_callback_list [lp].callback = NULL; + button_callback_list [lp].count = 0; + callback_count--; + return 0; + }; + lp--; + }; + return -EINVAL; +} + +/* + * This function is called by button_sequence_finished to search through the + * list of callback functions, and call any of them whose count argument + * matches the current count of button presses. It starts at the beginning + * of the list and works up to the end. It will refuse to follow a null + * pointer (which should never happen anyway). + */ + +static void button_consume_callbacks (int bpcount) +{ + int lp = 0; + for (; lp <= 31; lp++) { + if ((button_callback_list [lp].count) == bpcount) { + if (button_callback_list [lp].callback) { + button_callback_list[lp].callback(); + } + } + } +} + +/* + * This function is called when the button_timer times out. + * ie. When you don't press the button for bdelay jiffies, this is taken to + * mean you have ended the sequence of key presses, and this function is + * called to wind things up (write the press_count out to /dev/button, call + * any matching registered function callbacks, initiate reboot, etc.). + */ + +static void button_sequence_finished (unsigned long parameters) +{ +#ifdef CONFIG_NWBUTTON_REBOOT /* Reboot using button is enabled */ + if (button_press_count == reboot_count) { + kill_proc (1, SIGINT, 1); /* Ask init to reboot us */ + } +#endif /* CONFIG_NWBUTTON_REBOOT */ + button_consume_callbacks (button_press_count); + bcount = sprintf (button_output_buffer, "%d\n", button_press_count); + button_press_count = 0; /* Reset the button press counter */ + wake_up_interruptible (&button_wait_queue); +} + +/* + * This handler is called when the orange button is pressed (GPIO 10 of the + * SuperIO chip, which maps to logical IRQ 26). If the press_count is 0, + * this is the first press, so it starts a timer and increments the counter. + * If it is higher than 0, it deletes the old timer, starts a new one, and + * increments the counter. + */ + +static void button_handler (int irq, void *dev_id, struct pt_regs *regs) +{ + if (button_press_count) { + del_timer (&button_timer); + } + button_press_count++; + init_timer (&button_timer); + button_timer.function = button_sequence_finished; + button_timer.expires = (jiffies + bdelay); + add_timer (&button_timer); +} + +/* + * This function is called when a user space program attempts to read + * /dev/nwbutton. It puts the device to sleep on the wait queue until + * button_sequence_finished writes some data to the buffer and flushes + * the queue, at which point it writes the data out to the device and + * returns the number of characters it has written. This function is + * reentrant, so that many processes can be attempting to read from the + * device at any one time. + */ + +static int button_read (struct file *filp, char *buffer, + size_t count, loff_t *ppos) +{ + interruptible_sleep_on (&button_wait_queue); + return (copy_to_user (buffer, &button_output_buffer, bcount)) + ? -EFAULT : bcount; +} + +/* + * This function is called when a user space process attempts to open the + * device. If the driver is compiled into the kernel it does nothing but + * succeed, but if it is compiled in as a module it also increments the + * module usage count to prevent the module from being removed whilst a + * process has the device open. + */ + +static int button_open (struct inode *inode, struct file *filp) +{ + MOD_INC_USE_COUNT; + return 0; +} + +/* + * This function is called when a user space process attempts to close the + * device. If the driver is compiled into the kernel it does nothing at all, + * but if it is compiled in as a module it also decrements the module usage + * count so that it will be possible to unload the module again once all the + * user processes have closed the device. + */ + +static int button_release (struct inode *inode, struct file *filp) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * This structure is the file operations structure, which specifies what + * callbacks functions the kernel should call when a user mode process + * attempts to perform these operations on the device. + */ + +static struct file_operations button_fops = { + NULL, /* lseek */ + button_read, + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + button_open, + NULL, /* flush */ + button_release, +}; + +/* + * This structure is the misc device structure, which specifies the minor + * device number (158 in this case), the name of the device (for /proc/misc), + * and the address of the above file operations structure. + */ + +static struct miscdevice button_misc_device = { + BUTTON_MINOR, + "nwbutton", + &button_fops, +}; + +/* + * This function is called to initialise the driver, either from misc.c at + * bootup if the driver is compiled into the kernel, or from init_module + * below at module insert time. It attempts to register the device node + * and the IRQ and fails with a warning message if either fails, though + * neither ever should because the device number and IRQ are unique to + * this driver. + */ + +static int __init nwbutton_init(void) +{ + if (!machine_is_netwinder()) + return -ENODEV; + + printk (KERN_INFO "NetWinder Button Driver Version %s (C) Alex Holden " + "<alex@linuxhacker.org> 1998.\n", VERSION); + + if (misc_register (&button_misc_device)) { + printk (KERN_WARNING "nwbutton: Couldn't register device 10, " + "%d.\n", BUTTON_MINOR); + return -EBUSY; + } + + if (request_irq (IRQ_NETWINDER_BUTTON, button_handler, SA_INTERRUPT, + "nwbutton", NULL)) { + printk (KERN_WARNING "nwbutton: IRQ %d is not free.\n", + IRQ_NETWINDER_BUTTON); + misc_deregister (&button_misc_device); + return -EIO; + } + return 0; +} + +static void __exit nwbutton_exit (void) +{ + free_irq (IRQ_NETWINDER_BUTTON, NULL); + misc_deregister (&button_misc_device); +} + +EXPORT_NO_SYMBOLS; + +module_init(nwbutton_init); +module_exit(nwbutton_exit); diff --git a/drivers/char/nwbutton.h b/drivers/char/nwbutton.h new file mode 100644 index 000000000..ba5067443 --- /dev/null +++ b/drivers/char/nwbutton.h @@ -0,0 +1,48 @@ +#ifndef __NWBUTTON_H +#define __NWBUTTON_H + +/* + * NetWinder Button Driver- + * Copyright (C) Alex Holden <alex@linuxhacker.org> 1998, 1999. + */ + +#ifdef __NWBUTTON_C /* Actually compiling the driver itself */ + +/* Various defines: */ + +#define NUM_PRESSES_REBOOT 2 /* How many presses to activate shutdown */ +#define BUTTON_DELAY 30 /* How many jiffies for sequence to end */ +#define VERSION "0.3" /* Driver version number */ +#define BUTTON_MINOR 158 /* Major 10, Minor 158, /dev/nwbutton */ + +/* Structure definitions: */ + +struct button_callback { + void (*callback) (void); + int count; +}; + +/* Function prototypes: */ + +static void button_sequence_finished (unsigned long parameters); +static void button_handler (int irq, void *dev_id, struct pt_regs *regs); +static int button_read (struct file *filp, char *buffer, + size_t count, loff_t *ppos); +static int button_open (struct inode *inode, struct file *filp); +static int button_release (struct inode *inode, struct file *filp); +int button_init (void); +int button_add_callback (void (*callback) (void), int count); +int button_del_callback (void (*callback) (void)); +static void button_consume_callbacks (int bpcount); +#ifdef MODULE +int init_module (void); +void cleanup_module (void); +#endif /* MODULE */ + +#else /* Not compiling the driver itself */ + +extern int button_add_callback (void (*callback) (void), int count); +extern int button_del_callback (void (*callback) (void)); + +#endif /* __NWBUTTON_C */ +#endif /* __NWBUTTON_H */ diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c new file mode 100644 index 000000000..a905be058 --- /dev/null +++ b/drivers/char/nwflash.c @@ -0,0 +1,708 @@ +/* + * Flash memory interface rev.5 driver for the Intel + * Flash chips used on the NetWinder. + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/fs.h> +#include <linux/errno.h> +#include <linux/mm.h> +#include <linux/delay.h> +#include <linux/proc_fs.h> +#include <linux/sched.h> +#include <linux/miscdevice.h> +#include <linux/spinlock.h> +#include <linux/init.h> + +#include <asm/dec21285.h> +#include <asm/io.h> +#include <asm/leds.h> +#include <asm/system.h> +#include <asm/uaccess.h> + +/*****************************************************************************/ +#include <asm/nwflash.h> + +//#define MINIKERNEL 1 //export flash write, erase routines for MiniKernel + +#ifndef MINIKERNEL +#define MSTATIC static +#else +#define MSTATIC +#endif + +#define NWFLASH_VERSION "6.2" + +MSTATIC void kick_open(void); +MSTATIC int get_flash_id(void); +MSTATIC int erase_block(int nBlock); +MSTATIC int write_block(unsigned long p, const char *buf, int count); +static int open_flash(struct inode *inodep, struct file *filep); +static int release_flash(struct inode *inodep, struct file *filep); +static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg); +static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos); +static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos); +static long long flash_llseek(struct file *file, long long offset, int orig); + +#define KFLASH_SIZE 1024*1024 //1 Meg +#define KFLASH_SIZE4 4*1024*1024 //4 Meg +#define KFLASH_ID 0x89A6 //Intel flash +#define KFLASH_ID4 0xB0D4 //Intel flash 4Meg + +static int flashdebug = 0; //if set - we will display progress msgs + +static int gbWriteEnable = 0; +static int gbWriteBase64Enable = 0; +MSTATIC int gbFlashSize = KFLASH_SIZE; + +extern spinlock_t gpio_lock; + +static struct file_operations flash_fops = +{ + flash_llseek, /* llseek */ + flash_read, /* read */ + flash_write, /* write */ + NULL, /* no special readdir */ + NULL, /* no special select */ + flash_ioctl, + NULL, /* no special mmap */ + open_flash, + NULL, /* no special flush */ + release_flash, + NULL, /* no special fsync */ + NULL, /* no special fasync */ + NULL, /* no special check_media_change */ + NULL /* no special revaldate */ +}; + +static struct miscdevice flash_miscdev = +{ + FLASH_MINOR, + "nwflash", + &flash_fops +}; + +/* + * the delay routine - it is often required to let the flash "breeze"... + */ +void flash_wait(int timeout) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(timeout); +} + +MSTATIC int get_flash_id(void) +{ + volatile unsigned int c1, c2; + + /* + * try to get flash chip ID + */ + kick_open(); + c2 = inb(0x80); + *(unsigned char *) (FLASH_BASE + 0x8000) = 0x90; + udelay(15); + c1 = *(unsigned char *) FLASH_BASE; + c2 = inb(0x80); + + /* + * on 4 Meg flash the second byte is actually at offset 2... + */ + if (c1 == 0xB0) + c2 = *(unsigned char *) (FLASH_BASE + 2); + else + c2 = *(unsigned char *) (FLASH_BASE + 1); + + c2 += (c1 << 8); + + /* + * set it back to read mode + */ + *(unsigned char *) (FLASH_BASE + 0x8000) = 0xFF; + + if (c2 == KFLASH_ID4) + gbFlashSize = KFLASH_SIZE4; + + return c2; +} + +static int open_flash(struct inode *inodep, struct file *filep) +{ + int id; + + id = get_flash_id(); + if ((id != KFLASH_ID) && (id != KFLASH_ID4)) { + printk("Flash: incorrect ID 0x%04X.\n", id); + return -ENXIO; + } + MOD_INC_USE_COUNT; + + return 0; +} + + +static int release_flash(struct inode *inodep, struct file *filep) +{ + MOD_DEC_USE_COUNT; + return 0; +} + + +static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg) +{ +// printk("Flash_ioctl: cmd = 0x%X.\n",cmd); + + switch (cmd) { + case CMD_WRITE_DISABLE: + gbWriteBase64Enable = 0; + gbWriteEnable = 0; + break; + + case CMD_WRITE_ENABLE: + gbWriteEnable = 1; + break; + + case CMD_WRITE_BASE64K_ENABLE: + gbWriteBase64Enable = 1; + break; + + default: + gbWriteBase64Enable = 0; + gbWriteEnable = 0; + return -EINVAL; + } + + return 0; +} + + + +static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos) +{ + unsigned long p = file->f_pos; + int read; + + if (flashdebug) + printk("Flash_dev: flash_read: offset=0x%X, buffer=0x%X, count=0x%X.\n", + (unsigned int) p, (unsigned int) buf, count); + + + if (count < 0) + return -EINVAL; + + if (count > gbFlashSize - p) + count = gbFlashSize - p; + + /* + * flash virtual address + */ + p += FLASH_BASE; + + read = 0; + + if (copy_to_user(buf, (void *) p, count)) + return -EFAULT; + read += count; + file->f_pos += read; + return read; +} + +static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos) +{ + unsigned long p = file->f_pos; + int written; + int nBlock, temp, rc; + int i, j; + + + if (flashdebug) + printk("Flash_dev: flash_write: offset=0x%X, buffer=0x%X, count=0x%X.\n", + (unsigned int) p, (unsigned int) buf, count); + + if (!gbWriteEnable) + return -EINVAL; + + if (p < 64 * 1024 && (!gbWriteBase64Enable)) + return -EINVAL; + + if (count < 0) + return -EINVAL; + + /* + * if write size to big - error! + */ + if (count > gbFlashSize - p) + return -EINVAL; + + + if (verify_area(VERIFY_READ, buf, count)) + return -EFAULT; + + + written = 0; + + leds_event(led_claim); + leds_event(led_green_on); + + nBlock = (int) p >> 16; //block # of 64K bytes + + /* + * # of 64K blocks to erase and write + */ + temp = ((int) (p + count) >> 16) - nBlock + 1; + + /* + * write ends at exactly 64k boundry? + */ + if (((int) (p + count) & 0xFFFF) == 0) + temp -= 1; + + if (flashdebug) + printk("FlashWrite: writing %d block(s) starting at %d.\n", temp, nBlock); + + for (; temp; temp--, nBlock++) { + if (flashdebug) + printk("FlashWrite: erasing block %d.\n", nBlock); + + /* + * first we have to erase the block(s), where we will write... + */ + i = 0; + j = 0; + RetryBlock: + do { + rc = erase_block(nBlock); + i++; + } while (rc && i < 10); + + if (rc) { + if (flashdebug) + printk("FlashWrite: erase error %X. Aborting...\n", rc); + + break; + } + if (flashdebug) + printk("FlashWrite: writing offset %X, from buf %X, bytes left %X.\n", + (unsigned int) p, (unsigned int) buf, count - written); + + /* + * write_block will limit write to space left in this block + */ + rc = write_block(p, buf, count - written); + j++; + + /* + * if somehow write verify failed? Can't happen?? + */ + if (!rc) { + /* + * retry up to 10 times + */ + if (j < 10) + goto RetryBlock; + else + /* + * else quit with error... + */ + rc = -1; + + } + if (rc < 0) { + if (flashdebug) + printk("FlashWrite: write error %X. Aborting...\n", rc); + break; + } + p += rc; + buf += rc; + written += rc; + file->f_pos += rc; + + if (flashdebug) + printk("FlashWrite: written 0x%X bytes OK.\n", written); + } + + /* + * restore reg on exit + */ + leds_event(led_release); + + return written; +} + + +/* + * The memory devices use the full 32/64 bits of the offset, and so we cannot + * check against negative addresses: they are ok. The return value is weird, + * though, in that case (0). + * + * also note that seeking relative to the "end of file" isn't supported: + * it has no meaning, so it returns -EINVAL. + */ +static long long flash_llseek(struct file *file, long long offset, int orig) +{ + if (flashdebug) + printk("Flash_dev: flash_lseek, offset=0x%X, orig=0x%X.\n", + (unsigned int) offset, (unsigned int) orig); + + switch (orig) { + case 0: + if (offset < 0) + return -EINVAL; + + if ((unsigned int) offset > gbFlashSize) + return -EINVAL; + + file->f_pos = (unsigned int) offset; + return file->f_pos; + case 1: + if ((file->f_pos + offset) > gbFlashSize) + return -EINVAL; + if ((file->f_pos + offset) < 0) + return -EINVAL; + file->f_pos += offset; + return file->f_pos; + default: + return -EINVAL; + } +} + + +/* + * assume that main Write routine did the parameter checking... + * so just go ahead and erase, what requested! + */ + +MSTATIC int erase_block(int nBlock) +{ + volatile unsigned int c1; + volatile unsigned char *pWritePtr; + int temp, temp1; + + /* + * orange LED == erase + */ + leds_event(led_amber_on); + + /* + * reset footbridge to the correct offset 0 (...0..3) + */ + *CSR_ROMWRITEREG = 0; + + /* + * dummy ROM read + */ + c1 = *(volatile unsigned char *) (FLASH_BASE + 0x8000); + + kick_open(); + /* + * reset status if old errors + */ + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50; + + /* + * erase a block... + * aim at the middle of a current block... + */ + pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + 0x8000 + (nBlock << 16))); + /* + * dummy read + */ + c1 = *pWritePtr; + + kick_open(); + /* + * erase + */ + *(volatile unsigned char *) pWritePtr = 0x20; + + /* + * confirm + */ + *(volatile unsigned char *) pWritePtr = 0xD0; + + /* + * wait 10 ms + */ + flash_wait(HZ / 100); + + /* + * wait while erasing in process (up to 10 sec) + */ + temp = jiffies + 10 * HZ; + c1 = 0; + while (!(c1 & 0x80) && time_before(jiffies, temp)) { + flash_wait(HZ / 100); + /* + * read any address + */ + c1 = *(volatile unsigned char *) (pWritePtr); + // printk("Flash_erase: status=%X.\n",c1); + } + + /* + * set flash for normal read access + */ + kick_open(); +// *(volatile unsigned char*)(FLASH_BASE+0x8000) = 0xFF; + *(volatile unsigned char *) pWritePtr = 0xFF; //back to normal operation + + /* + * check if erase errors were reported + */ + if (c1 & 0x20) { + if (flashdebug) + printk("Flash_erase: err at %X.\n", (unsigned int) pWritePtr); + /* + * reset error + */ + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50; + + return -2; + } + + /* + * just to make sure - verify if erased OK... + */ + flash_wait(HZ / 100); + + pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + (nBlock << 16))); + + for (temp = 0; temp < 16 * 1024; temp++, pWritePtr += 4) { + if ((temp1 = *(volatile unsigned int *) pWritePtr) != 0xFFFFFFFF) { + if (flashdebug) + printk("Flash_erase: verify err at %X = %X.\n", + (unsigned int) pWritePtr, temp1); + return -1; + } + } + + return 0; + +} + +/* + * write_block will limit number of bytes written to the space in this block + */ +MSTATIC int write_block(unsigned long p, const char *buf, int count) +{ + volatile unsigned int c1; + volatile unsigned int c2; + unsigned char *pWritePtr; + unsigned int uAddress; + unsigned int offset; + unsigned int timeout; + unsigned int timeout1; + + /* + * red LED == write + */ + leds_event(led_amber_off); + leds_event(led_red_on); + + pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); + + /* + * check if write will end in this block.... + */ + offset = p & 0xFFFF; + + if (offset + count > 0x10000) + count = 0x10000 - offset; + + /* + * wait up to 30 sec for this block + */ + timeout = jiffies + 30 * HZ; + + for (offset = 0; offset < count; offset++, pWritePtr++) { + uAddress = (unsigned int) pWritePtr; + uAddress &= 0xFFFFFFFC; + if (__get_user(c2, buf + offset)) + return -EFAULT; + + WriteRetry: + /* + * dummy read + */ + c1 = *(volatile unsigned char *) (FLASH_BASE + 0x8000); + + /* + * kick open the write gate + */ + kick_open(); + + /* + * program footbridge to the correct offset...0..3 + */ + *CSR_ROMWRITEREG = (unsigned int) pWritePtr & 3; + + /* + * write cmd + */ + *(volatile unsigned char *) (uAddress) = 0x40; + + /* + * data to write + */ + *(volatile unsigned char *) (uAddress) = c2; + + /* + * get status + */ + *(volatile unsigned char *) (FLASH_BASE + 0x10000) = 0x70; + + c1 = 0; + + /* + * wait up to 1 sec for this byte + */ + timeout1 = jiffies + 1 * HZ; + + /* + * while not ready... + */ + while (!(c1 & 0x80) && time_before(jiffies, timeout1)) + c1 = *(volatile unsigned char *) (FLASH_BASE + 0x8000); + + /* + * if timeout getting status + */ + if (time_after_eq(jiffies, timeout1)) { + kick_open(); + /* + * reset err + */ + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50; + + goto WriteRetry; + } + /* + * switch on read access, as a default flash operation mode + */ + kick_open(); + /* + * read access + */ + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0xFF; + + /* + * if hardware reports an error writing, and not timeout - + * reset the chip and retry + */ + if (c1 & 0x10) { + kick_open(); + /* + * reset err + */ + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50; + + /* + * before timeout? + */ + if (time_before(jiffies, timeout)) { + if (flashdebug) + printk("FlashWrite: Retrying write (addr=0x%X)...\n", + (unsigned int) pWritePtr - FLASH_BASE); + + /* + * no LED == waiting + */ + leds_event(led_amber_off); + /* + * wait couple ms + */ + flash_wait(HZ / 100); + /* + * red LED == write + */ + leds_event(led_red_on); + + goto WriteRetry; + } else { + printk("Timeout in flash write! (addr=0x%X) Aborting...\n", + (unsigned int) pWritePtr - FLASH_BASE); + /* + * return error -2 + */ + return -2; + + } + } + } + + /* + * green LED == read/verify + */ + leds_event(led_amber_off); + leds_event(led_green_on); + + flash_wait(HZ / 100); + + pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); + + for (offset = 0; offset < count; offset++) { + char c, c1; + if (__get_user(c, buf)) + return -EFAULT; + buf++; + if ((c1 = *pWritePtr++) != c) { + if (flashdebug) + printk("flash write verify error at 0x%X! (%02X!=%02X) Retrying...\n", + (unsigned int) pWritePtr, c1, c); + return 0; + } + } + + return count; +} + + +MSTATIC void kick_open(void) +{ + unsigned long flags; + + /* + * we want to write a bit pattern XXX1 to Xilinx to enable + * the write gate, which will be open for about the next 2ms. + */ + spin_lock_irqsave(&gpio_lock, flags); + cpld_modify(1, 1); + spin_unlock_irqrestore(&gpio_lock, flags); + + /* + * let the ISA bus to catch on... + */ + udelay(25); +} + +MSTATIC int __init nwflash_init(void) +{ + int ret = -ENODEV; + + if (machine_is_netwinder()) { + int id; + + id = get_flash_id(); + printk("Flash ROM driver v.%s, flash device ID 0x%04X, size %d Mb.\n", + NWFLASH_VERSION, id, gbFlashSize / (1024 * 1024)); + + misc_register(&flash_miscdev); + + ret = 0; + } + + return ret; +} + +MSTATIC void __exit nwflash_exit(void) +{ + misc_deregister(&flash_miscdev); +} + +EXPORT_NO_SYMBOLS; + +MODULE_PARM(flashdebug, "i"); + +module_init(nwflash_init); +module_exit(nwflash_exit); diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 6ffbb517c..61dfd6e42 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -197,7 +197,12 @@ int raw_ctl_ioctl(struct inode *inode, raw_device_bindings[minor] = bdget(kdev_t_to_nr(MKDEV(rq.block_major, rq.block_minor))); } else { - kdev_t dev=to_kdev_t(raw_device_bindings[minor]->bd_dev); + kdev_t dev; + if (!raw_device_bindings[minor]) { + err = -ENODEV; + break; + } + dev = to_kdev_t(raw_device_bindings[minor]->bd_dev); rq.block_major = MAJOR(dev); rq.block_minor = MINOR(dev); err = copy_to_user((void *) arg, &rq, sizeof(rq)); diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 6296e789b..f68c65afe 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -36,9 +36,11 @@ * 1.09b Jeff Garzik: Modularize, init cleanup * 1.09c Jeff Garzik: SMP cleanup * 1.10 Paul Barton-Davis: add support for async I/O + * 1.10a Andrea Arcangeli: Alpha updates + * 1.10b Andrew Morton: SMP lock fix */ -#define RTC_VERSION "1.10" +#define RTC_VERSION "1.10b" #define RTC_IRQ 8 /* Can't see this changing soon. */ #define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */ @@ -378,7 +380,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { if (yrs > 169) { - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return -EINVAL; } if (yrs >= 100) @@ -706,7 +708,9 @@ static void __exit rtc_exit (void) free_irq (rtc_irq, &rtc_port); #else release_region (RTC_PORT (0), RTC_IO_EXTENT); +#ifndef __alpha__ free_irq (RTC_IRQ, NULL); +#endif #endif /* __sparc__ */ } diff --git a/drivers/char/wdt285.c b/drivers/char/wdt285.c new file mode 100644 index 000000000..b5dc94e2f --- /dev/null +++ b/drivers/char/wdt285.c @@ -0,0 +1,204 @@ +/* + * Intel 21285 watchdog driver + * Copyright (c) Phil Blundell <pb@nexus.co.uk>, 1998 + * + * based on + * + * SoftDog 0.05: A Software Watchdog Device + * + * (c) Copyright 1996 Alan Cox <alan@cymru.net>, All Rights Reserved. + * http://www.cymru.net + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/interrupt.h> + +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/hardware.h> +#include <asm/system.h> +#include <asm/dec21285.h> + +/* + * Define this to stop the watchdog actually rebooting the machine. + */ +#undef ONLY_TESTING + +#define TIMER_MARGIN 60 /* (secs) Default is 1 minute */ + +#define FCLK (50*1000*1000) /* 50MHz */ + +static int soft_margin = TIMER_MARGIN; /* in seconds */ +static int timer_alive = 0; + +#ifdef ONLY_TESTING +/* + * If the timer expires.. + */ + +static void watchdog_fire(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_CRIT "Watchdog: Would Reboot.\n"); + *CSR_TIMER4_CNTL = 0; + *CSR_TIMER4_CLR = 0; +} +#endif + +static void watchdog_ping(void) +{ + /* + * Refresh the timer. + */ + *CSR_TIMER4_LOAD = soft_margin * (FCLK / 256); +} + +/* + * Allow only one person to hold it open + */ + +static int watchdog_open(struct inode *inode, struct file *file) +{ + if(timer_alive) + return -EBUSY; + MOD_INC_USE_COUNT; + /* + * Ahead watchdog factor ten, Mr Sulu + */ + *CSR_TIMER4_CLR = 0; + watchdog_ping(); + *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD + | TIMER_CNTL_DIV256; +#ifdef ONLY_TESTING + request_irq(IRQ_TIMER4, watchdog_fire, 0, "watchdog", NULL); +#else + *CSR_SA110_CNTL |= 1 << 13; +#endif + timer_alive = 1; + return 0; +} + +static int watchdog_release(struct inode *inode, struct file *file) +{ +#ifdef ONLY_TESTING + free_irq(IRQ_TIMER4, NULL); + timer_alive = 0; + MOD_DEC_USE_COUNT; +#else + /* + * It's irreversible! + */ +#endif + return 0; +} + +static ssize_t watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* + * Refresh the timer. + */ + if(len) + { + watchdog_ping(); + return 1; + } + return 0; +} + +static int watchdog_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int i; + static struct watchdog_info ident= + { + 0, + 0, + "Footbridge Watchdog" + }; + switch(cmd) + { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct watchdog_info)); + if (i) + return i; + else + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)); + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0,(int *)arg); + case WDIOC_KEEPALIVE: + watchdog_ping(); + return 0; + } +} + +static struct file_operations watchdog_fops= +{ + NULL, /* Seek */ + NULL, /* Read */ + watchdog_write, /* Write */ + NULL, /* Readdir */ + NULL, /* Select */ + watchdog_ioctl, /* Ioctl */ + NULL, /* MMap */ + watchdog_open, + NULL, /* flush */ + watchdog_release, + NULL, + NULL /* Fasync */ +}; + +static struct miscdevice watchdog_miscdev= +{ + WATCHDOG_MINOR, + "watchdog", + &watchdog_fops +}; + +static int __init footbridge_watchdog_init(void) +{ + if (machine_is_netwinder()) + return -ENODEV; + + misc_register(&watchdog_miscdev); + printk("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n", + soft_margin); + if (machine_is_cats()) + printk("Warning: Watchdog reset may not work on this machine.\n"); + return 0; +} + +static void __exit footbridge_watchdog_exit(void) +{ + misc_deregister(&watchdog_miscdev); +} + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Phil Blundell <pb@nexus.co.uk>"); +MODULE_DESCRIPTION("21285 watchdog driver"); + +MODULE_PARM(soft_margin,"i"); +MODULE_PARM_DESC(soft_margin,"Watchdog timeout in seconds"); + +module_init(footbridge_watchdog_init); +module_exit(footbridge_watchdog_exit); diff --git a/drivers/char/wdt977.c b/drivers/char/wdt977.c new file mode 100644 index 000000000..c45e63d60 --- /dev/null +++ b/drivers/char/wdt977.c @@ -0,0 +1,204 @@ +/* + * Wdt977 0.01: A Watchdog Device for Netwinder W83977AF chip + * + * (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>) + * + * ----------------------- + * + * 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. + * + * ----------------------- + */ + +#include <linux/module.h> +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <asm/system.h> + +#define WATCHDOG_MINOR 130 + +static int timeout = 3; +static int timer_alive = 0; +static int testmode = 0; + +/* + * Allow only one person to hold it open + */ + +static int wdt977_open(struct inode *inode, struct file *file) +{ + if(timer_alive) + return -EBUSY; + MOD_INC_USE_COUNT; + timer_alive++; + + //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. + if (timeout>255) + timeout = 255; + + printk(KERN_INFO "Watchdog: active, current timeout %d min.\n",timeout); + + // unlock the SuperIO chip + outb(0x87,0x370); + outb(0x87,0x370); + + //select device Aux2 (device=8) and set watchdog regs F2, F3 and F4 + //F2 has the timeout in minutes + //F3 could be set to the POWER LED blink (with GP17 set to PowerLed) + // at timeout, and to reset timer on kbd/mouse activity (not now) + //F4 is used to just clear the TIMEOUT'ed state (bit 0) + + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(timeout,0x371); + outb(0xF3,0x370); + outb(0x00,0x371); //another setting is 0E for kbd/mouse/LED + outb(0xF4,0x370); + outb(0x00,0x371); + + //at last select device Aux1 (dev=7) and set GP16 as a watchdog output + if (!testmode) + { + outb(0x07,0x370); + outb(0x07,0x371); + outb(0xE6,0x370); + outb(0x08,0x371); + } + + // lock the SuperIO chip + outb(0xAA,0x370); + + return 0; +} + +static int wdt977_release(struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + * Lock it in if it's a module and we defined ...NOWAYOUT + */ +#ifndef CONFIG_WATCHDOG_NOWAYOUT + + // unlock the SuperIO chip + outb(0x87,0x370); + outb(0x87,0x370); + + //select device Aux2 (device=8) and set watchdog regs F2,F3 and F4 + //F3 is reset to its default state + //F4 can clear the TIMEOUT'ed state (bit 0) - back to default + //We can not use GP17 as a PowerLed, as we use its usage as a RedLed + + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(0xFF,0x371); + outb(0xF3,0x370); + outb(0x00,0x371); + outb(0xF4,0x370); + outb(0x00,0x371); + outb(0xF2,0x370); + outb(0x00,0x371); + + //at last select device Aux1 (dev=7) and set GP16 as a watchdog output + outb(0x07,0x370); + outb(0x07,0x371); + outb(0xE6,0x370); + outb(0x08,0x371); + + // lock the SuperIO chip + outb(0xAA,0x370); + + MOD_DEC_USE_COUNT; + timer_alive=0; + + printk(KERN_INFO "Watchdog: shutdown.\n"); +#endif + return 0; +} + +static ssize_t wdt977_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + + //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. + if (timeout>255) + timeout = 255; + + /* + * Refresh the timer. + */ + + //we have a hw bug somewhere, so each 977 minute is actually only 30sec + //as such limit the max timeout to half of max of 255 minutes... +// if (timeout>126) +// timeout = 126; + + // unlock the SuperIO chip + outb(0x87,0x370); + outb(0x87,0x370); + + //select device Aux2 (device=8) and kicks watchdog reg F2 + //F2 has the timeout in minutes + + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(timeout,0x371); + + // lock the SuperIO chip + outb(0xAA,0x370); + + return 1; +} + +static struct file_operations wdt977_fops= +{ + NULL, /* Seek */ + NULL, /* Read */ + wdt977_write, /* Write */ + NULL, /* Readdir */ + NULL, /* Select */ + NULL, /* Ioctl */ + NULL, /* MMap */ + wdt977_open, + NULL, /* flush */ + wdt977_release, + NULL, + NULL /* Fasync */ +}; + +static struct miscdevice wdt977_miscdev= +{ + WATCHDOG_MINOR, + "watchdog", + &wdt977_fops +}; + +static int __init nwwatchdog_init(void) +{ + if (!machine_is_netwinder()) + return -ENODEV; + + misc_register(&wdt977_miscdev); + printk(KERN_INFO "NetWinder Watchdog sleeping.\n"); + return 0; +} + +static void __exit nwwatchdog_exit(void) +{ + misc_deregister(&wdt977_miscdev); +} + +EXPORT_NO_SYMBOLS; + +module_init(nwwatchdog_init); +module_exit(nwwatchdog_exit); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index c98cb7c6f..493befb7d 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -101,10 +101,6 @@ static struct file_operations i2cproc_operations = { read: i2cproc_bus_read, }; -static struct inode_operations i2cproc_inode_operations = { - &i2cproc_operations -}; - static int i2cproc_initialized = 0; #else /* undef CONFIG_PROC_FS */ @@ -163,7 +159,7 @@ int i2c_add_adapter(struct i2c_adapter *adap) name); return -ENOENT; } - proc_entry->ops = &i2cproc_inode_operations; + proc_entry->proc_fops = &i2cproc_operations; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) proc_entry->owner = THIS_MODULE; #else diff --git a/drivers/isdn/avmb1/b1dma.c b/drivers/isdn/avmb1/b1dma.c index 8bf595282..d61b88375 100644 --- a/drivers/isdn/avmb1/b1dma.c +++ b/drivers/isdn/avmb1/b1dma.c @@ -1,11 +1,14 @@ /* - * $Id: b1dma.c,v 1.2 2000/01/25 14:44:47 calle Exp $ + * $Id: b1dma.c,v 1.3 2000/02/26 01:00:53 keil Exp $ * * Common module for AVM B1 cards that support dma with AMCC * * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1dma.c,v $ + * Revision 1.3 2000/02/26 01:00:53 keil + * changes from 2.3.47 + * * Revision 1.2 2000/01/25 14:44:47 calle * typo in b1pciv4_detect(). * @@ -31,7 +34,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.2 $"; +static char *revision = "$Revision: 1.3 $"; /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c index 62f246407..fb8a32460 100644 --- a/drivers/isdn/avmb1/capi.c +++ b/drivers/isdn/avmb1/capi.c @@ -1,11 +1,14 @@ /* - * $Id: capi.c,v 1.22 1999/11/13 21:27:16 keil Exp $ + * $Id: capi.c,v 1.23 2000/02/26 01:00:53 keil Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ + * Revision 1.23 2000/02/26 01:00:53 keil + * changes from 2.3.47 + * * Revision 1.22 1999/11/13 21:27:16 keil * remove KERNELVERSION * diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c index 110b5a172..de56823c0 100644 --- a/drivers/isdn/divert/divert_procfs.c +++ b/drivers/isdn/divert/divert_procfs.c @@ -315,8 +315,6 @@ static struct file_operations isdn_fops = NULL /* fsync */ }; -struct inode_operations divert_file_inode_operations; - /****************************/ /* isdn subdir in /proc/net */ /****************************/ @@ -342,9 +340,7 @@ divert_dev_init(void) remove_proc_entry("isdn", proc_net); return (-1); } - memset(&divert_file_inode_operations, 0, sizeof(struct inode_operations)); - divert_file_inode_operations.default_file_ops = &isdn_fops; - isdn_divert_entry->ops = &divert_file_inode_operations; + isdn_divert_entry->proc_fops = &isdn_fops; #endif /* CONFIG_PROC_FS */ return (0); diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c index e53469070..eb3590069 100644 --- a/drivers/isdn/eicon/eicon_idi.c +++ b/drivers/isdn/eicon/eicon_idi.c @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.29 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_idi.c,v 1.31 2000/02/22 16:26:40 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * IDI interface @@ -26,6 +26,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_idi.c,v $ + * Revision 1.31 2000/02/22 16:26:40 armin + * Fixed membase error message. + * Fixed missing log buffer struct. + * + * Revision 1.30 2000/02/16 16:08:46 armin + * Fixed virtual channel handling of IDI. + * * Revision 1.29 2000/01/23 21:21:23 armin * Added new trace capability and some updates. * DIVA Server BRI now supports data for ISDNLOG. @@ -149,7 +156,7 @@ #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.29 $"; +char *eicon_idi_revision = "$Revision: 1.31 $"; eicon_manifbuf *manbuf; @@ -255,10 +262,10 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) } int -idi_put_req(eicon_REQ *reqbuf, int rq, int signet) +idi_put_req(eicon_REQ *reqbuf, int rq, int signet, int Ch) { reqbuf->Req = rq; - reqbuf->ReqCh = 0; + reqbuf->ReqCh = Ch; reqbuf->ReqId = 1; reqbuf->XBuffer.length = 1; reqbuf->XBuffer.P[0] = 0; @@ -368,34 +375,34 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer) break; case REMOVE: case REMOVE|0x700: - idi_put_req(reqbuf, REMOVE, layer); + idi_put_req(reqbuf, REMOVE, layer, 0); break; case INDICATE_REQ: - idi_put_req(reqbuf, INDICATE_REQ, 0); + idi_put_req(reqbuf, INDICATE_REQ, 0, 0); break; case HANGUP: - idi_put_req(reqbuf, HANGUP, 0); + idi_put_req(reqbuf, HANGUP, 0, 0); break; case REJECT: - idi_put_req(reqbuf, REJECT, 0); + idi_put_req(reqbuf, REJECT, 0 ,0); break; case CALL_ALERT: - idi_put_req(reqbuf, CALL_ALERT, 0); + idi_put_req(reqbuf, CALL_ALERT, 0, 0); break; case CALL_RES: idi_call_res_req(reqbuf, chan); break; case IDI_N_CONNECT|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT, 1); + idi_put_req(reqbuf, IDI_N_CONNECT, 1, 0); break; case IDI_N_CONNECT_ACK|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1); + idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1, 0); break; case IDI_N_DISC|0x700: - idi_put_req(reqbuf, IDI_N_DISC, 1); + idi_put_req(reqbuf, IDI_N_DISC, 1, chan->e.IndCh); break; case IDI_N_DISC_ACK|0x700: - idi_put_req(reqbuf, IDI_N_DISC_ACK, 1); + idi_put_req(reqbuf, IDI_N_DISC_ACK, 1, chan->e.IndCh); break; default: eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No); @@ -813,6 +820,11 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi message->osa[i] = buffer[pos++]; eicon_log(ccard, 2, "idi_inf: Ch%d: OSA=%s\n", chan->No, message->osa); break; + case CAD: + pos += wlen; + eicon_log(ccard, 2, "idi_inf: Ch%d: Connected Address in ind, len:%x\n", + chan->No, wlen); + break; case BC: if (wlen > sizeof(message->bc)) { pos += wlen; @@ -1206,7 +1218,7 @@ idi_send_edata(eicon_card *card, eicon_chan *chan) reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ)); reqbuf->Req = IDI_N_EDATA; - reqbuf->ReqCh = 0; + reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; reqbuf->XBuffer.length = idi_fill_in_T30(chan, reqbuf->XBuffer.P); @@ -2205,7 +2217,7 @@ idi_send_udata(eicon_card *card, eicon_chan *chan, int UReq, u_char *buffer, int reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ)); reqbuf->Req = IDI_N_UDATA; - reqbuf->ReqCh = 0; + reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; reqbuf->XBuffer.length = len + 1; @@ -2322,7 +2334,7 @@ eicon_parse_trace(eicon_card *ccard, unsigned char *buffer, int len) unsigned char data[1]; } *q; - if (!(p = kmalloc(buflen, GFP_KERNEL))) { + if (!(p = kmalloc(buflen, GFP_ATOMIC))) { eicon_log(ccard, 1, "idi_err: Ch??: could not allocate trace buffer\n"); return; } @@ -2380,7 +2392,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) return; } - if (ind->Ind != 8) + if ((ind->Ind != 8) && (ind->Ind != 0xc)) dlev = 144; else dlev = 128; @@ -2634,6 +2646,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) break; case IDI_N_CONNECT: eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No); + chan->e.IndCh = ind->IndCh; if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1); if (chan->l2prot == ISDN_PROTO_L2_FAX) { break; @@ -2664,6 +2677,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) idi_fax_hangup(ccard, chan); } #endif + chan->e.IndCh = 0; save_flags(flags); cli(); chan->queued = 0; @@ -2693,7 +2707,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) #endif break; case IDI_N_DATA_ACK: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No); + eicon_log(ccard, 128, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No); break; case IDI_N_DATA: skb_pull(skb, sizeof(eicon_IND) - 1); @@ -2774,6 +2788,11 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) } else { /* Network layer */ switch(chan->e.Req & 0x0f) { + case IDI_N_CONNECT: + chan->e.IndCh = ack->RcCh; + eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, + ack->RcId, ack->RcCh, ack->Reference); + break; case IDI_N_MDATA: case IDI_N_DATA: if ((chan->e.Req & 0x0f) == IDI_N_DATA) { @@ -2999,7 +3018,7 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, reqbuf->Req = IDI_N_DATA; if (ack) reqbuf->Req |= N_D_BIT; } - reqbuf->ReqCh = 0; + reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; memcpy(&reqbuf->XBuffer.P, skb->data + offset, plen); reqbuf->XBuffer.length = plen; diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c index 86e6c0ef7..265e07e08 100644 --- a/drivers/isdn/eicon/eicon_isa.c +++ b/drivers/isdn/eicon/eicon_isa.c @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.c,v 1.13 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_isa.c,v 1.14 2000/02/22 16:26:40 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for old ISA cards. @@ -22,6 +22,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_isa.c,v $ + * Revision 1.14 2000/02/22 16:26:40 armin + * Fixed membase error message. + * Fixed missing log buffer struct. + * * Revision 1.13 2000/01/23 21:21:23 armin * Added new trace capability and some updates. * DIVA Server BRI now supports data for ISDNLOG. @@ -83,7 +87,7 @@ #define release_shmem release_region #define request_shmem request_region -char *eicon_isa_revision = "$Revision: 1.13 $"; +char *eicon_isa_revision = "$Revision: 1.14 $"; #undef EICON_MCA_DEBUG @@ -146,6 +150,9 @@ eicon_isa_find_card(int Mem, int Irq, char * Id) if (!strlen(Id)) return -1; + if (Mem == -1) + return -1; + /* Check for valid membase address */ if ((Mem < 0x0c0000) || (Mem > 0x0fc000) || diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c index 688d74de3..9bc91d6f4 100644 --- a/drivers/isdn/eicon/eicon_mod.c +++ b/drivers/isdn/eicon/eicon_mod.c @@ -1,4 +1,4 @@ -/* $Id: eicon_mod.c,v 1.24 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_mod.c,v 1.25 2000/02/22 16:26:40 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * @@ -31,6 +31,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_mod.c,v $ + * Revision 1.25 2000/02/22 16:26:40 armin + * Fixed membase error message. + * Fixed missing log buffer struct. + * * Revision 1.24 2000/01/23 21:21:23 armin * Added new trace capability and some updates. * DIVA Server BRI now supports data for ISDNLOG. @@ -140,7 +144,7 @@ static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.24 $"; +static char *eicon_revision = "$Revision: 1.25 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; @@ -886,8 +890,10 @@ eicon_putstatus(eicon_card * card, char * buf) u_char *p; struct sk_buff *skb; - if (!card) - return; + if (!card) { + if (!(card = cards)) + return; + } save_flags(flags); cli(); diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index 319e0b264..d87c43f37 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -1,4 +1,4 @@ -/* $Id: avm_pci.c,v 1.14 1999/12/19 13:09:41 keil Exp $ +/* $Id: avm_pci.c,v 1.15 2000/02/26 00:35:12 keil Exp $ * avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards * Thanks to AVM, Berlin for informations @@ -7,6 +7,9 @@ * * * $Log: avm_pci.c,v $ + * Revision 1.15 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.14 1999/12/19 13:09:41 keil * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for * signal proof delays @@ -63,7 +66,7 @@ #include <linux/interrupt.h> extern const char *CardType[]; -static const char *avm_pci_rev = "$Revision: 1.14 $"; +static const char *avm_pci_rev = "$Revision: 1.15 $"; #define AVM_FRITZ_PCI 1 #define AVM_FRITZ_PNP 2 @@ -499,7 +502,7 @@ HDLC_irq(struct BCState *bcs, u_int stat) { if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hdlc.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hdlc.count = 0; bcs->tx_skb = NULL; } @@ -626,7 +629,7 @@ close_hdlcstate(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index 8d389c623..377819551 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -1,10 +1,13 @@ -/* $Id: config.c,v 2.43 2000/01/20 19:49:36 keil Exp $ +/* $Id: config.c,v 2.44 2000/02/26 00:35:12 keil Exp $ * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * * * $Log: config.c,v $ + * Revision 2.44 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 2.43 2000/01/20 19:49:36 keil * Support teles 13.3c vendor version 2.1 * @@ -549,9 +552,9 @@ HiSaxVersion(void)) printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n"); #ifdef MODULE - printk(KERN_INFO "HiSax: Version 3.3d (module)\n"); + printk(KERN_INFO "HiSax: Version 3.3e (module)\n"); #else - printk(KERN_INFO "HiSax: Version 3.3d (kernel)\n"); + printk(KERN_INFO "HiSax: Version 3.3e (kernel)\n"); #endif strcpy(tmp, l1_revision); printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp)); diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 5dc868942..30c6331a5 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -1,4 +1,4 @@ -/* $Id: diva.c,v 1.18 1999/12/19 13:09:41 keil Exp $ +/* $Id: diva.c,v 1.19 2000/02/26 00:35:12 keil Exp $ * diva.c low level stuff for Eicon.Diehl Diva Family ISDN cards * @@ -12,6 +12,9 @@ * * * $Log: diva.c,v $ + * Revision 1.19 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.18 1999/12/19 13:09:41 keil * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for * signal proof delays @@ -84,7 +87,7 @@ extern const char *CardType[]; -const char *Diva_revision = "$Revision: 1.18 $"; +const char *Diva_revision = "$Revision: 1.19 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -585,7 +588,7 @@ Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hscx.count = 0; bcs->tx_skb = NULL; } diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c index 529a74815..8bff1db1c 100644 --- a/drivers/isdn/hisax/elsa_ser.c +++ b/drivers/isdn/hisax/elsa_ser.c @@ -298,7 +298,7 @@ modem_fill(struct BCState *bcs) { (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } } @@ -442,13 +442,13 @@ close_elsastate(struct BCState *bcs) bcs->hw.hscx.rcvbuf = NULL; } while ((skb = skb_dequeue(&bcs->rqueue))) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } while ((skb = skb_dequeue(&bcs->squeue))) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c index 2b22cdfea..bc4665863 100644 --- a/drivers/isdn/hisax/hfc_2bds0.c +++ b/drivers/isdn/hisax/hfc_2bds0.c @@ -1,4 +1,4 @@ -/* $Id: hfc_2bds0.c,v 1.11 1999/12/23 15:09:32 keil Exp $ +/* $Id: hfc_2bds0.c,v 1.12 2000/02/26 00:35:12 keil Exp $ * * specific routines for CCD's HFC 2BDS0 * @@ -6,6 +6,9 @@ * * * $Log: hfc_2bds0.c,v $ + * Revision 1.12 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.11 1999/12/23 15:09:32 keil * change email * @@ -293,7 +296,7 @@ static struct sk_buff sti(); debugl1(cs, "RFIFO BUSY error"); printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel); - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); skb = NULL; } else { cli(); @@ -309,7 +312,7 @@ static struct sk_buff bcs->channel, chksum, stat); if (stat) { debugl1(cs, "FIFO CRC error"); - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); skb = NULL; #ifdef ERROR_STATISTIC bcs->err_crc++; @@ -401,7 +404,7 @@ hfc_fill_fifo(struct BCState *bcs) if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } WaitForBusy(cs); @@ -603,7 +606,7 @@ close_2bs0(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } @@ -751,7 +754,7 @@ int receive_dmsg(struct IsdnCardState *cs) sti(); debugl1(cs, "RFIFO D BUSY error"); printk(KERN_WARNING "HFC DFIFO channel BUSY Error\n"); - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); skb = NULL; #ifdef ERROR_STATISTIC cs->err_rx++; @@ -770,7 +773,7 @@ int receive_dmsg(struct IsdnCardState *cs) chksum, stat); if (stat) { debugl1(cs, "FIFO CRC error"); - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); skb = NULL; #ifdef ERROR_STATISTIC cs->err_crc++; @@ -870,7 +873,7 @@ hfc_fill_dfifo(struct IsdnCardState *cs) cli(); WaitNoBusy(cs); ReadReg(cs, HFCD_DATA, HFCD_FIFO | HFCD_F1_INC | HFCD_SEND); - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; sti(); WaitForBusy(cs); @@ -1004,7 +1007,7 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val) } goto afterXPR; } else { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c index f3edefa3e..8a1d29762 100644 --- a/drivers/isdn/hisax/hfc_2bs0.c +++ b/drivers/isdn/hisax/hfc_2bs0.c @@ -1,4 +1,4 @@ -/* $Id: hfc_2bs0.c,v 1.12 1999/12/19 14:17:12 keil Exp $ +/* $Id: hfc_2bs0.c,v 1.13 2000/02/26 00:35:12 keil Exp $ * specific routines for CCD's HFC 2BS0 * @@ -6,6 +6,9 @@ * * * $Log: hfc_2bs0.c,v $ + * Revision 1.13 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.12 1999/12/19 14:17:12 keil * fix compiler warning * @@ -249,7 +252,7 @@ hfc_empty_fifo(struct BCState *bcs, int count) if (idx != count) { debugl1(cs, "RFIFO BUSY error"); printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); if (bcs->mode != L1_MODE_TRANS) { WaitNoBusy(cs); stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | @@ -270,7 +273,7 @@ hfc_empty_fifo(struct BCState *bcs, int count) bcs->channel, chksum, stat); if (stat) { debugl1(cs, "FIFO CRC error"); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); skb = NULL; #ifdef ERROR_STATISTIC bcs->err_crc++; @@ -359,7 +362,7 @@ hfc_fill_fifo(struct BCState *bcs) bcs->tx_cnt -= count; if (PACKET_NOACK == bcs->tx_skb->pkt_type) count = -1; - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; if (bcs->mode != L1_MODE_TRANS) { WaitForBusy(cs); @@ -573,7 +576,7 @@ close_hfcstate(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 76f353861..f2e7abf10 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.26 2000/02/09 20:22:55 werner Exp $ +/* $Id: hfc_pci.c,v 1.27 2000/02/26 00:35:12 keil Exp $ * hfc_pci.c low level driver for CCD´s hfc-pci based cards * @@ -23,6 +23,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hfc_pci.c,v $ + * Revision 1.27 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.26 2000/02/09 20:22:55 werner * * Updated PCI-ID table @@ -126,7 +129,7 @@ extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.26 $"; +static const char *hfcpci_revision = "$Revision: 1.27 $"; /* table entry in the PCI devices list */ typedef struct { @@ -636,7 +639,7 @@ hfcpci_fill_dfifo(struct IsdnCardState *cs) df->f1 = new_f1; /* next frame */ restore_flags(flags); - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; return; } @@ -710,7 +713,7 @@ hfcpci_fill_fifo(struct BCState *bcs) debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded", bcs->channel, bcs->tx_skb->len); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); cli(); bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */ sti(); @@ -778,7 +781,7 @@ hfcpci_fill_fifo(struct BCState *bcs) bz->f1 = new_f1; /* next frame */ restore_flags(flags); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); return; @@ -1130,7 +1133,7 @@ hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs) } goto afterXPR; } else { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } @@ -1522,7 +1525,7 @@ close_hfcpci(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index 462de9d91..85040aabf 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c @@ -1,4 +1,4 @@ -/* $Id: hfc_sx.c,v 1.3 2000/01/20 19:49:36 keil Exp $ +/* $Id: hfc_sx.c,v 1.4 2000/02/26 00:35:12 keil Exp $ * hfc_sx.c low level driver for CCD´s hfc-s+/sp based cards * @@ -22,6 +22,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hfc_sx.c,v $ + * Revision 1.4 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.3 2000/01/20 19:49:36 keil * Support teles 13.3c vendor version 2.1 * @@ -38,6 +41,7 @@ * */ +#include <linux/config.h> #define __NO_VERSION__ #include "hisax.h" #include "hfc_sx.h" @@ -46,7 +50,7 @@ extern const char *CardType[]; -static const char *hfcsx_revision = "$Revision: 1.3 $"; +static const char *hfcsx_revision = "$Revision: 1.4 $"; /***************************************/ /* IRQ-table for CCDs demo board */ @@ -327,7 +331,7 @@ read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max) Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 1 */ Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 2 */ if (Read_hfc(cs, HFCSX_FIF_DRD)) { - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); if (cs->debug & L1_DEB_ISAC_FIFO) debugl1(cs, "hfcsx_read_fifo %d crc error", fifo); skb = NULL; @@ -600,7 +604,7 @@ hfcsx_fill_dfifo(struct IsdnCardState *cs) return; if (write_fifo(cs, cs->tx_skb, HFCSX_SEL_D_TX, 0)) { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; } return; @@ -633,7 +637,7 @@ hfcsx_fill_fifo(struct BCState *bcs) if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } @@ -777,7 +781,7 @@ receive_emsg(struct IsdnCardState *cs) } else HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len); } - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } } while (--count && skb); @@ -931,7 +935,7 @@ hfcsx_interrupt(int intno, void *dev_id, struct pt_regs *regs) } goto afterXPR; } else { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } @@ -1305,7 +1309,7 @@ close_hfcsx(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 6f5b5615c..da55eb2df 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -1,8 +1,11 @@ -/* $Id: hisax.h,v 2.40 2000/01/20 19:51:46 keil Exp $ +/* $Id: hisax.h,v 2.41 2000/02/26 00:35:13 keil Exp $ * Basic declarations, defines and prototypes * * $Log: hisax.h,v $ + * Revision 2.41 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 2.40 2000/01/20 19:51:46 keil * Fix AddTimer message * Change CONFIG defines @@ -157,8 +160,9 @@ #include <linux/isdnif.h> #include <linux/tty.h> #include <linux/serial_reg.h> +#include <linux/netdevice.h> -#undef ERROR_STATISTIC +#define ERROR_STATISTIC #define REQUEST 0 #define CONFIRM 1 diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c index 1c57cd3f1..092b23243 100644 --- a/drivers/isdn/hisax/hscx.c +++ b/drivers/isdn/hisax/hscx.c @@ -1,4 +1,4 @@ -/* $Id: hscx.c,v 1.17 1999/07/01 08:11:41 keil Exp $ +/* $Id: hscx.c,v 1.18 2000/02/26 00:35:13 keil Exp $ * hscx.c HSCX specific routines * @@ -6,6 +6,9 @@ * * * $Log: hscx.c,v $ + * Revision 1.18 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.17 1999/07/01 08:11:41 keil * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel * @@ -219,7 +222,7 @@ close_hscxstate(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c index 655508f70..821f5bc8b 100644 --- a/drivers/isdn/hisax/hscx_irq.c +++ b/drivers/isdn/hisax/hscx_irq.c @@ -1,4 +1,4 @@ -/* $Id: hscx_irq.c,v 1.13 1999/10/14 20:25:28 keil Exp $ +/* $Id: hscx_irq.c,v 1.14 2000/02/26 00:35:13 keil Exp $ * hscx_irq.c low level b-channel stuff for Siemens HSCX * @@ -7,6 +7,9 @@ * This is an include file for fast inline IRQ stuff * * $Log: hscx_irq.c,v $ + * Revision 1.14 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.13 1999/10/14 20:25:28 keil * add a statistic for error monitoring * @@ -250,7 +253,7 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hscx.count = 0; bcs->tx_skb = NULL; } diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c index a992f76c4..07c76cf2f 100644 --- a/drivers/isdn/hisax/isac.c +++ b/drivers/isdn/hisax/isac.c @@ -1,4 +1,4 @@ -/* $Id: isac.c,v 1.24 1999/10/14 20:25:28 keil Exp $ +/* $Id: isac.c,v 1.25 2000/02/26 00:35:13 keil Exp $ * isac.c ISAC specific routines * @@ -9,6 +9,9 @@ * ../../../Documentation/isdn/HiSax.cert * * $Log: isac.c,v $ + * Revision 1.25 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.24 1999/10/14 20:25:28 keil * add a statistic for error monitoring * @@ -338,7 +341,7 @@ isac_interrupt(struct IsdnCardState *cs, u_char val) isac_fill_fifo(cs); goto afterXPR; } else { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } @@ -627,7 +630,7 @@ ISAC_l1hw(struct PStack *st, int pr, void *arg) discard_queue(&cs->rq); discard_queue(&cs->sq); if (cs->tx_skb) { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; } if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) @@ -683,7 +686,7 @@ dbusy_timer_handler(struct IsdnCardState *cs) /* discard frame; reset transceiver */ test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); if (cs->tx_skb) { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } else { diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index bfff86707..d53dc729a 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -1,4 +1,4 @@ -/* $Id: isar.c,v 1.9 2000/01/20 19:47:45 keil Exp $ +/* $Id: isar.c,v 1.10 2000/02/26 00:35:13 keil Exp $ * isar.c ISAR (Siemens PSB 7110) specific routines * @@ -6,6 +6,9 @@ * * * $Log: isar.c,v $ + * Revision 1.10 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.9 2000/01/20 19:47:45 keil * Add Fax Class 1 support * @@ -774,7 +777,7 @@ send_frames(struct BCState *bcs) } } } - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->hw.isar.txcnt = 0; bcs->tx_skb = NULL; } @@ -1631,7 +1634,7 @@ close_isarstate(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); if (bcs->cs->debug & L1_DEB_HSCX) diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c index 4f07eed87..c1bf72ca8 100644 --- a/drivers/isdn/hisax/jade.c +++ b/drivers/isdn/hisax/jade.c @@ -1,10 +1,13 @@ -/* $Id: jade.c,v 1.2 1999/07/01 08:07:57 keil Exp $ +/* $Id: jade.c,v 1.3 2000/02/26 00:35:13 keil Exp $ * * jade.c JADE stuff (derived from original hscx.c) * * Author Roland Klabunde (R.Klabunde@Berkom.de) * * $Log: jade.c,v $ + * Revision 1.3 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.2 1999/07/01 08:07:57 keil * Initial version * @@ -214,7 +217,7 @@ close_jadestate(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/jade_irq.c b/drivers/isdn/hisax/jade_irq.c index e54c80c1a..02fef2627 100644 --- a/drivers/isdn/hisax/jade_irq.c +++ b/drivers/isdn/hisax/jade_irq.c @@ -1,10 +1,13 @@ -/* $Id: jade_irq.c,v 1.2 1999/07/01 08:07:59 keil Exp $ +/* $Id: jade_irq.c,v 1.3 2000/02/26 00:35:13 keil Exp $ * * jade_irq.c Low level JADE IRQ stuff (derived from original hscx_irq.c) * * Author Roland Klabunde (R.Klabunde@Berkom.de) * * $Log: jade_irq.c,v $ + * Revision 1.3 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.2 1999/07/01 08:07:59 keil * Initial version * @@ -192,7 +195,7 @@ jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade) if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hscx.count = 0; bcs->tx_skb = NULL; } diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index 9fa10e326..2b0451a0a 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -1,4 +1,4 @@ -/* $Id: l3dss1.c,v 2.22 2000/01/20 19:44:20 keil Exp $ +/* $Id: l3dss1.c,v 2.23 2000/02/26 01:38:14 keil Exp $ * EURO/DSS1 D-channel protocol * @@ -13,6 +13,9 @@ * Fritz Elfert * * $Log: l3dss1.c,v $ + * Revision 2.23 2000/02/26 01:38:14 keil + * Fixes for V.110 encoding LLC from Jens Jakobsen + * * Revision 2.22 2000/01/20 19:44:20 keil * Fixed uninitialiesed location * Fixed redirecting number IE in Setup @@ -104,7 +107,7 @@ #include <linux/config.h> extern char *HiSax_getrev(const char *revision); -const char *dss1_revision = "$Revision: 2.22 $"; +const char *dss1_revision = "$Revision: 2.23 $"; #define EXT_BEARER_CAPS 1 @@ -1045,7 +1048,8 @@ u_char * EncodeASyncParams(u_char * p, u_char si2) { // 7c 06 88 90 21 42 00 bb - p[0] = p[1] = 0; + p[0] = 0; + p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19 p[2] = 0x80; if (si2 & 32) // 7 data bits @@ -1059,7 +1063,7 @@ EncodeASyncParams(u_char * p, u_char si2) p[2] += 96; else // 1 stop bit - p[2] = 32; + p[2] += 32; if (si2 & 8) // even parity diff --git a/drivers/isdn/hisax/md5sums.asc b/drivers/isdn/hisax/md5sums.asc index 985bd4cb4..afb83e1c8 100644 --- a/drivers/isdn/hisax/md5sums.asc +++ b/drivers/isdn/hisax/md5sums.asc @@ -6,26 +6,26 @@ # Eicon Technology Diva 2.01 PCI cards in the moment. # Read ../../../Documentation/isdn/HiSax.cert for more informations. # -3c2b1c96274cba97a8261d1cecc662b8 isac.c -a9a15d069dbacb383cc24c238cb5ebbe isdnl1.c +3fb9c99465857a4c136ae2881f4e30ba isac.c +dd3955847bbf680b41233478fe521d88 isdnl1.c bb51bd223040b511c18f091da5ab6456 isdnl2.c b7aa7f97b2374967a4aca7c52991142c isdnl3.c a23fbf8879c1432b04640b8b04bdf419 tei.c -d7072dbbeeb7c4c45f3810ed13cf5545 callc.c +ce248e56c2e1326012d0b25f92bbf99b callc.c bf9605b36429898f7be6630034e83230 cert.c -0e500813968adacaea2ef22c9cdd89eb l3dss1.c -2d748ced0eea375b21fe7ea91ca7917c l3_1tr6.c -d45fde1c90dda636ab134f2a51db435e elsa.c -0b5fb429f5bfe188fd42a5be01abbb14 diva.c +6ce0a184127be1a44747e2017ed24ad9 l3dss1.c +a3a570781f828b6d59e6b231653133de l3_1tr6.c +4aeba32c4c3480d2a6b9af34600b974f elsa.c +a296edc459b508bf0346c3132815a4db diva.c # end of md5sums -----BEGIN PGP SIGNATURE----- Version: 2.6.3i Charset: noconv -iQCVAwUBOCYF6jpxHvX/mS9tAQFnxQP/dpHyNjbo5BhFEZ8qIgpPJzoCgV+b2pB+ -h9Z/Q1jg8l23L/lP9dW00ogrKnKziVUUJqg+wWVEAA7BnNVr3aeyQKFTVuOnK5MC -Oy0Z98p530vgOBiZ47elNfpefjhfD3duSSYNA4R9fEHVZB/atKFYvB5GDGmrwjIZ -2f3g3kBP5Os= -=zNnO +iQCVAwUBOLcvXDpxHvX/mS9tAQGPWAP9Fg14RXcAwjCy4VeFoDBMOFpxllvG7xZR +HQKENCYIzXKPb6I/IBUv3+BhL8Lnhjw8a2DXz6c6u+0nmUIFnzyt1BfzT70P9rKd +BBN7f1KdIiQEmv0fZwd79Rz5PYvRDbY520bNTJZhorwqGI/qc3gGgHVtSR8OHhuS +ZMQ1pb9W6jE= +=CA5N -----END PGP SIGNATURE----- diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c index 3855625bd..b1b0fd8d4 100644 --- a/drivers/isdn/hisax/netjet.c +++ b/drivers/isdn/hisax/netjet.c @@ -1,4 +1,4 @@ -/* $Id: netjet.c,v 1.17 1999/12/19 13:09:42 keil Exp $ +/* $Id: netjet.c,v 1.18 2000/02/26 00:35:13 keil Exp $ * netjet.c low level stuff for Traverse Technologie NETJet ISDN cards * @@ -7,6 +7,9 @@ * Thanks to Traverse Technologie Australia for documents and informations * * $Log: netjet.c,v $ + * Revision 1.18 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.17 1999/12/19 13:09:42 keil * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for * signal proof delays @@ -85,7 +88,7 @@ extern const char *CardType[]; -const char *NETjet_revision = "$Revision: 1.17 $"; +const char *NETjet_revision = "$Revision: 1.18 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -730,7 +733,7 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); @@ -873,7 +876,7 @@ close_tigerstate(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index 724ce52c9..c6fe2acdd 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -1,4 +1,4 @@ -/* $Id: w6692.c,v 1.1 1999/09/04 06:28:58 keil Exp $ +/* $Id: w6692.c,v 1.2 2000/02/26 00:35:13 keil Exp $ * w6692.c Winbond W6692 specific routines * @@ -8,6 +8,9 @@ * This file is (c) under GNU PUBLIC LICENSE * * $Log: w6692.c,v $ + * Revision 1.2 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.1 1999/09/04 06:28:58 keil * first revision * @@ -47,7 +50,7 @@ static const PCI_ENTRY id_list[] = extern const char *CardType[]; -const char *w6692_revision = "$Revision: 1.1 $"; +const char *w6692_revision = "$Revision: 1.2 $"; #define DBUSY_TIMER_VALUE 80 @@ -378,7 +381,7 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan) if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.w6692.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.w6692.count = 0; bcs->tx_skb = NULL; } @@ -478,7 +481,7 @@ W6692_interrupt(int intno, void *dev_id, struct pt_regs *regs) W6692_fill_fifo(cs); goto afterXFR; } else { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } @@ -655,7 +658,7 @@ W6692_l1hw(struct PStack *st, int pr, void *arg) discard_queue(&cs->rq); discard_queue(&cs->sq); if (cs->tx_skb) { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; } if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) @@ -704,7 +707,7 @@ dbusy_timer_handler(struct IsdnCardState *cs) /* discard frame; reset transceiver */ test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); if (cs->tx_skb) { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } else { @@ -819,7 +822,7 @@ close_w6692state(struct BCState *bcs) discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index 81e1b84f0..4cb480588 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -416,8 +416,6 @@ static struct file_operations conf_fops = NULL /* fsync */ }; -static struct inode_operations conf_inode_operations; - /*****************************/ /* hysdn subdir in /proc/net */ /*****************************/ @@ -446,10 +444,8 @@ hysdn_procconf_init(void) if ((card->procconf = (void *) create_proc_entry(conf_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) { - memset(&conf_inode_operations, 0, sizeof(struct inode_operations)); - conf_inode_operations.default_file_ops = &conf_fops; - ((struct proc_dir_entry *) card->procconf)->ops = &conf_inode_operations; + ((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops; hysdn_proclog_init(card); /* init the log file entry */ } card = card->next; /* next entry */ diff --git a/drivers/isdn/hysdn/hysdn_procfs.c b/drivers/isdn/hysdn/hysdn_procfs.c index d70d350e9..b43e2ade7 100644 --- a/drivers/isdn/hysdn/hysdn_procfs.c +++ b/drivers/isdn/hysdn/hysdn_procfs.c @@ -351,27 +351,6 @@ static struct file_operations log_fops = NULL /* fsync */ }; -struct inode_operations log_inode_operations = -{ - &log_fops, /* log proc file-ops */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - NULL, /* readlink */ - NULL, /* follow_link */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* bmap */ - NULL, /* truncate */ - NULL /* permission */ -}; - /*****************************************/ /* Output info data to the cardinfo file */ /*****************************************/ @@ -464,7 +443,7 @@ hysdn_procfs_init(void) sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) - pd->log->ops = &log_inode_operations; /* set new operations table */ + pd->log->proc_fops = &log_fops; /* set new operations table */ init_waitqueue_head(&(pd->rd_queue)); diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index aea6a96ad..67a91cf0f 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -433,8 +433,6 @@ static struct file_operations log_fops = NULL /* fsync */ }; -struct inode_operations log_inode_operations; - /***********************************************************************************/ /* hysdn_proclog_init is called when the module is loaded after creating the cards */ /* conf files. */ @@ -448,12 +446,10 @@ hysdn_proclog_init(hysdn_card * card) if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) { memset(pd, 0, sizeof(struct procdata)); - memset(&log_inode_operations, 0, sizeof(struct inode_operations)); - log_inode_operations.default_file_ops = &log_fops; sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) - pd->log->ops = &log_inode_operations; /* set new operations table */ + pd->log->proc_fops = &log_fops; /* set new operations table */ init_waitqueue_head(&(pd->rd_queue)); diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index f1df11f55..b259cdc4b 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.97 2000/01/23 18:45:37 keil Exp $ +/* $Id: isdn_common.c,v 1.99 2000/02/26 01:00:52 keil Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.c,v $ + * Revision 1.99 2000/02/26 01:00:52 keil + * changes from 2.3.47 + * + * Revision 1.98 2000/02/16 14:56:27 paul + * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers + * * Revision 1.97 2000/01/23 18:45:37 keil * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN) * @@ -443,7 +449,7 @@ isdn_dev *dev = (isdn_dev *) 0; -static char *isdn_revision = "$Revision: 1.97 $"; +static char *isdn_revision = "$Revision: 1.99 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -1795,15 +1801,15 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) int i; if ((ret = verify_area(VERIFY_WRITE, (void *) arg, - (ISDN_MODEM_ANZREG + ISDN_MSNLEN + ISDN_LMSNLEN) + (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS))) return ret; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { if (copy_to_user(p, dev->mdm.info[i].emu.profile, - ISDN_MODEM_ANZREG)) + ISDN_MODEM_NUMREG)) return -EFAULT; - p += ISDN_MODEM_ANZREG; + p += ISDN_MODEM_NUMREG; if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN)) return -EFAULT; p += ISDN_MSNLEN; @@ -1811,7 +1817,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) return -EFAULT; p += ISDN_LMSNLEN; } - return (ISDN_MODEM_ANZREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS; + return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS; } else return -EINVAL; break; @@ -1822,15 +1828,15 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) int i; if ((ret = verify_area(VERIFY_READ, (void *) arg, - (ISDN_MODEM_ANZREG + ISDN_MSNLEN) + (ISDN_MODEM_NUMREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS))) return ret; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { if (copy_from_user(dev->mdm.info[i].emu.profile, p, - ISDN_MODEM_ANZREG)) + ISDN_MODEM_NUMREG)) return -EFAULT; - p += ISDN_MODEM_ANZREG; + p += ISDN_MODEM_NUMREG; if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)) return -EFAULT; p += ISDN_MSNLEN; @@ -2632,7 +2638,7 @@ static void isdn_cleanup_devfs(void) devfs_unregister (devfs_handle); } -#else /* CONFIG_DEVFS_FS */ +#else /* CONFIG_DEVFS_FS */ static void isdn_register_devfs(int dummy) { return; @@ -2653,7 +2659,7 @@ static void isdn_cleanup_devfs(void) return; } -#endif /* CONFIG_DEVFS_FS */ +#endif /* CONFIG_DEVFS_FS */ /* * Allocate and initialize all data, register modem-devices diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index 592d20ed9..ee3af91fa 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.107 2000/02/13 09:52:05 kai Exp $ +/* $Id: isdn_net.c,v 1.110 2000/02/26 01:00:53 keil Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -21,6 +21,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.110 2000/02/26 01:00:53 keil + * changes from 2.3.47 + * + * Revision 1.109 2000/02/25 11:29:17 paul + * changed chargetime to ulong from int (after about 20 days the "chargetime of + * ipppX is now 1234" message displays a negative number on alpha). + * + * Revision 1.108 2000/02/15 12:54:01 kai + * set TX timeout back to 2 secs for 2.2.x, just to be safe + * * Revision 1.107 2000/02/13 09:52:05 kai * increased TX_TIMEOUT to 20sec * @@ -521,6 +531,14 @@ static void __inline__ isdn_net_lp_xon(isdn_net_local * lp) netif_wake_queue(&lp->netdev->dev); } +/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just + * to be safe. + * For 2.3.x we push it up to 20 secs, because call establishment + * (in particular callback) may take such a long time, and we + * don't want confusing messages in the log. However, there is a slight + * possibility that this large timeout will break other things like MPPP, + * which might rely on the tx timeout. If so, we'll find out this way... + */ #define ISDN_NET_TX_TIMEOUT (20*HZ) @@ -530,7 +548,7 @@ int isdn_net_force_dial_lp(isdn_net_local *); static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); static int isdn_net_xmit(struct net_device *, isdn_net_local *, struct sk_buff *); -char *isdn_net_revision = "$Revision: 1.107 $"; +char *isdn_net_revision = "$Revision: 1.110 $"; /* * Code for raw-networking over ISDN @@ -727,7 +745,7 @@ isdn_net_autohup() isdn_net_hangup(&p->dev); } else if (jiffies - l->chargetime > l->chargeint) { printk(KERN_DEBUG - "isdn_net: %s: chtime = %d, chint = %d\n", + "isdn_net: %s: chtime = %lu, chint = %d\n", l->name, l->chargetime, l->chargeint); isdn_net_hangup(&p->dev); } @@ -868,7 +886,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) * we correct the timestamp here. */ lp->chargetime = jiffies; - printk(KERN_DEBUG "isdn_net: chargetime of %s now %d\n", + printk(KERN_DEBUG "isdn_net: chargetime of %s now %lu\n", lp->name, lp->chargetime); /* reset dial-timeout */ @@ -915,7 +933,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) if (lp->hupflags & ISDN_WAITCHARGE) lp->hupflags |= ISDN_HAVECHARGE; lp->chargetime = jiffies; - printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %d\n", + printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n", lp->name, lp->chargetime); return 1; } diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c index 0503c67a2..1e314128c 100644 --- a/drivers/isdn/isdn_tty.c +++ b/drivers/isdn/isdn_tty.c @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.82 2000/01/23 18:45:37 keil Exp $ +/* $Id: isdn_tty.c,v 1.84 2000/02/16 15:10:14 paul Exp $ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -20,6 +20,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.c,v $ + * Revision 1.84 2000/02/16 15:10:14 paul + * If a ttyI has no open FDs, don't connect incoming calls to it. + * (Hangup on close of last FD is still to be done.) + * + * Revision 1.83 2000/02/16 14:59:33 paul + * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers; + * used defines for result codes; + * fixed RING ... RUNG problem (no empty lines in between). + * * Revision 1.82 2000/01/23 18:45:37 keil * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN) * @@ -379,7 +388,7 @@ static int bit2si[8] = static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.82 $"; +char *isdn_tty_revision = "$Revision: 1.84 $"; /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() @@ -901,7 +910,7 @@ static void isdn_tty_modem_do_ncarrier(unsigned long data) { modem_info *info = (modem_info *) data; - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); } /* Next routine is called, whenever the DTR-signal is raised. @@ -986,7 +995,7 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m) i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); if (i < 0) { restore_flags(flags); - isdn_tty_modem_result(6, info); + isdn_tty_modem_result(RESULT_NO_DIALTONE, info); } else { info->isdn_driver = dev->drvmap[i]; info->isdn_channel = dev->chanmap[i]; @@ -1056,8 +1065,7 @@ isdn_tty_modem_hup(modem_info * info, int local) if (info->online) { info->last_lhup = local; info->online = 0; - /* NO CARRIER message */ - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); } #ifdef CONFIG_ISDN_AUDIO info->vonline = 0; @@ -1086,7 +1094,7 @@ isdn_tty_modem_hup(modem_info * info, int local) #endif if ((info->msr & UART_MSR_RI) && (info->emu.mdmreg[REG_RUNG] & BIT_RUNG)) - isdn_tty_modem_result(12, info); + isdn_tty_modem_result(RESULT_RUNG, info); info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); info->lsr |= UART_LSR_TEMT; if (info->isdn_driver >= 0) { @@ -1197,7 +1205,7 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m) i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); if (i < 0) { restore_flags(flags); - isdn_tty_modem_result(6, info); + isdn_tty_modem_result(RESULT_NO_DIALTONE, info); } else { info->isdn_driver = dev->drvmap[i]; info->isdn_channel = dev->chanmap[i]; @@ -1265,7 +1273,7 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg) l = strlen(msg); if (!l) { - isdn_tty_modem_result(4, info); + isdn_tty_modem_result(RESULT_ERROR, info); return; } for (j = 7; j >= 0; j--) @@ -1291,7 +1299,7 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg) i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); if (i < 0) { restore_flags(flags); - isdn_tty_modem_result(6, info); + isdn_tty_modem_result(RESULT_NO_DIALTONE, info); } else { info->isdn_driver = dev->drvmap[i]; info->isdn_channel = dev->chanmap[i]; @@ -1589,7 +1597,7 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in isdn_tty_write\n"); #endif - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); isdn_tty_modem_hup(info, 1); } else c = isdn_tty_edit_at(buf, c, info, from_user); @@ -2321,7 +2329,7 @@ isdn_tty_modem_reset_regs(modem_info * info, int force) { atemu *m = &info->emu; if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) { - memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG); + memcpy(m->mdmreg, m->profile, ISDN_MODEM_NUMREG); memcpy(m->msn, m->pmsn, ISDN_MSNLEN); memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN); info->xmit_size = m->mdmreg[REG_PSIZE] * 16; @@ -2338,7 +2346,7 @@ isdn_tty_modem_reset_regs(modem_info * info, int force) static void modem_write_profile(atemu * m) { - memcpy(m->profile, m->mdmreg, ISDN_MODEM_ANZREG); + memcpy(m->profile, m->mdmreg, ISDN_MODEM_NUMREG); memcpy(m->pmsn, m->msn, ISDN_MSNLEN); memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN); if (dev->profd) @@ -2447,6 +2455,13 @@ isdn_tty_modem_init(void) return 0; } + +/* + * isdn_tty_match_icall(char *MSN, atemu *tty_emulator, int dev_idx) + * match the MSN against the MSNs (glob patterns) defined for tty_emulator, + * and return 0 for match, 1 for no match, 2 if MSN could match if longer. + */ + static int isdn_tty_match_icall(char *cid, atemu *emu, int di) { @@ -2512,15 +2527,14 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup) int idx; int si1; int si2; - char nr[32]; + char *nr; ulong flags; if (!setup.phone[0]) { - nr[0] = '0'; - nr[1] = '\0'; + nr = "0"; printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n"); } else - strcpy(nr, setup.phone); + nr = setup.phone; si1 = (int) setup.si1; si2 = (int) setup.si2; if (!setup.eazmsn[0]) { @@ -2537,6 +2551,8 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup) for (i = 0; i < ISDN_MAX_CHANNELS; i++) { modem_info *info = &dev->mdm.info[i]; + if (info->count == 0) + continue; if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */ (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */ idx = isdn_dc2minor(di, ch); @@ -2574,7 +2590,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup) printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr, info->line); info->msr |= UART_MSR_RI; - isdn_tty_modem_result(2, info); + isdn_tty_modem_result(RESULT_RING, info); isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); return 1; } @@ -2660,9 +2676,9 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c) #endif if (TTY_IS_ACTIVE(info)) { if (info->dialing == 1) - isdn_tty_modem_result(7, info); + isdn_tty_modem_result(RESULT_BUSY, info); if (info->dialing > 1) - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); info->dialing = 0; #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n"); @@ -2691,12 +2707,12 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c) if (USG_MODEM(dev->usage[i])) { if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) { strcpy(info->emu.connmsg, c->parm.num); - isdn_tty_modem_result(1, info); + isdn_tty_modem_result(RESULT_CONNECT, info); } else - isdn_tty_modem_result(5, info); + isdn_tty_modem_result(RESULT_CONNECT64000, info); } if (USG_VOICE(dev->usage[i])) - isdn_tty_modem_result(11, info); + isdn_tty_modem_result(RESULT_VCON, info); return 1; } break; @@ -2722,7 +2738,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c) info->last_l2 = -1; info->last_si = 0; sprintf(info->last_cause, "0000"); - isdn_tty_modem_result(6, info); + isdn_tty_modem_result(RESULT_NO_DIALTONE, info); } isdn_tty_modem_hup(info, 0); return 1; @@ -2937,6 +2953,7 @@ isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount, * For CONNECT-messages also switch to online-mode. * For RING-message handle auto-ATA if register 0 != 0 */ + static void isdn_tty_modem_result(int code, modem_info * info) { @@ -2949,14 +2966,13 @@ isdn_tty_modem_result(int code, modem_info * info) char s[ISDN_MSNLEN+10]; switch (code) { - case 2: - m->mdmreg[REG_RINGCNT]++; /* RING */ + case RESULT_RING: + m->mdmreg[REG_RINGCNT]++; if (m->mdmreg[REG_RINGCNT] == m->mdmreg[REG_RINGATA]) /* Automatically accept incoming call */ isdn_tty_cmd_ATA(info); break; - case 3: - /* NO CARRIER */ + case RESULT_NO_CARRIER: #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n", (info->flags & ISDN_ASYNC_CLOSING), @@ -2991,13 +3007,13 @@ isdn_tty_modem_result(int code, modem_info * info) } #endif break; - case 1: - case 5: + case RESULT_CONNECT: + case RESULT_CONNECT64000: sprintf(info->last_cause, "0000"); if (!info->online) info->online = 2; break; - case 11: + case RESULT_VCON: #ifdef ISDN_DEBUG_MODEM_VOICE printk(KERN_DEBUG "res3: send VCON on ttyI%d\n", info->line); @@ -3006,27 +3022,30 @@ isdn_tty_modem_result(int code, modem_info * info) if (!info->online) info->online = 1; break; - } + } /* switch(code) */ + if (m->mdmreg[REG_RESP] & BIT_RESP) { /* Show results */ - isdn_tty_at_cout("\r\n", info); if (m->mdmreg[REG_RESPNUM] & BIT_RESPNUM) { - /* Show numeric results */ - sprintf(s, "%d", code); + /* Show numeric results only */ + sprintf(s, "\r\n%d\r\n", code); isdn_tty_at_cout(s, info); } else { - if ((code == 2) && - (m->mdmreg[REG_RUNG] & BIT_RUNG) && - (m->mdmreg[REG_RINGCNT] > 1)) - return; - if ((code == 2) && (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE))) { - isdn_tty_at_cout("CALLER NUMBER: ", info); - isdn_tty_at_cout(dev->num[info->drv_index], info); - isdn_tty_at_cout("\r\n", info); + if (code == RESULT_RING) { + /* return if "show RUNG" and ringcounter>1 */ + if ((m->mdmreg[REG_RUNG] & BIT_RUNG) && + (m->mdmreg[REG_RINGCNT] > 1)) + return; + /* print CID, _before_ _every_ ring */ + if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) { + isdn_tty_at_cout("\r\nCALLER NUMBER: ", info); + isdn_tty_at_cout(dev->num[info->drv_index], info); + } } + isdn_tty_at_cout("\r\n", info); isdn_tty_at_cout(msg[code], info); switch (code) { - case 1: + case RESULT_CONNECT: switch (m->mdmreg[REG_L2PROT]) { case ISDN_PROTO_L2_MODEM: isdn_tty_at_cout(" ", info); @@ -3034,13 +3053,13 @@ isdn_tty_modem_result(int code, modem_info * info) break; } break; - case 2: + case RESULT_RING: /* Append CPN, if enabled */ if ((m->mdmreg[REG_CPN] & BIT_CPN)) { sprintf(s, "/%s", m->cpn); isdn_tty_at_cout(s, info); } - /* Print CID only once, _after_ 1.st RING */ + /* Print CID only once, _after_ 1st RING */ if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) && (m->mdmreg[REG_RINGCNT] == 1)) { isdn_tty_at_cout("\r\n", info); @@ -3048,10 +3067,10 @@ isdn_tty_modem_result(int code, modem_info * info) isdn_tty_at_cout(dev->num[info->drv_index], info); } break; - case 3: - case 6: - case 7: - case 8: + case RESULT_NO_CARRIER: + case RESULT_NO_DIALTONE: + case RESULT_BUSY: + case RESULT_NO_ANSWER: m->mdmreg[REG_RINGCNT] = 0; /* Append Cause-Message if enabled */ if (m->mdmreg[REG_RESPXT] & BIT_RESPXT) { @@ -3059,7 +3078,7 @@ isdn_tty_modem_result(int code, modem_info * info) isdn_tty_at_cout(s, info); } break; - case 5: + case RESULT_CONNECT64000: /* Append Protocol to CONNECT message */ switch (m->mdmreg[REG_L2PROT]) { case ISDN_PROTO_L2_X75I: @@ -3087,10 +3106,10 @@ isdn_tty_modem_result(int code, modem_info * info) } break; } + isdn_tty_at_cout("\r\n", info); } - isdn_tty_at_cout("\r\n", info); } - if (code == 3) { + if (code == RESULT_NO_CARRIER) { save_flags(flags); cli(); if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { @@ -3108,6 +3127,7 @@ isdn_tty_modem_result(int code, modem_info * info) } } + /* * Display a modem-register-value. */ @@ -3160,8 +3180,8 @@ isdn_tty_getdial(char *p, char *q,int cnt) *q = 0; } -#define PARSE_ERROR { isdn_tty_modem_result(4, info); return; } -#define PARSE_ERROR1 { isdn_tty_modem_result(4, info); return 1; } +#define PARSE_ERROR { isdn_tty_modem_result(RESULT_ERROR, info); return; } +#define PARSE_ERROR1 { isdn_tty_modem_result(RESULT_ERROR, info); return 1; } static void isdn_tty_report(modem_info * info) @@ -3329,8 +3349,8 @@ isdn_tty_cmd_ATand(char **p, modem_info * info) /* &L -Set Numbers to listen on */ p[0]++; i = 0; - while ((strchr("0123456789,-*[]?;", *p[0])) && - (i < ISDN_LMSNLEN) && *p[0]) + while (*p[0] && (strchr("0123456789,-*[]?;", *p[0])) && + (i < ISDN_LMSNLEN)) m->lmsn[i++] = *p[0]++; m->lmsn[i] = '\0'; break; @@ -3381,7 +3401,7 @@ isdn_tty_cmd_ATand(char **p, modem_info * info) /* &V - Show registers */ p[0]++; isdn_tty_at_cout("\r\n", info); - for (i = 0; i < ISDN_MODEM_ANZREG; i++) { + for (i = 0; i < ISDN_MODEM_NUMREG; i++) { sprintf(rb, "S%02d=%03d%s", i, m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n"); isdn_tty_at_cout(rb, info); @@ -3486,7 +3506,7 @@ isdn_tty_cmd_ATS(char **p, modem_info * info) int bval; mreg = isdn_getnum(p); - if (mreg < 0 || mreg >= ISDN_MODEM_ANZREG) + if (mreg < 0 || mreg >= ISDN_MODEM_NUMREG) PARSE_ERROR1; switch (*p[0]) { case '=': @@ -3589,7 +3609,7 @@ isdn_tty_cmd_ATA(modem_info * info) isdn_command(&cmd); isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); } else - isdn_tty_modem_result(8, info); + isdn_tty_modem_result(RESULT_NO_ANSWER, info); } #ifdef CONFIG_ISDN_AUDIO @@ -3779,7 +3799,7 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info) if (!m->vpar[0]) PARSE_ERROR1; if (info->online != 1) { - isdn_tty_modem_result(8, info); + isdn_tty_modem_result(RESULT_NO_ANSWER, info); return 1; } info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); @@ -3803,7 +3823,7 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info) printk(KERN_DEBUG "AT: +VRX\n"); #endif info->vonline |= 1; - isdn_tty_modem_result(1, info); + isdn_tty_modem_result(RESULT_CONNECT, info); return 0; break; case 4: @@ -3893,7 +3913,7 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info) if (!m->vpar[0]) PARSE_ERROR1; if (info->online != 1) { - isdn_tty_modem_result(8, info); + isdn_tty_modem_result(RESULT_NO_ANSWER, info); return 1; } info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); @@ -3913,7 +3933,7 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info) #endif m->lastDLE = 0; info->vonline |= 2; - isdn_tty_modem_result(1, info); + isdn_tty_modem_result(RESULT_CONNECT, info); return 0; break; case 7: @@ -3998,13 +4018,13 @@ isdn_tty_parse_at(modem_info * info) if (info->msr & UART_MSR_DCD) PARSE_ERROR; if (info->msr & UART_MSR_RI) { - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); return; } isdn_tty_getdial(++p, ds, sizeof ds); p += strlen(p); if (!strlen(m->msn)) - isdn_tty_modem_result(10, info); + isdn_tty_modem_result(RESULT_NO_MSN_EAZ, info); else if (strlen(ds)) isdn_tty_dial(ds, info, m); else @@ -4076,9 +4096,9 @@ isdn_tty_parse_at(modem_info * info) p++; if (info->msr & UART_MSR_DCD) /* if B-Channel is up */ - isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? 1:5, info); + isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? RESULT_CONNECT:RESULT_CONNECT64000, info); else - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); return; case 'Q': /* Q - Turn Emulator messages on/off */ @@ -4171,7 +4191,7 @@ isdn_tty_parse_at(modem_info * info) #ifdef CONFIG_ISDN_AUDIO if (!info->vonline) #endif - isdn_tty_modem_result(0, info); + isdn_tty_modem_result(RESULT_OK, info); } /* Need own toupper() because standard-toupper is not available @@ -4282,7 +4302,7 @@ isdn_tty_modem_escape(void) ((jiffies - info->emu.lastplus) > PLUSWAIT2)) { info->emu.pluscount = 0; info->online = 0; - isdn_tty_modem_result(0, info); + isdn_tty_modem_result(RESULT_OK, info); } } } @@ -4304,7 +4324,7 @@ isdn_tty_modem_ring(void) modem_info *info = &dev->mdm.info[i]; if (info->msr & UART_MSR_RI) { ton = 1; - isdn_tty_modem_result(2, info); + isdn_tty_modem_result(RESULT_RING, info); } } isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton); @@ -4346,7 +4366,7 @@ isdn_tty_carrier_timeout(void) if (info->dialing) { if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) { info->dialing = 0; - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); isdn_tty_modem_hup(info, 1); } else diff --git a/drivers/isdn/isdn_tty.h b/drivers/isdn/isdn_tty.h index ff7e479f0..ed9190cfe 100644 --- a/drivers/isdn/isdn_tty.h +++ b/drivers/isdn/isdn_tty.h @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.h,v 1.18 2000/01/20 19:55:33 keil Exp $ +/* $Id: isdn_tty.h,v 1.19 2000/02/16 14:59:33 paul Exp $ * header for Linux ISDN subsystem, tty related functions (linklevel). * @@ -20,6 +20,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.h,v $ + * Revision 1.19 2000/02/16 14:59:33 paul + * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers; + * used defines for result codes; + * fixed RING ... RUNG problem (no empty lines in between). + * * Revision 1.18 2000/01/20 19:55:33 keil * Add FAX Class 1 support * @@ -110,7 +115,7 @@ * Definition of some special Registers of AT-Emulator */ #define REG_RINGATA 0 -#define REG_RINGCNT 1 +#define REG_RINGCNT 1 /* ring counter register */ #define REG_ESC 2 #define REG_CR 3 #define REG_LF 4 @@ -118,10 +123,10 @@ #define REG_WAITC 7 -#define REG_RESP 12 -#define BIT_RESP 1 -#define REG_RESPNUM 12 -#define BIT_RESPNUM 2 +#define REG_RESP 12 /* show response messages register */ +#define BIT_RESP 1 /* show response messages bit */ +#define REG_RESPNUM 12 /* show numeric responses register */ +#define BIT_RESPNUM 2 /* show numeric responses bit */ #define REG_ECHO 12 #define BIT_ECHO 4 #define REG_DCD 12 @@ -144,8 +149,8 @@ #define BIT_RESPXT 8 #define REG_CIDONCE 13 #define BIT_CIDONCE 16 -#define REG_RUNG 13 -#define BIT_RUNG 64 +#define REG_RUNG 13 /* show RUNG message register */ +#define BIT_RUNG 64 /* show RUNG message bit */ #define REG_DISPLAY 13 #define BIT_DISPLAY 128 @@ -163,6 +168,21 @@ #define BIT_CPN 1 #define BIT_CPNFCON 2 +/* defines for result codes */ +#define RESULT_OK 0 +#define RESULT_CONNECT 1 +#define RESULT_RING 2 +#define RESULT_NO_CARRIER 3 +#define RESULT_ERROR 4 +#define RESULT_CONNECT64000 5 +#define RESULT_NO_DIALTONE 6 +#define RESULT_BUSY 7 +#define RESULT_NO_ANSWER 8 +#define RESULT_RINGING 9 +#define RESULT_NO_MSN_EAZ 10 +#define RESULT_VCON 11 +#define RESULT_RUNG 12 + #define TTY_IS_FCLASS1(info) \ ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \ (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1)) diff --git a/drivers/isdn/sc/debug.h b/drivers/isdn/sc/debug.h index f813b5c99..ba100543d 100644 --- a/drivers/isdn/sc/debug.h +++ b/drivers/isdn/sc/debug.h @@ -1,5 +1,5 @@ /* - * $Id: debug.h,v 1.1 1996/11/07 13:07:42 fritz Exp $ + * $Id: debug.h,v 1.2 2000/02/26 01:00:53 keil Exp $ * Copyright (C) 1996 SpellCaster Telecommunications Inc. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index d66393649..5a5d5fcf0 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -361,8 +361,7 @@ static inline unsigned int send_pcb_fast(unsigned int base_addr, unsigned char b static inline void prime_rx(struct net_device *dev) { elp_device *adapter = dev->priv; - while (adapter->rx_active < ELP_RX_PCBS && - netif_running(dev->state)) { + while (adapter->rx_active < ELP_RX_PCBS && netif_running(dev)) { if (!start_receive(dev, &adapter->itx_pcb)) break; } diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index c2eceb8db..6169eb742 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -87,7 +87,7 @@ an MMIO register read. #include <asm/io.h> -#define RTL8139_VERSION "0.9.3" +#define RTL8139_VERSION "0.9.4" #define RTL8139_MODULE_NAME "8139too" #define RTL8139_DRIVER_NAME RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION #define PFX RTL8139_MODULE_NAME ": " @@ -101,8 +101,8 @@ an MMIO register read. #define DPRINTK(fmt, args...) #endif -#define RTL8139_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */ -#if RTL8139_NDEBUG +#undef RTL8139_NDEBUG /* define to 1 to disable lightweight runtime checks */ +#ifdef RTL8139_NDEBUG #define assert(expr) #else #define assert(expr) \ @@ -144,6 +144,7 @@ static int multicast_filter_limit = 32; #define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */ #define TX_DMA_BURST 4 /* Calculate as 16<<val. */ + /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (6*HZ) @@ -154,12 +155,13 @@ enum { HAS_LNK_CHNG = 0x040000, }; -#define RTL_IO_SIZE 0x80 +#define RTL_MIN_IO_SIZE 0x80 +#define RTL8139B_IO_SIZE 0xFF -#define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG +#define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG typedef enum { - RTL8139, + RTL8139 = 0, RTL8139_CB, SMC1211TX, /*MPX5030,*/ @@ -168,17 +170,16 @@ typedef enum { } chip_t; +/* indexed by chip_t, above */ static struct { - chip_t chip; const char *name; } chip_info[] __devinitdata = { - { RTL8139, "RealTek RTL8139 Fast Ethernet"}, - { RTL8139_CB, "RealTek RTL8139B PCI/CardBus"}, - { SMC1211TX, "SMC1211TX EZCard 10/100 (RealTek RTL8139)"}, -/* { MPX5030, "Accton MPX5030 (RealTek RTL8139)"},*/ - { DELTA8139, "Delta Electronics 8139 10/100BaseTX"}, - { ADDTRON8139, "Addtron Technolgy 8139 10/100BaseTX"}, - {0,}, + { "RealTek RTL8139 Fast Ethernet" }, + { "RealTek RTL8139B PCI/CardBus" }, + { "SMC1211TX EZCard 10/100 (RealTek RTL8139)" }, +/* { MPX5030, "Accton MPX5030 (RealTek RTL8139)" },*/ + { "Delta Electronics 8139 10/100BaseTX" }, + { "Addtron Technolgy 8139 10/100BaseTX" }, }; @@ -298,6 +299,14 @@ enum Config1Bits { Cfg1_LED1 = 0x80, }; +enum RxConfigBits { + RxCfgRcv8K = 0, + RxCfgRcv16K = (1 << 11), + RxCfgRcv32K = (1 << 12), + RxCfgRcv64K = (1 << 11) | (1 << 12), +}; + + /* Twister tuning parameters from RealTek. Completely undocumented, but required to tune bad links. */ enum CSCRBits { @@ -307,6 +316,14 @@ enum CSCRBits { CSCR_LinkDownOffCmd = 0x003c0, CSCR_LinkDownCmd = 0x0f3c0, }; + + +enum Cfg9346Bits { + Cfg9346_Lock = 0x00, + Cfg9346_Unlock = 0xC0, +}; + + #define PARA78_default 0x78fa8388 #define PARA7c_default 0xcb38de43 /* param[0][3] */ #define PARA7c_xxx 0xcb38de43 @@ -327,7 +344,6 @@ struct ring_info { struct rtl8139_private { chip_t chip; void *mmio_addr; - spinlock_t lock; int drv_flags; struct pci_dev *pci_dev; struct net_device_stats stats; @@ -349,6 +365,8 @@ struct rtl8139_private { unsigned int media2:4; /* Secondary monitored media port. */ unsigned int medialock:1; /* Don't sense media type. */ unsigned int mediasense:1; /* Media sensing in progress. */ + int extended_regs; /* bool: supports regs > 0x80 ? */ + spinlock_t lock; }; MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>"); @@ -374,6 +392,8 @@ static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static struct net_device_stats *rtl8139_get_stats (struct net_device *dev); static inline u32 ether_crc (int length, unsigned char *data); static void rtl8139_set_rx_mode (struct net_device *dev); +static void rtl8139_hw_start (struct net_device *dev); + /* write MMIO register, with flush */ /* Flush avoids rtl8139 bug w/ posted MMIO writes */ @@ -409,30 +429,17 @@ static const u16 rtl8139_intr_mask = TxErr | TxOK | RxErr | RxOK; static const unsigned int rtl8139_rx_config = - (RX_FIFO_THRESH << 13) | - (RX_BUF_LEN_IDX << 11) | + (RX_FIFO_THRESH << 13) | (RxCfgRcv32K) | (RX_DMA_BURST << 8); -static const char * __devinit rtl8139_name_from_chip (chip_t chip) -{ - int i; - - for (i = 0; i < arraysize (chip_info); i++) - if (chip == chip_info[i].chip) - return chip_info[i].name; - - return "unknown"; -} - - static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out) { void *ioaddr = NULL; u8 tmp8; int rc; - u32 pio_start, pio_end, pio_flags; - u32 mmio_start, mmio_end, mmio_flags; + u32 pio_start, pio_end, pio_flags, pio_len; + u32 mmio_start, mmio_end, mmio_flags, mmio_len; DPRINTK ("ENTER\n"); @@ -444,48 +451,67 @@ static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out) pio_start = pci_resource_start (pdev, 0); pio_end = pci_resource_end (pdev, 0); pio_flags = pci_resource_flags (pdev, 0); + pio_len = pci_resource_len (pdev, 0); mmio_start = pci_resource_start (pdev, 1); mmio_end = pci_resource_end (pdev, 1); mmio_flags = pci_resource_flags (pdev, 1); + mmio_len = pci_resource_len (pdev, 1); /* make sure PCI base addr 0 is PIO */ - if (pio_start == 0 || pio_end <= pio_start || - (!(pio_flags & IORESOURCE_IO))) { - printk (KERN_ERR PFX "no PIO resource, aborting\n"); - return -ENODEV; + if (!(pio_flags & IORESOURCE_IO)) { + printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n"); + rc = -ENODEV; + goto err_out; } /* make sure PCI base addr 1 is MMIO */ - if (mmio_start == 0 || mmio_end <= mmio_start || - (!(mmio_flags & IORESOURCE_MEM))) { - printk (KERN_ERR PFX "no MMIO resource, aborting\n"); - return -ENODEV; + if (!(mmio_flags & IORESOURCE_MEM)) { + printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n"); + rc = -ENODEV; + goto err_out; + } + + /* check for weird/broken PCI region reporting */ + if ((pio_len != mmio_len) || + (pio_len < RTL_MIN_IO_SIZE) || + (mmio_len < RTL_MIN_IO_SIZE)) { + printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n"); + rc = -ENODEV; + goto err_out; } /* make sure our PIO region in PCI space is available */ - if (!request_region (pio_start, RTL_IO_SIZE, RTL8139_MODULE_NAME)) { + if (!request_region (pio_start, pio_len, RTL8139_MODULE_NAME)) { printk (KERN_ERR PFX "no I/O resource available, aborting\n"); - return -EBUSY; + rc = -EBUSY; + goto err_out; } /* make sure our MMIO region in PCI space is available */ - if (!request_mem_region (mmio_start, RTL_IO_SIZE, RTL8139_MODULE_NAME)) { - release_region (pio_start, RTL_IO_SIZE); + if (!request_mem_region (mmio_start, mmio_len, RTL8139_MODULE_NAME)) { printk (KERN_ERR PFX "no mem resource available, aborting\n"); - return -EBUSY; + rc = -EBUSY; + goto err_out_free_pio; } /* enable device (incl. PCI PM wakeup), and bus-mastering */ - pci_enable_device (pdev); + rc = pci_enable_device (pdev); + if (rc) { + printk (KERN_ERR PFX "cannot enable PCI device (bus %d, " + "devfn %d), aborting\n", + pdev->bus->number, pdev->devfn); + goto err_out_free_mmio; + } + pci_set_master (pdev); /* ioremap MMIO region */ - ioaddr = ioremap (mmio_start, RTL_IO_SIZE); + ioaddr = ioremap (mmio_start, mmio_len); if (ioaddr == NULL) { printk (KERN_ERR PFX "cannot remap MMIO, aborting\n"); rc = -EIO; - goto err_out; + goto err_out_free_mmio; } /* Bring the chip out of low-power mode. */ @@ -496,12 +522,12 @@ static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out) if ((tmp8 & Cfg1_PIO) == 0) { printk (KERN_ERR PFX "PIO not enabled, Cfg1=%02X, aborting\n", tmp8); rc = -EIO; - goto err_out; + goto err_out_iounmap; } if ((tmp8 & Cfg1_MMIO) == 0) { printk (KERN_ERR PFX "MMIO not enabled, Cfg1=%02X, aborting\n", tmp8); rc = -EIO; - goto err_out; + goto err_out_iounmap; } /* sanity checks -- ensure PIO and MMIO registers agree */ @@ -514,28 +540,43 @@ static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out) *ioaddr_out = ioaddr; return 0; +err_out_iounmap: + assert (ioaddr > 0); + iounmap (ioaddr); +err_out_free_mmio: + release_mem_region (mmio_start, mmio_len); +err_out_free_pio: + release_region (pio_start, pio_len); err_out: - if (ioaddr) - iounmap (ioaddr); - release_region (pio_start, RTL_IO_SIZE); - release_mem_region (mmio_start, RTL_IO_SIZE); DPRINTK ("EXIT, returning %d\n", rc); return rc; } -static int __devinit rtl8139_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +static int __devinit rtl8139_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) { struct net_device *dev; struct rtl8139_private *tp; int i, addr_len, option = -1; void *ioaddr = NULL; +#ifndef RTL8139_NDEBUG + static int printed_version = 0; +#endif /* RTL8139_NDEBUG */ + DPRINTK ("ENTER\n"); assert (pdev != NULL); assert (ent != NULL); - + +#ifndef RTL8139_NDEBUG + if (!printed_version) { + printk (KERN_INFO RTL8139_DRIVER_NAME " loaded\n"); + printed_version = 1; + } +#endif /* RTL8139_NDEBUG */ + i = rtl8139_init_pci (pdev, &ioaddr); if (i < 0) { DPRINTK ("EXIT, returning %d\n", i); @@ -571,31 +612,34 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, const struct pci_de dev->irq = pdev->irq; dev->base_addr = pci_resource_start (pdev, 1); + /* dev->priv/tp zeroed in init_etherdev */ dev->priv = tp = (void *) (((long)dev->priv + PRIV_ALIGN) & ~PRIV_ALIGN); - printk (KERN_INFO "%s: %s at 0x%lx, IRQ %d, " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", - dev->name, rtl8139_name_from_chip(ent->driver_data), - dev->base_addr, dev->irq, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); - - /* tp zeroed in init_etherdev */ tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | RTL8139_CAPS; tp->pci_dev = pdev; tp->chip = ent->driver_data; tp->mmio_addr = ioaddr; + tp->extended_regs = + (pci_resource_len (pdev, 0) == RTL8139B_IO_SIZE) ? 1 : 0; tp->lock = SPIN_LOCK_UNLOCKED; PCI_SET_DRIVER_DATA (pdev, dev); tp->phys[0] = 32; + printk (KERN_INFO "%s: %s at 0x%lx, IRQ %d,%s " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + dev->name, chip_info[ent->driver_data].name, + dev->base_addr, dev->irq, + tp->extended_regs ? " 8139B regs," : "", + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); + /* Put the chip into low-power mode. */ - RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, 0x03); /* Enable PM & PCI VPD */ RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ @@ -635,8 +679,10 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev) unregister_netdev (dev); iounmap (np->mmio_addr); - release_region (pci_resource_start (pdev, 0), RTL_IO_SIZE); - release_mem_region (pci_resource_start (pdev, 1), RTL_IO_SIZE); + release_region (pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0)); + release_mem_region (pci_resource_start (pdev, 1), + pci_resource_len (pdev, 1)); #ifndef RTL8139_NDEBUG /* poison memory before freeing */ @@ -644,7 +690,7 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev) sizeof (struct net_device) + sizeof (struct rtl8139_private) + PRIV_ALIGN); -#endif +#endif /* RTL8139_NDEBUG */ kfree (dev); @@ -851,16 +897,14 @@ static void mdio_write (struct net_device *dev, int phy_id, int location, static int rtl8139_open (struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; +#ifdef RTL8139_DEBUG void *ioaddr = tp->mmio_addr; - int i; +#endif DPRINTK ("ENTER\n"); MOD_INC_USE_COUNT; - /* Soft reset the chip. */ - RTL_W8 (ChipCmd, CmdReset); - if (request_irq (dev->irq, &rtl8139_interrupt, SA_SHIRQ, dev->name, dev)) { DPRINTK ("EXIT, returning -EBUSY\n"); MOD_DEC_USE_COUNT; @@ -891,44 +935,7 @@ static int rtl8139_open (struct net_device *dev) tp->full_duplex = tp->duplex_lock; tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) - if ((RTL_R8 (ChipCmd) & CmdReset) == 0) - break; - - RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); - RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); - - /* Must enable Tx/Rx before setting transfer thresholds! */ - RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); - RTL_W32 (RxConfig, rtl8139_rx_config); - RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x00000000); - - /* Reset N-Way to chipset defaults */ - RTL_W16 (BasicModeCtrl, (1<<15)|(1<<12)|(1<<9)); - for (i = 1000; i > 0; i--) - if ((RTL_R8 (BasicModeCtrl) & (1<<15)) == 0) - break; - - /* Set N-Way to sane defaults */ - RTL_W16 (FIFOTMS, 0x0000); - RTL_W16 (NWayAdvert, (1<<13)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|0x1); - RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8)); - - RTL_W8 (Cfg9346, 0xC0); - RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); - RTL_W8 (Cfg9346, 0x00); - - RTL_W32 (RxBuf, tp->rx_ring_dma); - - /* Start the chip's Tx and Rx process. */ - RTL_W32 (RxMissed, 0); - rtl8139_set_rx_mode (dev); - - RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); - - /* Enable all known interrupts by setting the interrupt mask. */ - RTL_W16 (IntrMask, rtl8139_intr_mask); + rtl8139_hw_start (dev); DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d" " GP Pins %2.2x %s-duplex.\n", @@ -944,23 +951,26 @@ static int rtl8139_open (struct net_device *dev) tp->timer.function = &rtl8139_timer; add_timer (&tp->timer); - netif_start_queue (dev); - DPRINTK ("EXIT, returning 0\n"); return 0; } + /* Start the hardware at open or resume. */ static void rtl8139_hw_start (struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; int i; + unsigned long flags; DPRINTK ("ENTER\n"); + + spin_lock_irqsave (&tp->lock, flags); /* Soft reset the chip. */ RTL_W8 (ChipCmd, CmdReset); + /* Check that the chip has finished the reset. */ for (i = 1000; i > 0; i--) if ((RTL_R8 (ChipCmd) & CmdReset) == 0) @@ -970,8 +980,9 @@ static void rtl8139_hw_start (struct net_device *dev) RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); - /* Hmmm, do these belong here? */ - RTL_W8 (Cfg9346, 0x00); + /* unlock Config[01234] and BMCR register writes */ + RTL_W8 (Cfg9346, Cfg9346_Unlock); + tp->cur_rx = 0; /* Must enable Tx/Rx before setting transfer thresholds! */ @@ -993,19 +1004,30 @@ static void rtl8139_hw_start (struct net_device *dev) RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8)); /* check_duplex() here. */ - RTL_W8 (Cfg9346, 0xC0); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); - RTL_W8 (Cfg9346, 0x00); + + /* lock Config[01234] and BMCR register writes */ + RTL_W8 (Cfg9346, Cfg9346_Lock); RTL_W32 (RxBuf, tp->rx_ring_dma); + /* Start the chip's Tx and Rx process. */ RTL_W32 (RxMissed, 0); + + /* release lock cuz set_rx_mode wants it */ + spin_unlock_irqrestore (&tp->lock, flags); rtl8139_set_rx_mode (dev); + spin_lock_irqsave (&tp->lock, flags); + RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); + /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16 (IntrMask, rtl8139_intr_mask); - netif_start_queue (dev); + if (netif_queue_stopped (dev)) + netif_start_queue (dev); + + spin_unlock_irqrestore (&tp->lock, flags); DPRINTK ("EXIT\n"); } @@ -1111,9 +1133,14 @@ static void rtl8139_timer (unsigned long data) struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; int next_tick = 60 * HZ; - int mii_reg5 = mdio_read (dev, tp->phys[0], 5); + int mii_reg5; + unsigned long flags; DPRINTK ("ENTER\n"); + + spin_lock_irqsave (&tp->lock, flags); + + mii_reg5 = mdio_read (dev, tp->phys[0], 5); if (!tp->duplex_lock && mii_reg5 != 0xffff) { int duplex = (mii_reg5 & 0x0100) @@ -1125,9 +1152,9 @@ static void rtl8139_timer (unsigned long data) " partner ability of %4.4x.\n", dev->name, tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5); - RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); - RTL_W8 (Cfg9346, 0x00); + RTL_W8 (Cfg9346, Cfg9346_Lock); } } @@ -1144,6 +1171,8 @@ static void rtl8139_timer (unsigned long data) dev->name, RTL_R8 (Config0), RTL_R8 (Config1)); + spin_unlock_irqrestore (&tp->lock, flags); + tp->timer.expires = jiffies + next_tick; add_timer (&tp->timer); @@ -1156,10 +1185,11 @@ static void rtl8139_tx_timeout (struct net_device *dev) struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; int mii_reg, i; + unsigned long flags; DPRINTK ("ENTER\n"); - netif_stop_queue (dev); + spin_lock_irqsave (&tp->lock, flags); DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x " "media %2.2x.\n", dev->name, @@ -1201,6 +1231,8 @@ static void rtl8139_tx_timeout (struct net_device *dev) } } + spin_unlock_irqrestore (&tp->lock, flags); + rtl8139_hw_start (dev); DPRINTK ("EXIT\n"); @@ -1227,6 +1259,7 @@ static void rtl8139_init_ring (struct net_device *dev) DPRINTK ("EXIT\n"); } + static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; @@ -1236,13 +1269,11 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) DPRINTK ("ENTER\n"); - netif_stop_queue (dev); + spin_lock_irqsave (&tp->lock, flags); /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; - spin_lock_irqsave (&tp->lock, flags); - tp->tx_info[entry].skb = skb; if ((long) skb->data & 3) { /* Must use alignment buffer. */ tp->tx_info[entry].mapping = 0; @@ -1263,12 +1294,12 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); dev->trans_start = jiffies; - if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) /* Typical path */ - netif_start_queue (dev); + if (++tp->cur_tx - tp->dirty_tx >= NUM_TX_DESC) + netif_stop_queue (dev); spin_unlock_irqrestore (&tp->lock, flags); - - DPRINTK ("%s: Queued Tx packet at %p size %lu to slot %d.\n", + + DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", dev->name, skb->data, skb->len, entry); DPRINTK ("EXIT\n"); @@ -1277,16 +1308,16 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) static inline void rtl8139_tx_interrupt (struct net_device *dev, - struct rtl8139_private *tp) + struct rtl8139_private *tp, + void *ioaddr) { - void *ioaddr; unsigned int dirty_tx; assert (dev != NULL); assert (tp != NULL); - + assert (ioaddr != NULL); + dirty_tx = tp->dirty_tx; - ioaddr = tp->mmio_addr; while (tp->cur_tx - dirty_tx > 0) { int entry = dirty_tx % NUM_TX_DESC; @@ -1338,8 +1369,6 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev, dirty_tx++; if (tp->cur_tx - dirty_tx < NUM_TX_DESC) netif_wake_queue (dev); - else - netif_stop_queue (dev); } #ifndef RTL8139_NDEBUG @@ -1349,7 +1378,7 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev, dev->name, dirty_tx, tp->cur_tx); dirty_tx += NUM_TX_DESC; } -#endif +#endif /* RTL8139_NDEBUG */ tp->dirty_tx = dirty_tx; } @@ -1358,11 +1387,18 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev, /* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the field alignments and semantics. */ static inline void rtl8139_rx_interrupt (struct net_device *dev, - struct rtl8139_private *tp) + struct rtl8139_private *tp, + void *ioaddr) { - void *ioaddr = tp->mmio_addr; - unsigned char *rx_ring = tp->rx_ring; - u16 cur_rx = tp->cur_rx; + unsigned char *rx_ring; + u16 cur_rx; + + assert (dev != NULL); + assert (tp != NULL); + assert (ioaddr != NULL); + + rx_ring = tp->rx_ring; + cur_rx = tp->cur_rx; DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, @@ -1376,15 +1412,17 @@ static inline void rtl8139_rx_interrupt (struct net_device *dev, le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); int rx_size = rx_status >> 16; -#ifdef RTL8139_DEBUG - int i; DPRINTK ("%s: rtl8139_rx() status %4.4x, size %4.4x," " cur %4.4x.\n", dev->name, rx_status, rx_size, cur_rx); +#if RTL8139_DEBUG > 2 + { + int i; DPRINTK ("%s: Frame contents ", dev->name); for (i = 0; i < 70; i++) printk (" %2.2x", rx_ring[ring_offset + i]); printk (".\n"); + } #endif /* E. Gill */ @@ -1490,23 +1528,16 @@ static inline void rtl8139_rx_interrupt (struct net_device *dev, static inline int rtl8139_weird_interrupt (struct net_device *dev, struct rtl8139_private *tp, + void *ioaddr, int status, int link_changed) { - void *ioaddr; - DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n", dev->name, status); assert (dev != NULL); assert (tp != NULL); - - ioaddr = tp->mmio_addr; - - if (status == 0xffffffff) { - printk (KERN_WARNING PFX "abnormal interrupt, card ejected? (ok to ignore)\n"); - return -1; - } - + assert (ioaddr != NULL); + /* Update the error count. */ tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); @@ -1519,9 +1550,9 @@ static inline int rtl8139_weird_interrupt (struct net_device *dev, || tp->duplex_lock; if (tp->full_duplex != duplex) { tp->full_duplex = duplex; - RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); - RTL_W8 (Cfg9346, 0x00); + RTL_W8 (Cfg9346, Cfg9346_Lock); } status &= ~RxUnderrun; } @@ -1559,15 +1590,20 @@ static void rtl8139_interrupt (int irq, void *dev_instance, struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; int boguscnt = max_interrupt_work; void *ioaddr = tp->mmio_addr; - int link_changed = 0; /* Grrr, avoid bogus "uninitialized" warning */ - - spin_lock_irq (&tp->lock); + int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */ + spin_lock (&tp->lock); + /* disable interrupt generation while handling this interrupt */ RTL_W16 (IntrMask, 0x0000); do { - int status = RTL_R16 (IntrStatus); + status = RTL_R16 (IntrStatus); + + /* h/w no longer present (hotplug?) or major error, bail */ + if (status == 0xFFFFFFFF) + break; + /* Acknowledge all of the current interrupt sources ASAP, but an first get an additional status bit from CSCR. */ if (status & RxUnderrun) @@ -1606,42 +1642,45 @@ static void rtl8139_interrupt (int irq, void *dev_instance, /* Check uncommon events with one test. */ if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | RxErr)) - if (rtl8139_weird_interrupt (dev, tp, status, - link_changed) == -1) - break; + rtl8139_weird_interrupt (dev, tp, ioaddr, + status, link_changed); if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ - rtl8139_rx_interrupt (dev, tp); + rtl8139_rx_interrupt (dev, tp, ioaddr); if (status & (TxOK | TxErr)) - rtl8139_tx_interrupt (dev, tp); - - if (--boguscnt < 0) { - printk (KERN_WARNING - "%s: Too much work at interrupt, " - "IntrStatus=0x%4.4x.\n", dev->name, - status); - /* Clear all interrupt sources. */ - RTL_W16 (IntrStatus, 0xffff); - break; - } - } while (1); + rtl8139_tx_interrupt (dev, tp, ioaddr); + + boguscnt--; + } while (boguscnt > 0); + + if (boguscnt <= 0) { + printk (KERN_WARNING + "%s: Too much work at interrupt, " + "IntrStatus=0x%4.4x.\n", dev->name, + status); + + /* Clear all interrupt sources. */ + RTL_W16 (IntrStatus, 0xffff); + } /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16 (IntrMask, rtl8139_intr_mask); - spin_unlock_irq (&tp->lock); - + spin_unlock (&tp->lock); + DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, RTL_R16 (IntrStatus)); + dev->name, RTL_R16 (IntrStatus)); } + static int rtl8139_close (struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; int i; + unsigned long flags; DPRINTK ("ENTER\n"); @@ -1650,6 +1689,8 @@ static int rtl8139_close (struct net_device *dev) DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, RTL_R16 (IntrStatus)); + spin_lock_irqsave (&tp->lock, flags); + /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0x0000); @@ -1660,7 +1701,13 @@ static int rtl8139_close (struct net_device *dev) tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); + spin_unlock_irqrestore (&tp->lock, flags); + del_timer (&tp->timer); + + /* snooze for a small bit */ + if (current->need_resched) + schedule (); free_irq (dev->irq, dev); @@ -1685,7 +1732,7 @@ static int rtl8139_close (struct net_device *dev) tp->tx_bufs = NULL; /* Green! Put the chip in low-power mode. */ - RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, 0x03); RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ @@ -1695,10 +1742,13 @@ static int rtl8139_close (struct net_device *dev) return 0; } + static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; u16 *data = (u16 *) & rq->ifr_data; + unsigned long flags; + int rc = 0; DPRINTK ("ENTER\n"); @@ -1706,24 +1756,34 @@ static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = tp->phys[0] & 0x3f; /* Fall Through */ + case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */ + spin_lock_irqsave (&tp->lock, flags); data[3] = mdio_read (dev, data[0], data[1] & 0x1f); - DPRINTK ("EXIT\n"); - return 0; + spin_unlock_irqrestore (&tp->lock, flags); + break; + case SIOCDEVPRIVATE + 2: /* Write the specified MII register */ - if (!capable (CAP_NET_ADMIN)) - return -EPERM; + if (!capable (CAP_NET_ADMIN)) { + rc = -EPERM; + break; + } + + spin_lock_irqsave (&tp->lock, flags); mdio_write (dev, data[0], data[1] & 0x1f, data[2]); - DPRINTK ("EXIT\n"); - return 0; + spin_unlock_irqrestore (&tp->lock, flags); + break; + default: - DPRINTK ("EXIT\n"); - return -EOPNOTSUPP; + rc = -EOPNOTSUPP; + break; } - DPRINTK ("EXIT\n"); + DPRINTK ("EXIT, returning %d\n", rc); + return rc; } + static struct net_device_stats *rtl8139_get_stats (struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; @@ -1734,8 +1794,14 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev) assert (tp != NULL); if (netif_running(dev)) { + unsigned long flags; + + spin_lock_irqsave (&tp->lock, flags); + tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); + + spin_unlock_irqrestore (&tp->lock, flags); } DPRINTK ("EXIT\n"); @@ -1765,12 +1831,14 @@ static inline u32 ether_crc (int length, unsigned char *data) return crc; } + static void rtl8139_set_rx_mode (struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; u32 mc_filter[2]; /* Multicast hash filter */ int i, rx_mode; + unsigned long flags; DPRINTK ("ENTER\n"); @@ -1803,11 +1871,19 @@ static void rtl8139_set_rx_mode (struct net_device *dev) dmi_addr) >> 26, mc_filter); } + + /* if called from irq handler, lock already acquired */ + if (!in_irq ()) + spin_lock_irqsave (&tp->lock, flags); + /* We can safely update without stopping the chip. */ RTL_W32 (RxConfig, rtl8139_rx_config | rx_mode); RTL_W32_F (MAR0 + 0, mc_filter[0]); RTL_W32_F (MAR0 + 4, mc_filter[1]); + if (!in_irq ()) + spin_unlock_irqrestore (&tp->lock, flags); + DPRINTK ("EXIT\n"); } @@ -1817,9 +1893,12 @@ static void rtl8139_suspend (struct pci_dev *pdev) struct net_device *dev = PCI_GET_DRIVER_DATA (pdev); struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; + unsigned long flags; - netif_stop_queue (dev); + netif_device_detach (dev); + spin_lock_irqsave (&tp->lock, flags); + /* Disable interrupts, stop Tx and Rx. */ RTL_W16 (IntrMask, 0x0000); RTL_W8 (ChipCmd, 0x00); @@ -1827,6 +1906,8 @@ static void rtl8139_suspend (struct pci_dev *pdev) /* Update the error counts. */ tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); + + spin_unlock_irqrestore (&tp->lock, flags); } @@ -1834,7 +1915,8 @@ static void rtl8139_resume (struct pci_dev *pdev) { struct net_device *dev = PCI_GET_DRIVER_DATA (pdev); - rtl8139_hw_start(dev); + netif_device_attach (dev); + rtl8139_hw_start (dev); } @@ -1850,22 +1932,7 @@ static struct pci_driver rtl8139_pci_driver = { static int __init rtl8139_init_module (void) { - int rc; - - DPRINTK ("ENTER\n"); - - rc = pci_register_driver (&rtl8139_pci_driver); - - if (rc > 0) { - printk (KERN_INFO RTL8139_DRIVER_NAME - " loaded (%d device%s registered)\n", - rc, rc > 1 ? "s" : ""); - } else { - pci_unregister_driver (&rtl8139_pci_driver); - } - - DPRINTK ("EXIT\n"); - return rc > 0 ? 0 : -ENODEV; + return pci_module_init (&rtl8139_pci_driver); } diff --git a/drivers/net/Config.in b/drivers/net/Config.in index f3cc0af3a..abf7958ef 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -254,9 +254,7 @@ comment 'Wireless LAN (non-hamradio)' bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO if [ "$CONFIG_NET_RADIO" = "y" ]; then dep_tristate ' STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET - if [ "$CONFIG_OBSOLETE" = "y" ]; then - tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN - fi + tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN tristate ' Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN tristate ' Aironet 4500/4800 series adapters' CONFIG_AIRONET4500 dep_tristate ' Aironet 4500/4800 ISA/PCI/PNP/365 support ' CONFIG_AIRONET4500_NONCS $CONFIG_AIRONET4500 diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 3c2ede8f5..550a97ae2 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -18,7 +18,7 @@ SUB_DIRS := MOD_SUB_DIRS := MOD_IN_SUB_DIRS := ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin \ - arcnet skfp + arcnet skfp tulip O_TARGET := net.o MOD_LIST_NAME := NET_MODULES @@ -38,6 +38,15 @@ else endif endif +ifeq ($(CONFIG_TULIP),y) + SUB_DIRS += tulip + obj-y += tulip/tulip.o +else + ifeq ($(CONFIG_TULIP),m) + MOD_SUB_DIRS += tulip + endif +endif + ifeq ($(CONFIG_IRDA),y) SUB_DIRS += irda MOD_IN_SUB_DIRS += irda @@ -122,7 +131,6 @@ obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o obj-$(CONFIG_PCNET32) += pcnet32.o obj-$(CONFIG_EEPRO100) += eepro100.o obj-$(CONFIG_TLAN) += tlan.o -obj-$(CONFIG_TULIP) += tulip.o obj-$(CONFIG_EPIC100) += epic100.o obj-$(CONFIG_SIS900) += sis900.o obj-$(CONFIG_DM9102) += dmfe.o diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 8410c0cf8..404d4a996 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -536,6 +536,9 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev, static int did_version = 0; /* Already printed version info. */ + if (speedo_debug > 0 && did_version++ == 0) + printk(version); + #ifdef USE_IO ioaddr = pci_resource_start (pdev, 0); #else @@ -569,9 +572,6 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev, } #endif - if (speedo_debug > 0 && did_version++ == 0) - printk(version); - tx_ring = pci_alloc_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats), &tx_ring_dma); if (!tx_ring) { @@ -604,7 +604,11 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev, acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; } - pci_enable_device (pdev); + if (pci_enable_device (pdev)) { + printk(KERN_ERR PFX "Could not enable PCI device\n"); + goto err_out_free_netdev; + } + pci_set_master (pdev); /* Read the station address EEPROM before doing the reset. @@ -732,11 +736,12 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev, /* Return the chip to its original power state. */ pci_set_power_state (pdev, acpi_idle_state); + pdev->driver_data = dev; + dev->base_addr = ioaddr; dev->irq = irq; sp = dev->priv; - memset(sp, 0, sizeof(*sp)); sp->pdev = pdev; sp->acpi_pwr = acpi_idle_state; @@ -872,6 +877,8 @@ speedo_open(struct net_device *dev) if (speedo_debug > 1) printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq); + MOD_INC_USE_COUNT; + pci_set_power_state(sp->pdev, 0); /* Set up the Tx queue early.. */ @@ -882,12 +889,13 @@ speedo_open(struct net_device *dev) spin_lock_init(&sp->lock); /* .. we can safely take handler calls during init. */ - if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) + if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; return -EBUSY; - - MOD_INC_USE_COUNT; + } dev->if_port = sp->default_port; + #if 0 /* With some transceivers we must retrigger negotiation to reset power-up errors. */ @@ -1174,8 +1182,6 @@ speedo_start_xmit(struct sk_buff *skb, struct net_device *dev) long ioaddr = dev->base_addr; int entry; - netif_stop_queue (dev); - /* Caution: the write order is important here, set the base address with the "ownership" bits last. */ @@ -1216,16 +1222,15 @@ speedo_start_xmit(struct sk_buff *skb, struct net_device *dev) } if (sp->cur_tx - sp->dirty_tx >= TX_QUEUE_LIMIT) { sp->tx_full = 1; + netif_stop_queue (dev); } spin_unlock_irqrestore(&sp->lock, flags); } + wait_for_cmd_done(ioaddr + SCBCmd); outw(CUResume, ioaddr + SCBCmd); dev->trans_start = jiffies; - if (! sp->tx_full) - netif_start_queue (dev); - return 0; } @@ -1328,22 +1333,18 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs) && sp->cur_tx - dirty_tx < TX_QUEUE_LIMIT - 1) { /* The ring is no longer full, clear tbusy. */ sp->tx_full = 0; - } - - if (sp->tx_full) - netif_stop_queue (dev); - else netif_wake_queue (dev); + } } - if (--boguscnt < 0) { - printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n", - dev->name, status); - /* Clear all interrupt sources. */ - outl(0xfc00, ioaddr + SCBStatus); - break; - } - } while (1); + } while (--boguscnt > 0); + + if (boguscnt <= 0) { + printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n", + dev->name, status); + /* Clear all interrupt sources. */ + outl(0xfc00, ioaddr + SCBStatus); + } if (speedo_debug > 3) printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", @@ -1502,8 +1503,8 @@ speedo_close(struct net_device *dev) /* Clear the Tx descriptors. */ if (skb) { pci_unmap_single(sp->pdev, - le32_to_cpu(sp->tx_ring[i].tx_buf_addr0), - skb->len, PCI_DMA_TODEVICE); + le32_to_cpu(sp->tx_ring[i].tx_buf_addr0), + skb->len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); } } @@ -1811,8 +1812,6 @@ static void __devexit eepro100_remove_one (struct pci_dev *pdev) iounmap ((char *) dev->base_addr); #endif - pci_set_power_state (pdev, sp->acpi_pwr); - pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats), sp->tx_ring, sp->tx_ring_dma); @@ -1841,23 +1840,10 @@ static struct pci_driver eepro100_driver = { static int __init eepro100_init_module(void) { - int cards_found; - if (debug >= 0) speedo_debug = debug; - /* Always emit the version message. */ - if (speedo_debug) - printk(KERN_INFO "%s", version); - - cards_found = pci_register_driver (&eepro100_driver); - if (cards_found <= 0) { - printk(KERN_INFO PFX "No cards found, driver not installed.\n"); - pci_unregister_driver (&eepro100_driver); - return -ENODEV; - } - - return 0; + return pci_module_init (&eepro100_driver); } diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index b1871485a..8aa3ef765 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -752,8 +752,8 @@ static void __exit sixpack_cleanup_driver(void) * VSV = if dev->start==0, then device * unregistered while close proc. */ - if (netif_running(sixpack_ctrls[i]->dev)) - unregister_netdev(&(sixpack_ctrls[i]->dev)); + if (netif_running(&sixpack_ctrls[i]->dev)) + unregister_netdev(&sixpack_ctrls[i]->dev); kfree(sixpack_ctrls[i]); sixpack_ctrls[i] = NULL; diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 1886ec73a..7a6cc5091 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -6,7 +6,7 @@ * Status: Stable. * Author: Dag Brattli <dagb@cs.uit.no> * Created at: Sat Nov 7 21:43:15 1998 - * Modified at: Fri Jan 28 12:10:10 2000 + * Modified at: Fri Feb 18 01:48:51 2000 * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no> @@ -42,6 +42,7 @@ ********************************************************************/ #include <linux/module.h> + #include <linux/kernel.h> #include <linux/types.h> #include <linux/skbuff.h> @@ -1431,8 +1432,10 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) /* We must empty the status FIFO no matter what */ len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8); - if (st_fifo->tail >= MAX_RX_WINDOW) + if (st_fifo->tail >= MAX_RX_WINDOW) { + IRDA_DEBUG(0, __FUNCTION__ "(), window is full!\n"); continue; + } st_fifo->entries[st_fifo->tail].status = status; st_fifo->entries[st_fifo->tail].len = len; @@ -1492,7 +1495,18 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) st_fifo->pending_bytes += len; st_fifo->entries[st_fifo->head].status = status; st_fifo->entries[st_fifo->head].len = len; - + /* + * DMA not finished yet, so try again + * later, set timer value, resolution + * 125 us + */ + switch_bank(iobase, BANK4); + outb(0x02, iobase+TMRL); /* x 125 us */ + outb(0x00, iobase+TMRH); + + /* Start timer */ + outb(IRCR1_TMR_EN, iobase+IRCR1); + /* Restore bank register */ outb(bank, iobase+BSR); @@ -1597,7 +1611,7 @@ static void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir) else { self->stats.tx_packets++; - netif_wakeup_queue(self->netdev); + netif_wake_queue(self->netdev); self->ier = IER_TXEMP_IE; } @@ -1648,21 +1662,12 @@ static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, /* Status FIFO event*/ if (eir & EIR_SFIF_EV) { + /* Check if DMA has finished */ if (nsc_ircc_dma_receive_complete(self, iobase)) { /* Wait for next status FIFO interrupt */ self->ier = IER_SFIF_IE; } else { - /* - * DMA not finished yet, so try again later, set - * timer value, resolution 125 us - */ - switch_bank(iobase, BANK4); - outb(0x02, iobase+TMRL); /* 2 * 125 us */ - outb(0x00, iobase+TMRH); - - /* Start timer */ - outb(IRCR1_TMR_EN, iobase+IRCR1); - self->ier = IER_TMR_IE | IER_SFIF_IE; + self->ier = IER_SFIF_IE | IER_TMR_IE; } } else if (eir & EIR_TMR_EV) { /* Timer finished */ /* Disable timer */ @@ -1677,15 +1682,17 @@ static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, if (self->io.direction == IO_XMIT) { nsc_ircc_dma_xmit(self, iobase); - /* Interrupt on DMA */ + /* Interrupt on DMA */ self->ier = IER_DMA_IE; } else { - /* Check if DMA has now finished */ - nsc_ircc_dma_receive_complete(self, iobase); - - self->ier = IER_SFIF_IE; + /* Check (again) if DMA has finished */ + if (nsc_ircc_dma_receive_complete(self, iobase)) { + self->ier = IER_SFIF_IE; + } else { + self->ier = IER_SFIF_IE | IER_TMR_IE; + } } - } else if (eir & EIR_DMA_EV) { + } else if (eir & EIR_DMA_EV) { /* Finished with all transmissions? */ if (nsc_ircc_dma_xmit_complete(self)) { /* Check if there are more frames to be transmitted */ diff --git a/drivers/net/irda/smc-ircc.c b/drivers/net/irda/smc-ircc.c index a93720cc9..06ebc072c 100644 --- a/drivers/net/irda/smc-ircc.c +++ b/drivers/net/irda/smc-ircc.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Thomas Davis (tadavis@jps.net) * Created at: - * Modified at: Fri Jan 21 09:41:08 2000 + * Modified at: Tue Feb 22 10:05:06 2000 * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1999-2000 Dag Brattli @@ -567,7 +567,6 @@ static void ircc_change_speed(void *priv, __u32 speed) "(), using irport to change speed to %d\n", speed); irport_change_speed(self->irport, speed); } - dev->tbusy = 0; register_bank(iobase, 1); outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode), @@ -617,9 +616,7 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev) if ((speed = irda_get_speed(skb)) != self->io.speed) self->new_speed = speed; - /* Lock transmit buffer */ - if (irda_lock((void *) &dev->tbusy) == FALSE) - return -EBUSY; + netif_stop_queue(dev); memcpy(self->tx_buff.head, skb->data, skb->len); @@ -741,11 +738,7 @@ static void ircc_dma_xmit_complete(struct ircc_cb *self, int iobase) self->new_speed = 0; } - /* Unlock tx_buff and request another frame */ - self->netdev->tbusy = 0; /* Unlock */ - - /* Tell the network layer, that we can accept more frames */ - mark_bh(NET_BH); + netif_wake_queue(self->netdev); } /* @@ -875,7 +868,6 @@ static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) iobase = self->io.fir_base; spin_lock(&self->lock); - dev->interrupt = 1; register_bank(iobase, 0); iir = inb(iobase+IRCC_IIR); @@ -898,7 +890,6 @@ static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) register_bank(iobase, 0); outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER); - dev->interrupt = 0; spin_unlock(&self->lock); } diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 33b1dbc60..010c7cfd0 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -788,8 +788,7 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete | StatsFull)) { - if (!netif_device_present(dev)) || - ((status & 0xe000) != 0x2000)) { + if (!netif_device_present(dev) || ((status & 0xe000) != 0x2000)) { DEBUG(1, "%s: interrupt from dead card\n", dev->name); break; } diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c index d3722cf2d..fad404a4d 100644 --- a/drivers/net/sk_g16.c +++ b/drivers/net/sk_g16.c @@ -1172,7 +1172,7 @@ static int SK_lance_init(struct net_device *dev, unsigned short mode) * YY/MM/DD uid Description -*/ -static int SK_timeout(struct net_device *dev) +static void SK_timeout(struct net_device *dev) { printk(KERN_WARNING "%s: xmitter timed out, try to restart!\n", dev->name); SK_lance_init(dev, MODE_NORMAL); /* Reinit LANCE */ diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 5f80fc5eb..d4b2e0380 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -26,10 +26,9 @@ * resource. Driver also reports the card name returned by * the pci resource. * 1/11/00 - Added spinlocks for smp - * - * To Do: + * 2/23/00 - Updated to dev_kfree_irq * - * IPv6 Multicast + * To Do: * * If Problems do Occur * Most problems can be rectified by either closing and opening the interface @@ -88,7 +87,7 @@ */ static char *version = -"Olympic.c v0.3.1 1/11/00 - Peter De Schrijver & Mike Phillips" ; +"Olympic.c v0.3.2 2/23/00 - Peter De Schrijver & Mike Phillips" ; static char *open_maj_error[] = {"No error", "Lobe Media Test", "Physical Insertion", "Address Verification", "Neighbor Notification (Ring Poll)", @@ -777,7 +776,7 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) olympic_priv->free_tx_ring_entries++; olympic_priv->olympic_stats.tx_bytes += olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len; olympic_priv->olympic_stats.tx_packets++ ; - dev_kfree_skb(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]); + dev_kfree_skb_irq(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]); olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef; olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0; netif_wake_queue(dev); diff --git a/drivers/net/tulip.c b/drivers/net/tulip.c deleted file mode 100644 index 5619b961d..000000000 --- a/drivers/net/tulip.c +++ /dev/null @@ -1,3159 +0,0 @@ -/* tulip.c: A DEC 21040-family ethernet driver for Linux. */ -/* - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. - - This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. - - This driver is for the Digital "Tulip" Ethernet adapter interface. - It should work with most DEC 21*4*-based chips/ethercards, as well as - with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX. - - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - - Additional information available at - http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html - - For this specific driver variant please use linux-kernel for - bug reports. - - - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the DECchip "Tulip", Digital's -single-chip ethernet controllers for PCI. Supported members of the family -are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike -chips from Lite-On, Macronics, ASIX, Compex and other listed below are also -supported. - -These chips are used on at least 140 unique PCI board designs. The great -number of chips and board designs supported is the reason for the -driver size and complexity. Almost of the increasing complexity is in the -board configuration and media selection code. There is very little -increasing in the operational critical path length. - -II. Board-specific settings - -PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS preferably should assign the -PCI INTA signal to an otherwise unused system IRQ line. - -Some boards have EEPROMs tables with default media entry. The factory default -is usually "autoselect". This should only be overridden when using -transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!) -for forcing full-duplex when used with old link partners that do not do -autonegotiation. - -III. Driver operation - -IIIa. Ring buffers - -The Tulip can use either ring buffers or lists of Tx and Rx descriptors. -This driver uses statically allocated rings of Rx and Tx descriptors, set at -compile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffs -for the Rx ring buffers at open() time and passes the skb->data field to the -Tulip as receive data buffers. When an incoming frame is less than -RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is -copied to the new skbuff. When the incoming frame is larger, the skbuff is -passed directly up the protocol stack and replaced by a newly allocated -skbuff. - -The RX_COPYBREAK value is chosen to trade-off the memory wasted by -using a full-sized skbuff for small frames vs. the copying costs of larger -frames. For small frames the copying cost is negligible (esp. considering -that we are pre-loading the cache with immediately useful header -information). For large frames the copying cost is non-trivial, and the -larger copy might flush the cache of useful data. A subtle aspect of this -choice is that the Tulip only receives into longword aligned buffers, thus -the IP header at offset 14 isn't longword aligned for further processing. -Copied frames are put into the new skbuff at an offset of "+2", thus copying -has the beneficial effect of aligning the IP header and preloading the -cache. - -IIIC. Synchronization -The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the -dev->tbusy flag. The other thread is the interrupt handler, which is single -threaded by the hardware and other software. - -The send packet thread has partial control over the Tx ring and 'dev->tbusy' -flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next -queue slot is empty, it clears the tbusy flag when finished otherwise it sets -the 'tp->tx_full' flag. - -The interrupt handler has exclusive control over the Rx ring and records stats -from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so -we can't avoid the interrupt overhead by having the Tx routine reap the Tx -stats.) After reaping the stats, it marks the queue entry as empty by setting -the 'base' to zero. Iff the 'tp->tx_full' flag is set, it clears both the -tx_full and tbusy flags. - -IV. Notes - -Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board. -Greg LaPolla at Linksys provided PNIC and other Linksys boards. -Znyx provided a four-port card for testing. - -IVb. References - -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html -http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM") -http://www.national.com/pf/DP/DP83840A.html -http://www.asix.com.tw/pmac.htm -http://www.admtek.com.tw/ - -IVc. Errata - -The old DEC databooks were light on details. -The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last -register of the set CSR12-15 written. Hmmm, now how is that possible? - -The DEC SROM format is very badly designed not precisely defined, leading to -part of the media selection junkheap below. Some boards do not have EEPROM -media tables and need to be patched up. Worse, other boards use the DEC -design kit media table when it isn't correct for their board. - -We cannot use MII interrupts because there is no defined GPIO pin to attach -them. The MII transceiver status is polled using an kernel timer. - -*/ - -static const char version[] = "Linux Tulip driver version 0.9.2 (Feb 15, 2000)\n"; - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <linux/malloc.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/init.h> -#include <asm/processor.h> /* Processor type for cache alignment. */ -#include <asm/bitops.h> -#include <asm/io.h> -#include <asm/unaligned.h> -#include <asm/delay.h> - - -/* A few user-configurable values. */ - -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 25; - -#define MAX_UNITS 8 -/* Used to pass the full-duplex flag, etc. */ -static int full_duplex[MAX_UNITS] = {0, }; -static int options[MAX_UNITS] = {0, }; -static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */ - -/* The possible media types that can be set in options[] are: */ -static const char * const medianame[] = { - "10baseT", "10base2", "AUI", "100baseTx", - "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx", - "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII", - "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4", -}; - -/* Set if the PCI BIOS detects the chips on a multiport board backwards. */ -#ifdef REVERSE_PROBE_ORDER -static int reverse_probe = 1; -#else -static int reverse_probe = 0; -#endif - -/* Keep the ring sizes a power of two for efficiency. - Making the Tx ring too large decreases the effectiveness of channel - bonding and packet priority. - There are no ill effects from too-large receive rings. */ -#define TX_RING_SIZE 16 -#define RX_RING_SIZE 32 - -/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ -#ifdef __alpha__ -static int rx_copybreak = 1518; -#else -static int rx_copybreak = 100; -#endif - -/* - Set the bus performance register. - Typical: Set 16 longword cache alignment, no burst limit. - Cache alignment bits 15:14 Burst length 13:8 - 0000 No alignment 0x00000000 unlimited 0800 8 longwords - 4000 8 longwords 0100 1 longword 1000 16 longwords - 8000 16 longwords 0200 2 longwords 2000 32 longwords - C000 32 longwords 0400 4 longwords - Warning: many older 486 systems are broken and require setting 0x00A04800 - 8 longword cache alignment, 8 longword burst. - ToDo: Non-Intel setting could be better. -*/ - -#if defined(__alpha__) -static int csr0 = 0x01A00000 | 0xE000; -#elif defined(__i386__) || defined(__powerpc__) || defined(__sparc__) -static int csr0 = 0x01A00000 | 0x8000; -#else -#warning Processor architecture undefined! -static int csr0 = 0x00A00000 | 0x4800; -#endif - -/* Operational parameters that usually are not changed. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (4*HZ) -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -/* This is a mysterious value that can be written to CSR11 in the 21040 (only) - to support a pre-NWay full-duplex signaling mechanism using short frames. - No one knows what it should be, but if left at its default value some - 10base2(!) packets trigger a full-duplex-request interrupt. */ -#define FULL_DUPLEX_MAGIC 0x6969 - - -/* Kernel compatibility defines, some common to David Hind's PCMCIA package. - This is only in the support-all-kernels source code. */ - -MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>"); -MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver"); -MODULE_PARM(debug, "i"); -MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(reverse_probe, "i"); -MODULE_PARM(rx_copybreak, "i"); -MODULE_PARM(csr0, "i"); -MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); - -#define TULIP_MODULE_NAME "tulip" -#define PFX TULIP_MODULE_NAME ": " - -#define RUN_AT(x) (jiffies + (x)) - -/* Condensed operations for readability. */ -#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) -#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) - -#define tulip_debug debug -#ifdef TULIP_DEBUG -static int tulip_debug = TULIP_DEBUG; -#else -static int tulip_debug = 1; -#endif - - - -/* This table use during operation for capabilities and media timer. */ - -static void tulip_timer(unsigned long data); -static void t21142_timer(unsigned long data); -static void mxic_timer(unsigned long data); -static void pnic_timer(unsigned long data); -static void comet_timer(unsigned long data); - -enum tbl_flag { - HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8, - HAS_ACPI=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */ - HAS_PNICNWAY=0x80, HAS_NWAY143=0x40, /* Uses internal NWay xcvr. */ - HAS_8023X=0x100, -}; -static struct tulip_chip_table { - char *chip_name; - int io_size; - int valid_intrs; /* CSR7 interrupt enable settings */ - int flags; - void (*media_timer)(unsigned long data); -} tulip_tbl[] = { - { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer }, - { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer }, - { "Digital DS21140 Tulip", 128, 0x0001ebef, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, - { "Digital DS21143 Tulip", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, - t21142_timer }, - { "Lite-On 82c168 PNIC", 256, 0x0001ebef, - HAS_MII | HAS_PNICNWAY, pnic_timer }, - { "Macronix 98713 PMAC", 128, 0x0001ebef, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, - { "Macronix 98715 PMAC", 256, 0x0001ebef, - HAS_MEDIA_TABLE, mxic_timer }, - { "Macronix 98725 PMAC", 256, 0x0001ebef, - HAS_MEDIA_TABLE, mxic_timer }, - { "ASIX AX88140", 128, 0x0001fbff, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer }, - { "Lite-On PNIC-II", 256, 0x0801fbff, - HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer }, - { "ADMtek Comet", 256, 0x0001abef, - MC_HASH_ONLY, comet_timer }, - { "Compex 9881 PMAC", 128, 0x0001ebef, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, - { "Intel DS21145 Tulip", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143, - t21142_timer }, - { "Xircom tulip work-alike", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, - t21142_timer }, - {0}, -}; -/* This matches the table above. Note 21142 == 21143. */ -enum chips { - DC21040=0, - DC21041=1, - DC21140=2, - DC21142=3, DC21143=3, - LC82C168, - MX98713, - MX98715, - MX98725, - AX88140, - PNIC2, - COMET, - COMPEX9881, - I21145, - X3201_3, -}; - - -static struct pci_device_id tulip_pci_tbl[] __devinitdata = { - { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 }, - { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 }, - { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, - { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21143 }, - { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 }, - { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 }, - { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, - { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 }, - { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 }, - { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 }, - { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, - { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, - { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, - { 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 }, - {0}, -}; -MODULE_DEVICE_TABLE(pci,tulip_pci_tbl); - - -/* A full-duplex map for media types. */ -enum MediaIs { - MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8, - MediaIs100=16}; -static const char media_cap[] = -{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 }; -static u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0}; -/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/ -static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, }; -static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; -static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; - -static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, }; -static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, }; -static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; - -/* Offsets to the Command and Status Registers, "CSRs". All accesses - must be longword instructions and quadword aligned. */ -enum tulip_offsets { - CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, - CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58, - CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 }; - -/* The bits in the CSR5 status registers, mostly interrupt sources. */ -enum status_bits { - TimerInt=0x800, SytemError=0x2000, TPLnkFail=0x1000, TPLnkPass=0x10, - NormalIntr=0x10000, AbnormalIntr=0x8000, - RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40, - TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01, -}; - -/* The Tulip Rx and Tx buffer descriptors. */ -struct tulip_rx_desc { - s32 status; - s32 length; - u32 buffer1, buffer2; -}; - -struct tulip_tx_desc { - s32 status; - s32 length; - u32 buffer1, buffer2; /* We use only buffer 1. */ -}; - -enum desc_status_bits { - DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300, -}; - -/* Ring-wrap flag in length field, use for last ring entry. - 0x01000000 means chain on buffer2 address, - 0x02000000 means use the ring start address in CSR2/3. - Note: Some work-alike chips do not function correctly in chained mode. - The ASIX chip works only in chained mode. - Thus we indicates ring mode, but always write the 'next' field for - chained mode as well. -*/ -#define DESC_RING_WRAP 0x02000000 - -#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */ - -struct medialeaf { - u8 type; - u8 media; - unsigned char *leafdata; -}; - -struct mediatable { - u16 defaultmedia; - u8 leafcount, csr12dir; /* General purpose pin directions. */ - unsigned has_mii:1, has_nonmii:1, has_reset:6; - u32 csr15dir, csr15val; /* 21143 NWay setting. */ - struct medialeaf mleaf[0]; -}; - -struct mediainfo { - struct mediainfo *next; - int info_type; - int index; - unsigned char *info; -}; - -struct tulip_private { - char devname[8]; /* Used only for kernel debugging. */ - const char *product_name; - struct net_device *next_module; - struct tulip_rx_desc rx_ring[RX_RING_SIZE]; - struct tulip_tx_desc tx_ring[TX_RING_SIZE]; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - /* The addresses of receive-in-place skbuffs. */ - struct sk_buff* rx_skbuff[RX_RING_SIZE]; - char *rx_buffs; /* Address of temporary Rx buffers. */ - u16 setup_frame[96]; /* Pseudo-Tx frame to init address table. */ - int chip_id; - int revision; - int flags; - struct net_device_stats stats; - struct timer_list timer; /* Media selection timer. */ - spinlock_t tx_lock; - unsigned int cur_rx, cur_tx; /* The next free ring entry */ - unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int full_duplex_lock:1; - unsigned int fake_addr:1; /* Multiport board faked address. */ - unsigned int default_port:4; /* Last dev->if_port value. */ - unsigned int media2:4; /* Secondary monitored media port. */ - unsigned int medialock:1; /* Don't sense media type. */ - unsigned int mediasense:1; /* Media sensing in progress. */ - unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */ - unsigned int csr0; /* CSR0 setting. */ - unsigned int csr6; /* Current CSR6 control settings. */ - unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */ - void (*link_change)(struct net_device *dev, int csr5); - u16 to_advertise; /* NWay capabilities advertised. */ - u16 lpar; /* 21143 Link partner ability. */ - u16 advertising[4]; - signed char phys[4], mii_cnt; /* MII device addresses. */ - struct mediatable *mtable; - int cur_index; /* Current media index. */ - int saved_if_port; - struct pci_dev *pdev; - int ttimer; - int susp_rx; - unsigned long nir; - unsigned long base_addr; - int pad0, pad1; /* Used for 8-byte alignment */ -}; - -static void parse_eeprom(struct net_device *dev); -static int read_eeprom(long ioaddr, int location, int addr_len); -static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *dev, int phy_id, int location, int value); -static void select_media(struct net_device *dev, int startup); -/* Chip-specific media selection (timer functions prototyped above). */ -static void t21142_lnk_change(struct net_device *dev, int csr5); -static void t21142_start_nway(struct net_device *dev); -static void pnic_lnk_change(struct net_device *dev, int csr5); -static void pnic_do_nway(struct net_device *dev); - -static void tulip_tx_timeout(struct net_device *dev); -static void tulip_init_ring(struct net_device *dev); -static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int tulip_refill_rx(struct net_device *dev); -static int tulip_rx(struct net_device *dev); -static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static int tulip_open(struct net_device *dev); -static int tulip_close(struct net_device *dev); -static void tulip_up(struct net_device *dev); -static void tulip_down(struct net_device *dev); -static struct net_device_stats *tulip_get_stats(struct net_device *dev); -static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void set_rx_mode(struct net_device *dev); - - -/* Serial EEPROM section. */ -/* The main routine to parse the very complicated SROM structure. - Search www.digital.com for "21X4 SROM" to get details. - This code is very complex, and will require changes to support - additional cards, so I'll be verbose about what is going on. - */ - -/* Known cards that have old-style EEPROMs. */ -static struct fixups { - char *name; - unsigned char addr0, addr1, addr2; - u16 newtable[32]; /* Max length below. */ -} eeprom_fixups[] = { - {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, - 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, - {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f, - 0x0000, 0x009E, /* 10baseT */ - 0x0004, 0x009E, /* 10baseT-FD */ - 0x0903, 0x006D, /* 100baseTx */ - 0x0905, 0x006D, /* 100baseTx-FD */ }}, - {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f, - 0x0107, 0x8021, /* 100baseFx */ - 0x0108, 0x8021, /* 100baseFx-FD */ - 0x0100, 0x009E, /* 10baseT */ - 0x0104, 0x009E, /* 10baseT-FD */ - 0x0103, 0x006D, /* 100baseTx */ - 0x0105, 0x006D, /* 100baseTx-FD */ }}, - {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513, - 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ - 0x0000, 0x009E, /* 10baseT */ - 0x0004, 0x009E, /* 10baseT-FD */ - 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ - 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}}, - {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F, - 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ - 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ - 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */ - 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ - 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */ - }}, - {0, 0, 0, 0, {}}}; - -static const char * block_name[] = {"21140 non-MII", "21140 MII PHY", - "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"}; - -#if defined(__i386__) /* AKA get_unaligned() */ -#define get_u16(ptr) (*(u16 *)(ptr)) -#else -#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8)) -#endif - -static void parse_eeprom(struct net_device *dev) -{ - /* The last media info list parsed, for multiport boards. */ - static struct mediatable *last_mediatable = NULL; - static unsigned char *last_ee_data = NULL; - static int controller_index = 0; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - unsigned char *ee_data = tp->eeprom; - int i; - - tp->mtable = 0; - /* Detect an old-style (SA only) EEPROM layout: - memcmp(eedata, eedata+16, 8). */ - for (i = 0; i < 8; i ++) - if (ee_data[i] != ee_data[16+i]) - break; - if (i >= 8) { - if (ee_data[0] == 0xff) { - if (last_mediatable) { - controller_index++; - printk(KERN_INFO "%s: Controller %d of multiport board.\n", - dev->name, controller_index); - tp->mtable = last_mediatable; - ee_data = last_ee_data; - goto subsequent_board; - } else - printk(KERN_INFO "%s: Missing EEPROM, this interface may " - "not work correctly!\n", - dev->name); - return; - } - /* Do a fix-up based on the vendor half of the station address prefix. */ - for (i = 0; eeprom_fixups[i].name; i++) { - if (dev->dev_addr[0] == eeprom_fixups[i].addr0 - && dev->dev_addr[1] == eeprom_fixups[i].addr1 - && dev->dev_addr[2] == eeprom_fixups[i].addr2) { - if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) - i++; /* An Accton EN1207, not an outlaw Maxtech. */ - memcpy(ee_data + 26, eeprom_fixups[i].newtable, - sizeof(eeprom_fixups[i].newtable)); - printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using" - " substitute media control info.\n", - dev->name, eeprom_fixups[i].name); - break; - } - } - if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ - printk(KERN_INFO "%s: Old style EEPROM with no media selection " - "information.\n", - dev->name); - return; - } - } - - controller_index = 0; - if (ee_data[19] > 1) { /* Multiport board. */ - last_ee_data = ee_data; - } -subsequent_board: - - if (ee_data[27] == 0) { /* No valid media table. */ - } else if (tp->chip_id == DC21041) { - unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3]; - int media = get_u16(p); - int count = p[2]; - p += 3; - - printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n", - dev->name, media, - media & 0x0800 ? "Autosense" : medianame[media & 15]); - for (i = 0; i < count; i++) { - unsigned char media_code = *p++; - if (media_code & 0x40) - p += 6; - printk(KERN_INFO "%s: 21041 media #%d, %s.\n", - dev->name, media_code & 15, medianame[media_code & 15]); - } - } else { - unsigned char *p = (void *)ee_data + ee_data[27]; - unsigned char csr12dir = 0; - int count, new_advertise = 0; - struct mediatable *mtable; - u16 media = get_u16(p); - - p += 2; - if (tp->flags & CSR12_IN_SROM) - csr12dir = *p++; - count = *p++; - mtable = (struct mediatable *) - kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf), - GFP_KERNEL); - if (mtable == NULL) - return; /* Horrible, impossible failure. */ - last_mediatable = tp->mtable = mtable; - mtable->defaultmedia = media; - mtable->leafcount = count; - mtable->csr12dir = csr12dir; - mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0; - mtable->csr15dir = mtable->csr15val = 0; - - printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, - media & 0x0800 ? "Autosense" : medianame[media & 15]); - for (i = 0; i < count; i++) { - struct medialeaf *leaf = &mtable->mleaf[i]; - - if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */ - leaf->type = 0; - leaf->media = p[0] & 0x3f; - leaf->leafdata = p; - if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */ - mtable->has_mii = 1; - p += 4; - } else { - leaf->type = p[1]; - if (p[1] == 0x05) { - mtable->has_reset = i; - leaf->media = p[2] & 0x0f; - } else if (p[1] & 1) { - mtable->has_mii = 1; - leaf->media = 11; - } else { - mtable->has_nonmii = 1; - leaf->media = p[2] & 0x0f; - switch (leaf->media) { - case 0: new_advertise |= 0x0020; break; - case 4: new_advertise |= 0x0040; break; - case 3: new_advertise |= 0x0080; break; - case 5: new_advertise |= 0x0100; break; - case 6: new_advertise |= 0x0200; break; - } - if (p[1] == 2 && leaf->media == 0) { - if (p[2] & 0x40) { - u32 base15 = get_unaligned((u16*)&p[7]); - mtable->csr15dir = - (get_unaligned((u16*)&p[9])<<16) + base15; - mtable->csr15val = - (get_unaligned((u16*)&p[11])<<16) + base15; - } else { - mtable->csr15dir = get_unaligned((u16*)&p[3])<<16; - mtable->csr15val = get_unaligned((u16*)&p[5])<<16; - } - } - } - leaf->leafdata = p + 2; - p += (p[0] & 0x3f) + 1; - } - if (tulip_debug > 1 && leaf->media == 11) { - unsigned char *bp = leaf->leafdata; - printk(KERN_INFO "%s: MII interface PHY %d, setup/reset " - "sequences %d/%d long, capabilities %2.2x %2.2x.\n", - dev->name, bp[0], bp[1], bp[2 + bp[1]*2], - bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); - } - printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " - "by a %s (%d) block.\n", - dev->name, i, medianame[leaf->media], leaf->media, - block_name[leaf->type], leaf->type); - } - if (new_advertise) - tp->to_advertise = new_advertise; - } -} -/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ - -/* EEPROM_Ctrl bits. */ -#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ -#define EE_CS 0x01 /* EEPROM chip select. */ -#define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */ -#define EE_WRITE_0 0x01 -#define EE_WRITE_1 0x05 -#define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */ -#define EE_ENB (0x4800 | EE_CS) - -/* Delay between EEPROM clock transitions. - Even at 33Mhz current PCI implementations don't overrun the EEPROM clock. - We add a bus turn-around to insure that this remains true. */ -#define eeprom_delay() inl(ee_addr) - -/* The EEPROM commands include the alway-set leading bit. */ -#define EE_READ_CMD (6) - -/* Note: this routine returns extra data bits for size detection. */ -static int __devinit read_eeprom(long ioaddr, int location, int addr_len) -{ - int i; - unsigned retval = 0; - long ee_addr = ioaddr + CSR9; - int read_cmd = location | (EE_READ_CMD << addr_len); - - outl(EE_ENB & ~EE_CS, ee_addr); - outl(EE_ENB, ee_addr); - - /* Shift the read command bits out. */ - for (i = 4 + addr_len; i >= 0; i--) { - short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; - outl(EE_ENB | dataval, ee_addr); - eeprom_delay(); - outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); - } - outl(EE_ENB, ee_addr); - - for (i = 16; i > 0; i--) { - outl(EE_ENB | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); - outl(EE_ENB, ee_addr); - eeprom_delay(); - } - - /* Terminate the EEPROM access. */ - outl(EE_ENB & ~EE_CS, ee_addr); - return retval; -} - -/* MII transceiver control section. - Read and write the MII registers using software-generated serial - MDIO protocol. See the MII specifications or DP83840A data sheet - for details. */ - -/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually - met by back-to-back PCI I/O cycles, but we insert a delay to avoid - "overclocking" issues or future 66Mhz PCI. */ -#define mdio_delay() inl(mdio_addr) - -/* Read and write the MII registers using software-generated serial - MDIO protocol. It is just different enough from the EEPROM protocol - to not share code. The maxium data clock rate is 2.5 Mhz. */ -#define MDIO_SHIFT_CLK 0x10000 -#define MDIO_DATA_WRITE0 0x00000 -#define MDIO_DATA_WRITE1 0x20000 -#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ -#define MDIO_ENB_IN 0x40000 -#define MDIO_DATA_READ 0x80000 - -static int mdio_read(struct net_device *dev, int phy_id, int location) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int i; - int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; - int retval = 0; - long ioaddr = dev->base_addr; - long mdio_addr = ioaddr + CSR9; - - if (tp->chip_id == LC82C168) { - int i = 1000; - outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); - inl(ioaddr + 0xA0); - inl(ioaddr + 0xA0); - while (--i > 0) - if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) - return retval & 0xffff; - return 0xffff; - } - - if (tp->chip_id == COMET) { - if (phy_id == 1) { - if (location < 7) - return inl(ioaddr + 0xB4 + (location<<2)); - else if (location == 17) - return inl(ioaddr + 0xD0); - else if (location >= 29 && location <= 31) - return inl(ioaddr + 0xD4 + ((location-29)<<2)); - } - return 0xffff; - } - - /* Establish sync by sending at least 32 logic ones. */ - for (i = 32; i >= 0; i--) { - outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Shift the read command bits out. */ - for (i = 15; i >= 0; i--) { - int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; - - outl(MDIO_ENB | dataval, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Read the two transition, 16 data, and wire-idle bits. */ - for (i = 19; i > 0; i--) { - outl(MDIO_ENB_IN, mdio_addr); - mdio_delay(); - retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); - outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - return (retval>>1) & 0xffff; -} - -static void mdio_write(struct net_device *dev, int phy_id, int location, int value) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int i; - int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; - long ioaddr = dev->base_addr; - long mdio_addr = ioaddr + CSR9; - - if (tp->chip_id == LC82C168) { - int i = 1000; - outl(cmd, ioaddr + 0xA0); - do - if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) - break; - while (--i > 0); - return; - } - - if (tp->chip_id == COMET) { - if (phy_id != 1) - return; - if (location < 7) - outl(value, ioaddr + 0xB4 + (location<<2)); - else if (location == 17) - outl(value, ioaddr + 0xD0); - else if (location >= 29 && location <= 31) - outl(value, ioaddr + 0xD4 + ((location-29)<<2)); - return; - } - - /* Establish sync by sending 32 logic ones. */ - for (i = 32; i >= 0; i--) { - outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Shift the command bits out. */ - for (i = 31; i >= 0; i--) { - int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; - outl(MDIO_ENB | dataval, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Clear out extra bits. */ - for (i = 2; i > 0; i--) { - outl(MDIO_ENB_IN, mdio_addr); - mdio_delay(); - outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - return; -} - - -/* The Xircom cards are picky about when certain bits in CSR6 can be - manipulated. Keith Owens <kaos@ocs.com.au>. */ - -static void outl_CSR6 (struct tulip_private *tp, u32 newcsr6) -{ - long ioaddr = tp->base_addr; - const int strict_bits = 0x0060e202; - int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200; - long flags; - - /* really a hw lock */ - spin_lock_irqsave (&tp->tx_lock, flags); - - if (tp->chip_id != X3201_3) - goto out_write; - - newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */ - /* read 0 on the Xircom cards */ - newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */ - currcsr6 = inl (ioaddr + CSR6); - if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) || - ((currcsr6 & ~0x2002) == 0)) - goto out_write; - - /* make sure the transmitter and receiver are stopped first */ - currcsr6 &= ~0x2002; - while (1) { - csr5 = inl (ioaddr + CSR5); - if (csr5 == 0xffffffff) - break; /* cannot read csr5, card removed? */ - csr5_22_20 = csr5 & 0x700000; - csr5_19_17 = csr5 & 0x0e0000; - if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) && - (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000)) - break; /* both are stopped or suspended */ - if (!--attempts) { - printk (KERN_INFO "tulip.c: outl_CSR6 too many attempts," - "csr5=0x%08x\n", csr5); - goto out_write; - } - outl (currcsr6, ioaddr + CSR6); - udelay (1); - } - -out_write: - /* now it is safe to change csr6 */ - outl (newcsr6, ioaddr + CSR6); - - spin_unlock_irqrestore (&tp->lock, flags); -} - - -static void tulip_up(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 3*HZ; - int i; - - /* Wake the chip from sleep/snooze mode. */ - if (tp->flags & HAS_ACPI) - pci_write_config_dword(tp->pdev, 0x40, 0); - - /* On some chip revs we must set the MII/SYM port before the reset!? */ - if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) - outl_CSR6 (tp, 0x00040000); - - /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ - outl(0x00000001, ioaddr + CSR0); - - /* Deassert reset. - Wait the specified 50 PCI cycles after a reset by initializing - Tx and Rx queues and the address filter list. */ - outl(tp->csr0, ioaddr + CSR0); - - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq); - - if (tp->flags & MC_HASH_ONLY) { - u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); - u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4))); - if (tp->chip_id == AX88140) { - outl(0, ioaddr + CSR13); - outl(addr_low, ioaddr + CSR14); - outl(1, ioaddr + CSR13); - outl(addr_high, ioaddr + CSR14); - } else if (tp->chip_id == COMET) { - outl(addr_low, ioaddr + 0xA4); - outl(addr_high, ioaddr + 0xA8); - outl(0, ioaddr + 0xAC); - outl(0, ioaddr + 0xB0); - } - } else { - /* This is set_rx_mode(), but without starting the transmitter. */ - u16 *eaddrs = (u16 *)dev->dev_addr; - u16 *setup_frm = &tp->setup_frame[15*6]; - - /* 21140 bug: you must add the broadcast address. */ - memset(tp->setup_frame, 0xff, sizeof(tp->setup_frame)); - /* Fill the final entry of the table with our physical address. */ - *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; - *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; - *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; - /* Put the setup frame on the Tx list. */ - tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192); - tp->tx_ring[0].buffer1 = virt_to_le32desc(tp->setup_frame); - tp->tx_ring[0].status = cpu_to_le32(DescOwned); - - tp->cur_tx++; - } - - outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3); - outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4); - - tp->saved_if_port = dev->if_port; - if (dev->if_port == 0) - dev->if_port = tp->default_port; - - /* Allow selecting a default media. */ - i = 0; - if (tp->mtable == NULL) - goto media_picked; - if (dev->if_port) { - int looking_for = media_cap[dev->if_port] & MediaIsMII ? 11 : - (dev->if_port == 12 ? 0 : dev->if_port); - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == looking_for) { - printk(KERN_INFO "%s: Using user-specified media %s.\n", - dev->name, medianame[dev->if_port]); - goto media_picked; - } - } - if ((tp->mtable->defaultmedia & 0x0800) == 0) { - int looking_for = tp->mtable->defaultmedia & 15; - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == looking_for) { - printk(KERN_INFO "%s: Using EEPROM-set media %s.\n", - dev->name, medianame[looking_for]); - goto media_picked; - } - } - /* Start sensing first non-full-duplex media. */ - for (i = tp->mtable->leafcount - 1; - (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--) - ; -media_picked: - - tp->csr6 = 0; - tp->cur_index = i; - tp->nwayset = 0; - if (dev->if_port == 0 && tp->chip_id == DC21041) { - tp->nway = 1; - } - if (dev->if_port == 0 && tp->chip_id == DC21142) { - if (tp->mii_cnt) { - select_media(dev, 1); - if (tulip_debug > 1) - printk(KERN_INFO "%s: Using MII transceiver %d, status " - "%4.4x.\n", - dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1)); - outl_CSR6(tp, 0x82020000); - tp->csr6 = 0x820E0000; - dev->if_port = 11; - outl(0x0000, ioaddr + CSR13); - outl(0x0000, ioaddr + CSR14); - } else - t21142_start_nway(dev); - } else if (tp->chip_id == PNIC2) { - t21142_start_nway(dev); - } else if (tp->chip_id == LC82C168 && ! tp->medialock) { - if (tp->mii_cnt) { - dev->if_port = 11; - tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0); - outl(0x0001, ioaddr + CSR15); - } else if (inl(ioaddr + CSR5) & TPLnkPass) - pnic_do_nway(dev); - else { - /* Start with 10mbps to do autonegotiation. */ - outl(0x32, ioaddr + CSR12); - tp->csr6 = 0x00420000; - outl(0x0001B078, ioaddr + 0xB8); - outl(0x0201B078, ioaddr + 0xB8); - next_tick = 1*HZ; - } - } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) - && ! tp->medialock) { - dev->if_port = 0; - tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0); - outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); - } else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) { - /* Provided by BOLO, Macronix - 12/10/1998. */ - dev->if_port = 0; - tp->csr6 = 0x01a80200; - outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); - outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0); - } else if (tp->chip_id == DC21143 && - media_cap[dev->if_port] & MediaIsMII) { - /* We must reset the media CSRs when we force-select MII mode. */ - outl(0x0000, ioaddr + CSR13); - outl(0x0000, ioaddr + CSR14); - outl(0x0008, ioaddr + CSR15); - } else if (tp->chip_id == COMET) { - dev->if_port = 0; - tp->csr6 = 0x00040000; - } else if (tp->chip_id == AX88140) { - tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100; - } else - select_media(dev, 1); - - /* Start the chip's Tx to process setup frame. */ - outl_CSR6(tp, tp->csr6); - outl_CSR6(tp, tp->csr6 | 0x2000); - - /* Enable interrupts by setting the interrupt mask. */ - outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5); - outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); - outl_CSR6(tp, tp->csr6 | 0x2002); - outl(0, ioaddr + CSR2); /* Rx poll demand */ - - if (tulip_debug > 2) { - printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n", - dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5), - inl(ioaddr + CSR6)); - } - /* Set the timer to switch to check for link beat and perhaps switch - to an alternate media type. */ - init_timer(&tp->timer); - tp->timer.expires = RUN_AT(next_tick); - tp->timer.data = (unsigned long)dev; - tp->timer.function = tulip_tbl[tp->chip_id].media_timer; - add_timer(&tp->timer); - - netif_device_attach(dev); -} - - -static int -tulip_open(struct net_device *dev) -{ - MOD_INC_USE_COUNT; - - if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) { - MOD_DEC_USE_COUNT; - return -EBUSY; - } - - tulip_init_ring (dev); - - tulip_up (dev); - - return 0; -} - - -/* Set up the transceiver control registers for the selected media type. */ -static void select_media(struct net_device *dev, int startup) -{ - long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - struct mediatable *mtable = tp->mtable; - u32 new_csr6; - int i; - - if (mtable) { - struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index]; - unsigned char *p = mleaf->leafdata; - switch (mleaf->type) { - case 0: /* 21140 non-MII xcvr. */ - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver" - " with control setting %2.2x.\n", - dev->name, p[1]); - dev->if_port = p[0]; - if (startup) - outl(mtable->csr12dir | 0x100, ioaddr + CSR12); - outl(p[1], ioaddr + CSR12); - new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18); - break; - case 2: case 4: { - u16 setup[5]; - u32 csr13val, csr14val, csr15dir, csr15val; - for (i = 0; i < 5; i++) - setup[i] = get_u16(&p[i*2 + 1]); - - dev->if_port = p[0] & 15; - if (media_cap[dev->if_port] & MediaAlwaysFD) - tp->full_duplex = 1; - - if (startup && mtable->has_reset) { - struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; - unsigned char *rst = rleaf->leafdata; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Resetting the transceiver.\n", - dev->name); - for (i = 0; i < rst[0]; i++) - outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); - } - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control " - "%4.4x/%4.4x.\n", - dev->name, medianame[dev->if_port], setup[0], setup[1]); - if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ - csr13val = setup[0]; - csr14val = setup[1]; - csr15dir = (setup[3]<<16) | setup[2]; - csr15val = (setup[4]<<16) | setup[2]; - outl(0, ioaddr + CSR13); - outl(csr14val, ioaddr + CSR14); - outl(csr15dir, ioaddr + CSR15); /* Direction */ - outl(csr15val, ioaddr + CSR15); /* Data */ - outl(csr13val, ioaddr + CSR13); - } else { - csr13val = 1; - csr14val = 0x0003FF7F; - csr15dir = (setup[0]<<16) | 0x0008; - csr15val = (setup[1]<<16) | 0x0008; - if (dev->if_port <= 4) - csr14val = t21142_csr14[dev->if_port]; - if (startup) { - outl(0, ioaddr + CSR13); - outl(csr14val, ioaddr + CSR14); - } - outl(csr15dir, ioaddr + CSR15); /* Direction */ - outl(csr15val, ioaddr + CSR15); /* Data */ - if (startup) outl(csr13val, ioaddr + CSR13); - } - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n", - dev->name, csr15dir, csr15val); - if (mleaf->type == 4) - new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18); - else - new_csr6 = 0x82420000; - break; - } - case 1: case 3: { - int phy_num = p[0]; - int init_length = p[1]; - u16 *misc_info; - u16 to_advertise; - - dev->if_port = 11; - new_csr6 = 0x020E0000; - if (mleaf->type == 3) { /* 21142 */ - u16 *init_sequence = (u16*)(p+2); - u16 *reset_sequence = &((u16*)(p+3))[init_length]; - int reset_length = p[2 + init_length*2]; - misc_info = reset_sequence + reset_length; - if (startup) - for (i = 0; i < reset_length; i++) - outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); - for (i = 0; i < init_length; i++) - outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); - } else { - u8 *init_sequence = p + 2; - u8 *reset_sequence = p + 3 + init_length; - int reset_length = p[2 + init_length]; - misc_info = (u16*)(reset_sequence + reset_length); - if (startup) { - outl(mtable->csr12dir | 0x100, ioaddr + CSR12); - for (i = 0; i < reset_length; i++) - outl(reset_sequence[i], ioaddr + CSR12); - } - for (i = 0; i < init_length; i++) - outl(init_sequence[i], ioaddr + CSR12); - } - to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1; - tp->advertising[phy_num] = to_advertise; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n", - dev->name, to_advertise, phy_num, tp->phys[phy_num]); - /* Bogus: put in by a committee? */ - mdio_write(dev, tp->phys[phy_num], 4, to_advertise); - break; - } - default: - printk(KERN_DEBUG "%s: Invalid media table selection %d.\n", - dev->name, mleaf->type); - new_csr6 = 0x020E0000; - } - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n", - dev->name, medianame[dev->if_port], - inl(ioaddr + CSR12) & 0xff); - } else if (tp->chip_id == DC21041) { - int port = dev->if_port <= 4 ? dev->if_port : 0; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n", - dev->name, medianame[port == 3 ? 12: port], - inl(ioaddr + CSR12)); - outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ - outl(t21041_csr14[port], ioaddr + CSR14); - outl(t21041_csr15[port], ioaddr + CSR15); - outl(t21041_csr13[port], ioaddr + CSR13); - new_csr6 = 0x80020000; - } else if (tp->chip_id == LC82C168) { - if (startup && ! tp->medialock) - dev->if_port = tp->mii_cnt ? 11 : 0; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s.\n", - dev->name, inl(ioaddr + 0xB8), medianame[dev->if_port]); - if (tp->mii_cnt) { - new_csr6 = 0x810C0000; - outl(0x0001, ioaddr + CSR15); - outl(0x0201B07A, ioaddr + 0xB8); - } else if (startup) { - /* Start with 10mbps to do autonegotiation. */ - outl(0x32, ioaddr + CSR12); - new_csr6 = 0x00420000; - outl(0x0001B078, ioaddr + 0xB8); - outl(0x0201B078, ioaddr + 0xB8); - } else if (dev->if_port == 3 || dev->if_port == 5) { - outl(0x33, ioaddr + CSR12); - new_csr6 = 0x01860000; - /* Trigger autonegotiation. */ - outl(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8); - } else { - outl(0x32, ioaddr + CSR12); - new_csr6 = 0x00420000; - outl(0x1F078, ioaddr + 0xB8); - } - } else if (tp->chip_id == DC21040) { /* 21040 */ - /* Turn on the xcvr interface. */ - int csr12 = inl(ioaddr + CSR12); - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n", - dev->name, medianame[dev->if_port], csr12); - if (media_cap[dev->if_port] & MediaAlwaysFD) - tp->full_duplex = 1; - new_csr6 = 0x20000; - /* Set the full duplux match frame. */ - outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11); - outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ - if (t21040_csr13[dev->if_port] & 8) { - outl(0x0705, ioaddr + CSR14); - outl(0x0006, ioaddr + CSR15); - } else { - outl(0xffff, ioaddr + CSR14); - outl(0x0000, ioaddr + CSR15); - } - outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13); - } else { /* Unknown chip type with no media table. */ - if (tp->default_port == 0) - dev->if_port = tp->mii_cnt ? 11 : 3; - if (media_cap[dev->if_port] & MediaIsMII) { - new_csr6 = 0x020E0000; - } else if (media_cap[dev->if_port] & MediaIsFx) { - new_csr6 = 0x028600000; - } else - new_csr6 = 0x038600000; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: No media description table, assuming " - "%s transceiver, CSR12 %2.2x.\n", - dev->name, medianame[dev->if_port], - inl(ioaddr + CSR12)); - } - - tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); - return; -} - -/* - Check the MII negotiated duplex, and change the CSR6 setting if - required. - Return 0 if everything is OK. - Return < 0 if the transceiver is missing or has no link beat. - */ -static int check_duplex(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int mii_reg1, mii_reg5, negotiated, duplex; - - if (tp->full_duplex_lock) - return 0; - mii_reg1 = mdio_read(dev, tp->phys[0], 1); - mii_reg5 = mdio_read(dev, tp->phys[0], 5); - if (tulip_debug > 1) - printk(KERN_INFO "%s: MII status %4.4x, Link partner report " - "%4.4x.\n", dev->name, mii_reg1, mii_reg5); - if (mii_reg1 == 0xffff) - return -2; - if ((mii_reg1 & 0x0004) == 0) { - int new_reg1 = mdio_read(dev, tp->phys[0], 1); - if ((new_reg1 & 0x0004) == 0) { - if (tulip_debug > 1) - printk(KERN_INFO "%s: No link beat on the MII interface," - " status %4.4x.\n", dev->name, new_reg1); - return -1; - } - } - negotiated = mii_reg5 & tp->advertising[0]; - duplex = ((negotiated & 0x0300) == 0x0100 - || (negotiated & 0x00C0) == 0x0040); - /* 100baseTx-FD or 10T-FD, but not 100-HD */ - if (tp->full_duplex != duplex) { - tp->full_duplex = duplex; - if (negotiated & 0x038) /* 100mbps. */ - tp->csr6 &= ~0x00400000; - if (tp->full_duplex) tp->csr6 |= 0x0200; - else tp->csr6 &= ~0x0200; - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - if (tulip_debug > 0) - printk(KERN_INFO "%s: Setting %s-duplex based on MII" - "#%d link partner capability of %4.4x.\n", - dev->name, tp->full_duplex ? "full" : "half", - tp->phys[0], mii_reg5); - return 1; - } - return 0; -} - -static void tulip_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - u32 csr12 = inl(ioaddr + CSR12); - int next_tick = 2*HZ; - - if (tulip_debug > 2) { - printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode" - " %8.8x SIA %8.8x %8.8x %8.8x %8.8x.\n", - dev->name, medianame[dev->if_port], inl(ioaddr + CSR5), - inl(ioaddr + CSR6), csr12, inl(ioaddr + CSR13), - inl(ioaddr + CSR14), inl(ioaddr + CSR15)); - } - switch (tp->chip_id) { - case DC21040: - if (!tp->medialock && csr12 & 0x0002) { /* Network error */ - printk(KERN_INFO "%s: No link beat found.\n", - dev->name); - dev->if_port = (dev->if_port == 2 ? 0 : 2); - select_media(dev, 0); - dev->trans_start = jiffies; - } - break; - case DC21041: - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n", - dev->name, csr12); - if (tp->medialock) break; - switch (dev->if_port) { - case 0: case 3: case 4: - if (csr12 & 0x0004) { /*LnkFail */ - /* 10baseT is dead. Check for activity on alternate port. */ - tp->mediasense = 1; - if (csr12 & 0x0200) - dev->if_port = 2; - else - dev->if_port = 1; - printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n", - dev->name, medianame[dev->if_port]); - outl(0, ioaddr + CSR13); /* Reset */ - outl(t21041_csr14[dev->if_port], ioaddr + CSR14); - outl(t21041_csr15[dev->if_port], ioaddr + CSR15); - outl(t21041_csr13[dev->if_port], ioaddr + CSR13); - next_tick = 10*HZ; /* 2.4 sec. */ - } else - next_tick = 30*HZ; - break; - case 1: /* 10base2 */ - case 2: /* AUI */ - if (csr12 & 0x0100) { - next_tick = (30*HZ); /* 30 sec. */ - tp->mediasense = 0; - } else if ((csr12 & 0x0004) == 0) { - printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n", - dev->name); - dev->if_port = 0; - select_media(dev, 0); - next_tick = (24*HZ)/10; /* 2.4 sec. */ - } else if (tp->mediasense || (csr12 & 0x0002)) { - dev->if_port = 3 - dev->if_port; /* Swap ports. */ - select_media(dev, 0); - next_tick = 20*HZ; - } else { - next_tick = 20*HZ; - } - break; - } - break; - case DC21140: case DC21142: case MX98713: case COMPEX9881: default: { - struct medialeaf *mleaf; - unsigned char *p; - if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */ - /* Not much that can be done. - Assume this a generic MII or SYM transceiver. */ - next_tick = 60*HZ; - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x " - "CSR12 0x%2.2x.\n", - dev->name, inl(ioaddr + CSR6), csr12 & 0xff); - break; - } - mleaf = &tp->mtable->mleaf[tp->cur_index]; - p = mleaf->leafdata; - switch (mleaf->type) { - case 0: case 4: { - /* Type 0 serial or 4 SYM transceiver. Check the link beat bit. */ - int offset = mleaf->type == 4 ? 5 : 2; - s8 bitnum = p[offset]; - if (p[offset+1] & 0x80) { - if (tulip_debug > 1) - printk(KERN_DEBUG"%s: Transceiver monitor tick " - "CSR12=%#2.2x, no media sense.\n", - dev->name, csr12); - if (mleaf->type == 4) { - if (mleaf->media == 3 && (csr12 & 0x02)) - goto select_next_media; - } - break; - } - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x" - " bit %d is %d, expecting %d.\n", - dev->name, csr12, (bitnum >> 1) & 7, - (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, - (bitnum >= 0)); - /* Check that the specified bit has the proper value. */ - if ((bitnum < 0) != - ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name, - medianame[mleaf->media]); - if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */ - goto actually_mii; - break; - } - if (tp->medialock) - break; - select_next_media: - if (--tp->cur_index < 0) { - /* We start again, but should instead look for default. */ - tp->cur_index = tp->mtable->leafcount - 1; - } - dev->if_port = tp->mtable->mleaf[tp->cur_index].media; - if (media_cap[dev->if_port] & MediaIsFD) - goto select_next_media; /* Skip FD entries. */ - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: No link beat on media %s," - " trying transceiver type %s.\n", - dev->name, medianame[mleaf->media & 15], - medianame[tp->mtable->mleaf[tp->cur_index].media]); - select_media(dev, 0); - /* Restart the transmit process. */ - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - next_tick = (24*HZ)/10; - break; - } - case 1: case 3: /* 21140, 21142 MII */ - actually_mii: - check_duplex(dev); - next_tick = 60*HZ; - break; - case 2: /* 21142 serial block has no link beat. */ - default: - break; - } - } - break; - } - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - - -/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list - of available transceivers. */ -static void t21142_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr12 = inl(ioaddr + CSR12); - int next_tick = 60*HZ; - int new_csr6 = 0; - - if (tulip_debug > 2) - printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n", - dev->name, csr12, medianame[dev->if_port]); - if (media_cap[dev->if_port] & MediaIsMII) { - check_duplex(dev); - next_tick = 60*HZ; - } else if (tp->nwayset) { - /* Don't screw up a negotiated session! */ - if (tulip_debug > 1) - printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n", - dev->name, medianame[dev->if_port], csr12); - } else if (tp->medialock) { - ; - } else if (dev->if_port == 3) { - if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */ - if (tulip_debug > 1) - printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, " - "trying NWay.\n", dev->name, csr12); - t21142_start_nway(dev); - next_tick = 3*HZ; - } - } else if ((csr12 & 0x7000) != 0x5000) { - /* Negotiation failed. Search media types. */ - if (tulip_debug > 1) - printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n", - dev->name, csr12); - if (!(csr12 & 4)) { /* 10mbps link beat good. */ - new_csr6 = 0x82420000; - dev->if_port = 0; - outl(0, ioaddr + CSR13); - outl(0x0003FFFF, ioaddr + CSR14); - outw(t21142_csr15[dev->if_port], ioaddr + CSR15); - outl(t21142_csr13[dev->if_port], ioaddr + CSR13); - } else { - /* Select 100mbps port to check for link beat. */ - new_csr6 = 0x83860000; - dev->if_port = 3; - outl(0, ioaddr + CSR13); - outl(0x0003FF7F, ioaddr + CSR14); - outw(8, ioaddr + CSR15); - outl(1, ioaddr + CSR13); - } - if (tulip_debug > 1) - printk(KERN_INFO"%s: Testing new 21143 media %s.\n", - dev->name, medianame[dev->if_port]); - if (new_csr6 != (tp->csr6 & ~0x00D5)) { - tp->csr6 &= 0x00D5; - tp->csr6 |= new_csr6; - outl(0x0301, ioaddr + CSR12); - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - } - next_tick = 3*HZ; - } - - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - - -static void t21142_start_nway(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr14 = ((tp->to_advertise & 0x0780) << 9) | - ((tp->to_advertise&0x0020)<<1) | 0xffbf; - - dev->if_port = 0; - tp->nway = tp->mediasense = 1; - tp->nwayset = tp->lpar = 0; - if (debug > 1) - printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n", - dev->name, csr14); - outl(0x0001, ioaddr + CSR13); - outl(csr14, ioaddr + CSR14); - tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); - outl_CSR6(tp, tp->csr6); - if (tp->mtable && tp->mtable->csr15dir) { - outl(tp->mtable->csr15dir, ioaddr + CSR15); - outl(tp->mtable->csr15val, ioaddr + CSR15); - } else - outw(0x0008, ioaddr + CSR15); - outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */ -} - - -static void t21142_lnk_change(struct net_device *dev, int csr5) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr12 = inl(ioaddr + CSR12); - - if (tulip_debug > 1) - printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, " - "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14)); - - /* If NWay finished and we have a negotiated partner capability. */ - if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) { - int setup_done = 0; - int negotiated = tp->to_advertise & (csr12 >> 16); - tp->lpar = csr12 >> 16; - tp->nwayset = 1; - if (negotiated & 0x0100) dev->if_port = 5; - else if (negotiated & 0x0080) dev->if_port = 3; - else if (negotiated & 0x0040) dev->if_port = 4; - else if (negotiated & 0x0020) dev->if_port = 0; - else { - tp->nwayset = 0; - if ((csr12 & 2) == 0 && (tp->to_advertise & 0x0180)) - dev->if_port = 3; - } - tp->full_duplex = (media_cap[dev->if_port] & MediaAlwaysFD) ? 1:0; - - if (tulip_debug > 1) { - if (tp->nwayset) - printk(KERN_INFO "%s: Switching to %s based on link " - "negotiation %4.4x & %4.4x = %4.4x.\n", - dev->name, medianame[dev->if_port], tp->to_advertise, - tp->lpar, negotiated); - else - printk(KERN_INFO "%s: Autonegotiation failed, using %s," - " link beat status %4.4x.\n", - dev->name, medianame[dev->if_port], csr12); - } - - if (tp->mtable) { - int i; - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == dev->if_port) { - tp->cur_index = i; - select_media(dev, 0); - setup_done = 1; - break; - } - } - if ( ! setup_done) { - tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000; - if (tp->full_duplex) - tp->csr6 |= 0x0200; - outl(1, ioaddr + CSR13); - } -#if 0 /* Restart shouldn't be needed. */ - outl_CSR6(tp, tp->csr6 | 0x0000); - if (debug > 2) - printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n", - dev->name, inl(ioaddr + CSR5)); -#endif - outl_CSR6(tp, tp->csr6 | 0x2002); - if (debug > 2) - printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 %8.8x.\n", - dev->name, tp->csr6, inl(ioaddr + CSR6), - inl(ioaddr + CSR12)); - } else if ((tp->nwayset && (csr5 & 0x08000000) - && (dev->if_port == 3 || dev->if_port == 5) - && (csr12 & 2) == 2) || - (tp->nway && (csr5 & (TPLnkFail)))) { - /* Link blew? Maybe restart NWay. */ - del_timer(&tp->timer); - t21142_start_nway(dev); - tp->timer.expires = RUN_AT(3*HZ); - add_timer(&tp->timer); - } else if (dev->if_port == 3 || dev->if_port == 5) { - if (tulip_debug > 1) - printk(KERN_INFO"%s: 21143 %s link beat %s.\n", - dev->name, medianame[dev->if_port], - (csr12 & 2) ? "failed" : "good"); - if ((csr12 & 2) && ! tp->medialock) { - del_timer(&tp->timer); - t21142_start_nway(dev); - tp->timer.expires = RUN_AT(3*HZ); - add_timer(&tp->timer); - } - } else if (dev->if_port == 0 || dev->if_port == 4) { - if ((csr12 & 4) == 0) - printk(KERN_INFO"%s: 21143 10baseT link beat good.\n", - dev->name); - } else if (!(csr12 & 4)) { /* 10mbps link beat good. */ - if (tulip_debug) - printk(KERN_INFO"%s: 21143 10mbps sensed media.\n", - dev->name); - dev->if_port = 0; - } else if (tp->nwayset) { - if (tulip_debug) - printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n", - dev->name, medianame[dev->if_port], tp->csr6); - } else { /* 100mbps link beat good. */ - if (tulip_debug) - printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n", - dev->name); - dev->if_port = 3; - tp->csr6 = 0x83860000; - outl(0x0003FF7F, ioaddr + CSR14); - outl(0x0301, ioaddr + CSR12); - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - } -} - - -static void mxic_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 60*HZ; - - if (tulip_debug > 3) { - printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name, - inl(ioaddr + CSR12)); - } - if (next_tick) { - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); - } -} - - -static void pnic_do_nway(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - u32 phy_reg = inl(ioaddr + 0xB8); - u32 new_csr6 = tp->csr6 & ~0x40C40200; - - if (phy_reg & 0x78000000) { /* Ignore baseT4 */ - if (phy_reg & 0x20000000) dev->if_port = 5; - else if (phy_reg & 0x40000000) dev->if_port = 3; - else if (phy_reg & 0x10000000) dev->if_port = 4; - else if (phy_reg & 0x08000000) dev->if_port = 0; - tp->nwayset = 1; - new_csr6 = (dev->if_port & 1) ? 0x01860000 : 0x00420000; - outl(0x32 | (dev->if_port & 1), ioaddr + CSR12); - if (dev->if_port & 1) - outl(0x1F868, ioaddr + 0xB8); - if (phy_reg & 0x30000000) { - tp->full_duplex = 1; - new_csr6 |= 0x00000200; - } - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n", - dev->name, phy_reg, medianame[dev->if_port]); - if (tp->csr6 != new_csr6) { - tp->csr6 = new_csr6; - /* Restart Tx */ - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - dev->trans_start = jiffies; - } - } -} - - -static void pnic_lnk_change(struct net_device *dev, int csr5) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int phy_reg = inl(ioaddr + 0xB8); - - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n", - dev->name, phy_reg, csr5); - if (inl(ioaddr + CSR5) & TPLnkFail) { - outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7); - if (! tp->nwayset || jiffies - dev->trans_start > 1*HZ) { - tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff); - outl_CSR6(tp, tp->csr6); - outl(0x30, ioaddr + CSR12); - outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ - dev->trans_start = jiffies; - } - } else if (inl(ioaddr + CSR5) & TPLnkPass) { - pnic_do_nway(dev); - outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7); - } -} - - -static void pnic_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 60*HZ; - - if (media_cap[dev->if_port] & MediaIsMII) { - if (check_duplex(dev) > 0) - next_tick = 3*HZ; - } else { - int csr12 = inl(ioaddr + CSR12); - int new_csr6 = tp->csr6 & ~0x40C40200; - int phy_reg = inl(ioaddr + 0xB8); - int csr5 = inl(ioaddr + CSR5); - - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s " - "CSR5 %8.8x.\n", - dev->name, phy_reg, medianame[dev->if_port], csr5); - if (phy_reg & 0x04000000) { /* Remote link fault */ - outl(0x0201F078, ioaddr + 0xB8); - next_tick = 1*HZ; - tp->nwayset = 0; - } else if (phy_reg & 0x78000000) { /* Ignore baseT4 */ - pnic_do_nway(dev); - next_tick = 60*HZ; - } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */ - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, " - "CSR5 %8.8x, PHY %3.3x.\n", - dev->name, medianame[dev->if_port], csr12, - inl(ioaddr + CSR5), inl(ioaddr + 0xB8)); - next_tick = 3*HZ; - if (tp->medialock) { - } else if (tp->nwayset && (dev->if_port & 1)) { - next_tick = 1*HZ; - } else if (dev->if_port == 0) { - dev->if_port = 3; - outl(0x33, ioaddr + CSR12); - new_csr6 = 0x01860000; - outl(0x1F868, ioaddr + 0xB8); - } else { - dev->if_port = 0; - outl(0x32, ioaddr + CSR12); - new_csr6 = 0x00420000; - outl(0x1F078, ioaddr + 0xB8); - } - if (tp->csr6 != new_csr6) { - tp->csr6 = new_csr6; - /* Restart Tx */ - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - dev->trans_start = jiffies; - if (tulip_debug > 1) - printk(KERN_INFO "%s: Changing PNIC configuration to %s " - "%s-duplex, CSR6 %8.8x.\n", - dev->name, medianame[dev->if_port], - tp->full_duplex ? "full" : "half", new_csr6); - } - } - } - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - -static void comet_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 60*HZ; - - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability " - "%4.4x.\n", - dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8)); - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - -static void tulip_tx_timeout(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - - if (media_cap[dev->if_port] & MediaIsMII) { - /* Do nothing -- the media monitor should handle this. */ - if (tulip_debug > 1) - printk(KERN_WARNING "%s: Transmit timeout using MII device.\n", - dev->name); - } else if (tp->chip_id == DC21040) { - if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) { - dev->if_port = (dev->if_port == 2 ? 0 : 2); - printk(KERN_INFO "%s: transmit timed out, switching to " - "%s.\n", - dev->name, medianame[dev->if_port]); - select_media(dev, 0); - } - dev->trans_start = jiffies; - return; - } else if (tp->chip_id == DC21041) { - int csr12 = inl(ioaddr + CSR12); - - printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, " - "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n", - dev->name, inl(ioaddr + CSR5), csr12, - inl(ioaddr + CSR13), inl(ioaddr + CSR14)); - tp->mediasense = 1; - if ( ! tp->medialock) { - if (dev->if_port == 1 || dev->if_port == 2) - if (csr12 & 0x0004) { - dev->if_port = 2 - dev->if_port; - } else - dev->if_port = 0; - else - dev->if_port = 1; - select_media(dev, 0); - } - } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 - || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) { - printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " - "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", - dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12), - inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); - if ( ! tp->medialock && tp->mtable) { - do - --tp->cur_index; - while (tp->cur_index >= 0 - && (media_cap[tp->mtable->mleaf[tp->cur_index].media] - & MediaIsFD)); - if (--tp->cur_index < 0) { - /* We start again, but should instead look for default. */ - tp->cur_index = tp->mtable->leafcount - 1; - } - select_media(dev, 0); - printk(KERN_WARNING "%s: transmit timed out, switching to %s " - "media.\n", dev->name, medianame[dev->if_port]); - } - } else { - printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 " - "%8.8x, resetting...\n", - dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12)); - dev->if_port = 0; - } - -#if defined(way_too_many_messages) - if (tulip_debug > 3) { - int i; - for (i = 0; i < RX_RING_SIZE; i++) { - u8 *buf = (u8 *)(tp->rx_ring[i].buffer1); - int j; - printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x " - "%2.2x %2.2x %2.2x.\n", - i, (unsigned int)tp->rx_ring[i].status, - (unsigned int)tp->rx_ring[i].length, - (unsigned int)tp->rx_ring[i].buffer1, - (unsigned int)tp->rx_ring[i].buffer2, - buf[0], buf[1], buf[2]); - for (j = 0; buf[j] != 0xee && j < 1600; j++) - if (j < 100) printk(" %2.2x", buf[j]); - printk(" j=%d.\n", j); - } - printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring); - for (i = 0; i < RX_RING_SIZE; i++) - printk(" %8.8x", (unsigned int)tp->rx_ring[i].status); - printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring); - for (i = 0; i < TX_RING_SIZE; i++) - printk(" %8.8x", (unsigned int)tp->tx_ring[i].status); - printk("\n"); - } -#endif - - /* Stop and restart the chip's Tx processes . */ - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - /* Trigger an immediate transmit demand. */ - outl(0, ioaddr + CSR1); - - dev->trans_start = jiffies; - tp->stats.tx_errors++; - return; -} - - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void tulip_init_ring(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int i; - - tp->tx_full = 0; - tp->cur_rx = tp->cur_tx = 0; - tp->dirty_rx = tp->dirty_tx = 0; - tp->susp_rx = 0; - tp->ttimer = 0; - tp->nir = 0; - - for (i = 0; i < RX_RING_SIZE; i++) { - tp->rx_ring[i].status = 0x00000000; - tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ); - tp->rx_ring[i].buffer2 = virt_to_le32desc(&tp->rx_ring[i+1]); - tp->rx_skbuff[i] = NULL; - } - /* Mark the last entry as wrapping the ring. */ - tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP); - tp->rx_ring[i-1].buffer2 = virt_to_le32desc(&tp->rx_ring[0]); - - for (i = 0; i < RX_RING_SIZE; i++) { - /* Note the receive buffer must be longword aligned. - dev_alloc_skb() provides 16 byte alignment. But do *not* - use skb_reserve() to align the IP header! */ - struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ); - tp->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb->dev = dev; /* Mark as being used by this device. */ - tp->rx_ring[i].status = cpu_to_le32(DescOwned); /* Owned by Tulip chip */ - tp->rx_ring[i].buffer1 = virt_to_le32desc(skb->tail); - } - tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); - - /* The Tx buffer descriptor is filled in as needed, but we - do need to clear the ownership bit. */ - for (i = 0; i < TX_RING_SIZE; i++) { - tp->tx_skbuff[i] = 0; - tp->tx_ring[i].status = 0x00000000; - tp->tx_ring[i].buffer2 = virt_to_le32desc(&tp->tx_ring[i+1]); - } - tp->tx_ring[i-1].buffer2 = virt_to_le32desc(&tp->tx_ring[0]); -} - -static int -tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int entry; - u32 flag; - unsigned long cpuflags; - - /* Caution: the write order is important here, set the field - with the ownership bits last. */ - - spin_lock_irqsave(&tp->tx_lock, cpuflags); - - /* Calculate the next Tx descriptor entry. */ - entry = tp->cur_tx % TX_RING_SIZE; - - tp->tx_skbuff[entry] = skb; - tp->tx_ring[entry].buffer1 = virt_to_le32desc(skb->data); - - if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ - flag = 0x60000000; /* No interrupt */ - } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) { - flag = 0xe0000000; /* Tx-done intr. */ - } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) { - flag = 0x60000000; /* No Tx-done intr. */ - } else { /* Leave room for set_rx_mode() to fill entries. */ - tp->tx_full = 1; - flag = 0xe0000000; /* Tx-done intr. */ - netif_stop_queue(dev); - } - if (entry == TX_RING_SIZE-1) - flag = 0xe0000000 | DESC_RING_WRAP; - - tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag); - tp->tx_ring[entry].status = cpu_to_le32(DescOwned); - tp->cur_tx++; - spin_unlock_irqrestore(&tp->tx_lock, cpuflags); - - /* Trigger an immediate transmit demand. */ - outl(0, dev->base_addr + CSR1); - - dev->trans_start = jiffies; - - return 0; -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *)dev_instance; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr5; - int entry; - int missed; - int rx = 0; - int tx = 0; - int oi = 0; - int maxrx = RX_RING_SIZE; - int maxtx = TX_RING_SIZE; - int maxoi = TX_RING_SIZE; - - tp->nir++; - - do { - csr5 = inl(ioaddr + CSR5); - /* Acknowledge all of the current interrupt sources ASAP. */ - outl(csr5 & 0x0001ffff, ioaddr + CSR5); - - if (tulip_debug > 4) - printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", - dev->name, csr5, inl(dev->base_addr + CSR5)); - - if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) - break; - - if (csr5 & (RxIntr | RxNoBuf)) { - rx += tulip_rx(dev); - tulip_refill_rx(dev); - } - - if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { - unsigned int dirty_tx; - - spin_lock(&tp->tx_lock); - - for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; - dirty_tx++) { - int entry = dirty_tx % TX_RING_SIZE; - int status = le32_to_cpu(tp->tx_ring[entry].status); - - if (status < 0) - break; /* It still has not been Txed */ - /* Check for Rx filter setup frames. */ - if (tp->tx_skbuff[entry] == NULL) - continue; - - if (status & 0x8000) { - /* There was an major error, log it. */ -#ifndef final_version - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", - dev->name, status); -#endif - tp->stats.tx_errors++; - if (status & 0x4104) tp->stats.tx_aborted_errors++; - if (status & 0x0C00) tp->stats.tx_carrier_errors++; - if (status & 0x0200) tp->stats.tx_window_errors++; - if (status & 0x0002) tp->stats.tx_fifo_errors++; - if ((status & 0x0080) && tp->full_duplex == 0) - tp->stats.tx_heartbeat_errors++; -#ifdef ETHER_STATS - if (status & 0x0100) tp->stats.collisions16++; -#endif - } else { -#ifdef ETHER_STATS - if (status & 0x0001) tp->stats.tx_deferred++; -#endif - tp->stats.tx_bytes += tp->tx_skbuff[entry]->len; - tp->stats.collisions += (status >> 3) & 15; - tp->stats.tx_packets++; - } - - /* Free the original skb. */ - dev_kfree_skb_irq(tp->tx_skbuff[entry]); - tp->tx_skbuff[entry] = 0; - tx++; - } - -#ifndef final_version - if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { - printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dev->name, dirty_tx, tp->cur_tx, tp->tx_full); - dirty_tx += TX_RING_SIZE; - } -#endif - - if (tp->tx_full && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) { - /* The ring is no longer full, clear tbusy. */ - tp->tx_full = 0; - netif_wake_queue(dev); - } - - tp->dirty_tx = dirty_tx; - if (csr5 & TxDied) { - if (tulip_debug > 2) - printk(KERN_WARNING "%s: The transmitter stopped." - " CSR5 is %x, CSR6 %x, new CSR6 %x.\n", - dev->name, csr5, inl(ioaddr + CSR6), tp->csr6); - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - } - spin_unlock(&tp->tx_lock); - } - - /* Log errors. */ - if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ - if (csr5 == 0xffffffff) - break; - if (csr5 & TxJabber) tp->stats.tx_errors++; - if (csr5 & TxFIFOUnderflow) { - if ((tp->csr6 & 0xC000) != 0xC000) - tp->csr6 += 0x4000; /* Bump up the Tx threshold */ - else - tp->csr6 |= 0x00200000; /* Store-n-forward. */ - /* Restart the transmit process. */ - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - outl(0, ioaddr + CSR1); - } - if (csr5 & RxDied) { /* Missed a Rx frame. */ - tp->stats.rx_errors++; - tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; - outl_CSR6(tp, tp->csr6 | 0x2002); - } - if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { - if (tp->link_change) - (tp->link_change)(dev, csr5); - } - if (csr5 & SytemError) { - printk(KERN_ERR "%s: (%lu) System Error occured\n", dev->name, tp->nir); - } - /* Clear all error sources, included undocumented ones! */ - outl(0x0800f7ba, ioaddr + CSR5); - oi++; - } - if (csr5 & TimerInt) { -#if 0 - if (tulip_debug > 2) - printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n", - dev->name, csr5); - outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); -#endif - tp->ttimer = 0; - oi++; - } - if (tx > maxtx || rx > maxrx || oi > maxoi) { - if (tulip_debug > 1) - printk(KERN_WARNING "%s: Too much work during an interrupt, " - "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi); - /* Acknowledge all interrupt sources. */ -#if 0 - /* Clear all interrupting sources, set timer to re-enable. */ - outl(((~csr5) & 0x0001ebef) | NormalIntr | AbnormalIntr | TimerInt, - ioaddr + CSR7); - outl(12, ioaddr + CSR11); - tp->ttimer = 1; -#endif - break; - } - } while (1); - - tulip_refill_rx(dev); - - /* check if we card is in suspend mode */ - entry = tp->dirty_rx % RX_RING_SIZE; - if (tp->rx_skbuff[entry] == NULL) { - if (tulip_debug > 1) - printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx); - if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) { - if (tulip_debug > 1) - printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir); - outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt, - ioaddr + CSR7); - outl(TimerInt, ioaddr + CSR5); - outl(12, ioaddr + CSR11); - tp->ttimer = 1; - } - } - - if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) { - tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; - } - - if (tulip_debug > 4) - printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n", - dev->name, inl(ioaddr + CSR5)); - -} - -static int tulip_refill_rx(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int entry; - int refilled = 0; - - /* Refill the Rx ring buffers. */ - for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) { - entry = tp->dirty_rx % RX_RING_SIZE; - if (tp->rx_skbuff[entry] == NULL) { - struct sk_buff *skb; - skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ); - if (skb == NULL) - break; - skb->dev = dev; /* Mark as being used by this device. */ - tp->rx_ring[entry].buffer1 = virt_to_le32desc(skb->tail); - refilled++; - } - tp->rx_ring[entry].status = cpu_to_le32(DescOwned); - } - return refilled; -} - -static int tulip_rx(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int entry = tp->cur_rx % RX_RING_SIZE; - int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; - int received = 0; - - if (tulip_debug > 4) - printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, - tp->rx_ring[entry].status); - /* If we own the next entry, it is a new packet. Send it up. */ - while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { - s32 status = le32_to_cpu(tp->rx_ring[entry].status); - - if (tulip_debug > 5) - printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", - dev->name, entry, status); - if (--rx_work_limit < 0) - break; - if ((status & 0x38008300) != 0x0300) { - if ((status & 0x38000300) != 0x0300) { - /* Ingore earlier buffers. */ - if ((status & 0xffff) != 0x7fff) { - if (tulip_debug > 1) - printk(KERN_WARNING "%s: Oversized Ethernet frame " - "spanned multiple buffers, status %8.8x!\n", - dev->name, status); - tp->stats.rx_length_errors++; - } - } else if (status & RxDescFatalErr) { - /* There was a fatal error. */ - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", - dev->name, status); - tp->stats.rx_errors++; /* end of a packet.*/ - if (status & 0x0890) tp->stats.rx_length_errors++; - if (status & 0x0004) tp->stats.rx_frame_errors++; - if (status & 0x0002) tp->stats.rx_crc_errors++; - if (status & 0x0001) tp->stats.rx_fifo_errors++; - } - } else { - /* Omit the four octet CRC from the length. */ - short pkt_len = ((status >> 16) & 0x7ff) - 4; - struct sk_buff *skb; - -#ifndef final_version - if (pkt_len > 1518) { - printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", - dev->name, pkt_len, pkt_len); - pkt_len = 1518; - tp->stats.rx_length_errors++; - } -#endif - /* Check if the packet is long enough to accept without copying - to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { - skb->dev = dev; - skb_reserve(skb, 2); /* 16 byte align the IP header */ -#if ! defined(__alpha__) - eth_copy_and_sum(skb, tp->rx_skbuff[entry]->tail, pkt_len, 0); - skb_put(skb, pkt_len); -#else - memcpy(skb_put(skb, pkt_len), tp->rx_skbuff[entry]->tail, - pkt_len); -#endif - } else { /* Pass up the skb already on the Rx ring. */ - char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len); - tp->rx_skbuff[entry] = NULL; -#ifndef final_version - if (le32desc_to_virt(tp->rx_ring[entry].buffer1) != temp) - printk(KERN_ERR "%s: Internal fault: The skbuff addresses " - "do not match in tulip_rx: %p vs. %p / %p.\n", - dev->name, - le32desc_to_virt(tp->rx_ring[entry].buffer1), - skb->head, temp); -#endif - } - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; - tp->stats.rx_packets++; - tp->stats.rx_bytes += pkt_len; - } - received++; - entry = (++tp->cur_rx) % RX_RING_SIZE; - } - - return received; -} - - -static void tulip_down (struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *) dev->priv; - - netif_device_detach (dev); - - del_timer (&tp->timer); - - /* Disable interrupts by clearing the interrupt mask. */ - outl (0x00000000, ioaddr + CSR7); - - /* Stop the Tx and Rx processes. */ - outl_CSR6 (tp, inl (ioaddr + CSR6) & ~0x2002); - - /* 21040 -- Leave the card in 10baseT state. */ - if (tp->chip_id == DC21040) - outl (0x00000004, ioaddr + CSR13); - - if (inl (ioaddr + CSR6) != 0xffffffff) - tp->stats.rx_missed_errors += inl (ioaddr + CSR8) & 0xffff; - - dev->if_port = tp->saved_if_port; - - /* Leave the driver in snooze, not sleep, mode. */ - if (tp->flags & HAS_ACPI) - pci_write_config_dword (tp->pdev, 0x40, 0x40000000); -} - - -static int tulip_close (struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *) dev->priv; - int i; - - tulip_down (dev); - - if (tulip_debug > 1) - printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, inl (ioaddr + CSR5)); - - free_irq (dev->irq, dev); - - /* Free all the skbuffs in the Rx queue. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = tp->rx_skbuff[i]; - tp->rx_skbuff[i] = 0; - tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */ - tp->rx_ring[i].length = 0; - tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */ - if (skb) { - dev_kfree_skb (skb); - } - } - for (i = 0; i < TX_RING_SIZE; i++) { - if (tp->tx_skbuff[i]) - dev_kfree_skb (tp->tx_skbuff[i]); - tp->tx_skbuff[i] = 0; - } - - MOD_DEC_USE_COUNT; - - return 0; -} - -static struct enet_statistics *tulip_get_stats(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - - if (netif_running(dev)) - tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; - - return &tp->stats; -} - - -/* Provide ioctl() calls to examine the MII xcvr state. */ -static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; - int phy = tp->phys[0] & 0x1f; - long flags; - - switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - if (tp->mii_cnt) - data[0] = phy; - else if (tp->flags & HAS_NWAY143) - data[0] = 32; - else if (tp->chip_id == COMET) - data[0] = 1; - else - return -ENODEV; - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - if (data[0] == 32 && (tp->flags & HAS_NWAY143)) { - int csr12 = inl(ioaddr + CSR12); - int csr14 = inl(ioaddr + CSR14); - switch (data[1]) { - case 0: { - data[3] = (csr14<<5) & 0x1000; - break; } - case 1: - data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0) - + (csr12&0x06 ? 0x04 : 0); - break; - case 4: { - data[3] = ((csr14>>9)&0x07C0) + - ((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1; - break; - } - case 5: data[3] = csr12 >> 16; break; - default: data[3] = 0; break; - } - } else { - save_flags(flags); - cli(); - data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); - restore_flags(flags); - } - return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (data[0] == 32 && (tp->flags & HAS_NWAY143)) { - if (data[1] == 5) - tp->to_advertise = data[2]; - } else { - save_flags(flags); - cli(); - mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); - restore_flags(flags); - } - return 0; - default: - return -EOPNOTSUPP; - } - - return -EOPNOTSUPP; -} - - -/* Set or clear the multicast filter for this adaptor. - Note that we only use exclusion around actually queueing the - new frame, not around filling tp->setup_frame. This is non-deterministic - when re-entered but still correct. */ - -/* The little-endian AUTODIN32 ethernet CRC calculation. - N.B. Do not use for bulk data, use a table-based routine instead. - This is common code and should be moved to net/core/crc.c */ -static unsigned const ethernet_polynomial_le = 0xedb88320U; -static inline u32 ether_crc_le(int length, unsigned char *data) -{ - u32 crc = 0xffffffff; /* Initial value. */ - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 8; --bit >= 0; current_octet >>= 1) { - if ((crc ^ current_octet) & 1) { - crc >>= 1; - crc ^= ethernet_polynomial_le; - } else - crc >>= 1; - } - } - return crc; -} -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc(int length, unsigned char *data) -{ - int crc = -1; - - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - return crc; -} - -static void set_rx_mode(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr6 = inl(ioaddr + CSR6) & ~0x00D5; - unsigned long cpuflags; - - tp->csr6 &= ~0x00D5; - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - tp->csr6 |= 0x00C0; - csr6 |= 0x00C0; - /* Unconditionally log net taps. */ - printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); - } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { - /* Too many to filter well -- accept all multicasts. */ - tp->csr6 |= 0x0080; - csr6 |= 0x0080; - } else if (tp->flags & MC_HASH_ONLY) { - /* Some work-alikes have only a 64-entry hash filter table. */ - /* Should verify correctness on big-endian/__powerpc__ */ - struct dev_mc_list *mclist; - int i; - u32 mc_filter[2]; /* Multicast hash filter */ - if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */ - tp->csr6 |= 0x0080; - csr6 |= 0x0080; - } else { - mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) - set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter); - if (tp->chip_id == AX88140) { - outl(2, ioaddr + CSR13); - outl(mc_filter[0], ioaddr + CSR14); - outl(3, ioaddr + CSR13); - outl(mc_filter[1], ioaddr + CSR14); - } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */ - outl(mc_filter[0], ioaddr + 0xAC); - outl(mc_filter[1], ioaddr + 0xB0); - } - } - } else { - u16 *eaddrs, *setup_frm = tp->setup_frame; - struct dev_mc_list *mclist; - u32 tx_flags = 0x08000000 | 192; - int i; - - /* Note that only the low-address shortword of setup_frame is valid! - The values are doubled for big-endian architectures. */ - if (dev->mc_count > 14) { /* Must use a multicast hash table. */ - u16 hash_table[32]; - tx_flags = 0x08400000 | 192; /* Use hash filter. */ - memset(hash_table, 0, sizeof(hash_table)); - set_bit(255, hash_table); /* Broadcast entry */ - /* This should work on big-endian machines as well. */ - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) - set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, - hash_table); - for (i = 0; i < 32; i++) - *setup_frm++ = *setup_frm++ = hash_table[i]; - setup_frm = &tp->setup_frame[13*6]; - } else { - /* We have <= 14 addresses so we can use the wonderful - 16 address perfect filtering of the Tulip. */ - for (i = 0, mclist = dev->mc_list; i < dev->mc_count; - i++, mclist = mclist->next) { - eaddrs = (u16 *)mclist->dmi_addr; - *setup_frm++ = *setup_frm++ = *eaddrs++; - *setup_frm++ = *setup_frm++ = *eaddrs++; - *setup_frm++ = *setup_frm++ = *eaddrs++; - } - /* Fill the unused entries with the broadcast address. */ - memset(setup_frm, 0xff, (15-i)*12); - setup_frm = &tp->setup_frame[15*6]; - } - /* Fill the final entry with our physical address. */ - eaddrs = (u16 *)dev->dev_addr; - *setup_frm++ = *setup_frm++ = eaddrs[0]; - *setup_frm++ = *setup_frm++ = eaddrs[1]; - *setup_frm++ = *setup_frm++ = eaddrs[2]; - /* Now add this frame to the Tx list. */ - spin_lock_irqsave(&tp->tx_lock, cpuflags); - if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) { - /* Same setup recently queued, we need not add it. */ - } else { - unsigned long flags; - unsigned int entry; - - save_flags(flags); cli(); - entry = tp->cur_tx++ % TX_RING_SIZE; - - if (entry != 0) { - /* Avoid a chip errata by prefixing a dummy entry. */ - tp->tx_skbuff[entry] = 0; - tp->tx_ring[entry].length = - (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0; - tp->tx_ring[entry].buffer1 = 0; - tp->tx_ring[entry].status = cpu_to_le32(DescOwned); - entry = tp->cur_tx++ % TX_RING_SIZE; - } - - tp->tx_skbuff[entry] = 0; - /* Put the setup frame on the Tx list. */ - if (entry == TX_RING_SIZE-1) - tx_flags |= DESC_RING_WRAP; /* Wrap ring. */ - tp->tx_ring[entry].length = cpu_to_le32(tx_flags); - tp->tx_ring[entry].buffer1 = virt_to_le32desc(tp->setup_frame); - tp->tx_ring[entry].status = cpu_to_le32(DescOwned); - if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) { - netif_stop_queue(dev); - tp->tx_full = 1; - } - spin_unlock_irqrestore(&tp->tx_lock, cpuflags); - /* Trigger an immediate transmit demand. */ - outl(0, ioaddr + CSR1); - } - } - outl_CSR6(tp, csr6 | 0x0000); -} - - -static int __devinit tulip_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - static int did_version = 0; /* Already printed version info. */ - struct tulip_private *tp; - /* See note below on the multiport cards. */ - static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; - static int last_irq = 0; - static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */ - u8 chip_rev; - int i, irq; - unsigned short sum; - u8 ee_data[EEPROM_SIZE]; - struct net_device *dev; - long ioaddr; - static int board_idx = -1; - int chip_idx = ent->driver_data; - - board_idx++; - - if (tulip_debug > 0 && did_version++ == 0) - printk (KERN_INFO "%s", version); - - if( pdev->subsystem_vendor == 0x1376 ){ - printk (KERN_ERR PFX "skipping LMC card.\n"); - return -ENODEV; - } - - ioaddr = pci_resource_start (pdev, 0); - irq = pdev->irq; - - /* Make certain the data structures are quadword aligned. */ - dev = init_etherdev (NULL, sizeof (*tp)); - if (!dev) { - printk (KERN_ERR PFX "unable to allocate ether device, aborting\n"); - return -ENOMEM; - } - - /* We do a request_region() only to register /proc/ioports info. */ - /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */ - if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name)) { - printk (KERN_ERR PFX "unable to allocate ether device, aborting\n"); - goto err_out_free_netdev; - } - - if (pci_enable_device(pdev)) { - printk (KERN_ERR PFX "cannot enable PCI device (id %04x:%04x, bus %d, devfn %d), aborting\n", - pdev->vendor, pdev->device, - pdev->bus->number, pdev->devfn); - goto err_out_free_netdev; - } - - pci_set_master(pdev); - - tp = dev->priv; - memset(tp, 0, sizeof(*tp)); - - pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev); - - printk(KERN_INFO "%s: %s rev %d at %#3lx,", - dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); - - /* Stop the chip's Tx and Rx processes. */ - outl_CSR6(tp, inl(ioaddr + CSR6) & ~0x2002); - /* Clear the missed-packet counter. */ - (volatile int)inl(ioaddr + CSR8); - - if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) { - printk(" 21040 compatible mode,"); - chip_idx = DC21040; - } - - /* The station address ROM is read byte serially. The register must - be polled, waiting for the value to be read bit serially from the - EEPROM. - */ - sum = 0; - if (chip_idx == DC21040) { - outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */ - for (i = 0; i < 6; i++) { - int value, boguscnt = 100000; - do - value = inl(ioaddr + CSR9); - while (value < 0 && --boguscnt > 0); - dev->dev_addr[i] = value; - sum += value & 0xff; - } - } else if (chip_idx == LC82C168) { - for (i = 0; i < 3; i++) { - int value, boguscnt = 100000; - outl(0x600 | i, ioaddr + 0x98); - do - value = inl(ioaddr + CSR9); - while (value < 0 && --boguscnt > 0); - put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i); - sum += value & 0xffff; - } - } else if (chip_idx == COMET) { - /* No need to read the EEPROM. */ - put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr); - put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4)); - for (i = 0; i < 6; i ++) - sum += dev->dev_addr[i]; - } else { - /* A serial EEPROM interface, we read now and sort it out later. */ - int sa_offset = 0; - int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6; - - for (i = 0; i < sizeof(ee_data)/2; i++) - ((u16 *)ee_data)[i] = - le16_to_cpu(read_eeprom(ioaddr, i, ee_addr_size)); - - /* DEC now has a specification (see Notes) but early board makers - just put the address in the first EEPROM locations. */ - /* This does memcmp(eedata, eedata+16, 8) */ - for (i = 0; i < 8; i ++) - if (ee_data[i] != ee_data[16+i]) - sa_offset = 20; - if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) { - sa_offset = 2; /* Grrr, damn Matrox boards. */ - multiport_cnt = 4; - } - for (i = 0; i < 6; i ++) { - dev->dev_addr[i] = ee_data[i + sa_offset]; - sum += ee_data[i + sa_offset]; - } - } - /* Lite-On boards have the address byte-swapped. */ - if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0) - && dev->dev_addr[1] == 0x00) - for (i = 0; i < 6; i+=2) { - char tmp = dev->dev_addr[i]; - dev->dev_addr[i] = dev->dev_addr[i+1]; - dev->dev_addr[i+1] = tmp; - } - /* On the Zynx 315 Etherarray and other multiport boards only the - first Tulip has an EEPROM. - The addresses of the subsequent ports are derived from the first. - Many PCI BIOSes also incorrectly report the IRQ line, so we correct - that here as well. */ - if (sum == 0 || sum == 6*0xff) { - printk(" EEPROM not present,"); - for (i = 0; i < 5; i++) - dev->dev_addr[i] = last_phys_addr[i]; - dev->dev_addr[i] = last_phys_addr[i] + 1; -#if defined(__i386__) /* Patch up x86 BIOS bug. */ - if (last_irq) - irq = last_irq; -#endif - } - - for (i = 0; i < 6; i++) - printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]); - printk(", IRQ %d.\n", irq); - last_irq = irq; - - pdev->driver_data = dev; - dev->base_addr = ioaddr; - dev->irq = irq; - - tp->chip_id = chip_idx; - tp->revision = chip_rev; - tp->flags = tulip_tbl[chip_idx].flags; - tp->csr0 = csr0; - tp->pdev = pdev; - tp->base_addr = dev->base_addr; - - /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. - And the ASIX must have a burst limit or horrible things happen. */ - if (chip_idx == DC21143 && chip_rev == 65) - tp->csr0 &= ~0x01000000; - else if (chip_idx == AX88140) - tp->csr0 |= 0x2000; - -#ifdef TULIP_FULL_DUPLEX - tp->full_duplex = 1; - tp->full_duplex_lock = 1; -#endif -#ifdef TULIP_DEFAULT_MEDIA - tp->default_port = TULIP_DEFAULT_MEDIA; -#endif -#ifdef TULIP_NO_MEDIA_SWITCH - tp->medialock = 1; -#endif - tp->tx_lock = SPIN_LOCK_UNLOCKED; - - /* The lower four bits are the media type. */ - if (board_idx >= 0 && board_idx < MAX_UNITS) { - tp->default_port = options[board_idx] & 15; - if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0) - tp->full_duplex = 1; - if (mtu[board_idx] > 0) - dev->mtu = mtu[board_idx]; - } - if (dev->mem_start) - tp->default_port = dev->mem_start; - if (tp->default_port) { - tp->medialock = 1; - if (media_cap[tp->default_port] & MediaAlwaysFD) - tp->full_duplex = 1; - } - if (tp->full_duplex) - tp->full_duplex_lock = 1; - - if (media_cap[tp->default_port] & MediaIsMII) { - u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 }; - tp->to_advertise = media2advert[tp->default_port - 9]; - } else if (tp->flags & HAS_8023X) - tp->to_advertise = 0x05e1; - else - tp->to_advertise = 0x01e1; - - /* This is logically part of probe1(), but too complex to write inline. */ - if (tp->flags & HAS_MEDIA_TABLE) { - memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom)); - parse_eeprom(dev); - } - - if ((tp->flags & ALWAYS_CHECK_MII) || - (tp->mtable && tp->mtable->has_mii) || - ( ! tp->mtable && (tp->flags & HAS_MII))) { - int phy, phy_idx; - if (tp->mtable && tp->mtable->has_mii) { - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == 11) { - tp->cur_index = i; - tp->saved_if_port = dev->if_port; - select_media(dev, 1); - dev->if_port = tp->saved_if_port; - break; - } - } - /* Find the connected MII xcvrs. - Doing this in open() would allow detecting external xcvrs later, - but takes much time. */ - for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); - phy++) { - int mii_status = mdio_read(dev, phy, 1); - if ((mii_status & 0x8301) == 0x8001 || - ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { - int mii_reg0 = mdio_read(dev, phy, 0); - int mii_advert = mdio_read(dev, phy, 4); - int reg4 = ((mii_status>>6) & tp->to_advertise) | 1; - tp->phys[phy_idx] = phy; - tp->advertising[phy_idx++] = reg4; - printk(KERN_INFO "%s: MII transceiver #%d " - "config %4.4x status %4.4x advertising %4.4x.\n", - dev->name, phy, mii_reg0, mii_status, mii_advert); - /* Fixup for DLink with miswired PHY. */ - if (mii_advert != reg4) { - printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d," - " previously advertising %4.4x.\n", - dev->name, reg4, phy, mii_advert); - printk(KERN_DEBUG "%s: Advertising %4.4x (to advertise" - " is %4.4x).\n", - dev->name, reg4, tp->to_advertise); - mdio_write(dev, phy, 4, reg4); - } - /* Enable autonegotiation: some boards default to off. */ - mdio_write(dev, phy, 0, mii_reg0 | - (tp->full_duplex ? 0x1100 : 0x1000) | - (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0)); - } - } - tp->mii_cnt = phy_idx; - if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { - printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n", - dev->name); - tp->phys[0] = 1; - } - } - - /* The Tulip-specific entries in the device structure. */ - dev->open = tulip_open; - dev->hard_start_xmit = tulip_start_xmit; - dev->tx_timeout = tulip_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - dev->stop = tulip_close; - dev->get_stats = tulip_get_stats; - dev->do_ioctl = private_ioctl; - dev->set_multicast_list = set_rx_mode; - - if ((tp->flags & HAS_NWAY143) || tp->chip_id == DC21041) - tp->link_change = t21142_lnk_change; - else if (tp->flags & HAS_PNICNWAY) - tp->link_change = pnic_lnk_change; - - /* Reset the xcvr interface and turn on heartbeat. */ - switch (chip_idx) { - case DC21041: - tp->to_advertise = 0x0061; - outl(0x00000000, ioaddr + CSR13); - outl(0xFFFFFFFF, ioaddr + CSR14); - outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ - outl_CSR6(tp, inl(ioaddr + CSR6) | 0x0200); - outl(0x0000EF05, ioaddr + CSR13); - break; - case DC21040: - outl(0x00000000, ioaddr + CSR13); - outl(0x00000004, ioaddr + CSR13); - break; - case DC21140: default: - if (tp->mtable) - outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); - break; - case DC21142: - case PNIC2: - if (tp->mii_cnt || media_cap[dev->if_port] & MediaIsMII) { - outl_CSR6(tp, 0x82020000); - outl(0x0000, ioaddr + CSR13); - outl(0x0000, ioaddr + CSR14); - outl_CSR6(tp, 0x820E0000); - } else - t21142_start_nway(dev); - break; - case LC82C168: - if ( ! tp->mii_cnt) { - tp->nway = 1; - tp->nwayset = 0; - outl_CSR6(tp, 0x00420000); - outl(0x30, ioaddr + CSR12); - outl_CSR6(tp, 0x0001F078); - outl_CSR6(tp, 0x0201F078); /* Turn on autonegotiation. */ - } - break; - case MX98713: case COMPEX9881: - outl_CSR6(tp, 0x00000000); - outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */ - outl(0x00000001, ioaddr + CSR13); - break; - case MX98715: case MX98725: - outl_CSR6(tp, 0x01a80000); - outl(0xFFFFFFFF, ioaddr + CSR14); - outl(0x00001000, ioaddr + CSR12); - break; - case COMET: - /* No initialization necessary. */ - break; - } - - /* put the chip in snooze mode until opened */ - if (tulip_tbl[chip_idx].flags & HAS_ACPI) - pci_write_config_dword(pdev, 0x40, 0x40000000); - - return 0; - -err_out_free_netdev: - unregister_netdev (dev); - kfree (dev); - return -ENODEV; -} - - -static void tulip_suspend (struct pci_dev *pdev) -{ - struct net_device *dev = pdev->driver_data; - - if (dev && netif_device_present (dev)) - tulip_down (dev); -} - - -static void tulip_resume (struct pci_dev *pdev) -{ - struct net_device *dev = pdev->driver_data; - - if (dev && !netif_device_present (dev)) - tulip_up (dev); -} - - -static void __devexit tulip_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pdev->driver_data; - - if (dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; - unregister_netdev(dev); - release_region(dev->base_addr, - tulip_tbl[tp->chip_id].io_size); - kfree(dev); - } -} - - -static struct pci_driver tulip_driver = { - name: TULIP_MODULE_NAME, - id_table: tulip_pci_tbl, - probe: tulip_init_one, - remove: tulip_remove_one, - suspend: tulip_suspend, - resume: tulip_resume, -}; - - -static int __init tulip_init (void) -{ - return pci_module_init (&tulip_driver); -} - - -static void __exit tulip_cleanup (void) -{ - pci_unregister_driver (&tulip_driver); -} - - -module_init(tulip_init); -module_exit(tulip_cleanup); diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c new file mode 100644 index 000000000..57b3aa252 --- /dev/null +++ b/drivers/net/tulip/21142.c @@ -0,0 +1,235 @@ +/* + drivers/net/tulip/21142.c + + Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include "tulip.h" +#include <asm/io.h> + + +static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, }; +u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, }; +static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; + + + +/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list + of available transceivers. */ +void t21142_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr12 = inl(ioaddr + CSR12); + int next_tick = 60*HZ; + int new_csr6 = 0; + + if (tulip_debug > 2) + printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n", + dev->name, csr12, medianame[dev->if_port]); + if (tulip_media_cap[dev->if_port] & MediaIsMII) { + tulip_check_duplex(dev); + next_tick = 60*HZ; + } else if (tp->nwayset) { + /* Don't screw up a negotiated session! */ + if (tulip_debug > 1) + printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n", + dev->name, medianame[dev->if_port], csr12); + } else if (tp->medialock) { + ; + } else if (dev->if_port == 3) { + if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */ + if (tulip_debug > 1) + printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, " + "trying NWay.\n", dev->name, csr12); + t21142_start_nway(dev); + next_tick = 3*HZ; + } + } else if ((csr12 & 0x7000) != 0x5000) { + /* Negotiation failed. Search media types. */ + if (tulip_debug > 1) + printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n", + dev->name, csr12); + if (!(csr12 & 4)) { /* 10mbps link beat good. */ + new_csr6 = 0x82420000; + dev->if_port = 0; + outl(0, ioaddr + CSR13); + outl(0x0003FFFF, ioaddr + CSR14); + outw(t21142_csr15[dev->if_port], ioaddr + CSR15); + outl(t21142_csr13[dev->if_port], ioaddr + CSR13); + } else { + /* Select 100mbps port to check for link beat. */ + new_csr6 = 0x83860000; + dev->if_port = 3; + outl(0, ioaddr + CSR13); + outl(0x0003FF7F, ioaddr + CSR14); + outw(8, ioaddr + CSR15); + outl(1, ioaddr + CSR13); + } + if (tulip_debug > 1) + printk(KERN_INFO"%s: Testing new 21143 media %s.\n", + dev->name, medianame[dev->if_port]); + if (new_csr6 != (tp->csr6 & ~0x00D5)) { + tp->csr6 &= 0x00D5; + tp->csr6 |= new_csr6; + outl(0x0301, ioaddr + CSR12); + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + } + next_tick = 3*HZ; + } + + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + + +void t21142_start_nway(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr14 = ((tp->to_advertise & 0x0780) << 9) | + ((tp->to_advertise&0x0020)<<1) | 0xffbf; + + dev->if_port = 0; + tp->nway = tp->mediasense = 1; + tp->nwayset = tp->lpar = 0; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n", + dev->name, csr14); + outl(0x0001, ioaddr + CSR13); + outl(csr14, ioaddr + CSR14); + tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); + tulip_outl_CSR6(tp, tp->csr6); + if (tp->mtable && tp->mtable->csr15dir) { + outl(tp->mtable->csr15dir, ioaddr + CSR15); + outl(tp->mtable->csr15val, ioaddr + CSR15); + } else + outw(0x0008, ioaddr + CSR15); + outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */ +} + + +void t21142_lnk_change(struct net_device *dev, int csr5) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr12 = inl(ioaddr + CSR12); + + if (tulip_debug > 1) + printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, " + "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14)); + + /* If NWay finished and we have a negotiated partner capability. */ + if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) { + int setup_done = 0; + int negotiated = tp->to_advertise & (csr12 >> 16); + tp->lpar = csr12 >> 16; + tp->nwayset = 1; + if (negotiated & 0x0100) dev->if_port = 5; + else if (negotiated & 0x0080) dev->if_port = 3; + else if (negotiated & 0x0040) dev->if_port = 4; + else if (negotiated & 0x0020) dev->if_port = 0; + else { + tp->nwayset = 0; + if ((csr12 & 2) == 0 && (tp->to_advertise & 0x0180)) + dev->if_port = 3; + } + tp->full_duplex = (tulip_media_cap[dev->if_port] & MediaAlwaysFD) ? 1:0; + + if (tulip_debug > 1) { + if (tp->nwayset) + printk(KERN_INFO "%s: Switching to %s based on link " + "negotiation %4.4x & %4.4x = %4.4x.\n", + dev->name, medianame[dev->if_port], tp->to_advertise, + tp->lpar, negotiated); + else + printk(KERN_INFO "%s: Autonegotiation failed, using %s," + " link beat status %4.4x.\n", + dev->name, medianame[dev->if_port], csr12); + } + + if (tp->mtable) { + int i; + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == dev->if_port) { + tp->cur_index = i; + tulip_select_media(dev, 0); + setup_done = 1; + break; + } + } + if ( ! setup_done) { + tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000; + if (tp->full_duplex) + tp->csr6 |= 0x0200; + outl(1, ioaddr + CSR13); + } +#if 0 /* Restart shouldn't be needed. */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0000); + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n", + dev->name, inl(ioaddr + CSR5)); +#endif + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 %8.8x.\n", + dev->name, tp->csr6, inl(ioaddr + CSR6), + inl(ioaddr + CSR12)); + } else if ((tp->nwayset && (csr5 & 0x08000000) + && (dev->if_port == 3 || dev->if_port == 5) + && (csr12 & 2) == 2) || + (tp->nway && (csr5 & (TPLnkFail)))) { + /* Link blew? Maybe restart NWay. */ + del_timer(&tp->timer); + t21142_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + } else if (dev->if_port == 3 || dev->if_port == 5) { + if (tulip_debug > 1) + printk(KERN_INFO"%s: 21143 %s link beat %s.\n", + dev->name, medianame[dev->if_port], + (csr12 & 2) ? "failed" : "good"); + if ((csr12 & 2) && ! tp->medialock) { + del_timer(&tp->timer); + t21142_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + } + } else if (dev->if_port == 0 || dev->if_port == 4) { + if ((csr12 & 4) == 0) + printk(KERN_INFO"%s: 21143 10baseT link beat good.\n", + dev->name); + } else if (!(csr12 & 4)) { /* 10mbps link beat good. */ + if (tulip_debug) + printk(KERN_INFO"%s: 21143 10mbps sensed media.\n", + dev->name); + dev->if_port = 0; + } else if (tp->nwayset) { + if (tulip_debug) + printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n", + dev->name, medianame[dev->if_port], tp->csr6); + } else { /* 100mbps link beat good. */ + if (tulip_debug) + printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n", + dev->name); + dev->if_port = 3; + tp->csr6 = 0x83860000; + outl(0x0003FF7F, ioaddr + CSR14); + outl(0x0301, ioaddr + CSR12); + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + } +} + + diff --git a/drivers/net/tulip/Makefile b/drivers/net/tulip/Makefile new file mode 100644 index 000000000..6e1368e32 --- /dev/null +++ b/drivers/net/tulip/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the Tulip ethernet driver +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +O_TARGET := tulip.o +O_OBJS := 21142.o eeprom.o interrupt.o media.o pnic.o timer.o tulip_core.o +M_OBJS := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c new file mode 100644 index 000000000..7ac6aa08d --- /dev/null +++ b/drivers/net/tulip/eeprom.c @@ -0,0 +1,270 @@ +/* + drivers/net/tulip/eeprom.c + + Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include "tulip.h" +#include <linux/init.h> +#include <asm/io.h> +#include <asm/unaligned.h> + + + +/* Serial EEPROM section. */ +/* The main routine to parse the very complicated SROM structure. + Search www.digital.com for "21X4 SROM" to get details. + This code is very complex, and will require changes to support + additional cards, so I'll be verbose about what is going on. + */ + +/* Known cards that have old-style EEPROMs. */ +static struct eeprom_fixup eeprom_fixups[] __devinitdata = { + {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, + 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, + {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f, + 0x0000, 0x009E, /* 10baseT */ + 0x0004, 0x009E, /* 10baseT-FD */ + 0x0903, 0x006D, /* 100baseTx */ + 0x0905, 0x006D, /* 100baseTx-FD */ }}, + {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f, + 0x0107, 0x8021, /* 100baseFx */ + 0x0108, 0x8021, /* 100baseFx-FD */ + 0x0100, 0x009E, /* 10baseT */ + 0x0104, 0x009E, /* 10baseT-FD */ + 0x0103, 0x006D, /* 100baseTx */ + 0x0105, 0x006D, /* 100baseTx-FD */ }}, + {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513, + 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ + 0x0000, 0x009E, /* 10baseT */ + 0x0004, 0x009E, /* 10baseT-FD */ + 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ + 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}}, + {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F, + 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ + 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ + 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */ + 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ + 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */ + }}, + {0, 0, 0, 0, {}}}; + + +static const char *block_name[] __devinitdata = { + "21140 non-MII", + "21140 MII PHY", + "21142 Serial PHY", + "21142 MII PHY", + "21143 SYM PHY", + "21143 reset method" +}; + + +void __devinit tulip_parse_eeprom(struct net_device *dev) +{ + /* The last media info list parsed, for multiport boards. */ + static struct mediatable *last_mediatable = NULL; + static unsigned char *last_ee_data = NULL; + static int controller_index = 0; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + unsigned char *ee_data = tp->eeprom; + int i; + + tp->mtable = 0; + /* Detect an old-style (SA only) EEPROM layout: + memcmp(eedata, eedata+16, 8). */ + for (i = 0; i < 8; i ++) + if (ee_data[i] != ee_data[16+i]) + break; + if (i >= 8) { + if (ee_data[0] == 0xff) { + if (last_mediatable) { + controller_index++; + printk(KERN_INFO "%s: Controller %d of multiport board.\n", + dev->name, controller_index); + tp->mtable = last_mediatable; + ee_data = last_ee_data; + goto subsequent_board; + } else + printk(KERN_INFO "%s: Missing EEPROM, this interface may " + "not work correctly!\n", + dev->name); + return; + } + /* Do a fix-up based on the vendor half of the station address prefix. */ + for (i = 0; eeprom_fixups[i].name; i++) { + if (dev->dev_addr[0] == eeprom_fixups[i].addr0 + && dev->dev_addr[1] == eeprom_fixups[i].addr1 + && dev->dev_addr[2] == eeprom_fixups[i].addr2) { + if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) + i++; /* An Accton EN1207, not an outlaw Maxtech. */ + memcpy(ee_data + 26, eeprom_fixups[i].newtable, + sizeof(eeprom_fixups[i].newtable)); + printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using" + " substitute media control info.\n", + dev->name, eeprom_fixups[i].name); + break; + } + } + if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ + printk(KERN_INFO "%s: Old style EEPROM with no media selection " + "information.\n", + dev->name); + return; + } + } + + controller_index = 0; + if (ee_data[19] > 1) { /* Multiport board. */ + last_ee_data = ee_data; + } +subsequent_board: + + if (ee_data[27] == 0) { /* No valid media table. */ + } else if (tp->chip_id == DC21041) { + unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3]; + int media = get_u16(p); + int count = p[2]; + p += 3; + + printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n", + dev->name, media, + media & 0x0800 ? "Autosense" : medianame[media & 15]); + for (i = 0; i < count; i++) { + unsigned char media_code = *p++; + if (media_code & 0x40) + p += 6; + printk(KERN_INFO "%s: 21041 media #%d, %s.\n", + dev->name, media_code & 15, medianame[media_code & 15]); + } + } else { + unsigned char *p = (void *)ee_data + ee_data[27]; + unsigned char csr12dir = 0; + int count, new_advertise = 0; + struct mediatable *mtable; + u16 media = get_u16(p); + + p += 2; + if (tp->flags & CSR12_IN_SROM) + csr12dir = *p++; + count = *p++; + mtable = (struct mediatable *) + kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf), + GFP_KERNEL); + if (mtable == NULL) + return; /* Horrible, impossible failure. */ + last_mediatable = tp->mtable = mtable; + mtable->defaultmedia = media; + mtable->leafcount = count; + mtable->csr12dir = csr12dir; + mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0; + mtable->csr15dir = mtable->csr15val = 0; + + printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, + media & 0x0800 ? "Autosense" : medianame[media & 15]); + for (i = 0; i < count; i++) { + struct medialeaf *leaf = &mtable->mleaf[i]; + + if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */ + leaf->type = 0; + leaf->media = p[0] & 0x3f; + leaf->leafdata = p; + if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */ + mtable->has_mii = 1; + p += 4; + } else { + leaf->type = p[1]; + if (p[1] == 0x05) { + mtable->has_reset = i; + leaf->media = p[2] & 0x0f; + } else if (p[1] & 1) { + mtable->has_mii = 1; + leaf->media = 11; + } else { + mtable->has_nonmii = 1; + leaf->media = p[2] & 0x0f; + switch (leaf->media) { + case 0: new_advertise |= 0x0020; break; + case 4: new_advertise |= 0x0040; break; + case 3: new_advertise |= 0x0080; break; + case 5: new_advertise |= 0x0100; break; + case 6: new_advertise |= 0x0200; break; + } + if (p[1] == 2 && leaf->media == 0) { + if (p[2] & 0x40) { + u32 base15 = get_unaligned((u16*)&p[7]); + mtable->csr15dir = + (get_unaligned((u16*)&p[9])<<16) + base15; + mtable->csr15val = + (get_unaligned((u16*)&p[11])<<16) + base15; + } else { + mtable->csr15dir = get_unaligned((u16*)&p[3])<<16; + mtable->csr15val = get_unaligned((u16*)&p[5])<<16; + } + } + } + leaf->leafdata = p + 2; + p += (p[0] & 0x3f) + 1; + } + if (tulip_debug > 1 && leaf->media == 11) { + unsigned char *bp = leaf->leafdata; + printk(KERN_INFO "%s: MII interface PHY %d, setup/reset " + "sequences %d/%d long, capabilities %2.2x %2.2x.\n", + dev->name, bp[0], bp[1], bp[2 + bp[1]*2], + bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); + } + printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " + "by a %s (%d) block.\n", + dev->name, i, medianame[leaf->media], leaf->media, + block_name[leaf->type], leaf->type); + } + if (new_advertise) + tp->to_advertise = new_advertise; + } +} +/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ + +/* Note: this routine returns extra data bits for size detection. */ +int __devinit tulip_read_eeprom(long ioaddr, int location, int addr_len) +{ + int i; + unsigned retval = 0; + long ee_addr = ioaddr + CSR9; + int read_cmd = location | (EE_READ_CMD << addr_len); + + outl(EE_ENB & ~EE_CS, ee_addr); + outl(EE_ENB, ee_addr); + + /* Shift the read command bits out. */ + for (i = 4 + addr_len; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + outl(EE_ENB | dataval, ee_addr); + eeprom_delay(); + outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); + } + outl(EE_ENB, ee_addr); + + for (i = 16; i > 0; i--) { + outl(EE_ENB | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); + outl(EE_ENB, ee_addr); + eeprom_delay(); + } + + /* Terminate the EEPROM access. */ + outl(EE_ENB & ~EE_CS, ee_addr); + return retval; +} + diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c new file mode 100644 index 000000000..6d70ffd70 --- /dev/null +++ b/drivers/net/tulip/interrupt.c @@ -0,0 +1,337 @@ +/* + drivers/net/tulip/interrupt.c + + Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include "tulip.h" +#include <asm/io.h> +#include <linux/etherdevice.h> + + +int tulip_rx_copybreak; +int tulip_max_interrupt_work; + + + +static int tulip_refill_rx(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry; + int refilled = 0; + + /* Refill the Rx ring buffers. */ + for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) { + entry = tp->dirty_rx % RX_RING_SIZE; + if (tp->rx_skbuff[entry] == NULL) { + struct sk_buff *skb; + skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ); + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + tp->rx_ring[entry].buffer1 = virt_to_le32desc(skb->tail); + refilled++; + } + tp->rx_ring[entry].status = cpu_to_le32(DescOwned); + } + return refilled; +} + + +static int tulip_rx(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry = tp->cur_rx % RX_RING_SIZE; + int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; + int received = 0; + + if (tulip_debug > 4) + printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, + tp->rx_ring[entry].status); + /* If we own the next entry, it is a new packet. Send it up. */ + while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { + s32 status = le32_to_cpu(tp->rx_ring[entry].status); + + if (tulip_debug > 5) + printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", + dev->name, entry, status); + if (--rx_work_limit < 0) + break; + if ((status & 0x38008300) != 0x0300) { + if ((status & 0x38000300) != 0x0300) { + /* Ingore earlier buffers. */ + if ((status & 0xffff) != 0x7fff) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Oversized Ethernet frame " + "spanned multiple buffers, status %8.8x!\n", + dev->name, status); + tp->stats.rx_length_errors++; + } + } else if (status & RxDescFatalErr) { + /* There was a fatal error. */ + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", + dev->name, status); + tp->stats.rx_errors++; /* end of a packet.*/ + if (status & 0x0890) tp->stats.rx_length_errors++; + if (status & 0x0004) tp->stats.rx_frame_errors++; + if (status & 0x0002) tp->stats.rx_crc_errors++; + if (status & 0x0001) tp->stats.rx_fifo_errors++; + } + } else { + /* Omit the four octet CRC from the length. */ + short pkt_len = ((status >> 16) & 0x7ff) - 4; + struct sk_buff *skb; + +#ifndef final_version + if (pkt_len > 1518) { + printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", + dev->name, pkt_len, pkt_len); + pkt_len = 1518; + tp->stats.rx_length_errors++; + } +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < tulip_rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ +#if ! defined(__alpha__) + eth_copy_and_sum(skb, tp->rx_skbuff[entry]->tail, pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), tp->rx_skbuff[entry]->tail, + pkt_len); +#endif + } else { /* Pass up the skb already on the Rx ring. */ + char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len); + tp->rx_skbuff[entry] = NULL; +#ifndef final_version + if (le32desc_to_virt(tp->rx_ring[entry].buffer1) != temp) + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " + "do not match in tulip_rx: %p vs. %p / %p.\n", + dev->name, + le32desc_to_virt(tp->rx_ring[entry].buffer1), + skb->head, temp); +#endif + } + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->last_rx = jiffies; + tp->stats.rx_packets++; + tp->stats.rx_bytes += pkt_len; + } + received++; + entry = (++tp->cur_rx) % RX_RING_SIZE; + } + + return received; +} + + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr5; + int entry; + int missed; + int rx = 0; + int tx = 0; + int oi = 0; + int maxrx = RX_RING_SIZE; + int maxtx = TX_RING_SIZE; + int maxoi = TX_RING_SIZE; + int work_count = tulip_max_interrupt_work; + + tp->nir++; + + do { + csr5 = inl(ioaddr + CSR5); + /* Acknowledge all of the current interrupt sources ASAP. */ + outl(csr5 & 0x0001ffff, ioaddr + CSR5); + + if (tulip_debug > 4) + printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", + dev->name, csr5, inl(dev->base_addr + CSR5)); + + if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) + break; + + if (csr5 & (RxIntr | RxNoBuf)) { + rx += tulip_rx(dev); + tulip_refill_rx(dev); + } + + if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { + unsigned int dirty_tx; + + spin_lock(&tp->lock); + + for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; + dirty_tx++) { + int entry = dirty_tx % TX_RING_SIZE; + int status = le32_to_cpu(tp->tx_ring[entry].status); + + if (status < 0) + break; /* It still has not been Txed */ + /* Check for Rx filter setup frames. */ + if (tp->tx_skbuff[entry] == NULL) + continue; + + if (status & 0x8000) { + /* There was an major error, log it. */ +#ifndef final_version + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + dev->name, status); +#endif + tp->stats.tx_errors++; + if (status & 0x4104) tp->stats.tx_aborted_errors++; + if (status & 0x0C00) tp->stats.tx_carrier_errors++; + if (status & 0x0200) tp->stats.tx_window_errors++; + if (status & 0x0002) tp->stats.tx_fifo_errors++; + if ((status & 0x0080) && tp->full_duplex == 0) + tp->stats.tx_heartbeat_errors++; +#ifdef ETHER_STATS + if (status & 0x0100) tp->stats.collisions16++; +#endif + } else { +#ifdef ETHER_STATS + if (status & 0x0001) tp->stats.tx_deferred++; +#endif + tp->stats.tx_bytes += tp->tx_skbuff[entry]->len; + tp->stats.collisions += (status >> 3) & 15; + tp->stats.tx_packets++; + } + + /* Free the original skb. */ + dev_kfree_skb_irq(tp->tx_skbuff[entry]); + tp->tx_skbuff[entry] = 0; + tx++; + } + +#ifndef final_version + if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { + printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dev->name, dirty_tx, tp->cur_tx, tp->tx_full); + dirty_tx += TX_RING_SIZE; + } +#endif + + if (tp->tx_full && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) { + /* The ring is no longer full, clear tbusy. */ + tp->tx_full = 0; + netif_wake_queue(dev); + } + + tp->dirty_tx = dirty_tx; + if (csr5 & TxDied) { + if (tulip_debug > 2) + printk(KERN_WARNING "%s: The transmitter stopped." + " CSR5 is %x, CSR6 %x, new CSR6 %x.\n", + dev->name, csr5, inl(ioaddr + CSR6), tp->csr6); + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + } + spin_unlock(&tp->lock); + } + + /* Log errors. */ + if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ + if (csr5 == 0xffffffff) + break; + if (csr5 & TxJabber) tp->stats.tx_errors++; + if (csr5 & TxFIFOUnderflow) { + if ((tp->csr6 & 0xC000) != 0xC000) + tp->csr6 += 0x4000; /* Bump up the Tx threshold */ + else + tp->csr6 |= 0x00200000; /* Store-n-forward. */ + /* Restart the transmit process. */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + outl(0, ioaddr + CSR1); + } + if (csr5 & RxDied) { /* Missed a Rx frame. */ + tp->stats.rx_errors++; + tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + } + if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { + if (tp->link_change) + (tp->link_change)(dev, csr5); + } + if (csr5 & SytemError) { + printk(KERN_ERR "%s: (%lu) System Error occured\n", dev->name, tp->nir); + } + /* Clear all error sources, included undocumented ones! */ + outl(0x0800f7ba, ioaddr + CSR5); + oi++; + } + if (csr5 & TimerInt) { +#if 0 + if (tulip_debug > 2) + printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n", + dev->name, csr5); + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); +#endif + tp->ttimer = 0; + oi++; + } + if (tx > maxtx || rx > maxrx || oi > maxoi) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Too much work during an interrupt, " + "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi); + /* Acknowledge all interrupt sources. */ +#if 0 + /* Clear all interrupting sources, set timer to re-enable. */ + outl(((~csr5) & 0x0001ebef) | NormalIntr | AbnormalIntr | TimerInt, + ioaddr + CSR7); + outl(12, ioaddr + CSR11); + tp->ttimer = 1; +#endif + break; + } + } while (work_count-- > 0); + + tulip_refill_rx(dev); + + /* check if we card is in suspend mode */ + entry = tp->dirty_rx % RX_RING_SIZE; + if (tp->rx_skbuff[entry] == NULL) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx); + if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir); + outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt, + ioaddr + CSR7); + outl(TimerInt, ioaddr + CSR5); + outl(12, ioaddr + CSR11); + tp->ttimer = 1; + } + } + + if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) { + tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; + } + + if (tulip_debug > 4) + printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n", + dev->name, inl(ioaddr + CSR5)); + +} + diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c new file mode 100644 index 000000000..1d4c3b2e4 --- /dev/null +++ b/drivers/net/tulip/media.c @@ -0,0 +1,403 @@ +/* + drivers/net/tulip/media.c + + Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include "tulip.h" +#include <asm/io.h> + + +/* This is a mysterious value that can be written to CSR11 in the 21040 (only) + to support a pre-NWay full-duplex signaling mechanism using short frames. + No one knows what it should be, but if left at its default value some + 10base2(!) packets trigger a full-duplex-request interrupt. */ +#define FULL_DUPLEX_MAGIC 0x6969 + + +/* MII transceiver control section. + Read and write the MII registers using software-generated serial + MDIO protocol. See the MII specifications or DP83840A data sheet + for details. */ + +int tulip_mdio_read(struct net_device *dev, int phy_id, int location) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int retval = 0; + long ioaddr = dev->base_addr; + long mdio_addr = ioaddr + CSR9; + + if (tp->chip_id == LC82C168) { + int i = 1000; + outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); + inl(ioaddr + 0xA0); + inl(ioaddr + 0xA0); + while (--i > 0) + if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) + return retval & 0xffff; + return 0xffff; + } + + if (tp->chip_id == COMET) { + if (phy_id == 1) { + if (location < 7) + return inl(ioaddr + 0xB4 + (location<<2)); + else if (location == 17) + return inl(ioaddr + 0xD0); + else if (location >= 29 && location <= 31) + return inl(ioaddr + 0xD4 + ((location-29)<<2)); + } + return 0xffff; + } + + /* Establish sync by sending at least 32 logic ones. */ + for (i = 32; i >= 0; i--) { + outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Shift the read command bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + + outl(MDIO_ENB | dataval, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 19; i > 0; i--) { + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); + retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + return (retval>>1) & 0xffff; +} + +void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; + long ioaddr = dev->base_addr; + long mdio_addr = ioaddr + CSR9; + + if (tp->chip_id == LC82C168) { + int i = 1000; + outl(cmd, ioaddr + 0xA0); + do + if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) + break; + while (--i > 0); + return; + } + + if (tp->chip_id == COMET) { + if (phy_id != 1) + return; + if (location < 7) + outl(value, ioaddr + 0xB4 + (location<<2)); + else if (location == 17) + outl(value, ioaddr + 0xD0); + else if (location >= 29 && location <= 31) + outl(value, ioaddr + 0xD4 + ((location-29)<<2)); + return; + } + + /* Establish sync by sending 32 logic ones. */ + for (i = 32; i >= 0; i--) { + outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + outl(MDIO_ENB | dataval, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } +} + + +/* Set up the transceiver control registers for the selected media type. */ +void tulip_select_media(struct net_device *dev, int startup) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct mediatable *mtable = tp->mtable; + u32 new_csr6; + int i; + + if (mtable) { + struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index]; + unsigned char *p = mleaf->leafdata; + switch (mleaf->type) { + case 0: /* 21140 non-MII xcvr. */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver" + " with control setting %2.2x.\n", + dev->name, p[1]); + dev->if_port = p[0]; + if (startup) + outl(mtable->csr12dir | 0x100, ioaddr + CSR12); + outl(p[1], ioaddr + CSR12); + new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18); + break; + case 2: case 4: { + u16 setup[5]; + u32 csr13val, csr14val, csr15dir, csr15val; + for (i = 0; i < 5; i++) + setup[i] = get_u16(&p[i*2 + 1]); + + dev->if_port = p[0] & 15; + if (tulip_media_cap[dev->if_port] & MediaAlwaysFD) + tp->full_duplex = 1; + + if (startup && mtable->has_reset) { + struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; + unsigned char *rst = rleaf->leafdata; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Resetting the transceiver.\n", + dev->name); + for (i = 0; i < rst[0]; i++) + outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control " + "%4.4x/%4.4x.\n", + dev->name, medianame[dev->if_port], setup[0], setup[1]); + if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ + csr13val = setup[0]; + csr14val = setup[1]; + csr15dir = (setup[3]<<16) | setup[2]; + csr15val = (setup[4]<<16) | setup[2]; + outl(0, ioaddr + CSR13); + outl(csr14val, ioaddr + CSR14); + outl(csr15dir, ioaddr + CSR15); /* Direction */ + outl(csr15val, ioaddr + CSR15); /* Data */ + outl(csr13val, ioaddr + CSR13); + } else { + csr13val = 1; + csr14val = 0x0003FF7F; + csr15dir = (setup[0]<<16) | 0x0008; + csr15val = (setup[1]<<16) | 0x0008; + if (dev->if_port <= 4) + csr14val = t21142_csr14[dev->if_port]; + if (startup) { + outl(0, ioaddr + CSR13); + outl(csr14val, ioaddr + CSR14); + } + outl(csr15dir, ioaddr + CSR15); /* Direction */ + outl(csr15val, ioaddr + CSR15); /* Data */ + if (startup) outl(csr13val, ioaddr + CSR13); + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n", + dev->name, csr15dir, csr15val); + if (mleaf->type == 4) + new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18); + else + new_csr6 = 0x82420000; + break; + } + case 1: case 3: { + int phy_num = p[0]; + int init_length = p[1]; + u16 *misc_info; + u16 to_advertise; + + dev->if_port = 11; + new_csr6 = 0x020E0000; + if (mleaf->type == 3) { /* 21142 */ + u16 *init_sequence = (u16*)(p+2); + u16 *reset_sequence = &((u16*)(p+3))[init_length]; + int reset_length = p[2 + init_length*2]; + misc_info = reset_sequence + reset_length; + if (startup) + for (i = 0; i < reset_length; i++) + outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); + for (i = 0; i < init_length; i++) + outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); + } else { + u8 *init_sequence = p + 2; + u8 *reset_sequence = p + 3 + init_length; + int reset_length = p[2 + init_length]; + misc_info = (u16*)(reset_sequence + reset_length); + if (startup) { + outl(mtable->csr12dir | 0x100, ioaddr + CSR12); + for (i = 0; i < reset_length; i++) + outl(reset_sequence[i], ioaddr + CSR12); + } + for (i = 0; i < init_length; i++) + outl(init_sequence[i], ioaddr + CSR12); + } + to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1; + tp->advertising[phy_num] = to_advertise; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n", + dev->name, to_advertise, phy_num, tp->phys[phy_num]); + /* Bogus: put in by a committee? */ + tulip_mdio_write(dev, tp->phys[phy_num], 4, to_advertise); + break; + } + default: + printk(KERN_DEBUG "%s: Invalid media table selection %d.\n", + dev->name, mleaf->type); + new_csr6 = 0x020E0000; + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n", + dev->name, medianame[dev->if_port], + inl(ioaddr + CSR12) & 0xff); + } else if (tp->chip_id == DC21041) { + int port = dev->if_port <= 4 ? dev->if_port : 0; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n", + dev->name, medianame[port == 3 ? 12: port], + inl(ioaddr + CSR12)); + outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ + outl(t21041_csr14[port], ioaddr + CSR14); + outl(t21041_csr15[port], ioaddr + CSR15); + outl(t21041_csr13[port], ioaddr + CSR13); + new_csr6 = 0x80020000; + } else if (tp->chip_id == LC82C168) { + if (startup && ! tp->medialock) + dev->if_port = tp->mii_cnt ? 11 : 0; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s.\n", + dev->name, inl(ioaddr + 0xB8), medianame[dev->if_port]); + if (tp->mii_cnt) { + new_csr6 = 0x810C0000; + outl(0x0001, ioaddr + CSR15); + outl(0x0201B07A, ioaddr + 0xB8); + } else if (startup) { + /* Start with 10mbps to do autonegotiation. */ + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x0001B078, ioaddr + 0xB8); + outl(0x0201B078, ioaddr + 0xB8); + } else if (dev->if_port == 3 || dev->if_port == 5) { + outl(0x33, ioaddr + CSR12); + new_csr6 = 0x01860000; + /* Trigger autonegotiation. */ + outl(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8); + } else { + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x1F078, ioaddr + 0xB8); + } + } else if (tp->chip_id == DC21040) { /* 21040 */ + /* Turn on the xcvr interface. */ + int csr12 = inl(ioaddr + CSR12); + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n", + dev->name, medianame[dev->if_port], csr12); + if (tulip_media_cap[dev->if_port] & MediaAlwaysFD) + tp->full_duplex = 1; + new_csr6 = 0x20000; + /* Set the full duplux match frame. */ + outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11); + outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ + if (t21040_csr13[dev->if_port] & 8) { + outl(0x0705, ioaddr + CSR14); + outl(0x0006, ioaddr + CSR15); + } else { + outl(0xffff, ioaddr + CSR14); + outl(0x0000, ioaddr + CSR15); + } + outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13); + } else { /* Unknown chip type with no media table. */ + if (tp->default_port == 0) + dev->if_port = tp->mii_cnt ? 11 : 3; + if (tulip_media_cap[dev->if_port] & MediaIsMII) { + new_csr6 = 0x020E0000; + } else if (tulip_media_cap[dev->if_port] & MediaIsFx) { + new_csr6 = 0x028600000; + } else + new_csr6 = 0x038600000; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: No media description table, assuming " + "%s transceiver, CSR12 %2.2x.\n", + dev->name, medianame[dev->if_port], + inl(ioaddr + CSR12)); + } + + tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); + return; +} + +/* + Check the MII negotiated duplex, and change the CSR6 setting if + required. + Return 0 if everything is OK. + Return < 0 if the transceiver is missing or has no link beat. + */ +int tulip_check_duplex(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int mii_reg1, mii_reg5, negotiated, duplex; + + if (tp->full_duplex_lock) + return 0; + mii_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); + mii_reg5 = tulip_mdio_read(dev, tp->phys[0], 5); + if (tulip_debug > 1) + printk(KERN_INFO "%s: MII status %4.4x, Link partner report " + "%4.4x.\n", dev->name, mii_reg1, mii_reg5); + if (mii_reg1 == 0xffff) + return -2; + if ((mii_reg1 & 0x0004) == 0) { + int new_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); + if ((new_reg1 & 0x0004) == 0) { + if (tulip_debug > 1) + printk(KERN_INFO "%s: No link beat on the MII interface," + " status %4.4x.\n", dev->name, new_reg1); + return -1; + } + } + negotiated = mii_reg5 & tp->advertising[0]; + duplex = ((negotiated & 0x0300) == 0x0100 + || (negotiated & 0x00C0) == 0x0040); + /* 100baseTx-FD or 10T-FD, but not 100-HD */ + if (tp->full_duplex != duplex) { + tp->full_duplex = duplex; + if (negotiated & 0x038) /* 100mbps. */ + tp->csr6 &= ~0x00400000; + if (tp->full_duplex) tp->csr6 |= 0x0200; + else tp->csr6 &= ~0x0200; + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + if (tulip_debug > 0) + printk(KERN_INFO "%s: Setting %s-duplex based on MII" + "#%d link partner capability of %4.4x.\n", + dev->name, tp->full_duplex ? "full" : "half", + tp->phys[0], mii_reg5); + return 1; + } + return 0; +} + diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c new file mode 100644 index 000000000..445d4a440 --- /dev/null +++ b/drivers/net/tulip/pnic.c @@ -0,0 +1,146 @@ +/* + drivers/net/tulip/pnic.c + + Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include <linux/kernel.h> +#include "tulip.h" +#include <asm/io.h> + + +void pnic_do_nway(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + u32 phy_reg = inl(ioaddr + 0xB8); + u32 new_csr6 = tp->csr6 & ~0x40C40200; + + if (phy_reg & 0x78000000) { /* Ignore baseT4 */ + if (phy_reg & 0x20000000) dev->if_port = 5; + else if (phy_reg & 0x40000000) dev->if_port = 3; + else if (phy_reg & 0x10000000) dev->if_port = 4; + else if (phy_reg & 0x08000000) dev->if_port = 0; + tp->nwayset = 1; + new_csr6 = (dev->if_port & 1) ? 0x01860000 : 0x00420000; + outl(0x32 | (dev->if_port & 1), ioaddr + CSR12); + if (dev->if_port & 1) + outl(0x1F868, ioaddr + 0xB8); + if (phy_reg & 0x30000000) { + tp->full_duplex = 1; + new_csr6 |= 0x00000200; + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n", + dev->name, phy_reg, medianame[dev->if_port]); + if (tp->csr6 != new_csr6) { + tp->csr6 = new_csr6; + /* Restart Tx */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + dev->trans_start = jiffies; + } + } +} + + +void pnic_lnk_change(struct net_device *dev, int csr5) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int phy_reg = inl(ioaddr + 0xB8); + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n", + dev->name, phy_reg, csr5); + if (inl(ioaddr + CSR5) & TPLnkFail) { + outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7); + if (! tp->nwayset || jiffies - dev->trans_start > 1*HZ) { + tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff); + tulip_outl_CSR6(tp, tp->csr6); + outl(0x30, ioaddr + CSR12); + outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ + dev->trans_start = jiffies; + } + } else if (inl(ioaddr + CSR5) & TPLnkPass) { + pnic_do_nway(dev); + outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7); + } +} + + +void pnic_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (tulip_media_cap[dev->if_port] & MediaIsMII) { + if (tulip_check_duplex(dev) > 0) + next_tick = 3*HZ; + } else { + int csr12 = inl(ioaddr + CSR12); + int new_csr6 = tp->csr6 & ~0x40C40200; + int phy_reg = inl(ioaddr + 0xB8); + int csr5 = inl(ioaddr + CSR5); + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s " + "CSR5 %8.8x.\n", + dev->name, phy_reg, medianame[dev->if_port], csr5); + if (phy_reg & 0x04000000) { /* Remote link fault */ + outl(0x0201F078, ioaddr + 0xB8); + next_tick = 1*HZ; + tp->nwayset = 0; + } else if (phy_reg & 0x78000000) { /* Ignore baseT4 */ + pnic_do_nway(dev); + next_tick = 60*HZ; + } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, " + "CSR5 %8.8x, PHY %3.3x.\n", + dev->name, medianame[dev->if_port], csr12, + inl(ioaddr + CSR5), inl(ioaddr + 0xB8)); + next_tick = 3*HZ; + if (tp->medialock) { + } else if (tp->nwayset && (dev->if_port & 1)) { + next_tick = 1*HZ; + } else if (dev->if_port == 0) { + dev->if_port = 3; + outl(0x33, ioaddr + CSR12); + new_csr6 = 0x01860000; + outl(0x1F868, ioaddr + 0xB8); + } else { + dev->if_port = 0; + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x1F078, ioaddr + 0xB8); + } + if (tp->csr6 != new_csr6) { + tp->csr6 = new_csr6; + /* Restart Tx */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + dev->trans_start = jiffies; + if (tulip_debug > 1) + printk(KERN_INFO "%s: Changing PNIC configuration to %s " + "%s-duplex, CSR6 %8.8x.\n", + dev->name, medianame[dev->if_port], + tp->full_duplex ? "full" : "half", new_csr6); + } + } + } + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c new file mode 100644 index 000000000..796fdd136 --- /dev/null +++ b/drivers/net/tulip/timer.c @@ -0,0 +1,208 @@ +/* + drivers/net/tulip/timer.c + + Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include "tulip.h" +#include <asm/io.h> + + +void tulip_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + u32 csr12 = inl(ioaddr + CSR12); + int next_tick = 2*HZ; + + if (tulip_debug > 2) { + printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode" + " %8.8x SIA %8.8x %8.8x %8.8x %8.8x.\n", + dev->name, medianame[dev->if_port], inl(ioaddr + CSR5), + inl(ioaddr + CSR6), csr12, inl(ioaddr + CSR13), + inl(ioaddr + CSR14), inl(ioaddr + CSR15)); + } + switch (tp->chip_id) { + case DC21040: + if (!tp->medialock && csr12 & 0x0002) { /* Network error */ + printk(KERN_INFO "%s: No link beat found.\n", + dev->name); + dev->if_port = (dev->if_port == 2 ? 0 : 2); + tulip_select_media(dev, 0); + dev->trans_start = jiffies; + } + break; + case DC21041: + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n", + dev->name, csr12); + if (tp->medialock) break; + switch (dev->if_port) { + case 0: case 3: case 4: + if (csr12 & 0x0004) { /*LnkFail */ + /* 10baseT is dead. Check for activity on alternate port. */ + tp->mediasense = 1; + if (csr12 & 0x0200) + dev->if_port = 2; + else + dev->if_port = 1; + printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n", + dev->name, medianame[dev->if_port]); + outl(0, ioaddr + CSR13); /* Reset */ + outl(t21041_csr14[dev->if_port], ioaddr + CSR14); + outl(t21041_csr15[dev->if_port], ioaddr + CSR15); + outl(t21041_csr13[dev->if_port], ioaddr + CSR13); + next_tick = 10*HZ; /* 2.4 sec. */ + } else + next_tick = 30*HZ; + break; + case 1: /* 10base2 */ + case 2: /* AUI */ + if (csr12 & 0x0100) { + next_tick = (30*HZ); /* 30 sec. */ + tp->mediasense = 0; + } else if ((csr12 & 0x0004) == 0) { + printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n", + dev->name); + dev->if_port = 0; + tulip_select_media(dev, 0); + next_tick = (24*HZ)/10; /* 2.4 sec. */ + } else if (tp->mediasense || (csr12 & 0x0002)) { + dev->if_port = 3 - dev->if_port; /* Swap ports. */ + tulip_select_media(dev, 0); + next_tick = 20*HZ; + } else { + next_tick = 20*HZ; + } + break; + } + break; + case DC21140: case DC21142: case MX98713: case COMPEX9881: default: { + struct medialeaf *mleaf; + unsigned char *p; + if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */ + /* Not much that can be done. + Assume this a generic MII or SYM transceiver. */ + next_tick = 60*HZ; + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x " + "CSR12 0x%2.2x.\n", + dev->name, inl(ioaddr + CSR6), csr12 & 0xff); + break; + } + mleaf = &tp->mtable->mleaf[tp->cur_index]; + p = mleaf->leafdata; + switch (mleaf->type) { + case 0: case 4: { + /* Type 0 serial or 4 SYM transceiver. Check the link beat bit. */ + int offset = mleaf->type == 4 ? 5 : 2; + s8 bitnum = p[offset]; + if (p[offset+1] & 0x80) { + if (tulip_debug > 1) + printk(KERN_DEBUG"%s: Transceiver monitor tick " + "CSR12=%#2.2x, no media sense.\n", + dev->name, csr12); + if (mleaf->type == 4) { + if (mleaf->media == 3 && (csr12 & 0x02)) + goto select_next_media; + } + break; + } + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x" + " bit %d is %d, expecting %d.\n", + dev->name, csr12, (bitnum >> 1) & 7, + (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, + (bitnum >= 0)); + /* Check that the specified bit has the proper value. */ + if ((bitnum < 0) != + ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name, + medianame[mleaf->media]); + if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */ + goto actually_mii; + break; + } + if (tp->medialock) + break; + select_next_media: + if (--tp->cur_index < 0) { + /* We start again, but should instead look for default. */ + tp->cur_index = tp->mtable->leafcount - 1; + } + dev->if_port = tp->mtable->mleaf[tp->cur_index].media; + if (tulip_media_cap[dev->if_port] & MediaIsFD) + goto select_next_media; /* Skip FD entries. */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: No link beat on media %s," + " trying transceiver type %s.\n", + dev->name, medianame[mleaf->media & 15], + medianame[tp->mtable->mleaf[tp->cur_index].media]); + tulip_select_media(dev, 0); + /* Restart the transmit process. */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + next_tick = (24*HZ)/10; + break; + } + case 1: case 3: /* 21140, 21142 MII */ + actually_mii: + tulip_check_duplex(dev); + next_tick = 60*HZ; + break; + case 2: /* 21142 serial block has no link beat. */ + default: + break; + } + } + break; + } + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + + +void mxic_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (tulip_debug > 3) { + printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name, + inl(ioaddr + CSR12)); + } + if (next_tick) { + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); + } +} + + +void comet_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability " + "%4.4x.\n", + dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8)); + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h new file mode 100644 index 000000000..3642a13b4 --- /dev/null +++ b/drivers/net/tulip/tulip.h @@ -0,0 +1,342 @@ +/* + drivers/net/tulip/tulip.h + + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + +*/ + +#ifndef __NET_TULIP_H__ +#define __NET_TULIP_H__ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/netdevice.h> +#include <linux/timer.h> + + +struct tulip_chip_table { + char *chip_name; + int io_size; + int valid_intrs; /* CSR7 interrupt enable settings */ + int flags; + void (*media_timer) (unsigned long data); +}; + + +enum tbl_flag { + HAS_MII = 1, + HAS_MEDIA_TABLE = 2, + CSR12_IN_SROM = 4, + ALWAYS_CHECK_MII = 8, + HAS_ACPI = 0x10, + MC_HASH_ONLY = 0x20, /* Hash-only multicast filter. */ + HAS_PNICNWAY = 0x80, + HAS_NWAY143 = 0x40, /* Uses internal NWay xcvr. */ + HAS_8023X = 0x100, +}; + + +/* chip types. careful! order is VERY IMPORTANT here, as these + * are used throughout the driver as indices into arrays */ +/* Note 21142 == 21143. */ +enum chips { + DC21040 = 0, + DC21041 = 1, + DC21140 = 2, + DC21142 = 3, DC21143 = 3, + LC82C168, + NGMC169, + MX98713, + MX98715, + MX98725, + AX88140, + PNIC2, + COMET, + COMPEX9881, + I21145, + X3201_3, +}; + + +enum MediaIs { + MediaIsFD = 1, + MediaAlwaysFD = 2, + MediaIsMII = 4, + MediaIsFx = 8, + MediaIs100 = 16 +}; + + +/* Offsets to the Command and Status Registers, "CSRs". All accesses + must be longword instructions and quadword aligned. */ +enum tulip_offsets { + CSR0 = 0, + CSR1 = 0x08, + CSR2 = 0x10, + CSR3 = 0x18, + CSR4 = 0x20, + CSR5 = 0x28, + CSR6 = 0x30, + CSR7 = 0x38, + CSR8 = 0x40, + CSR9 = 0x48, + CSR10 = 0x50, + CSR11 = 0x58, + CSR12 = 0x60, + CSR13 = 0x68, + CSR14 = 0x70, + CSR15 = 0x78 +}; + + +/* The bits in the CSR5 status registers, mostly interrupt sources. */ +enum status_bits { + TimerInt = 0x800, + SytemError = 0x2000, + TPLnkFail = 0x1000, + TPLnkPass = 0x10, + NormalIntr = 0x10000, + AbnormalIntr = 0x8000, + RxJabber = 0x200, + RxDied = 0x100, + RxNoBuf = 0x80, + RxIntr = 0x40, + TxFIFOUnderflow = 0x20, + TxJabber = 0x08, + TxNoBuf = 0x04, + TxDied = 0x02, + TxIntr = 0x01, +}; + + +/* The Tulip Rx and Tx buffer descriptors. */ +struct tulip_rx_desc { + s32 status; + s32 length; + u32 buffer1; + u32 buffer2; +}; + + +struct tulip_tx_desc { + s32 status; + s32 length; + u32 buffer1; + u32 buffer2; /* We use only buffer 1. */ +}; + + +enum desc_status_bits { + DescOwned = 0x80000000, + RxDescFatalErr = 0x8000, + RxWholePkt = 0x0300, +}; + + +/* Keep the ring sizes a power of two for efficiency. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings. */ +#define TX_RING_SIZE 16 +#define RX_RING_SIZE 32 + + +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ + + +/* Ring-wrap flag in length field, use for last ring entry. + 0x01000000 means chain on buffer2 address, + 0x02000000 means use the ring start address in CSR2/3. + Note: Some work-alike chips do not function correctly in chained mode. + The ASIX chip works only in chained mode. + Thus we indicates ring mode, but always write the 'next' field for + chained mode as well. +*/ +#define DESC_RING_WRAP 0x02000000 + + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ +#define EE_CS 0x01 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x05 +#define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */ +#define EE_ENB (0x4800 | EE_CS) + +/* Delay between EEPROM clock transitions. + Even at 33Mhz current PCI implementations don't overrun the EEPROM clock. + We add a bus turn-around to insure that this remains true. */ +#define eeprom_delay() inl(ee_addr) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_READ_CMD (6) + +#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */ + + +/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back PCI I/O cycles, but we insert a delay to avoid + "overclocking" issues or future 66Mhz PCI. */ +#define mdio_delay() inl(mdio_addr) + +/* Read and write the MII registers using software-generated serial + MDIO protocol. It is just different enough from the EEPROM protocol + to not share code. The maxium data clock rate is 2.5 Mhz. */ +#define MDIO_SHIFT_CLK 0x10000 +#define MDIO_DATA_WRITE0 0x00000 +#define MDIO_DATA_WRITE1 0x20000 +#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ +#define MDIO_ENB_IN 0x40000 +#define MDIO_DATA_READ 0x80000 + + +#define RUN_AT(x) (jiffies + (x)) + + +#if defined(__i386__) /* AKA get_unaligned() */ +#define get_u16(ptr) (*(u16 *)(ptr)) +#else +#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8)) +#endif + + +/* Condensed operations for readability. */ +#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) + + +struct medialeaf { + u8 type; + u8 media; + unsigned char *leafdata; +}; + + +struct mediatable { + u16 defaultmedia; + u8 leafcount; + u8 csr12dir; /* General purpose pin directions. */ + unsigned has_mii:1; + unsigned has_nonmii:1; + unsigned has_reset:6; + u32 csr15dir; + u32 csr15val; /* 21143 NWay setting. */ + struct medialeaf mleaf[0]; +}; + + +struct mediainfo { + struct mediainfo *next; + int info_type; + int index; + unsigned char *info; +}; + + +struct tulip_private { + const char *product_name; + struct net_device *next_module; + struct tulip_rx_desc rx_ring[RX_RING_SIZE]; + struct tulip_tx_desc tx_ring[TX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff *rx_skbuff[RX_RING_SIZE]; + char *rx_buffs; /* Address of temporary Rx buffers. */ + u16 setup_frame[96]; /* Pseudo-Tx frame to init address table. */ + int chip_id; + int revision; + int flags; + struct net_device_stats stats; + struct timer_list timer; /* Media selection timer. */ + spinlock_t lock; + unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int full_duplex_lock:1; + unsigned int fake_addr:1; /* Multiport board faked address. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + unsigned int media2:4; /* Secondary monitored media port. */ + unsigned int medialock:1; /* Don't sense media type. */ + unsigned int mediasense:1; /* Media sensing in progress. */ + unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */ + unsigned int csr0; /* CSR0 setting. */ + unsigned int csr6; /* Current CSR6 control settings. */ + unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */ + void (*link_change) (struct net_device * dev, int csr5); + u16 to_advertise; /* NWay capabilities advertised. */ + u16 lpar; /* 21143 Link partner ability. */ + u16 advertising[4]; + signed char phys[4], mii_cnt; /* MII device addresses. */ + struct mediatable *mtable; + int cur_index; /* Current media index. */ + int saved_if_port; + struct pci_dev *pdev; + int ttimer; + int susp_rx; + unsigned long nir; + unsigned long base_addr; + int pad0, pad1; /* Used for 8-byte alignment */ +}; + + +struct eeprom_fixup { + char *name; + unsigned char addr0; + unsigned char addr1; + unsigned char addr2; + u16 newtable[32]; /* Max length below. */ +}; + + +/* 21142.c */ +extern u16 t21142_csr14[]; +void t21142_timer(unsigned long data); +void t21142_start_nway(struct net_device *dev); +void t21142_lnk_change(struct net_device *dev, int csr5); + +/* eeprom.c */ +void tulip_parse_eeprom(struct net_device *dev); +int tulip_read_eeprom(long ioaddr, int location, int addr_len); + +/* interrupt.c */ +extern int tulip_max_interrupt_work; +extern int tulip_rx_copybreak; +void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs); + +/* media.c */ +int tulip_mdio_read(struct net_device *dev, int phy_id, int location); +void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int value); +void tulip_select_media(struct net_device *dev, int startup); +int tulip_check_duplex(struct net_device *dev); + +/* pnic.c */ +void pnic_do_nway(struct net_device *dev); +void pnic_lnk_change(struct net_device *dev, int csr5); +void pnic_timer(unsigned long data); + +/* timer.c */ +void tulip_timer(unsigned long data); +void mxic_timer(unsigned long data); +void comet_timer(unsigned long data); + +/* tulip_core.c */ +extern int tulip_debug; +extern const char * const medianame[]; +extern const char tulip_media_cap[]; +extern struct tulip_chip_table tulip_tbl[]; +extern u8 t21040_csr13[]; +extern u16 t21041_csr13[]; +extern u16 t21041_csr14[]; +extern u16 t21041_csr15[]; +void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6); + + +#endif /* __NET_TULIP_H__ */ diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c new file mode 100644 index 000000000..3be78468b --- /dev/null +++ b/drivers/net/tulip/tulip_core.c @@ -0,0 +1,1391 @@ +/* tulip_core.c: A DEC 21040-family ethernet driver for Linux. */ + +/* + Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please read Documentation/networking/tulip.txt for more + information. + + For this specific driver variant please use linux-kernel for + bug reports. + + Additional information available at + http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html + +*/ + +static const char version[] = "Linux Tulip driver version 0.9.3 (Feb 23, 2000)\n"; + +#include <linux/module.h> +#include "tulip.h" +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/etherdevice.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/unaligned.h> + + +/* A few user-configurable values. */ + +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 25; + +#define MAX_UNITS 8 +/* Used to pass the full-duplex flag, etc. */ +static int full_duplex[MAX_UNITS] = {0, }; +static int options[MAX_UNITS] = {0, }; +static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */ + +/* The possible media types that can be set in options[] are: */ +const char * const medianame[] = { + "10baseT", "10base2", "AUI", "100baseTx", + "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx", + "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII", + "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4", +}; + +/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ +#ifdef __alpha__ +static int rx_copybreak = 1518; +#else +static int rx_copybreak = 100; +#endif + +/* + Set the bus performance register. + Typical: Set 16 longword cache alignment, no burst limit. + Cache alignment bits 15:14 Burst length 13:8 + 0000 No alignment 0x00000000 unlimited 0800 8 longwords + 4000 8 longwords 0100 1 longword 1000 16 longwords + 8000 16 longwords 0200 2 longwords 2000 32 longwords + C000 32 longwords 0400 4 longwords + Warning: many older 486 systems are broken and require setting 0x00A04800 + 8 longword cache alignment, 8 longword burst. + ToDo: Non-Intel setting could be better. +*/ + +#if defined(__alpha__) +static int csr0 = 0x01A00000 | 0xE000; +#elif defined(__i386__) || defined(__powerpc__) || defined(__sparc__) +static int csr0 = 0x01A00000 | 0x8000; +#else +#warning Processor architecture undefined! +static int csr0 = 0x00A00000 | 0x4800; +#endif + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (4*HZ) + + +/* Kernel compatibility defines, some common to David Hind's PCMCIA package. + This is only in the support-all-kernels source code. */ + +MODULE_AUTHOR("The Linux Kernel Team"); +MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver"); +MODULE_PARM(tulip_debug, "i"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(csr0, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +#define TULIP_MODULE_NAME "tulip" +#define PFX TULIP_MODULE_NAME ": " + +#ifdef TULIP_DEBUG +int tulip_debug = TULIP_DEBUG; +#else +int tulip_debug = 1; +#endif + + + +/* + * This table use during operation for capabilities and media timer. + * + * It is indexed via the values in 'enum chips' + */ + +struct tulip_chip_table tulip_tbl[] = { + { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer }, + { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer }, + { "Digital DS21140 Tulip", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, + { "Digital DS21143 Tulip", 128, 0x0801fbff, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, + t21142_timer }, + { "Lite-On 82c168 PNIC", 256, 0x0001ebef, + HAS_MII | HAS_PNICNWAY, pnic_timer }, + { "NETGEAR NGMC169 MAC", 256, 0x0001ebef, + HAS_MII | HAS_PNICNWAY, pnic_timer }, + { "Macronix 98713 PMAC", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, + { "Macronix 98715 PMAC", 256, 0x0001ebef, + HAS_MEDIA_TABLE, mxic_timer }, + { "Macronix 98725 PMAC", 256, 0x0001ebef, + HAS_MEDIA_TABLE, mxic_timer }, + { "ASIX AX88140", 128, 0x0001fbff, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer }, + { "Lite-On PNIC-II", 256, 0x0801fbff, + HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer }, + { "ADMtek Comet", 256, 0x0001abef, + MC_HASH_ONLY, comet_timer }, + { "Compex 9881 PMAC", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, + { "Intel DS21145 Tulip", 128, 0x0801fbff, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143, + t21142_timer }, + { "Xircom tulip work-alike", 128, 0x0801fbff, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, + t21142_timer }, + {0}, +}; + + +static struct pci_device_id tulip_pci_tbl[] __devinitdata = { + { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 }, + { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 }, + { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, + { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21143 }, + { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 }, + { 0x1385, 0xf004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NGMC169 }, + { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 }, + { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, + { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 }, + { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 }, + { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 }, + { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, + { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, + { 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 }, + {0}, +}; +MODULE_DEVICE_TABLE(pci,tulip_pci_tbl); + + +/* A full-duplex map for media types. */ +const char tulip_media_cap[] = +{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 }; +u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0}; + +/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/ +u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, }; +u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; +u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; + + +static void tulip_tx_timeout(struct net_device *dev); +static void tulip_init_ring(struct net_device *dev); +static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int tulip_open(struct net_device *dev); +static int tulip_close(struct net_device *dev); +static void tulip_up(struct net_device *dev); +static void tulip_down(struct net_device *dev); +static struct net_device_stats *tulip_get_stats(struct net_device *dev); +static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void set_rx_mode(struct net_device *dev); + + +/* The Xircom cards are picky about when certain bits in CSR6 can be + manipulated. Keith Owens <kaos@ocs.com.au>. */ + +void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6) +{ + long ioaddr = tp->base_addr; + const int strict_bits = 0x0060e202; + int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200; + + /* common path */ + if (tp->chip_id != X3201_3) { + outl (newcsr6, ioaddr + CSR6); + return; + } + + newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */ + /* read 0 on the Xircom cards */ + newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */ + currcsr6 = inl (ioaddr + CSR6); + if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) || + ((currcsr6 & ~0x2002) == 0)) + goto out_write; + + /* make sure the transmitter and receiver are stopped first */ + currcsr6 &= ~0x2002; + while (1) { + csr5 = inl (ioaddr + CSR5); + if (csr5 == 0xffffffff) + break; /* cannot read csr5, card removed? */ + csr5_22_20 = csr5 & 0x700000; + csr5_19_17 = csr5 & 0x0e0000; + if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) && + (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000)) + break; /* both are stopped or suspended */ + if (!--attempts) { + printk (KERN_INFO "tulip.c: tulip_outl_CSR6 too many attempts," + "csr5=0x%08x\n", csr5); + goto out_write; + } + outl (currcsr6, ioaddr + CSR6); + udelay (1); + } + +out_write: + /* now it is safe to change csr6 */ + outl (newcsr6, ioaddr + CSR6); +} + + +static void tulip_up(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 3*HZ; + int i; + + /* Wake the chip from sleep/snooze mode. */ + if (tp->flags & HAS_ACPI) + pci_write_config_dword(tp->pdev, 0x40, 0); + + /* On some chip revs we must set the MII/SYM port before the reset!? */ + if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) + tulip_outl_CSR6 (tp, 0x00040000); + + /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ + outl(0x00000001, ioaddr + CSR0); + + /* Deassert reset. + Wait the specified 50 PCI cycles after a reset by initializing + Tx and Rx queues and the address filter list. */ + outl(tp->csr0, ioaddr + CSR0); + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq); + + if (tp->flags & MC_HASH_ONLY) { + u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); + u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4))); + if (tp->chip_id == AX88140) { + outl(0, ioaddr + CSR13); + outl(addr_low, ioaddr + CSR14); + outl(1, ioaddr + CSR13); + outl(addr_high, ioaddr + CSR14); + } else if (tp->chip_id == COMET) { + outl(addr_low, ioaddr + 0xA4); + outl(addr_high, ioaddr + 0xA8); + outl(0, ioaddr + 0xAC); + outl(0, ioaddr + 0xB0); + } + } else { + /* This is set_rx_mode(), but without starting the transmitter. */ + u16 *eaddrs = (u16 *)dev->dev_addr; + u16 *setup_frm = &tp->setup_frame[15*6]; + + /* 21140 bug: you must add the broadcast address. */ + memset(tp->setup_frame, 0xff, sizeof(tp->setup_frame)); + /* Fill the final entry of the table with our physical address. */ + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + /* Put the setup frame on the Tx list. */ + tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192); + tp->tx_ring[0].buffer1 = virt_to_le32desc(tp->setup_frame); + tp->tx_ring[0].status = cpu_to_le32(DescOwned); + + tp->cur_tx++; + } + + outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3); + outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4); + + tp->saved_if_port = dev->if_port; + if (dev->if_port == 0) + dev->if_port = tp->default_port; + + /* Allow selecting a default media. */ + i = 0; + if (tp->mtable == NULL) + goto media_picked; + if (dev->if_port) { + int looking_for = tulip_media_cap[dev->if_port] & MediaIsMII ? 11 : + (dev->if_port == 12 ? 0 : dev->if_port); + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == looking_for) { + printk(KERN_INFO "%s: Using user-specified media %s.\n", + dev->name, medianame[dev->if_port]); + goto media_picked; + } + } + if ((tp->mtable->defaultmedia & 0x0800) == 0) { + int looking_for = tp->mtable->defaultmedia & 15; + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == looking_for) { + printk(KERN_INFO "%s: Using EEPROM-set media %s.\n", + dev->name, medianame[looking_for]); + goto media_picked; + } + } + /* Start sensing first non-full-duplex media. */ + for (i = tp->mtable->leafcount - 1; + (tulip_media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--) + ; +media_picked: + + tp->csr6 = 0; + tp->cur_index = i; + tp->nwayset = 0; + if (dev->if_port == 0 && tp->chip_id == DC21041) { + tp->nway = 1; + } + if (dev->if_port == 0 && tp->chip_id == DC21142) { + if (tp->mii_cnt) { + tulip_select_media(dev, 1); + if (tulip_debug > 1) + printk(KERN_INFO "%s: Using MII transceiver %d, status " + "%4.4x.\n", + dev->name, tp->phys[0], tulip_mdio_read(dev, tp->phys[0], 1)); + tulip_outl_CSR6(tp, 0x82020000); + tp->csr6 = 0x820E0000; + dev->if_port = 11; + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + } else + t21142_start_nway(dev); + } else if (tp->chip_id == PNIC2) { + t21142_start_nway(dev); + } else if (tp->chip_id == LC82C168 && ! tp->medialock) { + if (tp->mii_cnt) { + dev->if_port = 11; + tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0); + outl(0x0001, ioaddr + CSR15); + } else if (inl(ioaddr + CSR5) & TPLnkPass) + pnic_do_nway(dev); + else { + /* Start with 10mbps to do autonegotiation. */ + outl(0x32, ioaddr + CSR12); + tp->csr6 = 0x00420000; + outl(0x0001B078, ioaddr + 0xB8); + outl(0x0201B078, ioaddr + 0xB8); + next_tick = 1*HZ; + } + } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) + && ! tp->medialock) { + dev->if_port = 0; + tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0); + outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); + } else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) { + /* Provided by BOLO, Macronix - 12/10/1998. */ + dev->if_port = 0; + tp->csr6 = 0x01a80200; + outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); + outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0); + } else if (tp->chip_id == DC21143 && + tulip_media_cap[dev->if_port] & MediaIsMII) { + /* We must reset the media CSRs when we force-select MII mode. */ + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + outl(0x0008, ioaddr + CSR15); + } else if (tp->chip_id == COMET) { + dev->if_port = 0; + tp->csr6 = 0x00040000; + } else if (tp->chip_id == AX88140) { + tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100; + } else + tulip_select_media(dev, 1); + + /* Start the chip's Tx to process setup frame. */ + tulip_outl_CSR6(tp, tp->csr6); + tulip_outl_CSR6(tp, tp->csr6 | 0x2000); + + /* Enable interrupts by setting the interrupt mask. */ + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5); + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + outl(0, ioaddr + CSR2); /* Rx poll demand */ + + if (tulip_debug > 2) { + printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n", + dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5), + inl(ioaddr + CSR6)); + } + /* Set the timer to switch to check for link beat and perhaps switch + to an alternate media type. */ + init_timer(&tp->timer); + tp->timer.expires = RUN_AT(next_tick); + tp->timer.data = (unsigned long)dev; + tp->timer.function = tulip_tbl[tp->chip_id].media_timer; + add_timer(&tp->timer); + + netif_device_attach(dev); +} + + +static int +tulip_open(struct net_device *dev) +{ + MOD_INC_USE_COUNT; + + if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EBUSY; + } + + tulip_init_ring (dev); + + tulip_up (dev); + + return 0; +} + + +static void tulip_tx_timeout(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + unsigned long flags; + + spin_lock_irqsave (&tp->lock, flags); + + if (tulip_media_cap[dev->if_port] & MediaIsMII) { + /* Do nothing -- the media monitor should handle this. */ + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Transmit timeout using MII device.\n", + dev->name); + } else if (tp->chip_id == DC21040) { + if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) { + dev->if_port = (dev->if_port == 2 ? 0 : 2); + printk(KERN_INFO "%s: 21040 transmit timed out, switching to " + "%s.\n", + dev->name, medianame[dev->if_port]); + tulip_select_media(dev, 0); + } + goto out; + } else if (tp->chip_id == DC21041) { + int csr12 = inl(ioaddr + CSR12); + + printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, " + "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), csr12, + inl(ioaddr + CSR13), inl(ioaddr + CSR14)); + tp->mediasense = 1; + if ( ! tp->medialock) { + if (dev->if_port == 1 || dev->if_port == 2) + if (csr12 & 0x0004) { + dev->if_port = 2 - dev->if_port; + } else + dev->if_port = 0; + else + dev->if_port = 1; + tulip_select_media(dev, 0); + } + } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 + || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) { + printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " + "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12), + inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); + if ( ! tp->medialock && tp->mtable) { + do + --tp->cur_index; + while (tp->cur_index >= 0 + && (tulip_media_cap[tp->mtable->mleaf[tp->cur_index].media] + & MediaIsFD)); + if (--tp->cur_index < 0) { + /* We start again, but should instead look for default. */ + tp->cur_index = tp->mtable->leafcount - 1; + } + tulip_select_media(dev, 0); + printk(KERN_WARNING "%s: transmit timed out, switching to %s " + "media.\n", dev->name, medianame[dev->if_port]); + } + } else { + printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 " + "%8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12)); + dev->if_port = 0; + } + +#if defined(way_too_many_messages) + if (tulip_debug > 3) { + int i; + for (i = 0; i < RX_RING_SIZE; i++) { + u8 *buf = (u8 *)(tp->rx_ring[i].buffer1); + int j; + printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x " + "%2.2x %2.2x %2.2x.\n", + i, (unsigned int)tp->rx_ring[i].status, + (unsigned int)tp->rx_ring[i].length, + (unsigned int)tp->rx_ring[i].buffer1, + (unsigned int)tp->rx_ring[i].buffer2, + buf[0], buf[1], buf[2]); + for (j = 0; buf[j] != 0xee && j < 1600; j++) + if (j < 100) printk(" %2.2x", buf[j]); + printk(" j=%d.\n", j); + } + printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)tp->rx_ring[i].status); + printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)tp->tx_ring[i].status); + printk("\n"); + } +#endif + + /* Stop and restart the chip's Tx processes . */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + /* Trigger an immediate transmit demand. */ + outl(0, ioaddr + CSR1); + + tp->stats.tx_errors++; + +out: + dev->trans_start = jiffies; + netif_start_queue (dev); + spin_unlock_irqrestore (&tp->lock, flags); +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void tulip_init_ring(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + + tp->tx_full = 0; + tp->cur_rx = tp->cur_tx = 0; + tp->dirty_rx = tp->dirty_tx = 0; + tp->susp_rx = 0; + tp->ttimer = 0; + tp->nir = 0; + + for (i = 0; i < RX_RING_SIZE; i++) { + tp->rx_ring[i].status = 0x00000000; + tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ); + tp->rx_ring[i].buffer2 = virt_to_le32desc(&tp->rx_ring[i+1]); + tp->rx_skbuff[i] = NULL; + } + /* Mark the last entry as wrapping the ring. */ + tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP); + tp->rx_ring[i-1].buffer2 = virt_to_le32desc(&tp->rx_ring[0]); + + for (i = 0; i < RX_RING_SIZE; i++) { + /* Note the receive buffer must be longword aligned. + dev_alloc_skb() provides 16 byte alignment. But do *not* + use skb_reserve() to align the IP header! */ + struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ); + tp->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + tp->rx_ring[i].status = cpu_to_le32(DescOwned); /* Owned by Tulip chip */ + tp->rx_ring[i].buffer1 = virt_to_le32desc(skb->tail); + } + tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + /* The Tx buffer descriptor is filled in as needed, but we + do need to clear the ownership bit. */ + for (i = 0; i < TX_RING_SIZE; i++) { + tp->tx_skbuff[i] = 0; + tp->tx_ring[i].status = 0x00000000; + tp->tx_ring[i].buffer2 = virt_to_le32desc(&tp->tx_ring[i+1]); + } + tp->tx_ring[i-1].buffer2 = virt_to_le32desc(&tp->tx_ring[0]); +} + +static int +tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry; + u32 flag; + unsigned long cpuflags; + + /* Caution: the write order is important here, set the field + with the ownership bits last. */ + + spin_lock_irqsave(&tp->lock, cpuflags); + + /* Calculate the next Tx descriptor entry. */ + entry = tp->cur_tx % TX_RING_SIZE; + + tp->tx_skbuff[entry] = skb; + tp->tx_ring[entry].buffer1 = virt_to_le32desc(skb->data); + + if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ + flag = 0x60000000; /* No interrupt */ + } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) { + flag = 0xe0000000; /* Tx-done intr. */ + } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) { + flag = 0x60000000; /* No Tx-done intr. */ + } else { /* Leave room for set_rx_mode() to fill entries. */ + tp->tx_full = 1; + flag = 0xe0000000; /* Tx-done intr. */ + netif_stop_queue(dev); + } + if (entry == TX_RING_SIZE-1) + flag = 0xe0000000 | DESC_RING_WRAP; + + tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag); + tp->tx_ring[entry].status = cpu_to_le32(DescOwned); + tp->cur_tx++; + + /* Trigger an immediate transmit demand. */ + outl(0, dev->base_addr + CSR1); + + spin_unlock_irqrestore(&tp->lock, cpuflags); + + dev->trans_start = jiffies; + + return 0; +} + +static void tulip_down (struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *) dev->priv; + unsigned long flags; + + netif_device_detach (dev); + + del_timer (&tp->timer); + + spin_lock_irqsave (&tp->lock, flags); + + /* Disable interrupts by clearing the interrupt mask. */ + outl (0x00000000, ioaddr + CSR7); + + /* Stop the Tx and Rx processes. */ + tulip_outl_CSR6 (tp, inl (ioaddr + CSR6) & ~0x2002); + + /* 21040 -- Leave the card in 10baseT state. */ + if (tp->chip_id == DC21040) + outl (0x00000004, ioaddr + CSR13); + + if (inl (ioaddr + CSR6) != 0xffffffff) + tp->stats.rx_missed_errors += inl (ioaddr + CSR8) & 0xffff; + + spin_unlock_irqrestore (&tp->lock, flags); + + dev->if_port = tp->saved_if_port; + + /* Leave the driver in snooze, not sleep, mode. */ + if (tp->flags & HAS_ACPI) + pci_write_config_dword (tp->pdev, 0x40, 0x40000000); +} + + +static int tulip_close (struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *) dev->priv; + int i; + + tulip_down (dev); + + if (tulip_debug > 1) + printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, inl (ioaddr + CSR5)); + + free_irq (dev->irq, dev); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = tp->rx_skbuff[i]; + tp->rx_skbuff[i] = 0; + tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */ + tp->rx_ring[i].length = 0; + tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */ + if (skb) { + dev_kfree_skb (skb); + } + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (tp->tx_skbuff[i]) + dev_kfree_skb (tp->tx_skbuff[i]); + tp->tx_skbuff[i] = 0; + } + + MOD_DEC_USE_COUNT; + + return 0; +} + +static struct enet_statistics *tulip_get_stats(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + + if (netif_running(dev)) { + unsigned long flags; + + spin_lock_irqsave (&tp->lock, flags); + + tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; + + spin_unlock_irqrestore(&tp->lock, flags); + } + + return &tp->stats; +} + + +/* Provide ioctl() calls to examine the MII xcvr state. */ +static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + u16 *data = (u16 *)&rq->ifr_data; + int phy = tp->phys[0] & 0x1f; + long flags; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + if (tp->mii_cnt) + data[0] = phy; + else if (tp->flags & HAS_NWAY143) + data[0] = 32; + else if (tp->chip_id == COMET) + data[0] = 1; + else + return -ENODEV; + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + if (data[0] == 32 && (tp->flags & HAS_NWAY143)) { + int csr12 = inl(ioaddr + CSR12); + int csr14 = inl(ioaddr + CSR14); + switch (data[1]) { + case 0: { + data[3] = (csr14<<5) & 0x1000; + break; } + case 1: + data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0) + + (csr12&0x06 ? 0x04 : 0); + break; + case 4: { + data[3] = ((csr14>>9)&0x07C0) + + ((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1; + break; + } + case 5: data[3] = csr12 >> 16; break; + default: data[3] = 0; break; + } + } else { + spin_lock_irqsave (&tp->lock, flags); + data[3] = tulip_mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + spin_unlock_irqrestore (&tp->lock, flags); + } + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (data[0] == 32 && (tp->flags & HAS_NWAY143)) { + if (data[1] == 5) + tp->to_advertise = data[2]; + } else { + spin_lock_irqsave (&tp->lock, flags); + tulip_mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + spin_unlock_irqrestore(&tp->lock, flags); + } + return 0; + default: + return -EOPNOTSUPP; + } + + return -EOPNOTSUPP; +} + + +/* Set or clear the multicast filter for this adaptor. + Note that we only use exclusion around actually queueing the + new frame, not around filling tp->setup_frame. This is non-deterministic + when re-entered but still correct. */ + +/* The little-endian AUTODIN32 ethernet CRC calculation. + N.B. Do not use for bulk data, use a table-based routine instead. + This is common code and should be moved to net/core/crc.c */ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline u32 ether_crc_le(int length, unsigned char *data) +{ + u32 crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} +static unsigned const ethernet_polynomial = 0x04c11db7U; +static inline u32 ether_crc(int length, unsigned char *data) +{ + int crc = -1; + + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 0; bit < 8; bit++, current_octet >>= 1) + crc = (crc << 1) ^ + ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); + } + return crc; +} + +static void set_rx_mode(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr6 = inl(ioaddr + CSR6) & ~0x00D5; + + tp->csr6 &= ~0x00D5; + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + tp->csr6 |= 0x00C0; + csr6 |= 0x00C0; + /* Unconditionally log net taps. */ + printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); + } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { + /* Too many to filter well -- accept all multicasts. */ + tp->csr6 |= 0x0080; + csr6 |= 0x0080; + } else if (tp->flags & MC_HASH_ONLY) { + /* Some work-alikes have only a 64-entry hash filter table. */ + /* Should verify correctness on big-endian/__powerpc__ */ + struct dev_mc_list *mclist; + int i; + u32 mc_filter[2]; /* Multicast hash filter */ + if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */ + tp->csr6 |= 0x0080; + csr6 |= 0x0080; + } else { + mc_filter[1] = mc_filter[0] = 0; + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter); + if (tp->chip_id == AX88140) { + outl(2, ioaddr + CSR13); + outl(mc_filter[0], ioaddr + CSR14); + outl(3, ioaddr + CSR13); + outl(mc_filter[1], ioaddr + CSR14); + } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */ + outl(mc_filter[0], ioaddr + 0xAC); + outl(mc_filter[1], ioaddr + 0xB0); + } + } + } else { + u16 *eaddrs, *setup_frm = tp->setup_frame; + struct dev_mc_list *mclist; + u32 tx_flags = 0x08000000 | 192; + int i; + unsigned long flags; + + /* Note that only the low-address shortword of setup_frame is valid! + The values are doubled for big-endian architectures. */ + if (dev->mc_count > 14) { /* Must use a multicast hash table. */ + u16 hash_table[32]; + tx_flags = 0x08400000 | 192; /* Use hash filter. */ + memset(hash_table, 0, sizeof(hash_table)); + set_bit(255, hash_table); /* Broadcast entry */ + /* This should work on big-endian machines as well. */ + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, + hash_table); + for (i = 0; i < 32; i++) + *setup_frm++ = *setup_frm++ = hash_table[i]; + setup_frm = &tp->setup_frame[13*6]; + } else { + /* We have <= 14 addresses so we can use the wonderful + 16 address perfect filtering of the Tulip. */ + for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + i++, mclist = mclist->next) { + eaddrs = (u16 *)mclist->dmi_addr; + *setup_frm++ = *setup_frm++ = *eaddrs++; + *setup_frm++ = *setup_frm++ = *eaddrs++; + *setup_frm++ = *setup_frm++ = *eaddrs++; + } + /* Fill the unused entries with the broadcast address. */ + memset(setup_frm, 0xff, (15-i)*12); + setup_frm = &tp->setup_frame[15*6]; + } + + /* Fill the final entry with our physical address. */ + eaddrs = (u16 *)dev->dev_addr; + *setup_frm++ = *setup_frm++ = eaddrs[0]; + *setup_frm++ = *setup_frm++ = eaddrs[1]; + *setup_frm++ = *setup_frm++ = eaddrs[2]; + + spin_lock_irqsave(&tp->lock, flags); + + if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) { + /* Same setup recently queued, we need not add it. */ + } else { + unsigned int entry; + + /* Now add this frame to the Tx list. */ + + entry = tp->cur_tx++ % TX_RING_SIZE; + + if (entry != 0) { + /* Avoid a chip errata by prefixing a dummy entry. */ + tp->tx_skbuff[entry] = 0; + tp->tx_ring[entry].length = + (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0; + tp->tx_ring[entry].buffer1 = 0; + tp->tx_ring[entry].status = cpu_to_le32(DescOwned); + entry = tp->cur_tx++ % TX_RING_SIZE; + } + + tp->tx_skbuff[entry] = 0; + /* Put the setup frame on the Tx list. */ + if (entry == TX_RING_SIZE-1) + tx_flags |= DESC_RING_WRAP; /* Wrap ring. */ + tp->tx_ring[entry].length = cpu_to_le32(tx_flags); + tp->tx_ring[entry].buffer1 = virt_to_le32desc(tp->setup_frame); + tp->tx_ring[entry].status = cpu_to_le32(DescOwned); + if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) { + netif_stop_queue(dev); + tp->tx_full = 1; + } + + /* Trigger an immediate transmit demand. */ + outl(0, ioaddr + CSR1); + + } + + spin_unlock_irqrestore(&tp->lock, flags); + } + tulip_outl_CSR6(tp, csr6 | 0x0000); +} + + +static int __devinit tulip_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int did_version = 0; /* Already printed version info. */ + struct tulip_private *tp; + /* See note below on the multiport cards. */ + static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; + static int last_irq = 0; + static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */ + u8 chip_rev; + int i, irq; + unsigned short sum; + u8 ee_data[EEPROM_SIZE]; + struct net_device *dev; + long ioaddr; + static int board_idx = -1; + int chip_idx = ent->driver_data; + + board_idx++; + + if (tulip_debug > 0 && did_version++ == 0) + printk (KERN_INFO "%s", version); + + if( pdev->subsystem_vendor == 0x1376 ){ + printk (KERN_ERR PFX "skipping LMC card.\n"); + return -ENODEV; + } + + ioaddr = pci_resource_start (pdev, 0); + irq = pdev->irq; + + /* init_etherdev ensures qword aligned structures */ + dev = init_etherdev (NULL, sizeof (*tp)); + if (!dev) { + printk (KERN_ERR PFX "ether device alloc failed, aborting\n"); + return -ENOMEM; + } + + /* We do a request_region() only to register /proc/ioports info. */ + /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */ + if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name)) { + printk (KERN_ERR PFX "I/O ports (0x%x@0x%lx) unavailable, " + "aborting\n", tulip_tbl[chip_idx].io_size, ioaddr); + goto err_out_free_netdev; + } + + if (pci_enable_device(pdev)) { + printk (KERN_ERR PFX "cannot enable PCI device (id %04x:%04x, " + "bus %d, devfn %d), aborting\n", + pdev->vendor, pdev->device, + pdev->bus->number, pdev->devfn); + goto err_out_free_netdev; + } + + pci_set_master(pdev); + + pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev); + + /* + * initialize priviate data structure 'tp' + * it is zeroed and aligned in init_etherdev + */ + tp = dev->priv; + + tp->chip_id = chip_idx; + tp->flags = tulip_tbl[chip_idx].flags; + tp->pdev = pdev; + tp->base_addr = ioaddr; + tp->revision = chip_rev; + spin_lock_init(&tp->lock); + +#ifdef TULIP_FULL_DUPLEX + tp->full_duplex = 1; + tp->full_duplex_lock = 1; +#endif +#ifdef TULIP_DEFAULT_MEDIA + tp->default_port = TULIP_DEFAULT_MEDIA; +#endif +#ifdef TULIP_NO_MEDIA_SWITCH + tp->medialock = 1; +#endif + + printk(KERN_INFO "%s: %s rev %d at %#3lx,", + dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); + + /* Stop the chip's Tx and Rx processes. */ + tulip_outl_CSR6(tp, inl(ioaddr + CSR6) & ~0x2002); + /* Clear the missed-packet counter. */ + (volatile int)inl(ioaddr + CSR8); + + if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) { + printk(" 21040 compatible mode,"); + chip_idx = DC21040; + } + + /* The station address ROM is read byte serially. The register must + be polled, waiting for the value to be read bit serially from the + EEPROM. + */ + sum = 0; + if (chip_idx == DC21040) { + outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */ + for (i = 0; i < 6; i++) { + int value, boguscnt = 100000; + do + value = inl(ioaddr + CSR9); + while (value < 0 && --boguscnt > 0); + dev->dev_addr[i] = value; + sum += value & 0xff; + } + } else if (chip_idx == LC82C168) { + for (i = 0; i < 3; i++) { + int value, boguscnt = 100000; + outl(0x600 | i, ioaddr + 0x98); + do + value = inl(ioaddr + CSR9); + while (value < 0 && --boguscnt > 0); + put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i); + sum += value & 0xffff; + } + } else if (chip_idx == COMET) { + /* No need to read the EEPROM. */ + put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr); + put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4)); + for (i = 0; i < 6; i ++) + sum += dev->dev_addr[i]; + } else { + /* A serial EEPROM interface, we read now and sort it out later. */ + int sa_offset = 0; + int ee_addr_size = tulip_read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6; + + for (i = 0; i < sizeof(ee_data)/2; i++) + ((u16 *)ee_data)[i] = + le16_to_cpu(tulip_read_eeprom(ioaddr, i, ee_addr_size)); + + /* DEC now has a specification (see Notes) but early board makers + just put the address in the first EEPROM locations. */ + /* This does memcmp(eedata, eedata+16, 8) */ + for (i = 0; i < 8; i ++) + if (ee_data[i] != ee_data[16+i]) + sa_offset = 20; + if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) { + sa_offset = 2; /* Grrr, damn Matrox boards. */ + multiport_cnt = 4; + } + for (i = 0; i < 6; i ++) { + dev->dev_addr[i] = ee_data[i + sa_offset]; + sum += ee_data[i + sa_offset]; + } + } + /* Lite-On boards have the address byte-swapped. */ + if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0) + && dev->dev_addr[1] == 0x00) + for (i = 0; i < 6; i+=2) { + char tmp = dev->dev_addr[i]; + dev->dev_addr[i] = dev->dev_addr[i+1]; + dev->dev_addr[i+1] = tmp; + } + /* On the Zynx 315 Etherarray and other multiport boards only the + first Tulip has an EEPROM. + The addresses of the subsequent ports are derived from the first. + Many PCI BIOSes also incorrectly report the IRQ line, so we correct + that here as well. */ + if (sum == 0 || sum == 6*0xff) { + printk(" EEPROM not present,"); + for (i = 0; i < 5; i++) + dev->dev_addr[i] = last_phys_addr[i]; + dev->dev_addr[i] = last_phys_addr[i] + 1; +#if defined(__i386__) /* Patch up x86 BIOS bug. */ + if (last_irq) + irq = last_irq; +#endif + } + + for (i = 0; i < 6; i++) + printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]); + printk(", IRQ %d.\n", irq); + last_irq = irq; + + pdev->driver_data = dev; + dev->base_addr = ioaddr; + dev->irq = irq; + tp->csr0 = csr0; + + /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. + And the ASIX must have a burst limit or horrible things happen. */ + if (chip_idx == DC21143 && chip_rev == 65) + tp->csr0 &= ~0x01000000; + else if (chip_idx == AX88140) + tp->csr0 |= 0x2000; + + /* The lower four bits are the media type. */ + if (board_idx >= 0 && board_idx < MAX_UNITS) { + tp->default_port = options[board_idx] & 15; + if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0) + tp->full_duplex = 1; + if (mtu[board_idx] > 0) + dev->mtu = mtu[board_idx]; + } + if (dev->mem_start) + tp->default_port = dev->mem_start; + if (tp->default_port) { + tp->medialock = 1; + if (tulip_media_cap[tp->default_port] & MediaAlwaysFD) + tp->full_duplex = 1; + } + if (tp->full_duplex) + tp->full_duplex_lock = 1; + + if (tulip_media_cap[tp->default_port] & MediaIsMII) { + u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 }; + tp->to_advertise = media2advert[tp->default_port - 9]; + } else if (tp->flags & HAS_8023X) + tp->to_advertise = 0x05e1; + else + tp->to_advertise = 0x01e1; + + /* This is logically part of probe1(), but too complex to write inline. */ + if (tp->flags & HAS_MEDIA_TABLE) { + memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom)); + tulip_parse_eeprom(dev); + } + + if ((tp->flags & ALWAYS_CHECK_MII) || + (tp->mtable && tp->mtable->has_mii) || + ( ! tp->mtable && (tp->flags & HAS_MII))) { + int phy, phy_idx; + if (tp->mtable && tp->mtable->has_mii) { + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == 11) { + tp->cur_index = i; + tp->saved_if_port = dev->if_port; + tulip_select_media(dev, 1); + dev->if_port = tp->saved_if_port; + break; + } + } + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, + but takes much time. */ + for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); + phy++) { + int mii_status = tulip_mdio_read(dev, phy, 1); + if ((mii_status & 0x8301) == 0x8001 || + ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { + int mii_reg0 = tulip_mdio_read(dev, phy, 0); + int mii_advert = tulip_mdio_read(dev, phy, 4); + int reg4 = ((mii_status>>6) & tp->to_advertise) | 1; + tp->phys[phy_idx] = phy; + tp->advertising[phy_idx++] = reg4; + printk(KERN_INFO "%s: MII transceiver #%d " + "config %4.4x status %4.4x advertising %4.4x.\n", + dev->name, phy, mii_reg0, mii_status, mii_advert); + /* Fixup for DLink with miswired PHY. */ + if (mii_advert != reg4) { + printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d," + " previously advertising %4.4x.\n", + dev->name, reg4, phy, mii_advert); + printk(KERN_DEBUG "%s: Advertising %4.4x (to advertise" + " is %4.4x).\n", + dev->name, reg4, tp->to_advertise); + tulip_mdio_write(dev, phy, 4, reg4); + } + /* Enable autonegotiation: some boards default to off. */ + tulip_mdio_write(dev, phy, 0, mii_reg0 | + (tp->full_duplex ? 0x1100 : 0x1000) | + (tulip_media_cap[tp->default_port]&MediaIs100 ? 0x2000:0)); + } + } + tp->mii_cnt = phy_idx; + if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { + printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n", + dev->name); + tp->phys[0] = 1; + } + } + + /* The Tulip-specific entries in the device structure. */ + dev->open = tulip_open; + dev->hard_start_xmit = tulip_start_xmit; + dev->tx_timeout = tulip_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->stop = tulip_close; + dev->get_stats = tulip_get_stats; + dev->do_ioctl = private_ioctl; + dev->set_multicast_list = set_rx_mode; + + if ((tp->flags & HAS_NWAY143) || tp->chip_id == DC21041) + tp->link_change = t21142_lnk_change; + else if (tp->flags & HAS_PNICNWAY) + tp->link_change = pnic_lnk_change; + + /* Reset the xcvr interface and turn on heartbeat. */ + switch (chip_idx) { + case DC21041: + tp->to_advertise = 0x0061; + outl(0x00000000, ioaddr + CSR13); + outl(0xFFFFFFFF, ioaddr + CSR14); + outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ + tulip_outl_CSR6(tp, inl(ioaddr + CSR6) | 0x0200); + outl(0x0000EF05, ioaddr + CSR13); + break; + case DC21040: + outl(0x00000000, ioaddr + CSR13); + outl(0x00000004, ioaddr + CSR13); + break; + case DC21140: + default: + if (tp->mtable) + outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); + break; + case DC21142: + case PNIC2: + if (tp->mii_cnt || tulip_media_cap[dev->if_port] & MediaIsMII) { + tulip_outl_CSR6(tp, 0x82020000); + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + tulip_outl_CSR6(tp, 0x820E0000); + } else + t21142_start_nway(dev); + break; + case LC82C168: + if ( ! tp->mii_cnt) { + tp->nway = 1; + tp->nwayset = 0; + tulip_outl_CSR6(tp, 0x00420000); + outl(0x30, ioaddr + CSR12); + tulip_outl_CSR6(tp, 0x0001F078); + tulip_outl_CSR6(tp, 0x0201F078); /* Turn on autonegotiation. */ + } + break; + case MX98713: case COMPEX9881: + tulip_outl_CSR6(tp, 0x00000000); + outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */ + outl(0x00000001, ioaddr + CSR13); + break; + case MX98715: case MX98725: + tulip_outl_CSR6(tp, 0x01a80000); + outl(0xFFFFFFFF, ioaddr + CSR14); + outl(0x00001000, ioaddr + CSR12); + break; + case COMET: + /* No initialization necessary. */ + break; + } + + /* put the chip in snooze mode until opened */ + if (tulip_tbl[chip_idx].flags & HAS_ACPI) + pci_write_config_dword(pdev, 0x40, 0x40000000); + + return 0; + +err_out_free_netdev: + unregister_netdev (dev); + kfree (dev); + return -ENODEV; +} + + +static void tulip_suspend (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + + if (dev && netif_device_present (dev)) + tulip_down (dev); +} + + +static void tulip_resume (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + + if (dev && !netif_device_present (dev)) + tulip_up (dev); +} + + +static void __devexit tulip_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + + if (dev) { + struct tulip_private *tp = (struct tulip_private *)dev->priv; + unregister_netdev(dev); + release_region(dev->base_addr, + tulip_tbl[tp->chip_id].io_size); + kfree(dev); + } +} + + +static struct pci_driver tulip_driver = { + name: TULIP_MODULE_NAME, + id_table: tulip_pci_tbl, + probe: tulip_init_one, + remove: tulip_remove_one, + suspend: tulip_suspend, + resume: tulip_resume, +}; + + +static int __init tulip_init (void) +{ + /* copy module parms into globals */ + tulip_rx_copybreak = rx_copybreak; + tulip_max_interrupt_work = max_interrupt_work; + + /* probe for and init boards */ + return pci_module_init (&tulip_driver); +} + + +static void __exit tulip_cleanup (void) +{ + pci_unregister_driver (&tulip_driver); +} + + +module_init(tulip_init); +module_exit(tulip_cleanup); diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 873a561ef..72aeae112 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -1,4 +1,4 @@ -/* $Id: cosa.c,v 1.28 1999/10/11 21:06:58 kas Exp $ */ +/* $Id: cosa.c,v 1.30 2000/02/21 15:19:49 kas Exp $ */ /* * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz> @@ -222,6 +222,8 @@ static int cosa_major = 117; #undef DEBUG_IRQS 1 /* Print the message when the IRQ is received */ #undef DEBUG_IO 1 /* Dump the I/O traffic */ +#define TX_TIMEOUT (5*HZ) + /* Maybe the following should be allocated dynamically */ static struct cosa_data cosa_cards[MAX_CARDS]; static int nr_cards = 0; @@ -286,6 +288,7 @@ static void sppp_channel_init(struct channel_data *chan); static void sppp_channel_delete(struct channel_data *chan); static int cosa_sppp_open(struct net_device *d); static int cosa_sppp_close(struct net_device *d); +static void cosa_sppp_timeout(struct net_device *d); static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *d); static char *sppp_setup_rx(struct channel_data *channel, int size); static int sppp_rx_done(struct channel_data *channel); @@ -370,7 +373,7 @@ static int __init cosa_init(void) { int i; - printk(KERN_INFO "cosa v1.06 (c) 1997-8 Jan Kasprzak <kas@fi.muni.cz>\n"); + printk(KERN_INFO "cosa v1.07 (c) 1997-2000 Jan Kasprzak <kas@fi.muni.cz>\n"); #ifdef __SMP__ printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n"); #endif @@ -406,7 +409,6 @@ static int __init cosa_init(void) #ifdef MODULE void cleanup_module (void) { - int i; struct cosa_data *cosa; printk(KERN_INFO "Unloading the cosa module\n"); @@ -595,6 +597,8 @@ static void sppp_channel_init(struct channel_data *chan) d->hard_start_xmit = cosa_sppp_tx; d->do_ioctl = cosa_sppp_ioctl; d->get_stats = cosa_net_stats; + d->tx_timeout = cosa_sppp_timeout; + d->watchdog_timeo = TX_TIMEOUT; dev_init_buffers(d); if (register_netdev(d) == -1) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); @@ -609,7 +613,6 @@ static void sppp_channel_delete(struct channel_data *chan) unregister_netdev(chan->pppdev.dev); } - static int cosa_sppp_open(struct net_device *d) { struct channel_data *chan = d->priv; @@ -646,7 +649,7 @@ static int cosa_sppp_open(struct net_device *d) return err; } - d->tbusy = 0; + netif_start_queue(d); cosa_enable_rx(chan); return 0; } @@ -655,41 +658,39 @@ static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev) { struct channel_data *chan = dev->priv; - if (dev->tbusy) { - if (time_before(jiffies, dev->trans_start+2*HZ)) - return 1; /* Two seconds timeout */ - if (test_bit(RXBIT, &chan->cosa->rxtx)) { - chan->stats.rx_errors++; - chan->stats.rx_missed_errors++; - } else { - chan->stats.tx_errors++; - chan->stats.tx_aborted_errors++; - } - cosa_kick(chan->cosa); - if (chan->tx_skb) { - dev_kfree_skb(chan->tx_skb); - chan->tx_skb = 0; - } - dev->tbusy = 0; - } - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); - return 1; - } - + netif_stop_queue(dev); + chan->tx_skb = skb; - dev->trans_start = jiffies; cosa_start_tx(chan, skb->data, skb->len); return 0; } +static void cosa_sppp_timeout(struct net_device *dev) +{ + struct channel_data *chan = dev->priv; + + if (test_bit(RXBIT, &chan->cosa->rxtx)) { + chan->stats.rx_errors++; + chan->stats.rx_missed_errors++; + } else { + chan->stats.tx_errors++; + chan->stats.tx_aborted_errors++; + } + cosa_kick(chan->cosa); + if (chan->tx_skb) { + dev_kfree_skb(chan->tx_skb); + chan->tx_skb = 0; + } + netif_wake_queue(dev); +} + static int cosa_sppp_close(struct net_device *d) { struct channel_data *chan = d->priv; int flags; + netif_stop_queue(d); sppp_close(d); - d->tbusy = 1; cosa_disable_rx(chan); spin_lock_irqsave(&chan->cosa->lock, flags); if (chan->rx_skb) { @@ -760,8 +761,7 @@ static int sppp_tx_done(struct channel_data *chan, int size) chan->tx_skb = 0; chan->stats.tx_packets++; chan->stats.tx_bytes += size; - chan->pppdev.dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue(chan->pppdev.dev); return 1; } @@ -1350,14 +1350,14 @@ static void put_driver_status_nolock(struct cosa_data *cosa) static void cosa_kick(struct cosa_data *cosa) { unsigned flags, flags1; - char *s = "Unknown"; + char *s = "(probably) IRQ"; if (test_bit(RXBIT, &cosa->rxtx)) - s = "RX"; + s = "RX DMA"; if (test_bit(TXBIT, &cosa->rxtx)) - s = "TX"; + s = "TX DMA"; - printk(KERN_INFO "%s: %s DMA timeout - restarting.\n", cosa->name, s); + printk(KERN_INFO "%s: %s timeout - restarting.\n", cosa->name, s); spin_lock_irqsave(&cosa->lock, flags); cosa->rxtx = 0; diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index 6113365c1..e039bbc28 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -50,6 +50,7 @@ #include <linux/random.h> #include <linux/pkt_sched.h> #include <asm/byteorder.h> +#include <linux/spinlock.h> #include "syncppp.h" #define MAXALIVECNT 6 /* max. alive packets */ @@ -126,6 +127,7 @@ struct cisco_packet { static struct sppp *spppq; static struct timer_list sppp_keepalive_timer; +static spinlock_t spppq_lock; static void sppp_keepalive (unsigned long dummy); static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, @@ -359,8 +361,8 @@ static void sppp_keepalive (unsigned long dummy) { struct sppp *sp; unsigned long flags; - save_flags(flags); - cli(); + + spin_lock_irqsave(&spppq_lock, flags); for (sp=spppq; sp; sp=sp->pp_next) { @@ -402,7 +404,7 @@ static void sppp_keepalive (unsigned long dummy) sp->lcp.echoid, 4, &nmagic); } } - restore_flags(flags); + spin_unlock_irqrestore(&spppq_lock, flags); sppp_keepalive_timer.expires=jiffies+10*HZ; add_timer(&sppp_keepalive_timer); } @@ -915,7 +917,9 @@ void sppp_attach(struct ppp_device *pd) { struct net_device *dev = pd->dev; struct sppp *sp = &pd->sppp; - + unsigned long flags; + + spin_lock_irqsave(&spppq_lock, flags); /* Initialize keepalive handler. */ if (! spppq) { @@ -927,6 +931,7 @@ void sppp_attach(struct ppp_device *pd) /* Insert new entry into the keepalive list. */ sp->pp_next = spppq; spppq = sp; + spin_unlock_irqrestore(&spppq_lock, flags); sp->pp_loopcnt = 0; sp->pp_alivecnt = 0; @@ -971,7 +976,9 @@ EXPORT_SYMBOL(sppp_attach); void sppp_detach (struct net_device *dev) { struct sppp **q, *p, *sp = (struct sppp *)sppp_of(dev); + unsigned long flags; + spin_lock_irqsave(&spppq_lock, flags); /* Remove the entry from the keepalive list. */ for (q = &spppq; (p = *q); q = &p->pp_next) if (p == sp) { @@ -983,6 +990,7 @@ void sppp_detach (struct net_device *dev) if (! spppq) del_timer(&sppp_keepalive_timer); sppp_clear_timeout (sp); + spin_unlock_irqrestore(&spppq_lock, flags); } EXPORT_SYMBOL(sppp_detach); @@ -1292,6 +1300,7 @@ void sync_ppp_init(void) { printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"); printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n"); + spin_lock_init(&spppq_lock); sppp_packet_type.type=htons(ETH_P_WAN_PPP); dev_add_pack(&sppp_packet_type); } diff --git a/drivers/net/wavelan.c b/drivers/net/wavelan.c index cd5b7caa0..17b285ba4 100644 --- a/drivers/net/wavelan.c +++ b/drivers/net/wavelan.c @@ -24,24 +24,24 @@ /*------------------------------------------------------------------*/ /* - * Wrapper for disabling interrupts. + * Wrapper for disabling interrupts and locking the driver. + * (note : inline, so optimised away) */ - -static inline unsigned long wv_splhi(void) +static inline void wv_splhi(net_local * lp, + unsigned long * pflags) { - unsigned long flags; - save_flags(flags); - cli(); - return (flags); + spin_lock_irqsave(&lp->spinlock, *pflags); + /* Note : above does the cli(); itself */ } /*------------------------------------------------------------------*/ /* - * Wrapper for re-enabling interrupts. + * Wrapper for re-enabling interrupts and un-locking the driver. */ -static inline void wv_splx(unsigned long flags) +static inline void wv_splx(net_local * lp, + unsigned long * pflags) { - restore_flags(flags); + spin_unlock_irqrestore(&lp->spinlock, *pflags); } /*------------------------------------------------------------------*/ @@ -180,13 +180,12 @@ static inline void wv_ints_off(device * dev) unsigned long ioaddr = dev->base_addr; unsigned long flags; - save_flags(flags); - cli(); + wv_splhi(lp, &flags); lp->hacr &= ~HACR_INTRON; hacr_write(ioaddr, lp->hacr); - restore_flags(flags); + wv_splx(lp, &flags); } /* wv_ints_off */ /*------------------------------------------------------------------*/ @@ -199,11 +198,12 @@ static inline void wv_ints_on(device * dev) unsigned long ioaddr = dev->base_addr; unsigned long flags; - save_flags(flags); - cli(); + wv_splhi(lp, &flags); + lp->hacr |= HACR_INTRON; hacr_write(ioaddr, lp->hacr); - restore_flags(flags); + + wv_splx(lp, &flags); } /* wv_ints_on */ /******************* MODEM MANAGEMENT SUBROUTINES *******************/ @@ -707,7 +707,7 @@ wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp) printk(KERN_INFO "%s: wv_config_complete(): configure failed; status = 0x%x\n", dev->name, status); -#endif /* DEBUG_CONFIG_ERROR */ +#endif /* DEBUG_CONFIG_ERROR */ ret = 1; /* Ready to be scrapped */ } @@ -723,6 +723,8 @@ wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp) /* * Command completion interrupt. * Reclaim as many freed tx buffers as we can. + * (called in wavelan_interrupt()). + * Note : the spinlock is already grabbed for us. */ static int wv_complete(device * dev, unsigned long ioaddr, net_local * lp) { @@ -870,16 +872,20 @@ static inline void wv_82586_reconfig(device * dev) { net_local *lp = (net_local *) dev->priv; + /* Arm the flag, will be cleard in wv_82586_config() */ + lp->reconfig_82586 = 1; + /* Check if we can do it now ! */ - if (!netif_running(dev) && netif_queue_stopped(dev)) { - lp->reconfig_82586 = 1; + if((netif_running(dev)) && !(netif_queue_stopped(dev))) + /* May fail */ + wv_82586_config(dev); + else { #ifdef DEBUG_CONFIG_INFO printk(KERN_DEBUG "%s: wv_82586_reconfig(): delayed (state = %lX)\n", dev->name, dev->state); #endif - } else - wv_82586_config(dev); + } } /********************* DEBUG & INFO SUBROUTINES *********************/ @@ -1806,9 +1812,9 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is #endif /* Disable interrupts and save flags. */ - save_flags(flags); - cli(); + wv_splhi(lp, &flags); /* FIXME: can't copy*user when cli this is broken! */ + /* Note : is it still valid ? Jean II */ /* Look what is the request */ switch (cmd) { @@ -2271,7 +2277,7 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is } /* Enable interrupts and restore flags. */ - restore_flags(flags); + wv_splx(lp, &flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); @@ -2297,15 +2303,12 @@ static iw_stats *wavelan_get_wireless_stats(device * dev) dev->name); #endif - /* Disable interrupts and save flags. */ - save_flags(flags); - cli(); - + /* Check */ if (lp == (net_local *) NULL) - { - restore_flags(flags); return (iw_stats *) NULL; - } + + /* Disable interrupts and save flags. */ + wv_splhi(lp, &flags); wstats = &lp->wstats; @@ -2333,7 +2336,7 @@ static iw_stats *wavelan_get_wireless_stats(device * dev) wstats->discard.misc = 0L; /* Enable interrupts and restore flags. */ - restore_flags(flags); + wv_splx(lp, &flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", @@ -2455,7 +2458,8 @@ wv_packet_read(device * dev, u16 buf_off, int sksize) /* * Transfer as many packets as we can * from the device RAM. - * Called by the interrupt handler. + * (called in wavelan_interrupt()). + * Note : the spinlock is already grabbed for us. */ static inline void wv_receive(device * dev) { @@ -2640,7 +2644,7 @@ static inline void wv_receive(device * dev) * * (called in wavelan_packet_xmit()) */ -static inline void wv_packet_write(device * dev, void *buf, short length) +static inline int wv_packet_write(device * dev, void *buf, short length) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -2665,9 +2669,18 @@ static inline void wv_packet_write(device * dev, void *buf, short length) if (clen < ETH_ZLEN) clen = ETH_ZLEN; - save_flags(flags); - cli(); - + wv_splhi(lp, &flags); + + /* Check nothing bad has happened */ + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { +#ifdef DEBUG_TX_ERROR + printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n", + dev->name); +#endif + wv_splx(lp, &flags); + return 1; + } + /* Calculate addresses of next block and previous block. */ txblock = lp->tx_first_free; txpred = txblock - TXBLOCKZ; @@ -2736,20 +2749,13 @@ static inline void wv_packet_write(device * dev, void *buf, short length) /* Keep stats up to date. */ lp->stats.tx_bytes += length; - /* If watchdog not already active, activate it... */ - if (lp->watchdog.prev == (timer_list *) NULL) { - /* Set timer to expire in WATCHDOG_JIFFIES. */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); - } - if (lp->tx_first_in_use == I82586NULL) lp->tx_first_in_use = txblock; if (lp->tx_n_in_use < NTXBLOCKS - 1) netif_wake_queue(dev); - restore_flags(flags); + wv_splx(lp, &flags); #ifdef DEBUG_TX_INFO wv_packet_info((u8 *) buf, length, dev->name, @@ -2759,6 +2765,8 @@ static inline void wv_packet_write(device * dev, void *buf, short length) #ifdef DEBUG_TX_TRACE printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); #endif + + return 0; } /*------------------------------------------------------------------*/ @@ -2781,7 +2789,6 @@ static int wavelan_packet_xmit(struct sk_buff *skb, device * dev) * Block a timer-based transmit from overlapping. * In other words, prevent reentering this routine. */ - netif_stop_queue(dev); /* If somebody has asked to reconfigure the controller, @@ -2789,13 +2796,18 @@ static int wavelan_packet_xmit(struct sk_buff *skb, device * dev) */ if (lp->reconfig_82586) { wv_82586_config(dev); + /* Check that we can continue */ + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) + return 1; } #ifdef DEBUG_TX_ERROR if (skb->next) printk(KERN_INFO "skb has next\n"); #endif - wv_packet_write(dev, skb->data, skb->len); + /* Write packet on the card */ + if(wv_packet_write(dev, skb->data, skb->len)) + return 1; /* We failed */ dev_kfree_skb(skb); @@ -3161,7 +3173,7 @@ static inline int wv_cu_start(device * dev) } lp->tx_n_in_use = 0; - netif_wake_queue(dev); + netif_start_queue(dev); #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name); #endif @@ -3310,7 +3322,7 @@ static inline int wv_82586_start(device * dev) * as usual to the NOP command. * Note that only the last command (mc_set) will generate an interrupt. * - * (called by wv_hw_reset(), wv_82586_reconfig()) + * (called by wv_hw_reset(), wv_82586_reconfig(), wavelan_packet_xmit()) */ static void wv_82586_config(device * dev) { @@ -3336,9 +3348,18 @@ static void wv_82586_config(device * dev) printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name); #endif - save_flags(flags); - cli(); + wv_splhi(lp, &flags); + /* Check nothing bad has happened */ + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO "%s: wv_82586_config(): Tx queue full.\n", + dev->name); +#endif + wv_splx(lp, &flags); + return; + } + /* Calculate addresses of next block and previous block. */ txblock = lp->tx_first_free; txpred = txblock - TXBLOCKZ; @@ -3467,22 +3488,17 @@ static void wv_82586_config(device * dev) (unsigned char *) &nop.nop_h.ac_link, sizeof(nop.nop_h.ac_link)); - /* If watchdog not already active, activate it... */ - if (lp->watchdog.prev == (timer_list *) NULL) { - /* set timer to expire in WATCHDOG_JIFFIES */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); - } - + /* Job done, clear the flag */ lp->reconfig_82586 = 0; if (lp->tx_first_in_use == I82586NULL) lp->tx_first_in_use = txblock; - if (lp->tx_n_in_use < NTXBLOCKS - 1) - netif_wake_queue(dev); + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) + netif_stop_queue(dev); + + wv_splx(lp, &flags); - restore_flags(flags); #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name); #endif @@ -3539,10 +3555,6 @@ static int wv_hw_reset(device * dev) (unsigned int) dev); #endif - /* If watchdog was activated, kill it! */ - if (lp->watchdog.prev != (timer_list *) NULL) - del_timer(&lp->watchdog); - /* Increase the number of resets done. */ lp->nresets++; @@ -3637,8 +3649,19 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) lp = (net_local *) dev->priv; ioaddr = dev->base_addr; - /* Prevent reentrance. What should we do here? */ +#ifdef DEBUG_INTERRUPT_ERROR + /* Check state of our spinlock (it should be cleared) */ + if(spin_is_locked(&lp->spinlock)) + printk(KERN_INFO + "%s: wavelan_interrupt(): spinlock is already locked !!!\n", + dev->name); +#endif + + /* Prevent reentrancy. It is safe because wv_splhi disable interrupts + * before aquiring the spinlock */ + spin_lock(&lp->spinlock); + /* Check modem interupt */ if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) { u8 dce_status; @@ -3655,6 +3678,7 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) #endif } + /* Check if not controller interrupt */ if ((hasr & HASR_82586_INTR) == 0) { #ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO @@ -3689,15 +3713,6 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) dev->name); #endif wv_complete(dev, ioaddr, lp); - - /* If watchdog was activated, kill it ! */ - if (lp->watchdog.prev != (timer_list *) NULL) - del_timer(&lp->watchdog); - if (lp->tx_n_in_use > 0) { - /* set timer to expire in WATCHDOG_JIFFIES */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); - } } /* Frame received. */ @@ -3710,9 +3725,13 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) wv_receive(dev); } + /* Release spinlock here so that wv_hw_reset() can grab it */ + spin_unlock (&lp->lock); + /* Check the state of the command unit. */ if (((status & SCB_ST_CNA) == SCB_ST_CNA) || - (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && netif_running(dev))) { + (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && + (netif_running(dev)))) { #ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO "%s: wavelan_interrupt(): CU inactive -- restarting\n", @@ -3723,7 +3742,8 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* Check the state of the command unit. */ if (((status & SCB_ST_RNR) == SCB_ST_RNR) || - (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && netif_running(dev))) { + (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && + (netif_running(dev)))) { #ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO "%s: wavelan_interrupt(): RU not ready -- restarting\n", @@ -3739,26 +3759,16 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) /*------------------------------------------------------------------*/ /* - * Watchdog: when we start a transmission, we set a timer in the + * Watchdog: when we start a transmission, a timer is set for us in the * kernel. If the transmission completes, this timer is disabled. If - * the timer expires, we try to unlock the hardware. - * - * Note: this watchdog doesn't work on the same principle as the - * watchdog in the previous version of the ISA driver. I made it this - * way because the overhead of add_timer() and del_timer() is nothing - * and because it avoids calling the watchdog, saving some CPU. + * the timer expires, we are called and we try to unlock the hardware. */ -static void wavelan_watchdog(unsigned long a) +static void wavelan_watchdog(device * dev) { - device *dev; - net_local *lp; - unsigned long ioaddr; - unsigned long flags; - unsigned int nreaped; - - dev = (device *) a; - ioaddr = dev->base_addr; - lp = (net_local *) dev->priv; + net_local * lp = (net_local *)dev->priv; + u_long ioaddr = dev->base_addr; + unsigned long flags; + unsigned int nreaped; #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); @@ -3769,18 +3779,16 @@ static void wavelan_watchdog(unsigned long a) dev->name); #endif - save_flags(flags); - cli(); - - dev = (device *) a; - ioaddr = dev->base_addr; - lp = (net_local *) dev->priv; + wv_splhi(lp, &flags); + /* Check that we came here for something */ if (lp->tx_n_in_use <= 0) { - restore_flags(flags); + wv_splx(lp, &flags); return; } + /* Try to see if some buffers are not free (in case we missed + * an interrupt */ nreaped = wv_complete(dev, ioaddr, lp); #ifdef DEBUG_INTERRUPT_INFO @@ -3811,15 +3819,13 @@ static void wavelan_watchdog(unsigned long a) dev->name); #endif wv_hw_reset(dev); - } else - /* Reset watchdog for next transmission. */ - if (lp->tx_n_in_use > 0) { - /* set timer to expire in WATCHDOG_JIFFIES */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); } - restore_flags(flags); + /* At this point, we should have some free Tx buffer ;-) */ + if (lp->tx_n_in_use < NTXBLOCKS - 1) + netif_wake_queue(dev); + + wv_splx(lp, &flags); #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); @@ -3840,7 +3846,8 @@ static void wavelan_watchdog(unsigned long a) */ static int wavelan_open(device * dev) { - unsigned long flags; + net_local * lp = (net_local *)dev->priv; + unsigned long flags; #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, @@ -3865,8 +3872,7 @@ static int wavelan_open(device * dev) return -EAGAIN; } - save_flags(flags); - cli(); + wv_splhi(lp, &flags); if (wv_hw_reset(dev) != -1) { netif_start_queue(dev); @@ -3879,7 +3885,7 @@ static int wavelan_open(device * dev) #endif return -EAGAIN; } - restore_flags(flags); + wv_splx(lp, &flags); MOD_INC_USE_COUNT; @@ -3896,8 +3902,6 @@ static int wavelan_open(device * dev) */ static int wavelan_close(device * dev) { - net_local *lp = (net_local *) dev->priv; - #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, (unsigned int) dev); @@ -3905,10 +3909,6 @@ static int wavelan_close(device * dev) netif_stop_queue(dev); - /* If watchdog was activated, kill it! */ - if (lp->watchdog.prev != (timer_list *) NULL) - del_timer(&lp->watchdog); - /* * Flush the Tx and disable Rx. */ @@ -4001,11 +4001,13 @@ static int __init wavelan_config(device * dev) lp->hacr = HACR_DEFAULT; - lp->watchdog.function = wavelan_watchdog; - lp->watchdog.data = (unsigned long) dev; + /* Multicast stuff */ lp->promiscuous = 0; lp->mc_count = 0; + /* Init spinlock */ + spin_lock_init(&lp->lock); + /* * Fill in the fields of the device structure * with generic Ethernet values. @@ -4017,6 +4019,8 @@ static int __init wavelan_config(device * dev) dev->hard_start_xmit = wavelan_packet_xmit; dev->get_stats = wavelan_get_stats; dev->set_multicast_list = &wavelan_set_multicast_list; + dev->tx_timeout = &wavelan_watchdog; + dev->watchdog_timeo = WATCHDOG_JIFFIES; #ifdef SET_MAC_ADDRESS dev->set_mac_address = &wavelan_set_mac_address; #endif /* SET_MAC_ADDRESS */ diff --git a/drivers/net/wavelan.p.h b/drivers/net/wavelan.p.h index e4b722cf1..3e20776fb 100644 --- a/drivers/net/wavelan.p.h +++ b/drivers/net/wavelan.p.h @@ -34,6 +34,25 @@ * I try to maintain a web page with the Wireless LAN Howto at : * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html * + * SMP + * --- + * We now *should* be SMP compliant. + * I don't have a SMP box to verify that (my Pentium 90 is not), so + * someone has to certify that from me. + * Anyway, I spent enough time chasing interrupt re-entrancy during + * errors or reconfigure, and I designed the locked/unlocked sections + * of the driver with great care, and with the recent addition of + * the spinlock (thanks to the new API), we should be quite close to + * the truth. + * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast), + * but better safe than sorry (especially at 2 Mb/s ;-). + * + * I have also looked into disabling only our interrupt on the card + * (via HACR) instead of all interrupts in the processor (via cli), + * so that other driver are not impacted, and it look like it's + * possible, but it's very tricky to do right (full of races). As + * the gain would be mostly for SMP systems, it can wait... + * * Debugging and options * --------------------- * You will find below a set of '#define" allowing a very fine control @@ -171,7 +190,7 @@ * * Thanks go also to: * James Ashton <jaa101@syseng.anu.edu.au>, - * Alan Cox <iialan@iiit.swan.ac.uk>, + * Alan Cox <alan@redhat.com>, * Allan Creighton <allanc@cs.usyd.edu.au>, * Matthew Geier <matthew@cs.usyd.edu.au>, * Remo di Giovanni <remo@cs.usyd.edu.au>, @@ -188,8 +207,9 @@ * * Additional Credits: * - * My development has been done under Linux 2.0.x (Debian 1.1) with - * an HP Vectra XP/60. + * My development has been done initially under Debian 1.1 (Linux 2.0.x) + * and now under Debian 2.2, initially with an HP Vectra XP/60, and now + * an HP Vectra XP/90. * */ @@ -305,6 +325,21 @@ * - Fix check for root permission (break instead of exit) * - New nwid & encoding setting (Wireless Extension 9) * + * Changes made for release in 2.3.49 : + * ---------------------------------- + * - Indentation reformating (Alan) + * - Update to new network API (softnet - 2.3.43) : + * o replace dev->tbusy (Alan) + * o replace dev->tstart (Alan) + * o remove dev->interrupt (Alan) + * o add SMP locking via spinlock in splxx (me) + * o add spinlock in interrupt handler (me) + * o use kernel watchdog instead of ours (me) + * o increase watchdog timeout (kernel is more sensitive) (me) + * o verify that all the changes make sense and work (me) + * - Fixup a potential gotcha when reconfiguring and thighten a bit + * the interactions with Tx queue. + * * Wishes & dreams: * ---------------- * - roaming (see Pcmcia driver) @@ -395,11 +430,11 @@ /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan.c : v21 (wireless extensions) 16/10/99\n"; +static const char *version = "wavelan.c : v22 (wireless extensions) 21/02/00\n"; #endif /* Watchdog temporisation */ -#define WATCHDOG_JIFFIES (256*HZ/100) +#define WATCHDOG_JIFFIES (512*HZ/100) /* Macro to get the number of elements in an array */ #define NELS(a) (sizeof(a) / sizeof(a[0])) @@ -441,12 +476,12 @@ struct net_local { net_local * next; /* linked list of the devices */ device * dev; /* reverse link */ + spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ en_stats stats; /* Ethernet interface statistics */ int nresets; /* number of hardware resets */ u_char reconfig_82586; /* We need to reconfigure the controller. */ u_char promiscuous; /* promiscuous mode */ int mc_count; /* number of multicast addresses */ - timer_list watchdog; /* to avoid blocking state */ u_short hacr; /* current host interface state */ int tx_n_in_use; @@ -475,10 +510,12 @@ struct net_local /**************************** PROTOTYPES ****************************/ /* ----------------------- MISC. SUBROUTINES ------------------------ */ -static inline unsigned long /* flags */ - wv_splhi(void); /* Disable interrupts */ static inline void - wv_splx(unsigned long); /* Enable interrupts: flags */ + wv_splhi(net_local *, /* Disable interrupts, lock driver */ + unsigned long *); /* flags */ +static inline void + wv_splx(net_local *, /* Enable interrupts, unlock driver */ + unsigned long *); /* flags */ static u_char wv_irq_to_psa(int); static int @@ -580,7 +617,7 @@ static inline void int), wv_receive(device *); /* Read all packets waiting. */ /* --------------------- PACKET TRANSMISSION --------------------- */ -static inline void +static inline int wv_packet_write(device *, /* Write a packet to the Tx buffer. */ void *, short); @@ -607,7 +644,7 @@ static void void *, struct pt_regs *); static void - wavelan_watchdog(u_long); /* transmission watchdog */ + wavelan_watchdog(device *); /* transmission watchdog */ /* ------------------- CONFIGURATION CALLBACKS ------------------- */ static int wavelan_open(device *), /* Open the device. */ diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c index 830d9d400..c4003dd27 100644 --- a/drivers/parport/daisy.c +++ b/drivers/parport/daisy.c @@ -1,7 +1,7 @@ /* * IEEE 1284.3 Parallel port daisy chain and multiplexor code * - * Copyright (C) 1999 Tim Waugh <tim@cyberelk.demon.co.uk> + * Copyright (C) 1999, 2000 Tim Waugh <tim@cyberelk.demon.co.uk> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -12,6 +12,7 @@ * 31-01-1999: Make port-cloning transparent. * 13-02-1999: Move DeviceID technique from parport_probe. * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too. + * 22-02-2000: Count devices that are actually detected. * */ @@ -80,9 +81,11 @@ static struct parport *clone_parport (struct parport *real, int muxport) return extra; } -/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. */ +/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. + * Return value is number of devices actually detected. */ int parport_daisy_init (struct parport *port) { + int detected = 0; char *deviceid; static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" }; int num_ports; @@ -128,7 +131,7 @@ int parport_daisy_init (struct parport *port) select_port (port); parport_daisy_deselect_all (port); - assign_addrs (port); + detected += assign_addrs (port); /* Count the potential legacy device at the end. */ add_dev (numdevs++, port, -1); @@ -136,25 +139,31 @@ int parport_daisy_init (struct parport *port) /* Find out the legacy device's IEEE 1284 device ID. */ deviceid = kmalloc (1000, GFP_KERNEL); if (deviceid) { - parport_device_id (numdevs - 1, deviceid, 1000); + if (parport_device_id (numdevs - 1, deviceid, 1000) > 2) + detected++; + kfree (deviceid); } - return 0; + return detected; } /* Forget about devices on a physical port. */ void parport_daisy_fini (struct parport *port) { struct daisydev *dev, *prev = topology; - while (prev && prev->port == port) - prev = topology = topology->next; + while (prev && prev->port == port) { + topology = topology->next; + kfree (prev); + prev = topology; + } while (prev) { dev = prev->next; if (dev && dev->port == port) prev->next = dev->next; + kfree (dev); prev = prev->next; } @@ -162,7 +171,8 @@ void parport_daisy_fini (struct parport *port) someone enumerate through all IEEE1284.3 devices in the topology?. */ if (!topology) numdevs = 0; - return; } + return; +} /* Find a device by canonical device number. */ struct pardevice *parport_open (int devnum, const char *name, @@ -371,7 +381,7 @@ static int assign_addrs (struct parport *port) | PARPORT_STATUS_ERROR)) { DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n", port->name, s); - return -ENXIO; + return 0; } parport_write_data (port, 0x87); udelay (2); @@ -382,7 +392,7 @@ static int assign_addrs (struct parport *port) if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) { DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n", port->name, s); - return -ENXIO; + return 0; } parport_write_data (port, 0x78); udelay (2); @@ -421,7 +431,7 @@ static int assign_addrs (struct parport *port) parport_device_id (thisdev, deviceid, 1000); kfree (deviceid); - return 0; + return numdevs - thisdev; } /* Find a device with a particular manufacturer and model string, diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index beb0a68b7..cf0e092bf 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -681,6 +681,7 @@ size_t parport_pc_compat_write_block_pio (struct parport *port, /* Set up parallel port FIFO mode.*/ parport_pc_data_forward (port); /* Must be in PS2 mode */ + parport_pc_frob_control (port, PARPORT_CONTROL_STROBE, 0); change_mode (port, ECR_PPF); /* Parallel port FIFO */ port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; @@ -747,6 +748,10 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port, /* Set up ECP parallel port mode.*/ parport_pc_data_forward (port); /* Must be in PS2 mode */ + parport_pc_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD, + 0); change_mode (port, ECR_ECP); /* ECP FIFO */ port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; @@ -850,6 +855,10 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port, /* Set up ECP parallel port mode.*/ parport_pc_data_reverse (port); /* Must be in PS2 mode */ + parport_pc_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD, + 0); change_mode (port, ECR_ECP); /* ECP FIFO */ port->ieee1284.phase = IEEE1284_PH_REV_DATA; @@ -989,7 +998,7 @@ struct parport_operations parport_pc_ops = /* * Checks for port existence, all ports support SPP MODE */ -static int __maybe_init parport_SPP_supported(struct parport *pb) +static int __devinit parport_SPP_supported(struct parport *pb) { unsigned char r, w; @@ -1066,7 +1075,7 @@ static int __maybe_init parport_SPP_supported(struct parport *pb) * two bits of ECR aren't writable, so we check by writing ECR and * reading it back to see if it's what we expect. */ -static int __maybe_init parport_ECR_present(struct parport *pb) +static int __devinit parport_ECR_present(struct parport *pb) { struct parport_pc_private *priv = pb->private_data; unsigned char r = 0xc; @@ -1118,7 +1127,7 @@ static int __maybe_init parport_ECR_present(struct parport *pb) * be misdetected here is rather academic. */ -static int __maybe_init parport_PS2_supported(struct parport *pb) +static int __devinit parport_PS2_supported(struct parport *pb) { int ok = 0; @@ -1146,7 +1155,7 @@ static int __maybe_init parport_PS2_supported(struct parport *pb) return ok; } -static int __maybe_init parport_ECP_supported(struct parport *pb) +static int __devinit parport_ECP_supported(struct parport *pb) { int i; int config; @@ -1257,7 +1266,7 @@ static int __maybe_init parport_ECP_supported(struct parport *pb) return 1; } -static int __maybe_init parport_ECPPS2_supported(struct parport *pb) +static int __devinit parport_ECPPS2_supported(struct parport *pb) { const struct parport_pc_private *priv = pb->private_data; int result; @@ -1277,7 +1286,7 @@ static int __maybe_init parport_ECPPS2_supported(struct parport *pb) /* EPP mode detection */ -static int __maybe_init parport_EPP_supported(struct parport *pb) +static int __devinit parport_EPP_supported(struct parport *pb) { const struct parport_pc_private *priv = pb->private_data; @@ -1320,7 +1329,7 @@ static int __maybe_init parport_EPP_supported(struct parport *pb) return 1; } -static int __maybe_init parport_ECPEPP_supported(struct parport *pb) +static int __devinit parport_ECPEPP_supported(struct parport *pb) { struct parport_pc_private *priv = pb->private_data; int result; @@ -1351,18 +1360,18 @@ static int __maybe_init parport_ECPEPP_supported(struct parport *pb) #else /* No IEEE 1284 support */ /* Don't bother probing for modes we know we won't use. */ -static int __maybe_init parport_PS2_supported(struct parport *pb) { return 0; } -static int __maybe_init parport_ECP_supported(struct parport *pb) { return 0; } -static int __maybe_init parport_EPP_supported(struct parport *pb) { return 0; } -static int __maybe_init parport_ECPEPP_supported(struct parport *pb){return 0;} -static int __maybe_init parport_ECPPS2_supported(struct parport *pb){return 0;} +static int __devinit parport_PS2_supported(struct parport *pb) { return 0; } +static int __devinit parport_ECP_supported(struct parport *pb) { return 0; } +static int __devinit parport_EPP_supported(struct parport *pb) { return 0; } +static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;} +static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;} #endif /* No IEEE 1284 support */ /* --- IRQ detection -------------------------------------- */ /* Only if supports ECP mode */ -static int __maybe_init programmable_irq_support(struct parport *pb) +static int __devinit programmable_irq_support(struct parport *pb) { int irq, intrLine; unsigned char oecr = inb (ECONTROL (pb)); @@ -1379,7 +1388,7 @@ static int __maybe_init programmable_irq_support(struct parport *pb) return irq; } -static int __maybe_init irq_probe_ECP(struct parport *pb) +static int __devinit irq_probe_ECP(struct parport *pb) { int i; unsigned long irqs; @@ -1408,7 +1417,7 @@ static int __maybe_init irq_probe_ECP(struct parport *pb) * This detection seems that only works in National Semiconductors * This doesn't work in SMC, LGS, and Winbond */ -static int __maybe_init irq_probe_EPP(struct parport *pb) +static int __devinit irq_probe_EPP(struct parport *pb) { #ifndef ADVANCED_DETECT return PARPORT_IRQ_NONE; @@ -1448,7 +1457,7 @@ static int __maybe_init irq_probe_EPP(struct parport *pb) #endif /* Advanced detection */ } -static int __maybe_init irq_probe_SPP(struct parport *pb) +static int __devinit irq_probe_SPP(struct parport *pb) { /* Don't even try to do this. */ return PARPORT_IRQ_NONE; @@ -1461,7 +1470,7 @@ static int __maybe_init irq_probe_SPP(struct parport *pb) * When ECP is available we can autoprobe for IRQs. * NOTE: If we can autoprobe it, we can register the IRQ. */ -static int __maybe_init parport_irq_probe(struct parport *pb) +static int __devinit parport_irq_probe(struct parport *pb) { const struct parport_pc_private *priv = pb->private_data; @@ -1495,7 +1504,7 @@ out: /* --- DMA detection -------------------------------------- */ /* Only if supports ECP mode */ -static int __maybe_init programmable_dma_support (struct parport *p) +static int __devinit programmable_dma_support (struct parport *p) { unsigned char oecr = inb (ECONTROL (p)); int dma; @@ -1510,7 +1519,7 @@ static int __maybe_init programmable_dma_support (struct parport *p) return dma; } -static int __maybe_init parport_dma_probe (struct parport *p) +static int __devinit parport_dma_probe (struct parport *p) { const struct parport_pc_private *priv = p->private_data; if (priv->ecr) @@ -1521,7 +1530,7 @@ static int __maybe_init parport_dma_probe (struct parport *p) /* --- Initialisation code -------------------------------- */ -struct parport *__maybe_init parport_pc_probe_port (unsigned long int base, +struct parport *__devinit parport_pc_probe_port (unsigned long int base, unsigned long int base_hi, int irq, int dma, struct pci_dev *dev) @@ -1693,9 +1702,7 @@ struct parport *__maybe_init parport_pc_probe_port (unsigned long int base, #endif /* CONFIG_PARPORT_PC_FIFO */ } - /* Done probing. Now put the port into a sensible start-up state. - * SELECT | INIT also puts IEEE1284-compliant devices into - * compatibility mode. */ + /* Done probing. Now put the port into a sensible start-up state. */ if (priv->ecr) /* * Put the ECP detected port in PS2 mode. @@ -1714,9 +1721,143 @@ struct parport *__maybe_init parport_pc_probe_port (unsigned long int base, return p; } + +static int __devinit sio_via_686a_probe (struct pci_dev *pdev) +{ + u8 dma, irq, tmp; + unsigned port1, port2, have_eppecp; + + /* + * unlock super i/o configuration, set 0x85_1 + */ + pci_read_config_byte (pdev, 0x85, &tmp); + tmp |= (1 << 1); + pci_write_config_byte (pdev, 0x85, tmp); + + /* + * Super I/O configuration, index port == 3f0h, data port == 3f1h + */ + + /* 0xE2_1-0: Parallel Port Mode / Enable */ + outb (0xE2, 0x3F0); + tmp = inb (0x3F1); + + if ((tmp & 0x03) == 0x03) { + printk (KERN_INFO "parport_pc: Via 686A parallel port disabled in BIOS\n"); + return 0; + } + + /* 0xE6: Parallel Port I/O Base Address, bits 9-2 */ + outb (0xE6, 0x3F0); + port1 = inb (0x3F1) << 2; + + switch (port1) { + case 0x3bc: port2 = 0x7bc; break; + case 0x378: port2 = 0x778; break; + case 0x278: port2 = 0x678; break; + default: + printk (KERN_INFO "parport_pc: Via 686A weird parport base 0x%X, ignoring\n", + port1); + return 0; + } + + /* 0xF0_5: EPP+ECP enable */ + outb (0xF0, 0x3F0); + have_eppecp = (inb (0x3F1) & (1 << 5)); + + /* + * lock super i/o configuration, clear 0x85_1 + */ + pci_read_config_byte (pdev, 0x85, &tmp); + tmp &= ~(1 << 1); + pci_write_config_byte (pdev, 0x85, tmp); + + /* + * Get DMA and IRQ from PCI->ISA bridge PCI config registers + */ + + /* 0x50_3-2: PnP Routing for Parallel Port DRQ */ + pci_read_config_byte (pdev, 0x50, &dma); + dma = ((dma >> 2) & 0x03); + + /* 0x51_7-4: PnP Routing for Parallel Port IRQ */ + pci_read_config_byte (pdev, 0x51, &irq); + irq = ((irq >> 4) & 0x0F); + + /* filter bogus IRQs */ + switch (irq) { + case 0: + case 2: + case 8: + case 13: + irq = PARPORT_IRQ_NONE; + break; + + default: /* do nothing */ + break; + } + + /* if ECP not enabled, DMA is not enabled, assumed bogus 'dma' value */ + if (!have_eppecp) + dma = PARPORT_DMA_NONE; + + /* finally, do the probe with values obtained */ + if (parport_pc_probe_port (port1, port2, irq, dma, NULL)) { + printk (KERN_INFO "parport_pc: Via 686A parallel port: io=0x%X, irq=%d, dma=%d\n", + port1, irq, dma); + return 1; + } + + printk (KERN_WARNING "parport_pc: Strange, can't probe Via 686A parallel port: io=0x%X, irq=%d, dma=%d\n", + port1, irq, dma); + return 0; +} + + +enum parport_pc_sio_types { + sio_via_686a = 0, /* Via VT82C686A motherboard Super I/O */ +}; + + +/* each element directly indexed from enum list, above */ +static struct parport_pc_superio { + int (*probe) (struct pci_dev *pdev); +} parport_pc_superio_info[] __devinitdata = { + { sio_via_686a_probe, }, +}; + + +static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = { + { 0x1106, 0x0686, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_via_686a }, + { 0, }, /* terminate list */ +}; + + +static int __devinit parport_pc_init_superio(void) +{ + const struct pci_device_id *id; + struct pci_dev *pdev; + + pci_for_each_dev(pdev) { + id = pci_match_device (parport_pc_pci_tbl, pdev); + if (id == NULL) + continue; + + return parport_pc_superio_info[id->driver_data].probe (pdev); + } + + return 0; /* zero devices found */ +} + + /* Look for PCI parallel port cards. */ static int __init parport_pc_init_pci (int irq, int dma) { +#ifndef PCI_VENDOR_ID_AFAVLAB +#define PCI_VENDOR_ID_AFAVLAB 0x14db +#define PCI_DEVICE_ID_AFAVLAB_TK9902 0x2120 +#endif + struct { unsigned int vendor; unsigned int device; @@ -1800,6 +1941,9 @@ static int __init parport_pc_init_pci (int irq, int dma) { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014, 2, { { 4, -1 }, { 5, -1 }, } }, + { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_TK9902, + PCI_ANY_ID, PCI_ANY_ID, + 1, { { 0, 1 }, } }, { 0, } }; diff --git a/drivers/parport/probe.c b/drivers/parport/probe.c index 6772ea6d8..9ab6d97e2 100644 --- a/drivers/parport/probe.c +++ b/drivers/parport/probe.c @@ -150,13 +150,11 @@ ssize_t parport_device_id (int devnum, char *buffer, size_t len) if (!retval) { int idlen; unsigned char length[2]; - mm_segment_t oldfs = get_fs (); - set_fs (get_ds ()); /* First two bytes are MSB,LSB of inclusive length. */ retval = parport_read (dev->port, length, 2); - if (retval != 2) goto restore_fs; + if (retval != 2) goto end_id; idlen = (length[0] << 8) + length[1] - 2; if (idlen < len) @@ -169,8 +167,8 @@ ssize_t parport_device_id (int devnum, char *buffer, size_t len) len); /* Some printer manufacturers mistakenly believe that - the length field is supposed to be _exclusive_. */ - /* In addition, there are broken devices out there + the length field is supposed to be _exclusive_. + In addition, there are broken devices out there that don't even finish off with a semi-colon. */ if (buffer[len - 1] != ';') { ssize_t diff; @@ -196,9 +194,8 @@ ssize_t parport_device_id (int devnum, char *buffer, size_t len) } } - restore_fs: + end_id: buffer[len] = '\0'; - set_fs (oldfs); parport_negotiate (dev->port, IEEE1284_MODE_COMPAT); } parport_release (dev); diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 8059dfa22..fe5ea143b 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -247,7 +247,19 @@ void parport_announce_port (struct parport *port) { #ifdef CONFIG_PARPORT_1284 /* Analyse the IEEE1284.3 topology of the port. */ - parport_daisy_init (port); + if (parport_daisy_init (port) == 0) { + /* No devices were detected. Perhaps they are in some + funny state; let's try to reset them and see if + they wake up. */ + parport_daisy_fini (port); + parport_write_control (port, PARPORT_CONTROL_SELECT); + udelay (50); + parport_write_control (port, + PARPORT_CONTROL_SELECT | + PARPORT_CONTROL_INIT); + udelay (50); + parport_daisy_init (port); + } #endif /* Let drivers know that a new port has arrived. */ diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids index 9556874c1..1dfedc0dd 100644 --- a/drivers/pci/pci.ids +++ b/drivers/pci/pci.ids @@ -2682,6 +2682,7 @@ 13c0 Microgate Corporation 0010 SyncLink WAN Adapter 13c1 3ware Inc + 1000 3ware ATA-RAID 13c2 Technotrend Systemtechnik GmbH 13c3 Janz Computer AG 13c4 Phase Metrics @@ -3424,6 +3425,7 @@ 71a0 440GX - 82443GX Host bridge 71a1 440GX - 82443GX AGP bridge 71a2 440GX - 82443GX Host bridge (AGP disabled) + 7601 82372FB PIIX4 IDE 7602 82372FB [PCI-to-USB UHCI] 7800 i740 1092 0100 Stealth II G460 diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 36c3be081..067e25647 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -197,10 +197,6 @@ static struct file_operations proc_bus_pci_operations = { write: proc_bus_pci_write, }; -static struct inode_operations proc_bus_pci_inode_operations = { - &proc_bus_pci_operations, /* default base directory file-ops */ -}; - #if BITS_PER_LONG == 32 #define LONG_FORMAT "\t%08lx" #else @@ -265,7 +261,7 @@ int pci_proc_attach_device(struct pci_dev *dev) e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, de); if (!e) return -ENOMEM; - e->ops = &proc_bus_pci_inode_operations; + e->proc_fops = &proc_bus_pci_operations; e->data = dev; e->size = PCI_CFG_SPACE_SIZE; return 0; diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 18d47d9a8..6ea612b84 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -165,25 +165,6 @@ typedef struct vg46x_state_t { u_char ctl, ema; } vg46x_state_t; -typedef struct ti113x_state_t { - u_int sysctl; - u_char cardctl, devctl, diag; -} ti113x_state_t; - -typedef struct rl5c4xx_state_t { - u_short misc, ctl, io, mem; -} rl5c4xx_state_t; - -typedef struct o2micro_state_t { - u_char mode_a, mode_b, mode_c, mode_d; - u_char mhpg, fifo, mode_e; -} o2micro_state_t; - -typedef struct topic_state_t { - u_char slot, ccr, cdr; - u_int rcr; -} topic_state_t; - typedef struct socket_info_t { u_short type, flags; socket_cap_t cap; @@ -276,22 +257,6 @@ static pcic_t pcic[] = { /*====================================================================*/ -/* Some PCI shortcuts */ - -#define config_readb(sock, r, v) pci_read_config_byte((sock)->pdev, r, v) -#define config_readw(sock, r, v) pci_read_config_word((sock)->pdev, r, v) -#define config_readl(sock, r, v) pci_read_config_dword((sock)->pdev, r, v) -#define config_writeb(sock, r, v) pci_write_config_byte((sock)->pdev, r, v) -#define config_writew(sock, r, v) pci_write_config_word((sock)->pdev, r, v) -#define config_writel(sock, r, v) pci_write_config_dword((sock)->pdev, r, v) - -#define cb_readb(s, r) readb(socket[s].cb_virt + (r)) -#define cb_readl(s, r) readl(socket[s].cb_virt + (r)) -#define cb_writeb(s, r, v) writeb(v, socket[s].cb_virt + (r)) -#define cb_writel(s, r, v) writel(v, socket[s].cb_virt + (r)) - -/*====================================================================*/ - static u_char i365_get(u_short sock, u_short reg) { { diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c index 28821cbcf..3531348bb 100644 --- a/drivers/pcmcia/yenta.c +++ b/drivers/pcmcia/yenta.c @@ -17,6 +17,12 @@ #include "yenta.h" #include "i82365.h" +#if 0 +#define DEBUG(x,args...) printk(__FUNCTION__ ": " x,##args) +#else +#define DEBUG(x,args...) +#endif + /* Don't ask.. */ #define to_cycles(ns) ((ns)/120) #define to_ns(cycles) ((cycles)*120) @@ -26,13 +32,24 @@ * regular memory space ("cb_xxx"), configuration space * ("config_xxx") and compatibility space ("exca_xxxx") */ -#define cb_readl(sock,reg) readl((sock)->base + (reg)) -#define cb_writel(sock,reg,val) writel(val,(sock)->base + (reg)) +static inline u32 cb_readl(pci_socket_t *socket, unsigned reg) +{ + u32 val = readl(socket->base + reg); + DEBUG("%p %04x %08x\n", socket, reg, val); + return val; +} + +static inline void cb_writel(pci_socket_t *socket, unsigned reg, u32 val) +{ + DEBUG("%p %04x %08x\n", socket, reg, val); + writel(val, socket->base + reg); +} static inline u8 config_readb(pci_socket_t *socket, unsigned offset) { u8 val; pci_read_config_byte(socket->dev, offset, &val); + DEBUG("%p %04x %02x\n", socket, offset, val); return val; } @@ -40,6 +57,7 @@ static inline u16 config_readw(pci_socket_t *socket, unsigned offset) { u16 val; pci_read_config_word(socket->dev, offset, &val); + DEBUG("%p %04x %04x\n", socket, offset, val); return val; } @@ -47,25 +65,55 @@ static inline u32 config_readl(pci_socket_t *socket, unsigned offset) { u32 val; pci_read_config_dword(socket->dev, offset, &val); + DEBUG("%p %04x %08x\n", socket, offset, val); return val; } -#define config_writeb(s,off,val) pci_write_config_byte((s)->dev, (off), (val)) -#define config_writew(s,off,val) pci_write_config_word((s)->dev, (off), (val)) -#define config_writel(s,off,val) pci_write_config_dword((s)->dev, (off), (val)) +static inline void config_writeb(pci_socket_t *socket, unsigned offset, u8 val) +{ + DEBUG("%p %04x %02x\n", socket, offset, val); + pci_write_config_byte(socket->dev, offset, val); +} + +static inline void config_writew(pci_socket_t *socket, unsigned offset, u16 val) +{ + DEBUG("%p %04x %04x\n", socket, offset, val); + pci_write_config_word(socket->dev, offset, val); +} -#define exca_readb(sock,reg) readb((sock)->base + 0x800 + (reg)) -#define exca_writeb(sock,reg,v) writeb((v), (sock)->base + 0x800 + (reg)) +static inline void config_writel(pci_socket_t *socket, unsigned offset, u32 val) +{ + DEBUG("%p %04x %08x\n", socket, offset, val); + pci_write_config_dword(socket->dev, offset, val); +} + +static inline u8 exca_readb(pci_socket_t *socket, unsigned reg) +{ + u8 val = readb(socket->base + 0x800 + reg); + DEBUG("%p %04x %02x\n", socket, reg, val); + return val; +} + +static inline u8 exca_readw(pci_socket_t *socket, unsigned reg) +{ + u16 val; + val = readb(socket->base + 0x800 + reg); + val |= readb(socket->base + 0x800 + reg + 1) << 8; + DEBUG("%p %04x %04x\n", socket, reg, val); + return val; +} -static u16 exca_readw(pci_socket_t *socket, unsigned reg) +static inline void exca_writeb(pci_socket_t *socket, unsigned reg, u8 val) { - return exca_readb(socket, reg) | (exca_readb(socket, reg+1) << 8); + DEBUG("%p %04x %02x\n", socket, reg, val); + writeb(val, socket->base + 0x800 + reg); } static void exca_writew(pci_socket_t *socket, unsigned reg, u16 val) { - exca_writeb(socket, reg, val); - exca_writeb(socket, reg+1, val >> 8); + DEBUG("%p %04x %04x\n", socket, reg, val); + writeb(val, socket->base + 0x800 + reg); + writeb(val >> 8, socket->base + 0x800 + reg + 1); } /* diff --git a/drivers/pnp/isapnp_proc.c b/drivers/pnp/isapnp_proc.c index d9f73819f..658fa2ede 100644 --- a/drivers/pnp/isapnp_proc.c +++ b/drivers/pnp/isapnp_proc.c @@ -210,11 +210,6 @@ static struct file_operations isapnp_info_entry_operations = release: isapnp_info_entry_release, }; -static struct inode_operations isapnp_info_entry_inode_operations = -{ - &isapnp_info_entry_operations, /* default sound info directory file-ops */ -}; - static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence) { loff_t new; @@ -274,11 +269,6 @@ static struct file_operations isapnp_proc_bus_file_operations = read: isapnp_proc_bus_read, }; -static struct inode_operations isapnp_proc_bus_inode_operations = -{ - &isapnp_proc_bus_file_operations, -}; - static int isapnp_proc_attach_device(struct pci_dev *dev) { struct pci_bus *bus = dev->bus; @@ -295,7 +285,7 @@ static int isapnp_proc_attach_device(struct pci_dev *dev) e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de); if (!e) return -ENOMEM; - e->ops = &isapnp_proc_bus_inode_operations; + e->proc_fops = &isapnp_proc_bus_file_operations; e->data = dev; e->size = 256; return 0; @@ -378,7 +368,7 @@ int __init isapnp_proc_init(void) isapnp_proc_entry = NULL; p = create_proc_entry("isapnp", S_IFREG | S_IRUGO | S_IWUSR, &proc_root); if (p) - p->ops = &isapnp_info_entry_inode_operations; + p->proc_fops = &isapnp_info_entry_operations; isapnp_proc_entry = p; isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus); isapnp_proc_devices_entry = create_proc_info_entry("devices", 0, diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 5477bb1ac..42b86930d 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -85,7 +85,7 @@ static void tw_copy_mem_info(TW_Info *info, char *data, int len); static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs); /* Globals */ -char *tw_driver_version="0.4.001"; +char *tw_driver_version="1.0.000"; TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; int tw_device_extension_count = 0; @@ -2051,12 +2051,16 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) command_packet->status = 0; command_packet->flags = 0; + if ((srb->cmnd[0] == WRITE_6) || (srb->cmnd[0] == WRITE_10)) { + if ((srb->cmnd[1] & 0x8) || (srb->cmnd[1] & 0x10)) + command_packet->flags = 1; + } + if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6) { lba = ((u32)srb->cmnd[1] << 16) | ((u32)srb->cmnd[2] << 8) | (u32)srb->cmnd[3]; num_sectors = (u32)srb->cmnd[4]; } else { - lba = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) | - ((u32)srb->cmnd[4] << 8) | (u32)srb->cmnd[5]; + lba = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) | ((u32)srb->cmnd[4] << 8) | (u32)srb->cmnd[5]; num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8); } diff --git a/drivers/scsi/ChangeLog.sym53c8xx b/drivers/scsi/ChangeLog.sym53c8xx index ed169320a..4abf98759 100644 --- a/drivers/scsi/ChangeLog.sym53c8xx +++ b/drivers/scsi/ChangeLog.sym53c8xx @@ -1,3 +1,17 @@ +Sun Feb 20 11:00 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5j + - Add support for the new dynamic dma mapping kernel interface. + Requires Linux-2.3.47 (tested with pre-2.3.47-6). + Many thanks to David S. Miller for his preliminary changes + that have been useful guidelines, for having reviewed the + code and having tested this driver version on Ultra-Sparc. + - 2 tiny bugs fixed in the PCI wrapper that provides support + for early kernels without pci device structure. + - Get data transfer direction from the scsi command structure + (Scsi_Cmnd) with kernels that provide this information. + - Fix an old bug that only affected 896 rev. 1 when driver + profile support option was set in kernel configuration. + Sat Jan 8 22:00 2000 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.5h - Add year 2000 copyright. diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in index 9faa91e1b..4395cd682 100644 --- a/drivers/scsi/Config.in +++ b/drivers/scsi/Config.in @@ -44,6 +44,19 @@ if [ "$CONFIG_DECSTATION" = "y" ]; then dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI fi +if [ "$CONFIG_SGI_IP22" = "y" ]; then + dep_tristate 'SGI WD93C93 SCSI Driver' CONFIG_SCSI_SGIWD93 $CONFIG_SCSI +fi +if [ "$CONFIG_DECSTATION" = "y" ]; then + if [ "$CONFIG_TC" = "y" ]; then + dep_tristate 'DEC NCR53C94 Scsi Driver' CONFIG_SCSI_DECNCR $CONFIG_SCSI + fi + dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI +fi + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate '3ware Hardware ATA-RAID support (EXPERIMENTAL)' CONFIG_BLK_DEV_3W_XXXX_RAID $CONFIG_SCSI +fi dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI dep_tristate 'ACARD SCSI support' CONFIG_SCSI_ACARD $CONFIG_SCSI dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI @@ -188,9 +201,6 @@ fi if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then bool 'MIPS JAZZ FAS216 SCSI support' CONFIG_JAZZ_ESP fi -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate '3Ware Hardware ATA-RAID support (EXPERIMENTAL)' CONFIG_BLK_DEV_3W_XXXX_RAID $CONFIG_SCSI -fi endmenu diff --git a/drivers/scsi/eata_dma_proc.c b/drivers/scsi/eata_dma_proc.c index 725a70a4a..8768db48c 100644 --- a/drivers/scsi/eata_dma_proc.c +++ b/drivers/scsi/eata_dma_proc.c @@ -167,7 +167,7 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length, cmnd[9] = 0; scmd->cmd_len = 10; - scmd->sc_data_direction = DATA_READ; + scmd->sc_data_direction = SCSI_DATA_READ; /* * Do the command and wait for it to finish. diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c index e07417b7e..6aef8ae63 100644 --- a/drivers/scsi/pci2000.c +++ b/drivers/scsi/pci2000.c @@ -60,9 +60,6 @@ #include <linux/bios32.h> #endif -struct proc_dir_entry Proc_Scsi_Pci2000 = - { PROC_SCSI_PCI2000, 7, "pci2000", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; - //#define DEBUG 1 #ifdef DEBUG diff --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h index a3daa5f76..15652ca9f 100644 --- a/drivers/scsi/pci2000.h +++ b/drivers/scsi/pci2000.h @@ -200,59 +200,25 @@ int Pci2000_BiosParam (Disk *disk, kdev_t dev, int geom[]); #define NULL 0 #endif -extern struct proc_dir_entry Proc_Scsi_Pci2000; - -#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75) -#define PCI2000 { \ - next: NULL, \ - module: NULL, \ - proc_dir: &Proc_Scsi_Pci2000, \ - proc_info: NULL, /* let's not bloat the kernel */ \ - name: "PCI-2000 SCSI Intelligent Disk Controller",\ - detect: Pci2000_Detect, \ - release: Pci2000_Release, \ - info: NULL, /* let's not bloat the kernel */ \ - command: Pci2000_Command, \ - queuecommand: Pci2000_QueueCommand, \ - eh_strategy_handler: NULL, \ - eh_abort_handler: NULL, \ - eh_device_reset_handler: NULL, \ - eh_bus_reset_handler: NULL, \ - eh_host_reset_handler: NULL, \ - abort: Pci2000_Abort, \ - reset: Pci2000_Reset, \ - slave_attach: NULL, \ - bios_param: Pci2000_BiosParam, \ - can_queue: 16, \ - this_id: -1, \ - sg_tablesize: 16, \ - cmd_per_lun: 1, \ - present: 0, \ - unchecked_isa_dma: 0, \ - use_clustering: DISABLE_CLUSTERING, \ - use_new_eh_code: 0 \ - } -#else -#define PCI2000 { NULL, NULL, \ - &Proc_Scsi_Pci2000,/* proc_dir_entry */ \ - NULL, \ - "PCI-2000 SCSI Intelligent Disk Controller",\ - Pci2000_Detect, \ - Pci2000_Release, \ - NULL, \ - Pci2000_Command, \ - Pci2000_QueueCommand, \ - Pci2000_Abort, \ - Pci2000_Reset, \ - NULL, \ - Pci2000_BiosParam, \ - 16, \ - -1, \ - 16, \ - 1, \ - 0, \ - 0, \ - DISABLE_CLUSTERING } -#endif +/* screen is 80 columns wide, damnit! */ +#define PCI2000 { \ + proc_name: "pci2000", \ + name: "PCI-2000 SCSI Intelligent Disk Controller", \ + detect: Pci2000_Detect, \ + release: Pci2000_Release, \ + command: Pci2000_Command, \ + queuecommand: Pci2000_QueueCommand, \ + abort: Pci2000_Abort, \ + reset: Pci2000_Reset, \ + bios_param: Pci2000_BiosParam, \ + can_queue: 16, \ + this_id: -1, \ + sg_tablesize: 16, \ + cmd_per_lun: 1, \ + present: 0, \ + unchecked_isa_dma:0, \ + use_clustering: DISABLE_CLUSTERING, \ + use_new_eh_code:0 \ +} #endif diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c index 80f58cb8e..fabb61c0c 100644 --- a/drivers/scsi/pci2220i.c +++ b/drivers/scsi/pci2220i.c @@ -67,9 +67,6 @@ #define WRITE_CMD IDE_CMD_WRITE_MULTIPLE #define MAX_BUS_MASTER_BLOCKS SECTORSXFER // This is the maximum we can bus master -struct proc_dir_entry Proc_Scsi_Pci2220i = - { PROC_SCSI_PCI2220I, 8, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; - #ifdef DEBUG #define DEB(x) x #define STOP_HERE() {int st;for(st=0;st<100;st++){st=1;}} diff --git a/drivers/scsi/pci2220i.h b/drivers/scsi/pci2220i.h index aaa8457fc..689e62573 100644 --- a/drivers/scsi/pci2220i.h +++ b/drivers/scsi/pci2220i.h @@ -39,59 +39,23 @@ int Pci2220i_BiosParam (Disk *disk, kdev_t dev, int geom[]); #define NULL 0 #endif -extern struct proc_dir_entry Proc_Scsi_Pci2220i; - -#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75) -#define PCI2220I { \ - next: NULL, \ - module: NULL, \ - proc_dir: &Proc_Scsi_Pci2220i, \ - proc_info: NULL, /* let's not bloat the kernel */\ - name: "PCI-2220I/PCI-2240I", \ - detect: Pci2220i_Detect, \ - release: Pci2220i_Release, \ - info: NULL, /* let's not bloat the kernel */\ - command: Pci2220i_Command, \ - queuecommand: Pci2220i_QueueCommand, \ - eh_strategy_handler: NULL, \ - eh_abort_handler: NULL, \ - eh_device_reset_handler: NULL, \ - eh_bus_reset_handler: NULL, \ - eh_host_reset_handler: NULL, \ - abort: Pci2220i_Abort, \ - reset: Pci2220i_Reset, \ - slave_attach: NULL, \ - bios_param: Pci2220i_BiosParam, \ - can_queue: 1, \ - this_id: -1, \ - sg_tablesize: SG_ALL, \ - cmd_per_lun: 1, \ - present: 0, \ - unchecked_isa_dma: 0, \ - use_clustering: DISABLE_CLUSTERING, \ - use_new_eh_code: 0 \ - } -#else -#define PCI2220I { NULL, NULL, \ - &Proc_Scsi_Pci2220i,/* proc_dir_entry */\ - NULL, \ - "PCI-2220I/PCI-2240I", \ - Pci2220i_Detect, \ - Pci2220i_Release, \ - NULL, \ - Pci2220i_Command, \ - Pci2220i_QueueCommand, \ - Pci2220i_Abort, \ - Pci2220i_Reset, \ - NULL, \ - Pci2220i_BiosParam, \ - 1, \ - -1, \ - SG_ALL, \ - 1, \ - 0, \ - 0, \ - DISABLE_CLUSTERING } -#endif - +#define PCI2220I { \ + proc_name: "pci2220i", \ + name: "PCI-2220I/PCI-2240I", \ + detect: Pci2220i_Detect, \ + release: Pci2220i_Release, \ + command: Pci2220i_Command, \ + queuecommand: Pci2220i_QueueCommand, \ + abort: Pci2220i_Abort, \ + reset: Pci2220i_Reset, \ + bios_param: Pci2220i_BiosParam, \ + can_queue: 1, \ + this_id: -1, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 1, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: DISABLE_CLUSTERING, \ + use_new_eh_code: 0 \ +} #endif diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index e216ef03a..42f208062 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -426,25 +426,6 @@ static char dummy_buffer[60] = "Please don't add commas in your insmod command!! #endif - -/* - * Our directory Entry in /proc/scsi for the user to - * access the driver. - */ - -#if 0 - -/* Need to add in proc_fs.h PROC_SCSI_QL1280 */ -#define PROC_SCSI_QL1280 PROC_SCSI_QLOGICISP - -struct proc_dir_entry proc_scsi_qla1280 = { - PROC_SCSI_QL1280, 7, "qla1280", - S_IFDIR | S_IRUGO | S_IXUGO, 2, - 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; - -#endif - /* We use the Scsi_Pointer structure that's included with each command * SCSI_Cmnd as a scratchpad for our SRB. * @@ -2749,13 +2730,13 @@ qla1280_setup_chip(scsi_qla_host_t *ha) long risc_code_size; uint16_t mb[MAILBOX_REGISTER_COUNT]; #ifdef QLA1280_UNUSED + uint8_t *sp; int i; #endif uint16_t cnt; int num; - uint8_t *tbuf, *sp; + uint8_t *tbuf; u_long p_tbuf; - int i; #ifdef QL_DEBUG_LEVEL_3 ENTER("qla1280_setup_chip"); diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c index 283fe9c3d..df9ba38d4 100644 --- a/drivers/scsi/qlogicfc.c +++ b/drivers/scsi/qlogicfc.c @@ -18,6 +18,9 @@ /* This is a version of the isp1020 driver which was modified by * Chris Loveland <cwl@iol.unh.edu> to support the isp2100 and isp2200 + * + * Big endian support and dynamic DMA mapping added + * by Jakub Jelinek <jakub@redhat.com>. */ /* @@ -59,6 +62,24 @@ #include "sd.h" #include "hosts.h" + +#if 1 +/* Once pci64_ DMA mapping interface is in, kill this. */ +typedef dma_addr_t dma64_addr_t; +#define pci64_alloc_consistent(d,s,p) pci_alloc_consistent((d),(s),(p)) +#define pci64_free_consistent(d,s,c,a) pci_free_consistent((d),(s),(c),(a)) +#define pci64_map_single(d,c,s,dir) pci_map_single((d),(c),(s),(dir)) +#define pci64_map_sg(d,s,n,dir) pci_map_sg((d),(s),(n),(dir)) +#define pci64_unmap_single(d,a,s,dir) pci_unmap_single((d),(a),(s),(dir)) +#define pci64_unmap_sg(d,s,n,dir) pci_unmap_sg((d),(s),(n),(dir)) +#define pci64_dma_hi32(a) 0 +#define pci64_dma_lo32(a) (a) +#define pci64_dma_build(hi,lo) (lo) +#define sg_dma64_address(s) sg_dma_address(s) +#define sg_dma64_len(s) sg_dma_len(s) +#define PCI64_DMA_BITS 32 +#endif + #include "qlogicfc.h" /* Configuration section **************************************************** */ @@ -157,18 +178,6 @@ struct { #endif /* DEBUG ISP2x00_INTR */ -#if BITS_PER_LONG > 32 -#define virt_to_bus_low32(x) ((u32) (0xffffffff & virt_to_bus(x))) -#define virt_to_bus_high32(x) ((u32) (0xffffffff & (virt_to_bus(x)>>32))) -#define bus_to_virt_low32(x) ((u32) (0xffffffff & bus_to_virt(x))) -#define bus_to_virt_high32(x) ((u32) (0xffffffff & (bus_to_virt(x)>>32))) -#else -#define virt_to_bus_low32(x) virt_to_bus(x) -#define virt_to_bus_high32(x) 0x0 -#define bus_to_virt_low32(x) bus_to_virt(x) -#define bus_to_virt_high32(x) 0x0 -#endif - #define ISP2100_REV_ID1 1 #define ISP2100_REV_ID3 3 #define ISP2200_REV_ID5 5 @@ -230,7 +239,7 @@ struct Entry_header { }; /* entry header type commands */ -#if BITS_PER_LONG > 32 +#if PCI64_DMA_BITS > 32 #define ENTRY_COMMAND 0x19 #define ENTRY_CONTINUATION 0x0a #else @@ -247,34 +256,23 @@ struct Entry_header { #define EFLAG_BAD_HEADER 4 #define EFLAG_BAD_PAYLOAD 8 -#if BITS_PER_LONG > 32 +#if PCI64_DMA_BITS > 32 + struct dataseg { u_int d_base; u_int d_base_hi; u_int d_count; }; -struct Command_Entry { - struct Entry_header hdr; - u_int handle; - u_char target_lun; - u_char target_id; - u_short expanded_lun; - u_short control_flags; - u_short rsvd2; - u_short time_out; - u_short segment_cnt; - u_char cdb[16]; - u_int total_byte_cnt; - struct dataseg dataseg[DATASEGS_PER_COMMAND]; -}; - #else + struct dataseg { u_int d_base; u_int d_count; }; +#endif + struct Command_Entry { struct Entry_header hdr; u_int handle; @@ -290,9 +288,6 @@ struct Command_Entry { struct dataseg dataseg[DATASEGS_PER_COMMAND]; }; -#endif - - /* command entry control flag definitions */ #define CFLAG_NODISC 0x01 #define CFLAG_HEAD_TAG 0x02 @@ -302,7 +297,7 @@ struct Command_Entry { #define CFLAG_READ 0x20 #define CFLAG_WRITE 0x40 -#if BITS_PER_LONG > 32 +#if PCI64_DMA_BITS > 32 struct Continuation_Entry { struct Entry_header hdr; struct dataseg dataseg[DATASEGS_PER_CONT]; @@ -650,6 +645,9 @@ struct init_cb { #define AS_REDO_FABRIC_PORTDB 2 #define AS_REDO_LOOP_PORTDB 4 +#define RES_SIZE ((RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN) +#define REQ_SIZE ((QLOGICFC_REQ_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN) + struct isp2x00_hostdata { u_char revision; struct pci_dev *pci_dev; @@ -730,6 +728,7 @@ int isp2x00_detect(Scsi_Host_Template * tmpt) struct isp2x00_hostdata *hostdata; struct pci_dev *pdev = NULL; unsigned short device_ids[2]; + dma64_addr_t busaddr; int i; @@ -756,50 +755,43 @@ int isp2x00_detect(Scsi_Host_Template * tmpt) memset(hostdata, 0, sizeof(struct isp2x00_hostdata)); hostdata->pci_dev = pdev; - hostdata->res = (char *) kmalloc((RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN, GFP_KERNEL); + hostdata->res = pci64_alloc_consistent(pdev, RES_SIZE + REQ_SIZE, &busaddr); + if (!hostdata->res){ - printk("qlogicfc%d : could not allocate memory for response queue.\n", hostdata->host_id); - scsi_unregister(host); - continue; - } - hostdata->req = (char *) kmalloc((QLOGICFC_REQ_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN, GFP_KERNEL); - if (!hostdata->req){ - printk("qlogicfc%d : could not allocate memory for request queue.\n", hostdata->host_id); - kfree(hostdata->res); + printk("qlogicfc%d : could not allocate memory for request and response queue.\n", hostdata->host_id); scsi_unregister(host); continue; } - + hostdata->req = hostdata->res + (RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN; hostdata->queued = 0; /* set up the control block */ hostdata->control_block.version = 0x1; - hostdata->control_block.firm_opts = 0x800e; - hostdata->control_block.max_frame_len = 2048; - hostdata->control_block.max_iocb = QLOGICFC_REQ_QUEUE_LEN; - hostdata->control_block.exec_throttle = QLOGICFC_CMD_PER_LUN; + hostdata->control_block.firm_opts = cpu_to_le16(0x800e); + hostdata->control_block.max_frame_len = cpu_to_le16(2048); + hostdata->control_block.max_iocb = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN); + hostdata->control_block.exec_throttle = cpu_to_le16(QLOGICFC_CMD_PER_LUN); hostdata->control_block.retry_delay = 5; hostdata->control_block.retry_cnt = 1; - hostdata->control_block.node_name[0] = 0x0020; - hostdata->control_block.node_name[1] = 0xE000; - hostdata->control_block.node_name[2] = 0x008B; - hostdata->control_block.node_name[3] = 0x0000; - hostdata->control_block.hard_addr = 0x0003; - hostdata->control_block.req_queue_len = QLOGICFC_REQ_QUEUE_LEN + 1; - hostdata->control_block.res_queue_len = RES_QUEUE_LEN + 1; - hostdata->control_block.res_queue_addr_lo = virt_to_bus_low32(hostdata->res); - hostdata->control_block.res_queue_addr_high = virt_to_bus_high32(hostdata->res); - hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(hostdata->req); - hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(hostdata->req); - - - hostdata->control_block.add_firm_opts |= CONNECTION_PREFERENCE<<4; + hostdata->control_block.node_name[0] = cpu_to_le16(0x0020); + hostdata->control_block.node_name[1] = cpu_to_le16(0xE000); + hostdata->control_block.node_name[2] = cpu_to_le16(0x008B); + hostdata->control_block.node_name[3] = cpu_to_le16(0x0000); + hostdata->control_block.hard_addr = cpu_to_le16(0x0003); + hostdata->control_block.req_queue_len = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN + 1); + hostdata->control_block.res_queue_len = cpu_to_le16(RES_QUEUE_LEN + 1); + hostdata->control_block.res_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr)); + hostdata->control_block.res_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr)); + hostdata->control_block.req_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr + RES_SIZE)); + hostdata->control_block.req_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr + RES_SIZE)); + + + hostdata->control_block.add_firm_opts |= cpu_to_le16(CONNECTION_PREFERENCE<<4); hostdata->adapter_state = AS_LOOP_DOWN; hostdata->explore_timer.data = 1; hostdata->host_id = hosts; if (isp2x00_init(host) || isp2x00_reset_hardware(host)) { - kfree(hostdata->res); - kfree(hostdata->req); + pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } @@ -808,8 +800,7 @@ int isp2x00_detect(Scsi_Host_Template * tmpt) if (request_irq(host->irq, do_isp2x00_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) { printk("qlogicfc%d : interrupt %d already in use\n", hostdata->host_id, host->irq); - kfree(hostdata->res); - kfree(hostdata->req); + pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } @@ -818,8 +809,7 @@ int isp2x00_detect(Scsi_Host_Template * tmpt) "in use\n", hostdata->host_id, host->io_port, host->io_port + 0xff); free_irq(host->irq, host); - kfree(hostdata->res); - kfree(hostdata->req); + pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } @@ -977,12 +967,13 @@ int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int u_short loop_id = 0x81; u_short scsi_id = cur_scsi_id; u_int port_id; - struct sns_cb req; - u_char sns_response[608]; + struct sns_cb *req; + u_char *sns_response; + dma64_addr_t busaddr; struct isp2x00_hostdata *hostdata; hostdata = (struct isp2x00_hostdata *) host->hostdata; - + DEBUG_FABRIC(printk("qlogicfc%d : Checking for a fabric.\n", hostdata->host_id)); param[0] = MBOX_GET_PORT_NAME; param[1] = (u16)FABRIC_PORT << 8; @@ -995,52 +986,60 @@ int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int } printk("qlogicfc%d : Fabric found.\n", hostdata->host_id); + req = (struct sns_cb *)pci64_alloc_consistent(hostdata->pci_dev, sizeof(*req) + 608, &busaddr); + + if (!req){ + printk("qlogicfc%d : Could not allocate DMA resources for fabric initialization\n", hostdata->host_id); + return 0; + } + sns_response = (u_char *)(req + 1); + if (hostdata->adapter_state & AS_REDO_LOOP_PORTDB){ - memset(&req, 0, sizeof(req)); + memset(req, 0, sizeof(*req)); - req.len = 8; - req.response_low = virt_to_bus_low32(sns_response); - req.response_high = virt_to_bus_high32(sns_response); - req.sub_len = 22; - req.data[0] = 0x17; - req.data[1] = 0x02; - req.data[8] = (u_char) (hostdata->port_id & 0xff); - req.data[9] = (u_char) (hostdata->port_id >> 8 & 0xff); - req.data[10] = (u_char) (hostdata->port_id >> 16 & 0xff); - req.data[13] = 0x01; + req->len = cpu_to_le16(8); + req->response_low = cpu_to_le32(pci64_dma_lo32(busaddr + sizeof(*req))); + req->response_high = cpu_to_le32(pci64_dma_hi32(busaddr + sizeof(*req))); + req->sub_len = cpu_to_le16(22); + req->data[0] = 0x17; + req->data[1] = 0x02; + req->data[8] = (u_char) (hostdata->port_id & 0xff); + req->data[9] = (u_char) (hostdata->port_id >> 8 & 0xff); + req->data[10] = (u_char) (hostdata->port_id >> 16 & 0xff); + req->data[13] = 0x01; param[0] = MBOX_SEND_SNS; param[1] = 30; - param[2] = virt_to_bus_low32(&req) >> 16; - param[3] = virt_to_bus_low32(&req); - param[6] = virt_to_bus_high32(&req) >> 16; - param[7] = virt_to_bus_high32(&req); - + param[2] = pci64_dma_lo32(busaddr) >> 16; + param[3] = pci64_dma_lo32(busaddr); + param[6] = pci64_dma_hi32(busaddr) >> 16; + param[7] = pci64_dma_hi32(busaddr); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) - printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id); + printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id); } port_id = hostdata->port_id; while (!done) { - memset(&req, 0, sizeof(req)); - - req.len = 304; - req.response_low = virt_to_bus_low32(sns_response); - req.response_high = virt_to_bus_high32(sns_response); - req.sub_len = 6; - req.data[0] = 0x00; - req.data[1] = 0x01; - req.data[8] = (u_char) (port_id & 0xff); - req.data[9] = (u_char) (port_id >> 8 & 0xff); - req.data[10] = (u_char) (port_id >> 16 & 0xff); + memset(req, 0, sizeof(*req)); + + req->len = cpu_to_le16(304); + req->response_low = cpu_to_le32(pci64_dma_lo32(busaddr + sizeof(*req))); + req->response_high = cpu_to_le32(pci64_dma_hi32(busaddr + sizeof(*req))); + req->sub_len = cpu_to_le16(6); + req->data[0] = 0x00; + req->data[1] = 0x01; + req->data[8] = (u_char) (port_id & 0xff); + req->data[9] = (u_char) (port_id >> 8 & 0xff); + req->data[10] = (u_char) (port_id >> 16 & 0xff); param[0] = MBOX_SEND_SNS; param[1] = 14; - param[2] = virt_to_bus_low32(&req) >> 16; - param[3] = virt_to_bus_low32(&req); - param[6] = virt_to_bus_high32(&req) >> 16; - param[7] = virt_to_bus_high32(&req); + param[2] = pci64_dma_lo32(busaddr) >> 16; + param[3] = pci64_dma_lo32(busaddr); + param[6] = pci64_dma_hi32(busaddr) >> 16; + param[7] = pci64_dma_hi32(busaddr); isp2x00_mbox_command(host, param); @@ -1089,10 +1088,12 @@ int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int done = 1; } else { printk("qlogicfc%d : Get All Next failed %x.\n", hostdata->host_id, param[0]); + pci64_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr); return 0; } } + pci64_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr); return 1; } @@ -1102,6 +1103,7 @@ int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int int isp2x00_release(struct Scsi_Host *host) { struct isp2x00_hostdata *hostdata; + dma64_addr_t busaddr; ENTER("isp2x00_release"); @@ -1112,8 +1114,9 @@ int isp2x00_release(struct Scsi_Host *host) release_region(host->io_port, 0xff); - kfree(hostdata->res); - kfree(hostdata->req); + busaddr = pci64_dma_build(le32_to_cpu(hostdata->control_block.res_queue_addr_high), + le32_to_cpu(hostdata->control_block.res_queue_addr_lo)); + pci64_free_consistent(hostdata->pci_dev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); LEAVE("isp2x00_release"); @@ -1245,19 +1248,20 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) cmd->hdr.entry_type = ENTRY_COMMAND; cmd->hdr.entry_cnt = 1; cmd->target_lun = Cmnd->lun; - cmd->expanded_lun = Cmnd->lun; + cmd->expanded_lun = cpu_to_le16(Cmnd->lun); #if ISP2x00_PORTDB cmd->target_id = hostdata->port_db[Cmnd->target].loop_id; #else cmd->target_id = Cmnd->target; #endif - cmd->total_byte_cnt = (u_int) Cmnd->request_bufflen; + cmd->total_byte_cnt = cpu_to_le32(Cmnd->request_bufflen); cmd->time_out = 0; memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); if (Cmnd->use_sg) { - cmd->segment_cnt = sg_count = Cmnd->use_sg; sg = (struct scatterlist *) Cmnd->request_buffer; + sg_count = pci64_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + cmd->segment_cnt = cpu_to_le16(sg_count); ds = cmd->dataseg; /* fill in first two sg entries: */ n = sg_count; @@ -1265,11 +1269,11 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) n = DATASEGS_PER_COMMAND; for (i = 0; i < n; i++) { - ds[i].d_base = virt_to_bus_low32(sg->address); -#if BITS_PER_LONG > 32 - ds[i].d_base_hi = virt_to_bus_high32(sg->address); + ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma64_address(sg))); +#if PCI64_DMA_BITS > 32 + ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma64_address(sg))); #endif - ds[i].d_count = sg->length; + ds[i].d_count = cpu_to_le32(sg_dma64_len(sg)); ++sg; } sg_count -= DATASEGS_PER_COMMAND; @@ -1291,22 +1295,32 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) if (n > DATASEGS_PER_CONT) n = DATASEGS_PER_CONT; for (i = 0; i < n; ++i) { - ds[i].d_base = virt_to_bus_low32(sg->address); -#if BITS_PER_LONG > 32 - ds[i].d_base_hi = virt_to_bus_high32(sg->address); + ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma64_address(sg))); +#if PCI64_DMA_BITS > 32 + ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma64_address(sg))); #endif - ds[i].d_count = sg->length; + ds[i].d_count = cpu_to_le32(sg_dma64_len(sg)); ++sg; } sg_count -= n; } + } else if (Cmnd->request_bufflen) { + dma64_addr_t busaddr = pci64_map_single(hostdata->pci_dev, Cmnd->request_buffer, Cmnd->request_bufflen, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + + *(dma64_addr_t *)&Cmnd->SCp = busaddr; + cmd->dataseg[0].d_base = cpu_to_le32(pci64_dma_lo32(busaddr)); +#if PCI64_DMA_BITS > 32 + cmd->dataseg[0].d_base_hi = cpu_to_le32(pci64_dma_hi32(busaddr)); +#endif + cmd->dataseg[0].d_count = cpu_to_le32(Cmnd->request_bufflen); + cmd->segment_cnt = cpu_to_le16(1); } else { - cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->request_buffer); -#if BITS_PER_LONG > 32 - cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->request_buffer); + cmd->dataseg[0].d_base = 0; +#if PCI64_DMA_BITS > 32 + cmd->dataseg[0].d_base_hi = 0; #endif - cmd->dataseg[0].d_count = (u_int) Cmnd->request_bufflen; - cmd->segment_cnt = 1; + cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */ } switch (Cmnd->cmnd[0]) { @@ -1317,38 +1331,28 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) case WRITE_6: case WRITE_BUFFER: case MODE_SELECT: - cmd->control_flags = CFLAG_WRITE; - break; - case REQUEST_SENSE: - /* scsi.c expects sense info in a different buffer */ - cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->sense_buffer); -#if BITS_PER_LONG > 32 - cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->sense_buffer); -#endif - cmd->dataseg[0].d_count = sizeof(Cmnd->sense_buffer); - cmd->segment_cnt = 1; - cmd->control_flags = CFLAG_READ; + cmd->control_flags = cpu_to_le16(CFLAG_WRITE); break; default: - cmd->control_flags = CFLAG_READ; + cmd->control_flags = cpu_to_le16(CFLAG_READ); break; } if (Cmnd->device->tagged_supported) { if ((jiffies - hostdata->tag_ages[Cmnd->target]) > (2 * SCSI_TIMEOUT)) { - cmd->control_flags |= CFLAG_ORDERED_TAG; + cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG); hostdata->tag_ages[Cmnd->target] = jiffies; } else switch (Cmnd->tag) { case HEAD_OF_QUEUE_TAG: - cmd->control_flags |= CFLAG_HEAD_TAG; + cmd->control_flags |= cpu_to_le16(CFLAG_HEAD_TAG); break; case ORDERED_QUEUE_TAG: - cmd->control_flags |= CFLAG_ORDERED_TAG; + cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG); break; default: - cmd->control_flags |= CFLAG_SIMPLE_TAG; + cmd->control_flags |= cpu_to_le16(CFLAG_SIMPLE_TAG); break; } } @@ -1543,6 +1547,16 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[sts->handle])) { Cmnd->result = isp2x00_return_status(Cmnd, sts); hostdata->queued--; + + if (Cmnd->use_sg) + pci64_unmap_sg(hostdata->pci_dev, + (struct scatterlist *)Cmnd->buffer, Cmnd->use_sg, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + else if (Cmnd->request_bufflen) + pci64_unmap_single(hostdata->pci_dev, *(dma64_addr_t *)&Cmnd->SCp, + Cmnd->request_bufflen, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + /* * if any of the following are true we do not * call scsi_done. if the status is CS_ABORTED @@ -1550,7 +1564,7 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) * level should already know its aborted. */ if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number - || sts->completion_status == CS_ABORTED){ + || le16_to_cpu(sts->completion_status) == CS_ABORTED){ hostdata->handle_serials[sts->handle] = 0; hostdata->handle_ptrs[sts->handle] = NULL; outw(out_ptr, host->io_port + MBOX5); @@ -1564,7 +1578,7 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) * the device may well be back in a couple of * seconds. */ - if ((hostdata->adapter_state == AS_LOOP_DOWN || sts->completion_status == CS_PORT_UNAVAILABLE || sts->completion_status == CS_PORT_LOGGED_OUT || sts->completion_status == CS_PORT_CONFIG_CHANGED) && hostdata->port_db[Cmnd->target].wwn){ + if ((hostdata->adapter_state == AS_LOOP_DOWN || sts->completion_status == cpu_to_le16(CS_PORT_UNAVAILABLE) || sts->completion_status == cpu_to_le16(CS_PORT_LOGGED_OUT) || sts->completion_status == cpu_to_le16(CS_PORT_CONFIG_CHANGED)) && hostdata->port_db[Cmnd->target].wwn){ outw(out_ptr, host->io_port + MBOX5); continue; } @@ -1575,12 +1589,11 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) hostdata->handle_ptrs[sts->handle] = NULL; - if (sts->completion_status == CS_RESET_OCCURRED - || (sts->status_flags & STF_BUS_RESET)) + if (sts->completion_status == cpu_to_le16(CS_RESET_OCCURRED) + || (sts->status_flags & cpu_to_le16(STF_BUS_RESET))) hostdata->send_marker = 1; - memset(Cmnd->sense_buffer, 0, sizeof(Cmnd->sense_buffer)); - if (sts->scsi_status & 0x0200) + if (le16_to_cpu(sts->scsi_status) & 0x0200) memcpy(Cmnd->sense_buffer, sts->req_sense_data, sizeof(Cmnd->sense_buffer)); @@ -1638,9 +1651,9 @@ static int isp2x00_return_status(Scsi_Cmnd *Cmnd, struct Status_Entry *sts) ENTER("isp2x00_return_status"); DEBUG(printk("qlogicfc : completion status = 0x%04x\n", - sts->completion_status)); + le16_to_cpu(sts->completion_status))); - switch (sts->completion_status) { + switch (le16_to_cpu(sts->completion_status)) { case CS_COMPLETE: host_status = DID_OK; break; @@ -1660,7 +1673,7 @@ static int isp2x00_return_status(Scsi_Cmnd *Cmnd, struct Status_Entry *sts) host_status = DID_ERROR; break; case CS_DATA_UNDERRUN: - if (Cmnd->underflow <= (Cmnd->request_bufflen - sts->residual)) + if (Cmnd->underflow <= (Cmnd->request_bufflen - le32_to_cpu(sts->residual))) host_status = DID_OK; else host_status = DID_ERROR; @@ -1675,17 +1688,17 @@ static int isp2x00_return_status(Scsi_Cmnd *Cmnd, struct Status_Entry *sts) break; default: printk("qlogicfc : unknown completion status 0x%04x\n", - sts->completion_status); + le16_to_cpu(sts->completion_status)); host_status = DID_ERROR; break; } DEBUG_INTR(printk("qlogicfc : host status (%s) scsi status %x\n", - reason[host_status], sts->scsi_status)); + reason[host_status], le16_to_cpu(sts->scsi_status))); LEAVE("isp2x00_return_status"); - return (sts->scsi_status & STATUS_MASK) | (host_status << 16); + return (le16_to_cpu(sts->scsi_status) & STATUS_MASK) | (host_status << 16); } @@ -1802,6 +1815,7 @@ static int isp2x00_reset_hardware(struct Scsi_Host *host) u_short param[8]; struct isp2x00_hostdata *hostdata; int loop_count; + dma64_addr_t busaddr; ENTER("isp2x00_reset_hardware"); @@ -1896,6 +1910,14 @@ static int isp2x00_reset_hardware(struct Scsi_Host *host) } #endif +#ifdef __BIG_ENDIAN + { + u64 val; + memcpy(&val, &hostdata->control_block.node_name, sizeof(u64)); + hostdata->wwn = ((val & 0xff00ff00ff00ff00ULL) >> 8) + | ((val & 0x00ff00ff00ff00ffULL) << 8); + } +#else hostdata->wwn = (u64) (hostdata->control_block.node_name[0]) << 56; hostdata->wwn |= (u64) (hostdata->control_block.node_name[0] & 0xff00) << 48; hostdata->wwn |= (u64) (hostdata->control_block.node_name[1] & 0xff00) << 24; @@ -1904,26 +1926,37 @@ static int isp2x00_reset_hardware(struct Scsi_Host *host) hostdata->wwn |= (u64) (hostdata->control_block.node_name[2] & 0xff00) << 8; hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0x00ff) << 8; hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0xff00) >> 8; +#endif + + /* FIXME: If the DMA transfer goes one way only, this should use PCI_DMA_TODEVICE and below as well. */ + busaddr = pci64_map_single(hostdata->pci_dev, &hostdata->control_block, sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); param[0] = MBOX_INIT_FIRMWARE; - param[2] = (u_short) (virt_to_bus_low32(&hostdata->control_block) >> 16); - param[3] = (u_short) (virt_to_bus_low32(&hostdata->control_block) & 0xffff); + param[2] = (u_short) (pci64_dma_lo32(busaddr) >> 16); + param[3] = (u_short) (pci64_dma_lo32(busaddr) & 0xffff); param[4] = 0; param[5] = 0; - param[6] = (u_short) (virt_to_bus_high32(&hostdata->control_block) >> 16); - param[7] = (u_short) (virt_to_bus_high32(&hostdata->control_block) & 0xffff); + param[6] = (u_short) (pci64_dma_hi32(busaddr) >> 16); + param[7] = (u_short) (pci64_dma_hi32(busaddr) & 0xffff); isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d.c: Ouch 0x%04x\n", hostdata->host_id, param[0]); + pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); return 1; } param[0] = MBOX_GET_FIRMWARE_STATE; isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d.c: 0x%04x\n", hostdata->host_id, param[0]); + pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); return 1; } + pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); LEAVE("isp2x00_reset_hardware"); return 0; @@ -1939,11 +1972,11 @@ static int isp2x00_get_nvram_defaults(struct Scsi_Host *host, struct init_cb *co return 1; value = isp2x00_read_nvram_word(host, 8); - control_block->node_name[0] = isp2x00_read_nvram_word(host, 9); - control_block->node_name[1] = isp2x00_read_nvram_word(host, 10); - control_block->node_name[2] = isp2x00_read_nvram_word(host, 11); - control_block->node_name[3] = isp2x00_read_nvram_word(host, 12); - control_block->hard_addr = isp2x00_read_nvram_word(host, 13); + control_block->node_name[0] = cpu_to_le16(isp2x00_read_nvram_word(host, 9)); + control_block->node_name[1] = cpu_to_le16(isp2x00_read_nvram_word(host, 10)); + control_block->node_name[2] = cpu_to_le16(isp2x00_read_nvram_word(host, 11)); + control_block->node_name[3] = cpu_to_le16(isp2x00_read_nvram_word(host, 12)); + control_block->hard_addr = cpu_to_le16(isp2x00_read_nvram_word(host, 13)); return 0; @@ -2156,12 +2189,12 @@ void isp2x00_print_status_entry(struct Status_Entry *status) printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags); printk("qlogicfc : scsi status = 0x%04x, completion status = 0x%04x\n", - status->scsi_status, status->completion_status); + le16_to_cpu(status->scsi_status), le16_to_cpu(status->completion_status)); printk("qlogicfc : state flags = 0x%04x, status flags = 0x%04x\n", - status->state_flags, status->status_flags); + le16_to_cpu(status->state_flags), le16_to_cpu(status->status_flags)); printk("qlogicfc : response info length = 0x%04x, request sense length = 0x%04x\n", - status->res_info_len, status->req_sense_len); - printk("qlogicfc : residual transfer length = 0x%08x, response = 0x%02x\n", status->residual, status->res_info[3]); + le16_to_cpu(status->res_info_len), le16_to_cpu(status->req_sense_len)); + printk("qlogicfc : residual transfer length = 0x%08x, response = 0x%02x\n", le32_to_cpu(status->residual), status->res_info[3]); } diff --git a/drivers/scsi/qlogicfc.h b/drivers/scsi/qlogicfc.h index 10539d3db..e00e8c645 100644 --- a/drivers/scsi/qlogicfc.h +++ b/drivers/scsi/qlogicfc.h @@ -62,7 +62,7 @@ * determined for each queue request anew. */ -#if BITS_PER_LONG > 32 +#if PCI64_DMA_BITS > 32 #define DATASEGS_PER_COMMAND 2 #define DATASEGS_PER_CONT 5 #else diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 32e71e06f..bbb24f4eb 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -149,7 +149,7 @@ static int test_unit_ready(int minor) sr_cmd[0] = GPCMD_TEST_UNIT_READY; sr_cmd[1] = ((scsi_CDs[minor].device->lun) << 5); sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; - return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1, SCSI_DATA_NONE); + return sr_do_ioctl(minor, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE); } int sr_tray_move(struct cdrom_device_info *cdi, int pos) @@ -161,7 +161,7 @@ int sr_tray_move(struct cdrom_device_info *cdi, int pos) sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ; - return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0, SCSI_DATA_NONE); + return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE); } int sr_lock_door(struct cdrom_device_info *cdi, int lock) diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index 45f504fa3..741c86d52 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -121,10 +121,6 @@ static Scsi_Cmnd *sun3_dma_setup_done = NULL; /* minimum number of bytes to to dma on */ #define SUN3_DMA_MINSIZE 128 -static struct proc_dir_entry proc_scsi_sun3_5380 = { - PROC_SCSI_MAC, 13, "Sun3 5380 SCSI", S_IFDIR | S_IRUGO, S_IXUGO, 2 -}; - static volatile unsigned char *sun3_scsi_regp; static volatile struct sun3_dma_regs *dregs; static unsigned char *dmabuf = NULL; /* dma memory buffer */ @@ -196,7 +192,7 @@ int sun3scsi_detect(Scsi_Host_Template * tpnt) if(called) return 0; - tpnt->proc_dir = &proc_scsi_sun3_5380; + tpnt->proc_name = "Sun3 5380 SCSI"; /* setup variables */ tpnt->can_queue = diff --git a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c index f56d66756..36eb7b0c1 100644 --- a/drivers/scsi/sym53c8xx.c +++ b/drivers/scsi/sym53c8xx.c @@ -55,7 +55,7 @@ */ /* -** January 9 2000, sym53c8xx 1.5h +** February 20 2000, sym53c8xx 1.5j ** ** Supported SCSI features: ** Synchronous data transfers @@ -84,7 +84,7 @@ /* ** Name and version of the driver */ -#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5h" +#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5j" /* #define DEBUG_896R1 */ #define SCSI_NCR_OPTIMIZE_896 @@ -174,6 +174,15 @@ typedef u64 u_int64; #include "sym53c8xx.h" +/* +** Hmmm... What complex some PCI-HOST bridges actually are, +** despite the fact that the PCI specifications are looking +** so smart and simple! ;-) +*/ +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,47) +#define SCSI_NCR_DYNAMIC_DMA_MAPPING +#endif + /*========================================================== ** ** A la VMS/CAM-3 queue management. @@ -501,7 +510,7 @@ pci_get_base_address(struct pci_dev *pdev, int index, u_long *base) typedef unsigned int pcidev_t; #define PCIDEV_NULL (~0u) #define PciBusNumber(d) ((d)>>8) -#define PciDeviceFn(n) ((d)&0xff) +#define PciDeviceFn(d) ((d)&0xff) #define __PciDev(busn, devfn) (((busn)<<8)+(devfn)) #define pci_present pcibios_present @@ -539,7 +548,7 @@ pci_find_device(unsigned int vendor, unsigned int device, pcidev_t prev) static u_short __init PciVendorId(pcidev_t dev) { u_short vendor_id; - pcibios_read_config_word(dev, PCI_VENDOR_ID, &vendor_id); + pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id); return vendor_id; } @@ -552,7 +561,7 @@ static u_short __init PciDeviceId(pcidev_t dev) static u_int __init PciIrqLine(pcidev_t dev) { - u_short irq; + u_char irq; pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); return irq; } @@ -652,17 +661,6 @@ spinlock_t sym53c8xx_lock = SPIN_LOCK_UNLOCKED; #endif /* -** Address translation -** -** The driver has to provide bus memory addresses to -** the script processor. Because some architectures use -** different physical addressing scheme from the PCI BUS, -** we use virt_to_bus() instead of virt_to_phys(). -*/ - -#define vtobus(p) virt_to_bus(p) - -/* ** Memory mapped IO ** ** Since linux-2.1, we must use ioremap() to map the io memory space. @@ -736,44 +734,76 @@ static void MDELAY(long ms) { while (ms--) UDELAY(1000); } ** this allocator allows simple and fast address calculations ** from the SCRIPTS code. In addition, cache line alignment ** is guaranteed for power of 2 cache line size. +** Enhanced in linux-2.3.44 to provide a memory pool per pcidev +** to support dynamic dma mapping. (I would have preferred a +** real bus astraction, btw). */ -#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */ -#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum (for now (ever?) */ -typedef unsigned long addr; /* Enough bits to bit-hack addresses */ - -#define MEMO_FREE_UNUSED /* Free unused pages immediately */ - -struct m_link { - struct m_link *next; /* Simple links are enough */ -}; - -#ifndef GFP_DMA_32BIT -#define GFP_DMA_32BIT 0 /* Will this flag ever exist */ -#endif - #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0) -#define GetPages(order) __get_free_pages(GFP_ATOMIC | GFP_DMA_32BIT, order) +#define __GetFreePages(flags, order) __get_free_pages(flags, order) #else -#define GetPages(order) __get_free_pages(GFP_ATOMIC | GFP_DMA_32BIT, order, 0) +#define __GetFreePages(flags, order) __get_free_pages(flags, order, 0) #endif -/* -** Lists of available memory chunks. -** Starts with 16 bytes chunks until 1 PAGE chunks. -*/ -static struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1]; +#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */ +#if PAGE_SIZE >= 8192 +#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum */ +#else +#define MEMO_PAGE_ORDER 1 /* 2 PAGES maximum */ +#endif +#define MEMO_FREE_UNUSED /* Free unused pages immediately */ +#define MEMO_WARN 1 +#define MEMO_GFP_FLAGS GFP_ATOMIC +#define MEMO_CLUSTER_SHIFT (PAGE_SHIFT+MEMO_PAGE_ORDER) +#define MEMO_CLUSTER_SIZE (1UL << MEMO_CLUSTER_SHIFT) +#define MEMO_CLUSTER_MASK (MEMO_CLUSTER_SIZE-1) + +typedef u_long m_addr_t; /* Enough bits to bit-hack addresses */ +typedef pcidev_t m_bush_t; /* Something that addresses DMAable */ + +typedef struct m_link { /* Link between free memory chunks */ + struct m_link *next; +} m_link_s; + +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING +typedef struct m_vtob { /* Virtual to Bus address translation */ + struct m_vtob *next; + m_addr_t vaddr; + m_addr_t baddr; +} m_vtob_s; +#define VTOB_HASH_SHIFT 5 +#define VTOB_HASH_SIZE (1UL << VTOB_HASH_SHIFT) +#define VTOB_HASH_MASK (VTOB_HASH_SIZE-1) +#define VTOB_HASH_CODE(m) \ + ((((m_addr_t) (m)) >> MEMO_CLUSTER_SHIFT) & VTOB_HASH_MASK) +#endif + +typedef struct m_pool { /* Memory pool of a given kind */ +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + m_bush_t bush; + m_addr_t (*getp)(struct m_pool *); + void (*freep)(struct m_pool *, m_addr_t); +#define M_GETP() mp->getp(mp) +#define M_FREEP(p) mp->freep(mp, p) +#define GetPages() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER) +#define FreePages(p) free_pages(p, MEMO_PAGE_ORDER) + int nump; + m_vtob_s *(vtob[VTOB_HASH_SIZE]); + struct m_pool *next; +#else +#define M_GETP() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER) +#define M_FREEP(p) free_pages(p, MEMO_PAGE_ORDER) +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1]; +} m_pool_s; -/* -** Allocate a memory area aligned on the lowest power of 2 -** greater than the requested size. -*/ -static void *__m_alloc(int size) +static void *___m_alloc(m_pool_s *mp, int size) { int i = 0; int s = (1 << MEMO_SHIFT); int j; - addr a ; + m_addr_t a; + m_link_s *h = mp->h; if (size > (PAGE_SIZE << MEMO_PAGE_ORDER)) return 0; @@ -786,7 +816,7 @@ static void *__m_alloc(int size) j = i; while (!h[j].next) { if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) { - h[j].next = (struct m_link *) GetPages(MEMO_PAGE_ORDER); + h[j].next = (m_link_s *) M_GETP(); if (h[j].next) h[j].next->next = 0; break; @@ -794,36 +824,32 @@ static void *__m_alloc(int size) ++j; s <<= 1; } - a = (addr) h[j].next; + a = (m_addr_t) h[j].next; if (a) { h[j].next = h[j].next->next; while (j > i) { j -= 1; s >>= 1; - h[j].next = (struct m_link *) (a+s); + h[j].next = (m_link_s *) (a+s); h[j].next->next = 0; } } #ifdef DEBUG - printk("m_alloc(%d) = %p\n", size, (void *) a); + printk("___m_alloc(%d) = %p\n", size, (void *) a); #endif return (void *) a; } -/* -** Free a memory area allocated using m_alloc(). -** Coalesce buddies. -** Free pages that become unused if MEMO_FREE_UNUSED is defined. -*/ -static void __m_free(void *ptr, int size) +static void ___m_free(m_pool_s *mp, void *ptr, int size) { int i = 0; int s = (1 << MEMO_SHIFT); - struct m_link *q; - addr a, b; + m_link_s *q; + m_addr_t a, b; + m_link_s *h = mp->h; #ifdef DEBUG - printk("m_free(%p, %d)\n", ptr, size); + printk("___m_free(%p, %d)\n", ptr, size); #endif if (size > (PAGE_SIZE << MEMO_PAGE_ORDER)) @@ -834,23 +860,23 @@ static void __m_free(void *ptr, int size) ++i; } - a = (addr) ptr; + a = (m_addr_t) ptr; while (1) { #ifdef MEMO_FREE_UNUSED if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) { - free_pages(a, MEMO_PAGE_ORDER); + M_FREEP(a); break; } #endif b = a ^ s; q = &h[i]; - while (q->next && q->next != (struct m_link *) b) { + while (q->next && q->next != (m_link_s *) b) { q = q->next; } if (!q->next) { - ((struct m_link *) a)->next = h[i].next; - h[i].next = (struct m_link *) a; + ((m_link_s *) a)->next = h[i].next; + h[i].next = (m_link_s *) a; break; } q->next = q->next->next; @@ -860,45 +886,338 @@ static void __m_free(void *ptr, int size) } } -#define MEMO_WARN 1 - -/* -** The memory pool is shared by all instances. -** We use a global SMP LOCK to be SMP safe. -*/ - -static void *m_calloc(int size, char *name, int uflags) +static void *__m_calloc2(m_pool_s *mp, int size, char *name, int uflags) { - u_long flags; void *p; - NCR_LOCK_DRIVER(flags); - p = __m_alloc(size); - NCR_UNLOCK_DRIVER(flags); + p = ___m_alloc(mp, size); if (DEBUG_FLAGS & DEBUG_ALLOC) printk ("new %-10s[%4d] @%p.\n", name, size, p); if (p) - memset(p, 0, size); + bzero(p, size); else if (uflags & MEMO_WARN) printk (NAME53C8XX ": failed to allocate %s[%d]\n", name, size); return p; } +#define __m_calloc(mp, s, n) __m_calloc2(mp, s, n, MEMO_WARN) + +static void __m_free(m_pool_s *mp, void *ptr, int size, char *name) +{ + if (DEBUG_FLAGS & DEBUG_ALLOC) + printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr); + + ___m_free(mp, ptr, size); + +} + +/* + * With pci bus iommu support, we use a default pool of unmapped memory + * for memory we donnot need to DMA from/to and one pool per pcidev for + * memory accessed by the PCI chip. `mp0' is the default not DMAable pool. + */ + +#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING + +static m_pool_s mp0; + +#else + +static m_addr_t ___mp0_getp(m_pool_s *mp) +{ + m_addr_t m = GetPages(); + if (m) + ++mp->nump; + return m; +} + +static void ___mp0_freep(m_pool_s *mp, m_addr_t m) +{ + FreePages(m); + --mp->nump; +} + +static m_pool_s mp0 = {0, ___mp0_getp, ___mp0_freep}; + +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + +static void *m_calloc(int size, char *name) +{ + u_long flags; + void *m; + NCR_LOCK_DRIVER(flags); + m = __m_calloc(&mp0, size, name); + NCR_UNLOCK_DRIVER(flags); + return m; +} + static void m_free(void *ptr, int size, char *name) { u_long flags; + NCR_LOCK_DRIVER(flags); + __m_free(&mp0, ptr, size, name); + NCR_UNLOCK_DRIVER(flags); +} - if (DEBUG_FLAGS & DEBUG_ALLOC) - printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr); +/* + * DMAable pools. + */ + +#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING + +/* Without pci bus iommu support, all the memory is assumed DMAable */ + +#define __m_calloc_dma(b, s, n) m_calloc(s, n) +#define __m_free_dma(b, p, s, n) m_free(p, s, n) +#define __vtobus(b, p) virt_to_bus(p) + +#else + +/* + * With pci bus iommu support, we maintain one pool per pcidev and a + * hashed reverse table for virtual to bus physical address translations. + */ +static m_addr_t ___dma_getp(m_pool_s *mp) +{ + m_addr_t vp; + m_vtob_s *vbp; + + vbp = __m_calloc(&mp0, sizeof(*vbp), "VTOB"); + if (vbp) { + dma_addr_t daddr; + vp = (m_addr_t) pci_alloc_consistent(mp->bush, + PAGE_SIZE<<MEMO_PAGE_ORDER, + &daddr); + if (vp) { + int hc = VTOB_HASH_CODE(vp); + vbp->vaddr = vp; + vbp->baddr = daddr; + vbp->next = mp->vtob[hc]; + mp->vtob[hc] = vbp; + ++mp->nump; + return vp; + } + } + __m_free(&mp0, vbp, sizeof(*vbp), "VTOB"); + return 0; +} + +static void ___dma_freep(m_pool_s *mp, m_addr_t m) +{ + m_vtob_s **vbpp, *vbp; + int hc = VTOB_HASH_CODE(m); + + vbpp = &mp->vtob[hc]; + while (*vbpp && (*vbpp)->vaddr != m) + vbpp = &(*vbpp)->next; + if (*vbpp) { + vbp = *vbpp; + *vbpp = (*vbpp)->next; + pci_free_consistent(mp->bush, PAGE_SIZE<<MEMO_PAGE_ORDER, + (void *)vbp->vaddr, (dma_addr_t)vbp->baddr); + __m_free(&mp0, vbp, sizeof(*vbp), "VTOB"); + --mp->nump; + } +} + +static inline m_pool_s *___get_dma_pool(m_bush_t bush) +{ + m_pool_s *mp; + for (mp = mp0.next; mp && mp->bush != bush; mp = mp->next); + return mp; +} + +static m_pool_s *___cre_dma_pool(m_bush_t bush) +{ + m_pool_s *mp; + mp = __m_calloc(&mp0, sizeof(*mp), "MPOOL"); + if (mp) { + bzero(mp, sizeof(*mp)); + mp->bush = bush; + mp->getp = ___dma_getp; + mp->freep = ___dma_freep; + mp->next = mp0.next; + mp0.next = mp; + } + return mp; +} + +static void ___del_dma_pool(m_pool_s *p) +{ + struct m_pool **pp = &mp0.next; + + while (*pp && *pp != p) + pp = &(*pp)->next; + if (*pp) { + *pp = (*pp)->next; + __m_free(&mp0, p, sizeof(*p), "MPOOL"); + } +} + +static void *__m_calloc_dma(m_bush_t bush, int size, char *name) +{ + u_long flags; + struct m_pool *mp; + void *m = 0; + + NCR_LOCK_DRIVER(flags); + mp = ___get_dma_pool(bush); + if (!mp) + mp = ___cre_dma_pool(bush); + if (mp) + m = __m_calloc(mp, size, name); + if (mp && !mp->nump) + ___del_dma_pool(mp); + NCR_UNLOCK_DRIVER(flags); + + return m; +} + +static void __m_free_dma(m_bush_t bush, void *m, int size, char *name) +{ + u_long flags; + struct m_pool *mp; NCR_LOCK_DRIVER(flags); - __m_free(ptr, size); + mp = ___get_dma_pool(bush); + if (mp) + __m_free(mp, m, size, name); + if (mp && !mp->nump) + ___del_dma_pool(mp); NCR_UNLOCK_DRIVER(flags); } +static m_addr_t __vtobus(m_bush_t bush, void *m) +{ + u_long flags; + m_pool_s *mp; + int hc = VTOB_HASH_CODE(m); + m_vtob_s *vp = 0; + m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK; + + NCR_LOCK_DRIVER(flags); + mp = ___get_dma_pool(bush); + if (mp) { + vp = mp->vtob[hc]; + while (vp && (m_addr_t) vp->vaddr != a) + vp = vp->next; + } + NCR_UNLOCK_DRIVER(flags); + return vp ? vp->baddr + (((m_addr_t) m) - a) : 0; +} + +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + +#define _m_calloc_dma(np, s, n) __m_calloc_dma(np->pdev, s, n) +#define _m_free_dma(np, p, s, n) __m_free_dma(np->pdev, p, s, n) +#define m_calloc_dma(s, n) _m_calloc_dma(np, s, n) +#define m_free_dma(p, s, n) _m_free_dma(np, p, s, n) +#define _vtobus(np, p) __vtobus(np->pdev, p) +#define vtobus(p) _vtobus(np, p) + +/* + * Deal with DMA mapping/unmapping. + */ + +#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING + +/* Linux versions prior to pci bus iommu kernel interface */ + +#define __unmap_scsi_data(pdev, cmd) do {; } while (0) +#define __map_scsi_single_data(pdev, cmd) (__vtobus(pdev,(cmd)->request_buffer)) +#define __map_scsi_sg_data(pdev, cmd) ((cmd)->use_sg) +#define __sync_scsi_data(pdev, cmd) do {; } while (0) + +#define scsi_sg_dma_address(sc) vtobus((sc)->address) +#define scsi_sg_dma_len(sc) ((sc)->length) + +#else + +/* Linux version with pci bus iommu kernel interface */ + +/* To keep track of the dma mapping (sg/single) that has been set */ +#define __data_mapped SCp.phase +#define __data_mapping SCp.have_data_in + +static void __unmap_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + switch(cmd->__data_mapped) { + case 2: + pci_unmap_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + break; + case 1: + pci_unmap_single(pdev, cmd->__data_mapping, + cmd->request_bufflen, dma_dir); + break; + } + cmd->__data_mapped = 0; +} + +static u_long __map_scsi_single_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + dma_addr_t mapping; + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + if (cmd->request_bufflen == 0) + return 0; + + mapping = pci_map_single(pdev, cmd->request_buffer, + cmd->request_bufflen, dma_dir); + cmd->__data_mapped = 1; + cmd->__data_mapping = mapping; + + return mapping; +} + +static int __map_scsi_sg_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + int use_sg; + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + if (cmd->use_sg == 0) + return 0; + + use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + cmd->__data_mapped = 2; + cmd->__data_mapping = use_sg; + + return use_sg; +} + +static void __sync_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + switch(cmd->__data_mapped) { + case 2: + pci_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + break; + case 1: + pci_dma_sync_single(pdev, cmd->__data_mapping, + cmd->request_bufflen, dma_dir); + break; + } +} + +#define scsi_sg_dma_address(sc) sg_dma_address(sc) +#define scsi_sg_dma_len(sc) sg_dma_len(sc) + +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + +#define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->pdev, cmd) +#define map_scsi_single_data(np, cmd) __map_scsi_single_data(np->pdev, cmd) +#define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->pdev, cmd) +#define sync_scsi_data(np, cmd) __sync_scsi_data(np->pdev, cmd) + + +/* + * Print out some buffer. + */ static void ncr_print_hex(u_char *p, int n) { while (n-- > 0) @@ -915,21 +1234,49 @@ static void ncr_printl_hex(char *label, u_char *p, int n) /* ** Transfer direction ** -** Low-level scsi drivers under Linux do not receive the expected -** data transfer direction from upper scsi drivers. -** The driver will only check actual data direction for common -** scsi opcodes. Other ones may cause problem, since they may -** depend on device type or be vendor specific. -** I would prefer to never trust the device for data direction, -** but that is not possible. -** -** The original driver requires the expected direction to be known. -** The Linux version of the driver has been enhanced in order to -** be able to transfer data in the direction choosen by the target. +** Until some linux kernel version near 2.3.40, low-level scsi +** drivers were not told about data transfer direction. +** We check the existence of this feature that has been expected +** for a _long_ time by all SCSI driver developers by just +** testing against the definition of SCSI_DATA_UNKNOWN. Indeed +** this is a hack, but testing against a kernel version would +** have been a shame. ;-) */ +#ifdef SCSI_DATA_UNKNOWN + +#define scsi_data_direction(cmd) (cmd->sc_data_direction) + +#else + +#define SCSI_DATA_UNKNOWN 0 +#define SCSI_DATA_WRITE 1 +#define SCSI_DATA_READ 2 +#define SCSI_DATA_NONE 3 -#define XFER_IN (1) -#define XFER_OUT (2) +static __inline__ scsi_data_direction(Scsi_Cmnd *cmd) +{ + int direction; + + switch((int) cmd->cmnd[0]) { + case 0x08: /* READ(6) 08 */ + case 0x28: /* READ(10) 28 */ + case 0xA8: /* READ(12) A8 */ + direction = SCSI_DATA_READ; + break; + case 0x0A: /* WRITE(6) 0A */ + case 0x2A: /* WRITE(10) 2A */ + case 0xAA: /* WRITE(12) AA */ + direction = SCSI_DATA_WRITE; + break; + default: + direction = SCSI_DATA_UNKNOWN; + break; + } + + return direction; +} + +#endif /* SCSI_DATA_UNKNOWN */ /* ** Head of list of NCR boards @@ -1039,6 +1386,7 @@ typedef struct { ** to save data on each detected board for ncr_attach(). */ typedef struct { + pcidev_t pdev; ncr_slot slot; ncr_chip chip; ncr_nvram *nvram; @@ -1796,6 +2144,8 @@ struct ccb { **---------------------------------------------------------------- */ Scsi_Cmnd *cmd; /* SCSI command */ + u_char cdb_buf[16]; /* Copy of CDB */ + u_char sense_buf[64]; int data_len; /* Total data length */ int segments; /* Number of SG segments */ @@ -1964,6 +2314,7 @@ struct ncb { ** General controller parameters and configuration. **---------------------------------------------------------------- */ + pcidev_t pdev; u_short device_id; /* PCI device id */ u_char revision_id; /* PCI device revision id */ u_char bus; /* PCI BUS number */ @@ -1995,7 +2346,8 @@ struct ncb { ** SCRIPTS processor in order to start SCSI commands. **---------------------------------------------------------------- */ - u_int32 *squeue; /* Start queue */ + u_long p_squeue; /* Start queue BUS address */ + u_int32 *squeue; /* Start queue virtual address */ u_short squeueput; /* Next free slot of the queue */ u_short actccbs; /* Number of allocated CCBs */ u_short queuedepth; /* Start queue depth */ @@ -2045,6 +2397,7 @@ struct ncb { u_char order; /* Tag order to use */ u_char verbose; /* Verbosity for this controller*/ u_int32 ncr_cache; /* Used for cache test at init. */ + u_long p_ncb; /* BUS address of this NCB */ /*---------------------------------------------------------------- ** CCB lists and queue. @@ -2085,7 +2438,7 @@ struct ncb { ** We use a different scatter function for 896 rev 1. **---------------------------------------------------------------- */ - int (*scatter) (ccb_p, Scsi_Cmnd *); + int (*scatter) (ncb_p, ccb_p, Scsi_Cmnd *); /*---------------------------------------------------------------- ** Command abort handling. @@ -2106,6 +2459,7 @@ struct ncb { u_char release_stage; /* Synchronisation stage on release */ }; +#define NCB_PHYS(np, lbl) (np->p_ncb + offsetof(struct ncb, lbl)) #define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl)) #define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth,lbl)) #define NCB_SCRIPTH0_PHYS(np,lbl) (np->p_scripth0+offsetof (struct scripth,lbl)) @@ -2336,8 +2690,8 @@ static void ncb_profile (ncb_p np, ccb_p cp); static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len); static void ncr_script_fill (struct script * scr, struct scripth * scripth); -static int ncr_scatter_896R1 (ccb_p cp, Scsi_Cmnd *cmd); -static int ncr_scatter (ccb_p cp, Scsi_Cmnd *cmd); +static int ncr_scatter_896R1 (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd); +static int ncr_scatter (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd); static void ncr_getsync (ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p); static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer); static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln); @@ -4529,7 +4883,7 @@ ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len) new = (old & ~RELOC_MASK) + np->p_scripth; break; case RELOC_SOFTC: - new = (old & ~RELOC_MASK) + vtobus(np); + new = (old & ~RELOC_MASK) + np->p_ncb; break; #ifdef RELOC_KVAR case RELOC_KVAR: @@ -5191,10 +5545,12 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) /* ** Allocate the host control block. */ - np = m_calloc(sizeof(struct ncb), "NCB", MEMO_WARN); + np = __m_calloc_dma(device->pdev, sizeof(struct ncb), "NCB"); if (!np) goto attach_error; NCR_INIT_LOCK_NCB(np); + np->pdev = device->pdev; + np->p_ncb = __vtobus(device->pdev, np); host_data->ncb = np; /* @@ -5218,22 +5574,23 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) ** Allocate the start queue. */ np->squeue = (ncrcmd *) - m_calloc(sizeof(ncrcmd)*(MAX_START*2), "SQUEUE", MEMO_WARN); + m_calloc_dma(sizeof(ncrcmd)*(MAX_START*2), "SQUEUE"); if (!np->squeue) goto attach_error; + np->p_squeue = vtobus(np->squeue); /* ** Allocate the done queue. */ np->dqueue = (ncrcmd *) - m_calloc(sizeof(ncrcmd)*(MAX_START*2), "DQUEUE", MEMO_WARN); + m_calloc_dma(sizeof(ncrcmd)*(MAX_START*2), "DQUEUE"); if (!np->dqueue) goto attach_error; /* ** Allocate the target bus address array. */ - np->targtbl = (u_int32 *) m_calloc(256, "TARGTBL", MEMO_WARN); + np->targtbl = (u_int32 *) m_calloc_dma(256, "TARGTBL"); if (!np->targtbl) goto attach_error; @@ -5241,11 +5598,11 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) ** Allocate SCRIPTS areas */ np->script0 = (struct script *) - m_calloc(sizeof(struct script), "SCRIPT", MEMO_WARN); + m_calloc_dma(sizeof(struct script), "SCRIPT"); if (!np->script0) goto attach_error; np->scripth0 = (struct scripth *) - m_calloc(sizeof(struct scripth), "SCRIPTH", MEMO_WARN); + m_calloc_dma(sizeof(struct scripth), "SCRIPTH"); if (!np->scripth0) goto attach_error; @@ -5457,24 +5814,24 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) */ np->idletask.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); np->idletask.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); - np->p_idletask = vtobus(&np->idletask); + np->p_idletask = NCB_PHYS(np, idletask); np->notask.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); np->notask.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); - np->p_notask = vtobus(&np->notask); + np->p_notask = NCB_PHYS(np, notask); np->bad_i_t_l.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); np->bad_i_t_l.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); - np->p_bad_i_t_l = vtobus(&np->bad_i_t_l); + np->p_bad_i_t_l = NCB_PHYS(np, bad_i_t_l); np->bad_i_t_l_q.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); np->bad_i_t_l_q.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np,bad_i_t_l_q)); - np->p_bad_i_t_l_q = vtobus(&np->bad_i_t_l_q); + np->p_bad_i_t_l_q = NCB_PHYS(np, bad_i_t_l_q); /* ** Allocate and prepare the bad lun table. */ - np->badluntbl = m_calloc(256, "BADLUNTBL", MEMO_WARN); + np->badluntbl = m_calloc_dma(256, "BADLUNTBL"); if (!np->badluntbl) goto attach_error; @@ -5482,16 +5839,16 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) np->resel_badlun = cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_identify)); for (i = 0 ; i < 64 ; i++) - np->badluntbl[i] = cpu_to_scr(vtobus(&np->resel_badlun)); + np->badluntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun)); /* ** Prepare the target bus address array. */ np->scripth0->targtbl[0] = cpu_to_scr(vtobus(np->targtbl)); for (i = 0 ; i < MAX_TARGET ; i++) { - np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i])); + np->targtbl[i] = cpu_to_scr(NCB_PHYS(np, target[i])); np->target[i].b_luntbl = cpu_to_scr(vtobus(np->badluntbl)); - np->target[i].b_lun0 = cpu_to_scr(vtobus(&np->resel_badlun)); + np->target[i].b_lun0 = cpu_to_scr(NCB_PHYS(np, resel_badlun)); } /* @@ -5533,7 +5890,7 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) #ifndef SCSI_NCR_PROFILE_SUPPORT #define XXX 0 #else -#define XXX 3 +#define XXX 2 #endif np->script0->dataphase[XXX] = cpu_to_scr(SCR_JUMP); np->script0->dataphase[XXX+1] = @@ -5699,21 +6056,21 @@ static void ncr_free_resources(ncb_p np) unmap_pci_mem(np->base2_va, np->base2_ws); #endif if (np->scripth0) - m_free(np->scripth0, sizeof(struct scripth), "SCRIPTH"); + m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH"); if (np->script0) - m_free(np->script0, sizeof(struct script), "SCRIPT"); + m_free_dma(np->script0, sizeof(struct script), "SCRIPT"); if (np->squeue) - m_free(np->squeue, sizeof(ncrcmd)*(MAX_START*2), "SQUEUE"); + m_free_dma(np->squeue, sizeof(ncrcmd)*(MAX_START*2), "SQUEUE"); if (np->dqueue) - m_free(np->dqueue, sizeof(ncrcmd)*(MAX_START*2),"DQUEUE"); + m_free_dma(np->dqueue, sizeof(ncrcmd)*(MAX_START*2),"DQUEUE"); while ((cp = np->ccbc) != NULL) { np->ccbc = cp->link_ccb; - m_free(cp, sizeof(*cp), "CCB"); + m_free_dma(cp, sizeof(*cp), "CCB"); } if (np->badluntbl) - m_free(np->badluntbl, 256,"BADLUNTBL"); + m_free_dma(np->badluntbl, 256,"BADLUNTBL"); for (target = 0; target < MAX_TARGET ; target++) { tp = &np->target[target]; @@ -5722,18 +6079,23 @@ static void ncr_free_resources(ncb_p np) if (!lp) continue; if (lp->tasktbl != &lp->tasktbl_0) - m_free(lp->tasktbl, MAX_TASKS*4, "TASKTBL"); + m_free_dma(lp->tasktbl, MAX_TASKS*4, "TASKTBL"); if (lp->cb_tags) m_free(lp->cb_tags, MAX_TAGS, "CB_TAGS"); - m_free(lp, sizeof(*lp), "LCB"); + m_free_dma(lp, sizeof(*lp), "LCB"); } #if MAX_LUN > 1 if (tp->lmp) m_free(tp->lmp, MAX_LUN * sizeof(lcb_p), "LMP"); + if (tp->luntbl) + m_free_dma(tp->luntbl, 256, "LUNTBL"); #endif } - m_free(np, sizeof(*np), "NCB"); + if (np->targtbl) + m_free_dma(np->targtbl, 256, "TARGTBL"); + + m_free_dma(np, sizeof(*np), "NCB"); } @@ -5761,13 +6123,14 @@ static inline void ncr_queue_done_cmd(ncb_p np, Scsi_Cmnd *cmd) np->done_list = cmd; } -static inline void ncr_flush_done_cmds(Scsi_Cmnd *lcmd) +static inline void ncr_flush_done_cmds(pcidev_t pdev, Scsi_Cmnd *lcmd) { Scsi_Cmnd *cmd; while (lcmd) { cmd = lcmd; lcmd = (Scsi_Cmnd *) cmd->host_scribble; + __unmap_scsi_data(pdev, cmd); cmd->scsi_done(cmd); } } @@ -6013,7 +6376,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd) **---------------------------------------------------- */ - cp->segments = segments = np->scatter (cp, cp->cmd); + cp->segments = segments = np->scatter (np, cp, cp->cmd); if (segments < 0) { ncr_free_ccb(np, cp); @@ -6027,61 +6390,34 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd) **---------------------------------------------------- */ if (!cp->data_len) - direction = 0; - else { - switch((int) cmd->cmnd[0]) { - case 0x08: /* READ(6) 08 */ - case 0x28: /* READ(10) 28 */ - case 0xA8: /* READ(12) A8 */ - direction = XFER_IN; - break; - case 0x0A: /* WRITE(6) 0A */ - case 0x2A: /* WRITE(10) 2A */ - case 0xAA: /* WRITE(12) AA */ - direction = XFER_OUT; - break; - default: - direction = (XFER_IN|XFER_OUT); - break; - } - } - - /*---------------------------------------------------- - ** - ** Set the DATA POINTER. - ** - **---------------------------------------------------- - */ - - /* - ** Default to no data transfer. - */ - lastp = goalp = NCB_SCRIPTH_PHYS (np, no_data); + direction = SCSI_DATA_NONE; + else + direction = scsi_data_direction(cmd); /* - ** Compute data out pointers, if needed. + ** If data direction is UNKNOWN, speculate DATA_READ + ** but prepare alternate pointers for WRITE in case + ** of our speculation will be just wrong. + ** SCRIPTS will swap values if needed. */ - if (direction & XFER_OUT) { + switch(direction) { + case SCSI_DATA_UNKNOWN: + case SCSI_DATA_WRITE: goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8; lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4)); - - /* - ** If actual data direction is unknown, save pointers - ** in header. The SCRIPTS will swap them to current - ** if target decision will be data out. - */ - if (direction & XFER_IN) { - cp->phys.header.wgoalp = cpu_to_scr(goalp); - cp->phys.header.wlastp = cpu_to_scr(lastp); - } - } - - /* - ** Compute data in pointers, if needed. - */ - if (direction & XFER_IN) { + if (direction != SCSI_DATA_UNKNOWN) + break; + cp->phys.header.wgoalp = cpu_to_scr(goalp); + cp->phys.header.wlastp = cpu_to_scr(lastp); + /* fall through */ + case SCSI_DATA_READ: goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8; lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4)); + break; + default: + case SCSI_DATA_NONE: + lastp = goalp = NCB_SCRIPTH_PHYS (np, no_data); + break; } /* @@ -6091,7 +6427,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd) cp->phys.header.lastp = cpu_to_scr(lastp); cp->phys.header.goalp = cpu_to_scr(goalp); - if ((direction & (XFER_IN|XFER_OUT)) == (XFER_IN|XFER_OUT)) + if (direction == SCSI_DATA_UNKNOWN) cp->phys.header.savep = cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io)); else @@ -6152,7 +6488,8 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd) /* ** command */ - cp->phys.cmd.addr = cpu_to_scr(vtobus (&cmd->cmnd[0])); + memcpy(cp->cdb_buf, cmd->cmnd, cmd->cmd_len); + cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, cdb_buf[0])); cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len); /* @@ -6719,6 +7056,7 @@ void ncr_complete (ncb_p np, ccb_p cp) */ if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) && cmd->cmnd[4] >= 7 && !cmd->use_sg) { + sync_scsi_data(np, cmd); /* SYNC the data */ ncr_setup_lcb (np, cp->target, cp->lun, (char *) cmd->request_buffer); } @@ -6941,7 +7279,7 @@ void ncr_init (ncb_p np, int reset, char * msg, u_long code) /* ** Clear Start Queue */ - phys = vtobus(np->squeue); + phys = np->p_squeue; np->queuedepth = MAX_START - 1; /* 1 entry needed as end marker */ for (i = 0; i < MAX_START*2; i += 2) { np->squeue[i] = cpu_to_scr(np->p_idletask); @@ -7131,7 +7469,7 @@ void ncr_init (ncb_p np, int reset, char * msg, u_long code) np->istat_sem = 0; - OUTL (nc_dsa, vtobus(np)); + OUTL (nc_dsa, np->p_ncb); OUTL (nc_dsp, phys); } @@ -8733,7 +9071,7 @@ static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp) ** them back in the LUN CCB wait queue. */ busyccbs = lp->queuedccbs; - i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4; + i = (INL (nc_scratcha) - np->p_squeue) / 4; j = i; while (i != np->squeueput) { cp2 = ncr_ccb_from_dsa(np, scr_to_cpu(np->squeue[i])); @@ -8888,11 +9226,9 @@ next: /* ** sense data */ - bzero(cmd->sense_buffer, sizeof(cmd->sense_buffer)); - cp->phys.sense.addr = - cpu_to_scr(vtobus (&cmd->sense_buffer[0])); - cp->phys.sense.size = - cpu_to_scr(sizeof(cmd->sense_buffer)); + bzero(cp->sense_buf, sizeof(cp->sense_buf)); + cp->phys.sense.addr = cpu_to_scr(CCB_PHYS(cp,sense_buf[0])); + cp->phys.sense.size = cpu_to_scr(sizeof(cp->sense_buf)); /* ** requeue the command. @@ -9073,7 +9409,7 @@ static void ncr_sir_task_recovery(ncb_p np, int num) np->abrt_sel.sel_id = target; np->abrt_sel.sel_scntl3 = tp->wval; np->abrt_sel.sel_sxfer = tp->sval; - OUTL(nc_dsa, vtobus(np)); + OUTL(nc_dsa, np->p_ncb); OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sel_for_abort)); return; } @@ -9114,7 +9450,7 @@ static void ncr_sir_task_recovery(ncb_p np, int num) ** Compute index of next position in the start ** queue the SCRIPTS will schedule. */ - i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4; + i = (INL (nc_scratcha) - np->p_squeue) / 4; /* ** Remove the job from the start queue. @@ -9315,11 +9651,17 @@ static void ncr_sir_task_recovery(ncb_p np, int num) */ case SIR_AUTO_SENSE_DONE: cp = ncr_ccb_from_dsa(np, INL (nc_dsa)); + if (!cp) + break; + memcpy(cp->cmd->sense_buffer, cp->sense_buf, + sizeof(cp->cmd->sense_buffer)); p = &cp->cmd->sense_buffer[0]; if (p[0] != 0x70 || p[2] != 0x6 || p[12] != 0x29) break; +#if 0 (void) ncr_clear_tasks(np, HS_RESET, cp->target, cp->lun, -1); +#endif break; } @@ -10036,6 +10378,7 @@ void ncr_int_sir (ncb_p np) case SIR_SCRIPT_STOPPED: case SIR_TARGET_SELECTED: case SIR_ABORT_SENT: + case SIR_AUTO_SENSE_DONE: ncr_sir_task_recovery(np, num); return; /* @@ -10397,7 +10740,7 @@ static ccb_p ncr_alloc_ccb(ncb_p np) /* ** Allocate memory for this CCB. */ - cp = m_calloc(sizeof(struct ccb), "CCB", MEMO_WARN); + cp = m_calloc_dma(sizeof(struct ccb), "CCB"); if (!cp) return 0; @@ -10427,7 +10770,7 @@ static ccb_p ncr_alloc_ccb(ncb_p np) /* ** Initilialyze some other fields. */ - cp->phys.smsg_ext.addr = cpu_to_scr(vtobus(&np->msgin[2])); + cp->phys.smsg_ext.addr = cpu_to_scr(NCB_PHYS(np, msgin[2])); /* ** Chain into wakeup list and free ccb queue. @@ -10519,11 +10862,11 @@ static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln) if (ln && !tp->luntbl) { int i; - tp->luntbl = m_calloc(256, "LUNTBL", MEMO_WARN); + tp->luntbl = m_calloc_dma(256, "LUNTBL"); if (!tp->luntbl) goto fail; for (i = 0 ; i < 64 ; i++) - tp->luntbl[i] = cpu_to_scr(vtobus(&np->resel_badlun)); + tp->luntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun)); tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl)); } @@ -10531,7 +10874,7 @@ static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln) ** Allocate the table of pointers for LUN(s) > 0, if needed. */ if (ln && !tp->lmp) { - tp->lmp = m_calloc(MAX_LUN * sizeof(lcb_p), "LMP", MEMO_WARN); + tp->lmp = m_calloc(MAX_LUN * sizeof(lcb_p), "LMP"); if (!tp->lmp) goto fail; } @@ -10540,7 +10883,7 @@ static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln) ** Allocate the lcb. ** Make it available to the chip. */ - lp = m_calloc(sizeof(struct lcb), "LCB", MEMO_WARN); + lp = m_calloc_dma(sizeof(struct lcb), "LCB"); if (!lp) goto fail; if (ln) { @@ -10652,7 +10995,7 @@ static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data) ** initialyze the task table if not yet. */ if ((inq_byte7 & INQ7_QUEUE) && lp->tasktbl == &lp->tasktbl_0) { - lp->tasktbl = m_calloc(MAX_TASKS*4, "TASKTBL", MEMO_WARN); + lp->tasktbl = m_calloc_dma(MAX_TASKS*4, "TASKTBL"); if (!lp->tasktbl) { lp->tasktbl = &lp->tasktbl_0; goto fail; @@ -10661,7 +11004,7 @@ static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data) for (i = 0 ; i < MAX_TASKS ; i++) lp->tasktbl[i] = cpu_to_scr(np->p_notask); - lp->cb_tags = m_calloc(MAX_TAGS, "CB_TAGS", MEMO_WARN); + lp->cb_tags = m_calloc(MAX_TAGS, "CB_TAGS"); if (!lp->cb_tags) goto fail; for (i = 0 ; i < MAX_TAGS ; i++) @@ -10741,7 +11084,7 @@ fail: #define CROSS_16MB(p, n) (((((u_long) p) + n - 1) ^ ((u_long) p)) & ~0xffffff) -static int ncr_scatter_no_sglist(ccb_p cp, Scsi_Cmnd *cmd) +static int ncr_scatter_no_sglist(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd) { struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER-1]; int segment; @@ -10749,7 +11092,8 @@ static int ncr_scatter_no_sglist(ccb_p cp, Scsi_Cmnd *cmd) cp->data_len = cmd->request_bufflen; if (cmd->request_bufflen) { - u_long baddr = vtobus(cmd->request_buffer); + u_long baddr = map_scsi_single_data(np, cmd); + SCATTER_ONE(data, baddr, cmd->request_bufflen); if (CROSS_16MB(baddr, cmd->request_bufflen)) { cp->host_flags |= HF_PM_TO_C; @@ -10780,7 +11124,7 @@ printk("He! we are crossing a 16 MB boundary (0x%lx, 0x%x)\n", ** nicely power-of-two sized and aligned. But, since this may change ** at any time, a work-around was required. */ -static int ncr_scatter_896R1(ccb_p cp, Scsi_Cmnd *cmd) +static int ncr_scatter_896R1(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd) { int segn; int use_sg = (int) cmd->use_sg; @@ -10788,18 +11132,23 @@ static int ncr_scatter_896R1(ccb_p cp, Scsi_Cmnd *cmd) cp->data_len = 0; if (!use_sg) - segn = ncr_scatter_no_sglist(cp, cmd); + segn = ncr_scatter_no_sglist(np, cp, cmd); else if (use_sg > MAX_SCATTER) segn = -1; else { struct scatterlist *scatter = (struct scatterlist *)cmd->buffer; - struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER - use_sg]; + struct scr_tblmove *data; + + use_sg = map_scsi_sg_data(np, cmd); + data = &cp->phys.data[MAX_SCATTER - use_sg]; for (segn = 0; segn < use_sg; segn++) { - u_long baddr = vtobus(scatter[segn].address); + u_long baddr = scsi_sg_dma_address(&scatter[segn]); + unsigned int len = scsi_sg_dma_len(&scatter[segn]); + SCATTER_ONE(&data[segn], baddr, - scatter[segn].length); + len); if (CROSS_16MB(baddr, scatter[segn].length)) { cp->host_flags |= HF_PM_TO_C; #ifdef DEBUG_896R1 @@ -10807,14 +11156,14 @@ printk("He! we are crossing a 16 MB boundary (0x%lx, 0x%x)\n", baddr, scatter[segn].length); #endif } - cp->data_len += scatter[segn].length; + cp->data_len += len; } } return segn; } -static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd) +static int ncr_scatter(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd) { int segment; int use_sg = (int) cmd->use_sg; @@ -10822,19 +11171,24 @@ static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd) cp->data_len = 0; if (!use_sg) - segment = ncr_scatter_no_sglist(cp, cmd); + segment = ncr_scatter_no_sglist(np, cp, cmd); else if (use_sg > MAX_SCATTER) segment = -1; else { struct scatterlist *scatter = (struct scatterlist *)cmd->buffer; - struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER - use_sg]; + struct scr_tblmove *data; + + use_sg = map_scsi_sg_data(np, cmd); + data = &cp->phys.data[MAX_SCATTER - use_sg]; for (segment = 0; segment < use_sg; segment++) { - u_long baddr = vtobus(scatter[segment].address); + u_long baddr = scsi_sg_dma_address(&scatter[segment]); + unsigned int len = scsi_sg_dma_len(&scatter[segment]); + SCATTER_ONE(&data[segment], baddr, - scatter[segment].length); - cp->data_len += scatter[segment].length; + len); + cp->data_len += len; } } @@ -10901,7 +11255,7 @@ static int __init ncr_snooptest (struct ncb* np) /* ** Start script (exchange values) */ - OUTL (nc_dsa, vtobus(np)); + OUTL (nc_dsa, np->p_ncb); OUTL (nc_dsp, pc); /* ** Wait 'til done (with timeout) @@ -11580,7 +11934,7 @@ if (sym53c8xx) ** overflow the kernel stack. ** 1 x 4K PAGE is enough for more than 40 devices for i386. */ - devtbl = m_calloc(PAGE_SIZE, "devtbl", MEMO_WARN); + devtbl = m_calloc(PAGE_SIZE, "devtbl"); if (!devtbl) return 0; @@ -11745,6 +12099,15 @@ sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device) PciBusNumber(pdev), (int) (PciDeviceFn(pdev) & 0xf8) >> 3, (int) (PciDeviceFn(pdev) & 7)); + +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + if (!pci_dma_supported(pdev, (dma_addr_t) (0xffffffffUL))) { + printk(KERN_WARNING NAME53C8XX + "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n"); + return -1; + } +#endif + /* ** Read info from the PCI config space. ** pci_read_config_xxx() functions are assumed to be used for @@ -12032,6 +12395,7 @@ sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device) /* ** Initialise ncr_device structure with items required by ncr_attach. */ + device->pdev = pdev; device->slot.bus = PciBusNumber(pdev); device->slot.device_fn = PciDeviceFn(pdev); device->slot.base = base; @@ -12232,6 +12596,10 @@ printk("sym53c8xx_queue_command\n"); cmd->host_scribble = NULL; cmd->SCp.ptr = NULL; cmd->SCp.buffer = NULL; +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + cmd->__data_mapped = 0; + cmd->__data_mapping = 0; +#endif NCR_LOCK_NCB(np, flags); @@ -12267,6 +12635,7 @@ static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs) unsigned long flags; ncb_p np = (ncb_p) dev_id; Scsi_Cmnd *done_list; + pcidev_t pdev; #ifdef DEBUG_SYM53C8XX printk("sym53c8xx : interrupt received\n"); @@ -12276,6 +12645,7 @@ static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs) NCR_LOCK_NCB(np, flags); ncr_exception(np); + pdev = np->pdev; done_list = np->done_list; np->done_list = 0; NCR_UNLOCK_NCB(np, flags); @@ -12284,7 +12654,7 @@ static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs) if (done_list) { NCR_LOCK_SCSI_DONE(np, flags); - ncr_flush_done_cmds(done_list); + ncr_flush_done_cmds(pdev, done_list); NCR_UNLOCK_SCSI_DONE(np, flags); } } @@ -12297,17 +12667,19 @@ static void sym53c8xx_timeout(unsigned long npref) { ncb_p np = (ncb_p) npref; unsigned long flags; + pcidev_t pdev; Scsi_Cmnd *done_list; NCR_LOCK_NCB(np, flags); ncr_timeout((ncb_p) np); + pdev = np->pdev; done_list = np->done_list; np->done_list = 0; NCR_UNLOCK_NCB(np, flags); if (done_list) { NCR_LOCK_SCSI_DONE(np, flags); - ncr_flush_done_cmds(done_list); + ncr_flush_done_cmds(pdev, done_list); NCR_UNLOCK_SCSI_DONE(np, flags); } } @@ -12325,6 +12697,7 @@ int sym53c8xx_reset(Scsi_Cmnd *cmd) ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb; int sts; unsigned long flags; + pcidev_t pdev; Scsi_Cmnd *done_list; #if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS @@ -12369,11 +12742,12 @@ int sym53c8xx_reset(Scsi_Cmnd *cmd) #endif out: + pdev = np->pdev; done_list = np->done_list; np->done_list = 0; NCR_UNLOCK_NCB(np, flags); - ncr_flush_done_cmds(done_list); + ncr_flush_done_cmds(pdev, done_list); return sts; } @@ -12387,6 +12761,7 @@ int sym53c8xx_abort(Scsi_Cmnd *cmd) ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb; int sts; unsigned long flags; + pcidev_t pdev; Scsi_Cmnd *done_list; #if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS @@ -12410,11 +12785,12 @@ int sym53c8xx_abort(Scsi_Cmnd *cmd) sts = ncr_abort_command(np, cmd); out: + pdev = np->pdev; done_list = np->done_list; np->done_list = 0; NCR_UNLOCK_NCB(np, flags); - ncr_flush_done_cmds(done_list); + ncr_flush_done_cmds(pdev, done_list); return sts; } diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index b9ae751bf..41b55ea4c 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -66,7 +66,7 @@ obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_SB) += sb.o uart401.o obj-$(CONFIG_SOUND_SOFTOSS) += softoss2.o obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o ad1848.o -obj-$(CONFIG_SOUND_AD1816) += ad1816.o +obj-$(CONFIG_SOUND_AD1816) += ad1816.o obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb.o uart401.o obj-$(CONFIG_SOUND_UART6850) += uart6850.o @@ -104,7 +104,7 @@ pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o sb-objs := sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o \ sb_ess.o softoss2-objs := softoss.o softoss_rs.o -vidc_mod-objs := vidc.o vidc_audio.o vidc_fill.o vidc_mixer.o vidc_synth.o +vidc_mod-objs := vidc.o vidc_fill.o wavefront-objs := wavfront.o wf_midi.o yss225.o nm256-objs := nm256_audio.o ac97.o diff --git a/drivers/sound/README.CONFIG b/drivers/sound/README.CONFIG deleted file mode 100644 index 5cd199230..000000000 --- a/drivers/sound/README.CONFIG +++ /dev/null @@ -1,75 +0,0 @@ -Sound Driver Configuration Notes -Michael Chastain, <mailto:mec@shout.net> -18 Apr 1998 - -The Linux sound driver is derived from OSS/Free, a multi-platform -Unix sound driver by Hannu Savolainen. You can find out -more about OSS/Free and the commercial version, OSS/Linux, at -<http://www.opensound.com/ossfree>. - -OSS/Free comes with the configuration program 'configure.c'. We have -discarded that program in favor of a standard Linux configuration file -Config.in. - -Config.in defines a set of symbols with the form CONFIG_SOUND_*. -These are the -native symbols-. Here is a description: - - CONFIG_SOUND - - This is the master symbol. It controls whether the basic - sound-driver code is resident, modular, or not present at all. - - If the basic driver is resident, each primary and secondary - driver can be resident, modular, or not present. - - If the basic driver is modular, each primary and secondary driver - can be modular or not present. - - And if the basic driver is not present, all other drivers are - not present, too. - - Primary drivers - - These are symbols such as CONFIG_SOUND_SB, CONFIG_SOUND_SB_MODULE, - CONFIG_SOUND_TRIX, or CONFIG_SOUND_TRIX_MODULE. Each driver - that the user can directly select is a primary driver and has - the usual pair of symbols: one resident and one modular. - - Each primary driver can be either resident or modular. - - Secondary drivers - - Primary drivers require the support of secondary drivers, such - as ad1848.o and uart401.o. - - In Makefile, each primary driver has a list of required secondary - drivers. The secondary driver requirements are merged and a - single definition is emitted at the end. - - For each secondary driver: if any resident primary driver - requires it, that secondary driver will be resident. If no - resident primary driver requires it but some modular primary - driver requires it, then that secondary driver will be modular. - Otherwise that secondary driver will be not present. - - OSS/Free also contains tests for secondary drivers. The Makefile - defines symbols for these drivers in EXTRA_CFLAGS. - - CONFIG_AUDIO, CONFIG_MIDI, CONFIG_SEQUENCER - - These three drivers are like secondary drivers, but not quite. - They can not yet be separated into modules. They are always - linked into the basic sound driver, whether they are needed - or not. (This is in case a primary driver is added to the - system later, as a module, and needs these facilities. If it - were possible to modularise them, then they would get built as - additional modules at that time). - -The OSS/Free code does not use the native symbols directly, primarily -because it does not know about modules. I could edit the code, but that -would make it harder to upgrade to new versions of OSS/Free. Instead, -the OSS/Free code continues to use -legacy symbols-. - -legacy.h defines all the legacy symbols to 1. This is because, whenever -OSS/Free tests a symbol, the Makefile has already arranged for that -driver to be included. diff --git a/drivers/sound/ac97_codec.c b/drivers/sound/ac97_codec.c index 56ee3df89..175cd38e0 100644 --- a/drivers/sound/ac97_codec.c +++ b/drivers/sound/ac97_codec.c @@ -28,8 +28,7 @@ #include <linux/module.h> #include <linux/version.h> #include <linux/kernel.h> - -#include "ac97_codec.h" +#include <linux/ac97_codec.h> static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel); static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, diff --git a/drivers/sound/ac97_codec.h b/drivers/sound/ac97_codec.h deleted file mode 100644 index a614edbdb..000000000 --- a/drivers/sound/ac97_codec.h +++ /dev/null @@ -1,161 +0,0 @@ -#ifndef _AC97_CODEC_H_ -#define _AC97_CODEC_H_ - -#include "sound_config.h" -#include "sound_calls.h" - -/* AC97 1.0 */ -#define AC97_RESET 0x0000 // -#define AC97_MASTER_VOL_STEREO 0x0002 // Line Out -#define AC97_HEADPHONE_VOL 0x0004 // -#define AC97_MASTER_VOL_MONO 0x0006 // TAD Output -#define AC97_MASTER_TONE 0x0008 // -#define AC97_PCBEEP_VOL 0x000a // none -#define AC97_PHONE_VOL 0x000c // TAD Input (mono) -#define AC97_MIC_VOL 0x000e // MIC Input (mono) -#define AC97_LINEIN_VOL 0x0010 // Line Input (stereo) -#define AC97_CD_VOL 0x0012 // CD Input (stereo) -#define AC97_VIDEO_VOL 0x0014 // none -#define AC97_AUX_VOL 0x0016 // Aux Input (stereo) -#define AC97_PCMOUT_VOL 0x0018 // Wave Output (stereo) -#define AC97_RECORD_SELECT 0x001a // -#define AC97_RECORD_GAIN 0x001c -#define AC97_RECORD_GAIN_MIC 0x001e -#define AC97_GENERAL_PURPOSE 0x0020 -#define AC97_3D_CONTROL 0x0022 -#define AC97_MODEM_RATE 0x0024 -#define AC97_POWER_CONTROL 0x0026 - -/* AC'97 2.0 */ -#define AC97_EXTENDED_ID 0x0028 /* Extended Audio ID */ -#define AC97_EXTENDED_STATUS 0x002A /* Extended Audio Status */ -#define AC97_PCM_FRONT_DAC_RATE 0x002C /* PCM Front DAC Rate */ -#define AC97_PCM_SURR_DAC_RATE 0x002E /* PCM Surround DAC Rate */ -#define AC97_PCM_LFE_DAC_RATE 0x0030 /* PCM LFE DAC Rate */ -#define AC97_PCM_LR_DAC_RATE 0x0032 /* PCM LR DAC Rate */ -#define AC97_PCM_MIC_ADC_RATE 0x0034 /* PCM MIC ADC Rate */ -#define AC97_CENTER_LFE_MASTER 0x0036 /* Center + LFE Master Volume */ -#define AC97_SURROUND_MASTER 0x0038 /* Surround (Rear) Master Volume */ -#define AC97_RESERVED_3A 0x003A /* Reserved */ - -/* range 0x3c-0x58 - MODEM */ - -/* registers 0x005a - 0x007a are vendor reserved */ - -#define AC97_VENDOR_ID1 0x007c -#define AC97_VENDOR_ID2 0x007e - -/* volume control bit defines */ -#define AC97_MUTE 0x8000 -#define AC97_MICBOOST 0x0040 -#define AC97_LEFTVOL 0x3f00 -#define AC97_RIGHTVOL 0x003f - -/* record mux defines */ -#define AC97_RECMUX_MIC 0x0000 -#define AC97_RECMUX_CD 0x0101 -#define AC97_RECMUX_VIDEO 0x0202 /* not used */ -#define AC97_RECMUX_AUX 0x0303 -#define AC97_RECMUX_LINE 0x0404 -#define AC97_RECMUX_STEREO_MIX 0x0505 -#define AC97_RECMUX_MONO_MIX 0x0606 -#define AC97_RECMUX_PHONE 0x0707 - - -/* general purpose register bit defines */ -#define AC97_GP_LPBK 0x0080 /* Loopback mode */ -#define AC97_GP_MS 0x0100 /* Mic Select 0=Mic1, 1=Mic2 */ -#define AC97_GP_MIX 0x0200 /* Mono output select 0=Mix, 1=Mic */ -#define AC97_GP_RLBK 0x0400 /* Remote Loopback - Modem line codec */ -#define AC97_GP_LLBK 0x0800 /* Local Loopback - Modem Line codec */ -#define AC97_GP_LD 0x1000 /* Loudness 1=on */ -#define AC97_GP_3D 0x2000 /* 3D Enhancement 1=on */ -#define AC97_GP_ST 0x4000 /* Stereo Enhancement 1=on */ -#define AC97_GP_POP 0x8000 /* Pcm Out Path, 0=pre 3D, 1=post 3D */ - - -/* powerdown control and status bit defines */ - -/* status */ -#define AC97_PWR_MDM 0x0010 /* Modem section ready */ -#define AC97_PWR_REF 0x0008 /* Vref nominal */ -#define AC97_PWR_ANL 0x0004 /* Analog section ready */ -#define AC97_PWR_DAC 0x0002 /* DAC section ready */ -#define AC97_PWR_ADC 0x0001 /* ADC section ready */ - -/* control */ -#define AC97_PWR_PR0 0x0100 /* ADC and Mux powerdown */ -#define AC97_PWR_PR1 0x0200 /* DAC powerdown */ -#define AC97_PWR_PR2 0x0400 /* Output mixer powerdown (Vref on) */ -#define AC97_PWR_PR3 0x0800 /* Output mixer powerdown (Vref off) */ -#define AC97_PWR_PR4 0x1000 /* AC-link powerdown */ -#define AC97_PWR_PR5 0x2000 /* Internal Clk disable */ -#define AC97_PWR_PR6 0x4000 /* HP amp powerdown */ -#define AC97_PWR_PR7 0x8000 /* Modem off - if supported */ - -/* useful power states */ -#define AC97_PWR_D0 0x0000 /* everything on */ -#define AC97_PWR_D1 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR4 -#define AC97_PWR_D2 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4 -#define AC97_PWR_D3 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4 -#define AC97_PWR_ANLOFF AC97_PWR_PR2|AC97_PWR_PR3 /* analog section off */ - -/* Total number of defined registers. */ -#define AC97_REG_CNT 64 - - -/* OSS interface to the ac97s.. */ -#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|SOUND_MASK_PCM|\ - SOUND_MASK_LINE|SOUND_MASK_CD|\ - SOUND_MASK_ALTPCM|SOUND_MASK_IGAIN|\ - SOUND_MASK_LINE1|SOUND_MASK_VIDEO) - -#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \ - SOUND_MASK_BASS|SOUND_MASK_TREBLE|\ - SOUND_MASK_SPEAKER|SOUND_MASK_MIC|\ - SOUND_MASK_PHONEIN|SOUND_MASK_PHONEOUT) - -#define AC97_RECORD_MASK (SOUND_MASK_MIC|\ - SOUND_MASK_CD|SOUND_MASK_VIDEO|\ - SOUND_MASK_LINE1| SOUND_MASK_LINE|\ - SOUND_MASK_PHONEIN) - -#define supported_mixer(CODEC,FOO) ( CODEC->supported_mixers & (1<<FOO) ) - -struct ac97_codec { - /* AC97 controller connected with */ - void *private_data; - - char *name; - int id; - int dev_mixer; - - /* codec specific init/reset routines, used mainly for 4 or 6 channel support */ - int (*codec_init) (struct ac97_codec *codec); - - /* controller specific lower leverl ac97 accessing routines */ - u16 (*codec_read) (struct ac97_codec *codec, u8 reg); - void (*codec_write) (struct ac97_codec *codec, u8 reg, u16 val); - - /* OSS mixer masks */ - int modcnt; - int supported_mixers; - int stereo_mixers; - int record_sources; - - /* OSS mixer interface */ - int (*read_mixer) (struct ac97_codec *codec, int oss_channel); - void (*write_mixer)(struct ac97_codec *codec, int oss_channel, - unsigned int left, unsigned int right); - int (*recmask_io) (struct ac97_codec *codec, int rw, int mask); - int (*mixer_ioctl)(struct ac97_codec *codec, unsigned int cmd, unsigned long arg); - - /* saved OSS mixer states */ - unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; -}; - -extern int ac97_read_proc (char *page_out, char **start, off_t off, - int count, int *eof, void *data); -extern int ac97_probe_codec(struct ac97_codec *); - -#endif /* _AC97_CODEC_H_ */ diff --git a/drivers/sound/ad1816.c b/drivers/sound/ad1816.c index c94481524..e45609e5c 100644 --- a/drivers/sound/ad1816.c +++ b/drivers/sound/ad1816.c @@ -59,8 +59,6 @@ Changes: #include "soundmodule.h" #include "sound_config.h" -#ifdef CONFIG_AD1816 - #define DEBUGNOISE(x) #define DEBUGINFO(x) #define DEBUGLOG(x) x @@ -1429,5 +1427,3 @@ void cleanup_module(void) } #endif /* MODULE */ - -#endif /* CONFIG_AD1816 */ diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c index 498db82f0..b7d93fdb4 100644 --- a/drivers/sound/ad1848.c +++ b/drivers/sound/ad1848.c @@ -40,9 +40,6 @@ #define DEB(x) #define DEB1(x) #include "sound_config.h" - -#ifdef CONFIG_AD1848 - #include "ad1848_mixer.h" typedef struct @@ -113,7 +110,7 @@ static volatile signed char irq2dev[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) || defined(MODULE) +#ifdef MODULE static int timer_installed = -1; @@ -167,7 +164,7 @@ static void ad1848_halt_input(int dev); static void ad1848_halt_output(int dev); static void ad1848_trigger(int dev, int bits); -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) +#ifndef EXCLUDE_TIMERS static int ad1848_tmr_install(int dev); static void ad1848_tmr_reprogram(int dev); @@ -1131,7 +1128,7 @@ static int ad1848_prepare_for_output(int dev, int bsize, int bcount) restore_flags(flags); devc->xfer_count = 0; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) +#ifndef EXCLUDE_TIMERS if (dev == timer_installed && devc->timer_running) if ((fs & 0x01) != (old_fs & 0x01)) { @@ -1245,7 +1242,7 @@ static int ad1848_prepare_for_input(int dev, int bsize, int bcount) restore_flags(flags); devc->xfer_count = 0; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) +#ifndef EXCLUDE_TIMERS if (dev == timer_installed && devc->timer_running) { if ((fs & 0x01) != (old_fs & 0x01)) @@ -1931,7 +1928,7 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt } if (capabilities[devc->model].flags & CAP_F_TIMER) { -#ifndef __SMP__ +#ifndef CONFIG_SMP int x; unsigned char tmp = ad_read(devc, 16); #endif @@ -1940,7 +1937,7 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt ad_write(devc, 21, 0x00); /* Timer MSB */ ad_write(devc, 20, 0x10); /* Timer LSB */ -#ifndef __SMP__ +#ifndef CONFIG_SMP ad_write(devc, 16, tmp | 0x40); /* Enable timer */ for (x = 0; x < 100000 && devc->timer_ticks == 0; x++); ad_write(devc, 16, tmp & ~0x40); /* Disable timer */ @@ -1961,7 +1958,7 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt } else if (irq < 0) irq2dev[-irq] = devc->dev_no = my_dev; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) +#ifndef EXCLUDE_TIMERS if ((capabilities[devc->model].flags & CAP_F_TIMER) && devc->irq_ok) ad1848_tmr_install(my_dev); @@ -2146,7 +2143,7 @@ interrupt_again: /* Jump back here if int status doesn't reset */ if (devc->model != MD_1848 && (alt_stat & 0x40)) /* Timer interrupt */ { devc->timer_ticks++; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) +#ifndef EXCLUDE_TIMERS if (timer_installed == dev && devc->timer_running) sound_timer_interrupt(); #endif @@ -2583,7 +2580,7 @@ void unload_ms_sound(struct address_info *hw_config) release_region(hw_config->io_base, 4); } -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) +#ifndef EXCLUDE_TIMERS /* * Timer stuff (for /dev/music). @@ -2693,7 +2690,7 @@ static int ad1848_tmr_install(int dev) return 1; } -#endif +#endif /* EXCLUDE_TIMERS */ EXPORT_SYMBOL(ad1848_detect); @@ -2757,5 +2754,4 @@ void cleanup_module(void) unload_ms_sound(&hw_config); } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/adlib_card.c b/drivers/sound/adlib_card.c index c48fb5eb8..087c57b68 100644 --- a/drivers/sound/adlib_card.c +++ b/drivers/sound/adlib_card.c @@ -65,4 +65,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif +#endif /* MODULE */ diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c index b15a9423c..ba7231aa9 100644 --- a/drivers/sound/audio.c +++ b/drivers/sound/audio.c @@ -29,8 +29,6 @@ #include <linux/kmod.h> #include "sound_config.h" - -#ifdef CONFIG_AUDIO #include "ulaw.h" #include "coproc.h" @@ -517,8 +515,6 @@ void audio_init_devices(void) */ } -#endif - void reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording) { /* diff --git a/drivers/sound/cs4232.c b/drivers/sound/cs4232.c index 11feddccc..0778273f9 100644 --- a/drivers/sound/cs4232.c +++ b/drivers/sound/cs4232.c @@ -176,7 +176,6 @@ int probe_cs4232(struct address_info *hw_config) * Initialize logical device 3 (MPU) */ -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) if (mpu_base != 0 && mpu_irq != 0) { CS_OUT2(0x15, 0x03); /* Select logical device 3 (MPU) */ @@ -184,7 +183,6 @@ int probe_cs4232(struct address_info *hw_config) CS_OUT2(0x22, mpu_irq); /* MPU IRQ */ CS_OUT2(0x33, 0x01); /* Activate logical dev 3 */ } -#endif if(synth_base != 0) { @@ -238,7 +236,6 @@ void attach_cs4232(struct address_info *hw_config) AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM synth */ } -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) if (mpu_base != 0 && mpu_irq != 0) { static struct address_info hw_config2 = { @@ -266,7 +263,6 @@ void attach_cs4232(struct address_info *hw_config) } hw_config->slots[1] = hw_config2.slots[1]; } -#endif } void unload_cs4232(struct address_info *hw_config) @@ -284,7 +280,6 @@ void unload_cs4232(struct address_info *hw_config) 0); sound_unload_audiodev(hw_config->slots[0]); -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) if (mpu_base != 0 && mpu_irq != 0 && mpu_detected) { static struct address_info hw_config2 = @@ -305,7 +300,6 @@ void unload_cs4232(struct address_info *hw_config) unload_uart401(&hw_config2); } -#endif } void unload_cs4232_mpu(struct address_info *hw_config) @@ -397,4 +391,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif +#endif /* MODULE */ diff --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c index 603886504..5e9657c8a 100644 --- a/drivers/sound/dev_table.c +++ b/drivers/sound/dev_table.c @@ -43,7 +43,6 @@ static void start_services(void) return; /* No cards detected */ #endif -#ifdef CONFIG_AUDIO if (num_audiodevs) /* Audio devices present */ { int dev; @@ -52,7 +51,6 @@ static void start_services(void) } audio_init_devices(); } -#endif return; } @@ -410,7 +408,6 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, int driver_size, int flags, unsigned int format_mask, void *devc, int dma1, int dma2) { -#ifdef CONFIG_AUDIO struct audio_driver *d; struct audio_operations *op; int l, num; @@ -470,9 +467,6 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, audio_init_devices(); return num; -#else - return -EINVAL; -#endif } int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, @@ -544,7 +538,6 @@ int sound_alloc_audiodev(void) int sound_alloc_mididev(void) { -#ifdef CONFIG_MIDI int i = register_sound_midi(&oss_sound_fops, -1); if(i==-1) return i; @@ -552,9 +545,6 @@ int sound_alloc_mididev(void) if(i>=num_midis) num_midis = i + 1; return i; -#else - return (-1); -#endif } int sound_alloc_synthdev(void) @@ -611,13 +601,11 @@ void sound_unload_mixerdev(int dev) void sound_unload_mididev(int dev) { -#ifdef CONFIG_MIDI if (dev != -1) { midi_devs[dev] = NULL; unregister_sound_midi((dev<<4)+2); } -#endif } void sound_unload_synthdev(int dev) diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h index 427c6f4db..5c0cf1d0f 100644 --- a/drivers/sound/dev_table.h +++ b/drivers/sound/dev_table.h @@ -357,7 +357,7 @@ struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0; struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; int num_synths = 0; struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) && !defined(VMIDI) +#ifndef EXCLUDE_TIMERS extern struct sound_timer_operations default_sound_timer; struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = { &default_sound_timer, NULL @@ -386,11 +386,9 @@ struct driver_info sound_drivers[] = #ifdef CONFIG_GUS16 {"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16, unload_gus_db16}, #endif -#ifdef CONFIG_GUS {"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, unload_gus}, {"GUSPNP", 1, SNDCARD_GUSPNP, "GUS PnP", attach_gus_card, probe_gus, unload_gus}, #endif -#endif #ifdef CONFIG_SOUND_MSS {"MSS", 0, SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound}, @@ -433,11 +431,11 @@ probe_ad1816, unload_ad1816}, {"PAS16", 0, SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas, unload_pas}, #endif -#if (defined(CONFIG_SOUND_MPU401) || defined(CONFIG_SOUND_MPU_EMU)) && defined(CONFIG_MIDI) +#if (defined(CONFIG_SOUND_MPU401) || defined(CONFIG_SOUND_MPU_EMU)) {"MPU401", 0, SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401, unload_mpu401}, #endif -#if defined(CONFIG_SOUND_UART401) && defined(CONFIG_MIDI) +#if defined(CONFIG_SOUND_UART401) {"UART401", 0, SNDCARD_UART401,"MPU-401 (UART)", attach_uart401, probe_uart401, unload_uart401}, #endif @@ -450,7 +448,7 @@ probe_ad1816, unload_ad1816}, {"MAUI", 0, SNDCARD_MAUI,"TB Maui", attach_maui, probe_maui, unload_maui}, #endif -#if defined(CONFIG_SOUND_UART6850) && defined(CONFIG_MIDI) +#if defined(CONFIG_SOUND_UART6850) {"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850, unload_uart6850}, #endif @@ -461,10 +459,8 @@ probe_ad1816, unload_ad1816}, {"SBLAST", 0, SNDCARD_SB, "Sound Blaster", attach_sb_card, probe_sb, unload_sb}, {"SBPNP", 6, SNDCARD_SBPNP, "Sound Blaster PnP", attach_sb_card, probe_sb, unload_sb}, -#ifdef CONFIG_MIDI {"SBMPU", 0, SNDCARD_SB16MIDI,"SB MPU-401", attach_sbmpu, probe_sbmpu, unload_sbmpu}, #endif -#endif #ifdef CONFIG_SOUND_SSCAPE {"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq SoundScape", attach_sscape, probe_sscape, unload_sscape}, @@ -488,7 +484,7 @@ probe_ad1816, unload_ad1816}, attach_softsyn_card, probe_softsyn, unload_softsyn}, #endif -#if defined(CONFIG_SOUND_VMIDI) && defined(CONFIG_MIDI) +#ifdef CONFIG_SOUND_VMIDI {"VMIDI", 0, SNDCARD_VMIDI,"Loopback MIDI Device", attach_v_midi, probe_v_midi, unload_v_midi}, #endif #ifdef CONFIG_SOUND_VIDC @@ -503,8 +499,6 @@ probe_ad1816, unload_ad1816}, int num_sound_drivers = sizeof(sound_drivers) / sizeof (struct driver_info); -#ifndef FULL_SOUND - /* * List of devices actually configured in the system. * @@ -632,7 +626,7 @@ struct card_info snd_installed_cards[] = {SNDCARD_MAUI, {CONFIG_MAUI_BASE, CONFIG_MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif -#if defined(CONFIG_SOUND_MPU401) && defined(CONFIG_MIDI) +#ifdef CONFIG_SOUND_MPU401 {SNDCARD_MPU401, {CONFIG_MPU_BASE, CONFIG_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #ifdef MPU2_BASE {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, @@ -642,12 +636,12 @@ struct card_info snd_installed_cards[] = #endif #endif -#if defined(CONFIG_SOUND_UART6850) && defined(CONFIG_MIDI) +#ifdef CONFIG_SOUND_UART6850 {SNDCARD_UART6850, {CONFIG_U6850_BASE, CONFIG_U6850_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif #ifdef CONFIG_SOUND_SB -#if defined(CONFIG_MIDI) && defined(CONFIG_SB_MPU_BASE) +#ifdef CONFIG_SB_MPU_BASE {SNDCARD_SB16MIDI,{CONFIG_SB_MPU_BASE, CONFIG_SB_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif #endif @@ -666,7 +660,7 @@ struct card_info snd_installed_cards[] = {SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE}, #endif -#if defined(CONFIG_SOUND_VMIDI) && defined(CONFIG_MIDI) +#ifdef CONFIG_SOUND_VMIDI {SNDCARD_VMIDI, {0, 0, 0, -1}, SND_DEFAULT_ENABLE}, #endif @@ -683,13 +677,7 @@ struct card_info snd_installed_cards[] = int num_sound_cards = sizeof(snd_installed_cards) / sizeof (struct card_info); static int max_sound_cards = sizeof(snd_installed_cards) / sizeof (struct card_info); -#else -int num_sound_cards = 0; -struct card_info snd_installed_cards[20] = {{0}}; -static int max_sound_cards = 20; -#endif - -#if defined(MODULE) || (!defined(linux) && !defined(_AIX)) +#if defined(MODULE) int trace_init = 0; #else int trace_init = 1; diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index e70c10841..1296da1ea 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -29,8 +29,6 @@ #include "sound_config.h" -#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS) - #define DMAP_FREE_ON_CLOSE 0 #define DMAP_KEEP_ON_CLOSE 1 extern int sound_dmap_flag; @@ -1286,5 +1284,3 @@ void DMAbuf_deinit(int dev) sound_free_dmap(adev->dmap_in); } } - -#endif diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index feeb11956..95158296a 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -119,11 +119,11 @@ #include <linux/bitops.h> #include <linux/proc_fs.h> #include <linux/spinlock.h> +#include <linux/ac97_codec.h> #include <asm/io.h> #include <asm/dma.h> #include <asm/uaccess.h> #include <asm/hardirq.h> -#include "ac97_codec.h" /* --------------------------------------------------------------------- */ @@ -376,6 +376,9 @@ static const unsigned sample_shift[] = { 0, 1, 1, 2 }; #define SND_DEV_DSP16 5 +#define ES1371_MODULE_NAME "es1371" +#define PFX ES1371_MODULE_NAME ": " + /* --------------------------------------------------------------------- */ struct es1371_state { @@ -496,7 +499,7 @@ static unsigned wait_src_ready(struct es1371_state *s) return r; udelay(1); } - printk(KERN_DEBUG "es1371: sample rate converter timeout r = 0x%08x\n", r); + printk(KERN_DEBUG PFX "sample rate converter timeout r = 0x%08x\n", r); return r; } @@ -1113,7 +1116,7 @@ static void es1371_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* --------------------------------------------------------------------- */ -static const char invalid_magic[] = KERN_CRIT "es1371: invalid magic value\n"; +static const char invalid_magic[] = KERN_CRIT PFX "invalid magic value\n"; #define VALIDATE_STATE(s) \ ({ \ @@ -1216,7 +1219,7 @@ static int drain_dac1(struct es1371_state *s, int nonblock) tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate; tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; if (!schedule_timeout(tmo + 1)) - DBG(printk(KERN_DEBUG "es1371: dac1 dma timed out??\n");) + DBG(printk(KERN_DEBUG PFX "dac1 dma timed out??\n");) } remove_wait_queue(&s->dma_dac1.wait, &wait); set_current_state(TASK_RUNNING); @@ -1251,7 +1254,7 @@ static int drain_dac2(struct es1371_state *s, int nonblock) tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate; tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; if (!schedule_timeout(tmo + 1)) - DBG(printk(KERN_DEBUG "es1371: dac2 dma timed out??\n");) + DBG(printk(KERN_DEBUG PFX "dac2 dma timed out??\n");) } remove_wait_queue(&s->dma_dac2.wait, &wait); set_current_state(TASK_RUNNING); @@ -2502,7 +2505,7 @@ static int es1371_midi_release(struct inode *inode, struct file *file) } tmo = (count * HZ) / 3100; if (!schedule_timeout(tmo ? : 1) && tmo) - printk(KERN_DEBUG "es1371: midi timed out??\n"); + printk(KERN_DEBUG PFX "midi timed out??\n"); } remove_wait_queue(&s->midi.owait, &wait); set_current_state(TASK_RUNNING); @@ -2629,7 +2632,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic return -1; } if (!(s = kmalloc(sizeof(struct es1371_state), GFP_KERNEL))) { - printk(KERN_WARNING "es1371: out of memory\n"); + printk(KERN_WARNING PFX "out of memory\n"); return -1; } memset(s, 0, sizeof(struct es1371_state)); @@ -2652,19 +2655,19 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic s->codec.id = 0; s->codec.codec_read = rdcodec; s->codec.codec_write = wrcodec; - printk(KERN_INFO "es1371: found chip, vendor id 0x%04x device id 0x%04x revision 0x%02x\n", + printk(KERN_INFO PFX "found chip, vendor id 0x%04x device id 0x%04x revision 0x%02x\n", s->vendor, s->device, s->rev); if (!request_region(s->io, ES1371_EXTENT, "es1371")) { - printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1); + printk(KERN_ERR PFX "io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1); goto err_region; } if (request_irq(s->irq, es1371_interrupt, SA_SHIRQ, "es1371", s)) { - printk(KERN_ERR "es1371: irq %u in use\n", s->irq); + printk(KERN_ERR PFX "irq %u in use\n", s->irq); goto err_irq; } pci_enable_device(pcidev); - printk(KERN_INFO "es1371: found es1371 rev %d at io %#lx irq %u\n" - KERN_INFO "es1371: features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[devindex]); + printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u\n" + KERN_INFO PFX "features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[devindex]); /* register devices */ if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops, -1)) < 0) goto err_dev1; @@ -2683,7 +2686,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic s->ctrl = 0; if ((joystick[devindex] & ~0x18) == 0x200) { if (check_region(joystick[devindex], JOY_EXTENT)) - printk(KERN_ERR "es1371: joystick address 0x%x already in use\n", joystick[devindex]); + printk(KERN_ERR PFX "joystick address 0x%x already in use\n", joystick[devindex]); else { s->ctrl |= CTRL_JYSTK_EN | (((joystick[devindex] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT); } @@ -2693,11 +2696,11 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic /* check to see if s/pdif mode is being requested */ if (spdif[devindex]) { if (s->rev >= 4) { - printk(KERN_INFO "es1371: enabling S/PDIF output\n"); + printk(KERN_INFO PFX "enabling S/PDIF output\n"); cssr |= STAT_EN_SPDIF; s->ctrl |= CTRL_SPDIFEN_B; } else { - printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", s->rev); + printk(KERN_ERR PFX "revision %d does not support S/PDIF\n", s->rev); } } /* initialize the chips */ @@ -2731,6 +2734,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic if (!ac97_probe_codec(&s->codec)) goto err_dev4; /* set default values */ + fs = get_fs(); set_fs(KERNEL_DS); val = SOUND_MASK_LINE; @@ -2759,7 +2763,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic err_dev2: unregister_sound_dsp(s->dev_audio); err_dev1: - printk(KERN_ERR "es1371: cannot register misc device\n"); + printk(KERN_ERR PFX "cannot register misc device\n"); free_irq(s->irq, s); err_irq: release_region(s->io, ES1371_EXTENT); @@ -2822,7 +2826,7 @@ static int __init init_es1371(void) static void __exit cleanup_es1371(void) { - printk(KERN_INFO "es1371: unloading\n"); + printk(KERN_INFO PFX "unloading\n"); pci_unregister_driver(&es1371_driver); } diff --git a/drivers/sound/finetune.h b/drivers/sound/finetune.h deleted file mode 100644 index f3253cab9..000000000 --- a/drivers/sound/finetune.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifdef SEQUENCER_C -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ - - - unsigned short finetune_table[128] = - { -/* 0 */ 9439, 9447, 9456, 9464, 9473, 9481, 9490, 9499, -/* 8 */ 9507, 9516, 9524, 9533, 9542, 9550, 9559, 9567, -/* 16 */ 9576, 9585, 9593, 9602, 9611, 9619, 9628, 9637, -/* 24 */ 9645, 9654, 9663, 9672, 9680, 9689, 9698, 9707, -/* 32 */ 9715, 9724, 9733, 9742, 9750, 9759, 9768, 9777, -/* 40 */ 9786, 9795, 9803, 9812, 9821, 9830, 9839, 9848, -/* 48 */ 9857, 9866, 9874, 9883, 9892, 9901, 9910, 9919, -/* 56 */ 9928, 9937, 9946, 9955, 9964, 9973, 9982, 9991, -/* 64 */ 10000, 10009, 10018, 10027, 10036, 10045, 10054, 10063, -/* 72 */ 10072, 10082, 10091, 10100, 10109, 10118, 10127, 10136, -/* 80 */ 10145, 10155, 10164, 10173, 10182, 10191, 10201, 10210, -/* 88 */ 10219, 10228, 10237, 10247, 10256, 10265, 10274, 10284, -/* 96 */ 10293, 10302, 10312, 10321, 10330, 10340, 10349, 10358, -/* 104 */ 10368, 10377, 10386, 10396, 10405, 10415, 10424, 10433, -/* 112 */ 10443, 10452, 10462, 10471, 10481, 10490, 10499, 10509, -/* 120 */ 10518, 10528, 10537, 10547, 10556, 10566, 10576, 10585 - }; -#else - extern unsigned short finetune_table[128]; -#endif diff --git a/drivers/sound/gus_card.c b/drivers/sound/gus_card.c index f1ab09179..6a42c4ce5 100644 --- a/drivers/sound/gus_card.c +++ b/drivers/sound/gus_card.c @@ -26,8 +26,6 @@ #include "sound_config.h" #include "soundmodule.h" -#ifdef CONFIG_GUS - #include "gus_hw.h" void gusintr(int irq, void *dev_id, struct pt_regs *dummy); @@ -55,9 +53,7 @@ void attach_gus_card(struct address_info *hw_config) if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) if (sound_alloc_dma(hw_config->dma2, "GUS(2)")) printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma2); -#ifdef CONFIG_MIDI gus_midi_init(hw_config); -#endif if(request_irq(hw_config->irq, gusintr, 0, "Gravis Ultrasound", hw_config)<0) printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq); @@ -156,28 +152,20 @@ void gusintr(int irq, void *dev_id, struct pt_regs *dummy) } if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) { -#ifdef CONFIG_MIDI gus_midi_interrupt(0); -#endif } if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) { -#ifdef CONFIG_SEQUENCER if (gus_timer_enabled) sound_timer_interrupt(); gus_write8(0x45, 0); /* Ack IRQ */ gus_timer_command(4, 0x80); /* Reset IRQ flags */ -#else - gus_write8(0x45, 0); /* Stop timers */ -#endif } if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) gus_voice_irq(); } } -#endif - /* * Some extra code for the 16 bit sampling option */ @@ -191,10 +179,8 @@ int probe_gus_db16(struct address_info *hw_config) void attach_gus_db16(struct address_info *hw_config) { -#ifdef CONFIG_GUS gus_pcm_volume = 100; gus_wave_volume = 90; -#endif hw_config->slots[3] = ad1848_init("GUS 16 bit sampling", hw_config->io_base, hw_config->irq, @@ -292,4 +278,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif +#endif /* MODULE */ diff --git a/drivers/sound/gus_midi.c b/drivers/sound/gus_midi.c index 7f82d3997..175eeb6a1 100644 --- a/drivers/sound/gus_midi.c +++ b/drivers/sound/gus_midi.c @@ -12,14 +12,9 @@ */ #include <linux/config.h> - #include "sound_config.h" - #include "gus_hw.h" -#ifdef CONFIG_GUS -#ifdef CONFIG_MIDI - static int midi_busy = 0, input_opened = 0; static int my_dev; static int output_used = 0; @@ -265,6 +260,3 @@ void gus_midi_interrupt(int dummy) } restore_flags(flags); } - -#endif -#endif diff --git a/drivers/sound/gus_vol.c b/drivers/sound/gus_vol.c index 3e5752d8f..783ff7d03 100644 --- a/drivers/sound/gus_vol.c +++ b/drivers/sound/gus_vol.c @@ -12,7 +12,6 @@ #include <linux/config.h> #include "sound_config.h" -#ifdef CONFIG_GUS #include "gus_linearvol.h" #define GUS_VOLUME gus_wave_volume @@ -152,5 +151,3 @@ unsigned short gus_linear_vol(int vol, int mainvol) #endif return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100]; } - -#endif diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c index 0dddaacaa..16eac5769 100644 --- a/drivers/sound/gus_wave.c +++ b/drivers/sound/gus_wave.c @@ -25,8 +25,6 @@ #include <linux/ultrasound.h> #include "gus_hw.h" -#ifdef CONFIG_GUS - #define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024)) #define MAX_SAMPLE 150 @@ -3111,9 +3109,7 @@ void gus_wave_init(struct address_info *hw_config) hw_config->slots[0] = sdev; synth_devs[sdev] = &guswave_operations; sequencer_init(); -#ifdef CONFIG_SEQUENCER gus_tmr_install(gus_base + 8); -#endif } reset_sample_memory(); @@ -3433,8 +3429,6 @@ void guswave_dma_irq(void) } } -#ifdef CONFIG_SEQUENCER - /* * Timer stuff */ @@ -3535,6 +3529,3 @@ static void gus_tmr_install(int io_base) sound_timer_init(&gus_tmr, "GUS"); #endif } -#endif - -#endif diff --git a/drivers/sound/ics2101.c b/drivers/sound/ics2101.c index dffb83265..7cf9cc031 100644 --- a/drivers/sound/ics2101.c +++ b/drivers/sound/ics2101.c @@ -17,7 +17,6 @@ #include "sound_config.h" -#ifdef CONFIG_GUS #include <linux/ultrasound.h> #include "gus_hw.h" @@ -244,5 +243,3 @@ ics2101_mixer_init(void) } return n; } - -#endif diff --git a/drivers/sound/legacy.h b/drivers/sound/legacy.h deleted file mode 100644 index 6c3b87ce6..000000000 --- a/drivers/sound/legacy.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef _SOUND_LEGACY_H_ -#define _SOUND_LEGACY_H_ - -/* - * Force on additional support - */ - -#define __SGNXPRO__ -#define DESKPROXL -/* #define SM_GAMES */ -#define SM_WAVE - -/* - * Define legacy options. - */ - -#define SELECTED_SOUND_OPTIONS 0x0 - -#define HAVE_MAUI_BOOT -#define PSS_HAVE_LD -#define INCLUDE_TRIX_BOOT - -#define CONFIG_CS4232 -#define CONFIG_GUS -#define CONFIG_MAD16 -#define CONFIG_MAUI -#define CONFIG_MPU401 -#define CONFIG_MSS -#define CONFIG_OPL3SA1 -#define CONFIG_OPL3SA2 -#define CONFIG_PAS -#define CONFIG_PSS -#define CONFIG_SB -#define CONFIG_SOFTOSS -#define CONFIG_SSCAPE -#define CONFIG_AD1816 -#define CONFIG_TRIX -#define CONFIG_VMIDI -#define CONFIG_YM3812 - -#define CONFIG_AUDIO -#define CONFIG_MIDI -#define CONFIG_SEQUENCER - -#define CONFIG_AD1848 -#define CONFIG_MPU_EMU -#define CONFIG_SBDSP -#define CONFIG_UART401 - -#endif /* _SOUND_LEGACY_H */ diff --git a/drivers/sound/lowlevel/Config.in b/drivers/sound/lowlevel/Config.in index 30f1713f9..091a8df33 100644 --- a/drivers/sound/lowlevel/Config.in +++ b/drivers/sound/lowlevel/Config.in @@ -2,6 +2,15 @@ dep_tristate ' ACI mixer (miroPCM12)' CONFIG_ACI_MIXER $CONFIG_SOUND_OSS dep_tristate ' AWE32 synth' CONFIG_AWE32_SYNTH $CONFIG_SOUND_OSS +if [ "$CONFIG_AWE32_SYNTH" = "y" -o "$CONFIG_AWE32_SYNTH" = "m" ]; then + comment 'AWE32 PnP-ISA Cards are not always setup correctly' + bool 'Configure AWE32 synth Base Address and Default Memory Size' CONFIG_AWE32_SYNTH_DEFAULTS + if [ "$CONFIG_AWE32_SYNTH_DEFAULTS" = "y" ]; then + hex 'AWE32 synth Base Address 620' AWE_DEFAULT_BASE_ADDR 620 + int 'AWE32 synth Default Memory Size 512 1024 or 4096' AWE_DEFAULT_MEM_SIZE 512 + fi +fi + if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND" = "m" ]; then dep_tristate ' Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 $CONFIG_SOUND_OSS if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then diff --git a/drivers/sound/mad16.c b/drivers/sound/mad16.c index 8dc338aec..dedf7c843 100644 --- a/drivers/sound/mad16.c +++ b/drivers/sound/mad16.c @@ -86,8 +86,6 @@ static int mad16_cdsel; #endif -#ifdef CONFIG_MAD16 - #include "sb.h" static int already_initialized = 0; @@ -724,7 +722,7 @@ void attach_mad16(struct address_info *hw_config) void attach_mad16_mpu(struct address_info *hw_config) { -#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD) +#ifdef CONFIG_MAD16_OLDCARD if (mad_read(MC1_PORT) & 0x20) hw_config->io_base = 0x240; @@ -746,7 +744,6 @@ void attach_mad16_mpu(struct address_info *hw_config) int probe_mad16_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) static int mpu_attached = 0; static int valid_ports[] = { 0x330, 0x320, 0x310, 0x300 @@ -766,7 +763,7 @@ int probe_mad16_mpu(struct address_info *hw_config) if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ { -#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD) +#ifdef CONFIG_MAD16_OLDCARD unsigned char tmp; tmp = mad_read(MC3_PORT); @@ -899,9 +896,6 @@ int probe_mad16_mpu(struct address_info *hw_config) mad_write(MC6_PORT, tmp); /* Write MPU401 config */ return probe_uart401(hw_config); -#else - return 0; -#endif } void unload_mad16(struct address_info *hw_config) @@ -917,7 +911,7 @@ void unload_mad16(struct address_info *hw_config) void unload_mad16_mpu(struct address_info *hw_config) { -#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD) +#ifdef CONFIG_MAD16_OLDCARD if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ { sb_dsp_unload(hw_config, 0); @@ -925,9 +919,7 @@ unload_mad16_mpu(struct address_info *hw_config) } #endif -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) unload_uart401(hw_config); -#endif } #ifdef MODULE @@ -1126,9 +1118,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif - - - -/* That's all folks */ -#endif +#endif /* MODULE */ diff --git a/drivers/sound/maui.c b/drivers/sound/maui.c index 75ea6c118..532e7573b 100644 --- a/drivers/sound/maui.c +++ b/drivers/sound/maui.c @@ -32,8 +32,6 @@ #include "soundmodule.h" #include "sound_firmware.h" -#ifdef CONFIG_MAUI - static int maui_base = 0x330; static volatile int irq_ok = 0; @@ -53,12 +51,7 @@ static int *maui_osp; static int (*orig_load_patch) (int dev, int format, const char *addr, int offs, int count, int pmgr_flag) = NULL; -#ifdef HAVE_MAUI_BOOT #include "maui_boot.h" -#else -static unsigned char *maui_os = NULL; -static int maui_osLen = 0; -#endif static int maui_wait(int mask) { @@ -190,7 +183,7 @@ failure: static int maui_init(int irq) { -#ifdef __SMP__ +#ifdef CONFIG_SMP int i; #endif unsigned char bits; @@ -221,7 +214,7 @@ static int maui_init(int irq) outb((0x80), HOST_CTRL_PORT); /* Leave reset */ outb((0xD0), HOST_CTRL_PORT); /* Cause interrupt */ -#ifdef __SMP__ +#ifdef CONFIG_SMP for (i = 0; i < 1000000 && !irq_ok; i++); if (!irq_ok) @@ -500,5 +493,4 @@ void cleanup_module(void) unload_maui(&cfg); SOUND_LOCK_END; } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/midi_synth.c b/drivers/sound/midi_synth.c index 03d7d284f..6e524e21d 100644 --- a/drivers/sound/midi_synth.c +++ b/drivers/sound/midi_synth.c @@ -21,8 +21,6 @@ #include "sound_config.h" -#ifdef CONFIG_MIDI - #define _MIDI_SYNTH_C_ #include "midi_synth.h" @@ -32,9 +30,6 @@ static int sysex_state[MAX_MIDI_DEV] = {0}; static unsigned char prev_out_status[MAX_MIDI_DEV]; -#ifndef CONFIG_SEQUENCER -#define STORE(cmd) -#else #define STORE(cmd) \ { \ int len; \ @@ -42,7 +37,6 @@ static unsigned char prev_out_status[MAX_MIDI_DEV]; cmd; \ seq_input_event(obuf, len); \ } -#endif #define _seqbuf obuf #define _seqbufptr 0 @@ -709,6 +703,3 @@ midi_synth_send_sysex(int dev, unsigned char *bytes, int len) return 0; } - - -#endif diff --git a/drivers/sound/midibuf.c b/drivers/sound/midibuf.c index 426821753..32549ed2a 100644 --- a/drivers/sound/midibuf.c +++ b/drivers/sound/midibuf.c @@ -21,7 +21,6 @@ #include "sound_config.h" -#ifdef CONFIG_MIDI /* * Don't make MAX_QUEUE_SIZE larger than 4000 @@ -431,6 +430,3 @@ int MIDIbuf_avail(int dev) return DATA_AVAIL (midi_in_buf[dev]); return 0; } - - -#endif diff --git a/drivers/sound/mpu401.c b/drivers/sound/mpu401.c index 17089b0ad..b57c2dbca 100644 --- a/drivers/sound/mpu401.c +++ b/drivers/sound/mpu401.c @@ -24,15 +24,11 @@ #include "sound_config.h" #include "soundmodule.h" -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) #include "coproc.h" -#ifdef CONFIG_SEQUENCER static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL; -#endif - struct mpu_config { int base; /* @@ -159,9 +155,6 @@ static unsigned char len_tab[] = /* # of data bytes following a status 0 /* Fx */ }; -#ifndef CONFIG_SEQUENCER -#define STORE(cmd) -#else #define STORE(cmd) \ { \ int len; \ @@ -169,7 +162,6 @@ static unsigned char len_tab[] = /* # of data bytes following a status cmd; \ seq_input_event(obuf, len); \ } -#endif #define _seqbuf obuf #define _seqbufptr 0 @@ -1225,8 +1217,6 @@ void unload_mpu401(struct address_info *hw_config) * Timer stuff ****************************************************/ -#if defined(CONFIG_SEQUENCER) - static volatile int timer_initialized = 0, timer_open = 0, tmr_running = 0; static volatile int curr_tempo, curr_timebase, hw_timebase; static int max_timebase = 8; /* 8*24=192 ppqn */ @@ -1718,9 +1708,6 @@ static int mpu_timer_init(int midi_dev) } -#endif - - EXPORT_SYMBOL(probe_mpu401); EXPORT_SYMBOL(attach_mpu401); EXPORT_SYMBOL(unload_mpu401); @@ -1762,5 +1749,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/opl3.c b/drivers/sound/opl3.c index 7e005e754..acaf989ca 100644 --- a/drivers/sound/opl3.c +++ b/drivers/sound/opl3.c @@ -1204,7 +1204,7 @@ int init_module (void) void cleanup_module(void) { - if (devc) + if (devc && io != -1) { if(devc->base) release_region(devc->base,4); @@ -1217,7 +1217,7 @@ void cleanup_module(void) MODULE_PARM(io, "i"); -#endif +#endif /* MODULE */ EXPORT_SYMBOL(opl3_init); EXPORT_SYMBOL(opl3_detect); diff --git a/drivers/sound/opl3sa.c b/drivers/sound/opl3sa.c index 9e5fd5a6b..213a0a099 100644 --- a/drivers/sound/opl3sa.c +++ b/drivers/sound/opl3sa.c @@ -31,8 +31,6 @@ static int sb_initialized = 0; #endif -#ifdef CONFIG_OPL3SA1 - static int kilroy_was_here = 0; /* Don't detect twice */ static int mpu_initialized = 0; @@ -177,15 +175,12 @@ void attach_opl3sa_wss(struct address_info *hw_config) void attach_opl3sa_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) hw_config->name = "OPL3-SA (MPU401)"; attach_uart401(hw_config); -#endif } int probe_opl3sa_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) unsigned char conf; static signed char irq_bits[] = { -1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4 @@ -240,9 +235,6 @@ int probe_opl3sa_mpu(struct address_info *hw_config) mpu_initialized = 1; return probe_uart401(hw_config); -#else - return 0; -#endif } void unload_opl3sa_wss(struct address_info *hw_config) @@ -265,17 +257,13 @@ void unload_opl3sa_wss(struct address_info *hw_config) void unload_opl3sa_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) unload_uart401(hw_config); -#endif } #ifdef SB_OK void unload_opl3sa_sb(struct address_info *hw_config) { -#ifdef CONFIG_SBDSP sb_dsp_unload(hw_config); -#endif } #endif @@ -334,6 +322,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif - -#endif +#endif /* MODULE */ diff --git a/drivers/sound/opl3sa2.c b/drivers/sound/opl3sa2.c index 68c37778f..c3fff526f 100644 --- a/drivers/sound/opl3sa2.c +++ b/drivers/sound/opl3sa2.c @@ -67,8 +67,6 @@ #define CHIPSET_OPL3SAX 4 -#ifdef CONFIG_OPL3SA2 - /* What's my version? */ static int chipset = CHIPSET_UNKNOWN; @@ -443,27 +441,19 @@ static struct mixer_operations opl3sa2_mixer_operations = int probe_opl3sa2_mpu(struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) return probe_mpu401(hw_config); -#else - return 0; -#endif } void attach_opl3sa2_mpu(struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) attach_mpu401(hw_config); -#endif } void unload_opl3sa2_mpu(struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) unload_mpu401(hw_config); -#endif } @@ -706,7 +696,6 @@ int init_module(void) attach_opl3sa2(&cfg); attach_opl3sa2_mss(&mss_cfg); -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) if(mpu_io != -1) { /* MPU config: */ @@ -720,7 +709,6 @@ int init_module(void) attach_opl3sa2_mpu(&mpu_cfg); } } -#endif SOUND_LOCK; return 0; } @@ -728,16 +716,13 @@ int init_module(void) void cleanup_module(void) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) if(mpu_cfg.slots[1] != -1) { unload_opl3sa2_mpu(&mpu_cfg); } -#endif unload_opl3sa2_mss(&mss_cfg); unload_opl3sa2(&cfg); SOUND_LOCK_END; } #endif /* MODULE */ -#endif /* CONFIG_OPL3SA2 */ diff --git a/drivers/sound/pas2_card.c b/drivers/sound/pas2_card.c index 488e77a63..762871063 100644 --- a/drivers/sound/pas2_card.c +++ b/drivers/sound/pas2_card.c @@ -9,8 +9,6 @@ #include "sound_config.h" #include "soundmodule.h" -#ifdef CONFIG_PAS - static unsigned char dma_bits[] = { 4, 1, 2, 3, 0, 5, 6, 7 }; @@ -92,16 +90,12 @@ static void pasintr(int irq, void *dev_id, struct pt_regs *dummy) if (status & 0x08) { -#ifdef CONFIG_AUDIO pas_pcm_interrupt(status, 1); -#endif status &= ~0x08; } if (status & 0x10) { -#ifdef CONFIG_MIDI pas_midi_interrupt(); -#endif status &= ~0x10; } } @@ -239,7 +233,7 @@ static int config_pas_hw(struct address_info *hw_config) mix_write(0x80 | 5, 0x078B); mix_write(5, 0x078B); -#if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB) +#if !defined(DISABLE_SB_EMULATION) { struct address_info *sb_config; @@ -351,18 +345,14 @@ void attach_pas_card(struct address_info *hw_config) } if (config_pas_hw(hw_config)) { -#ifdef CONFIG_AUDIO pas_pcm_init(hw_config); -#endif -#if !defined(MODULE) && !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB) +#if !defined(MODULE) && !defined(DISABLE_SB_EMULATION) sb_dsp_disable_midi(pas_sb_base); /* No MIDI capability */ #endif -#ifdef CONFIG_MIDI pas_midi_init(); -#endif pas_init_mixer(); } } @@ -453,5 +443,4 @@ void cleanup_module(void) } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/pas2_midi.c b/drivers/sound/pas2_midi.c index d029d4c4d..0dda4df5c 100644 --- a/drivers/sound/pas2_midi.c +++ b/drivers/sound/pas2_midi.c @@ -12,12 +12,8 @@ */ #include <linux/config.h> - #include "sound_config.h" -#ifdef CONFIG_PAS -#ifdef CONFIG_MIDI - static int midi_busy = 0, input_opened = 0; static int my_dev; @@ -264,6 +260,3 @@ void pas_midi_interrupt(void) } pas_write(stat, 0x1B88); /* Acknowledge interrupts */ } - -#endif -#endif diff --git a/drivers/sound/pas2_mixer.c b/drivers/sound/pas2_mixer.c index 04a98fead..3b9b167c1 100644 --- a/drivers/sound/pas2_mixer.c +++ b/drivers/sound/pas2_mixer.c @@ -19,8 +19,6 @@ #include "sound_config.h" -#ifdef CONFIG_PAS - #ifndef DEB #define DEB(what) /* (what) */ #endif @@ -332,5 +330,3 @@ pas_init_mixer(void) } return 1; } - -#endif diff --git a/drivers/sound/pas2_pcm.c b/drivers/sound/pas2_pcm.c index dc49d04b5..c0776ae4f 100644 --- a/drivers/sound/pas2_pcm.c +++ b/drivers/sound/pas2_pcm.c @@ -18,9 +18,6 @@ #include "sound_config.h" -#ifdef CONFIG_PAS -#ifdef CONFIG_AUDIO - #ifndef DEB #define DEB(WHAT) #endif @@ -440,6 +437,3 @@ void pas_pcm_interrupt(unsigned char status, int cause) } } } - -#endif -#endif diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c index 1fa943741..ffbb08b77 100644 --- a/drivers/sound/pss.c +++ b/drivers/sound/pss.c @@ -34,9 +34,6 @@ #include "sound_firmware.h" #include "soundmodule.h" -#ifdef CONFIG_PSS -#ifdef CONFIG_AUDIO - /* * PSS registers. */ @@ -82,14 +79,7 @@ #define NO_WSS_MIXER -1 #include "coproc.h" - -#ifdef PSS_HAVE_LD #include "pss_boot.h" -#else -static int pss_synthLen = 0; -static unsigned char *pss_synth = -NULL; -#endif /* If compiled into kernel, it enable or disable pss mixer */ #ifdef CONFIG_PSS_MIXER @@ -675,11 +665,7 @@ int probe_pss_mpu(struct address_info *hw_config) break; /* No more input */ } -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) return probe_mpu401(hw_config); -#else - return 0; -#endif } static int pss_coproc_open(void *dev_info, int sub_device) @@ -926,11 +912,9 @@ static coproc_operations pss_coproc_operations = void attach_pss_mpu(struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) attach_mpu401(hw_config); /* Slot 1 */ if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations; -#endif } int probe_pss_mss(struct address_info *hw_config) @@ -1015,9 +999,7 @@ void unload_pss(struct address_info *hw_config) void unload_pss_mpu(struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) unload_mpu401(hw_config); -#endif } void unload_pss_mss(struct address_info *hw_config) @@ -1114,6 +1096,4 @@ void cleanup_module(void) unload_pss(&cfgpss); SOUND_LOCK_END; } -#endif -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h index 2cb785565..13c1cce55 100644 --- a/drivers/sound/sb.h +++ b/drivers/sound/sb.h @@ -1,7 +1,5 @@ #include <linux/config.h> -#include "legacy.h" -#ifdef CONFIG_SBDSP #define DSP_RESET (devc->base + 0x6) #define DSP_READ (devc->base + 0xA) #define DSP_WRITE (devc->base + 0xC) @@ -168,4 +166,3 @@ void sb_audio_close(int dev); extern int acer; extern sb_devc *last_sb; -#endif diff --git a/drivers/sound/sb_audio.c b/drivers/sound/sb_audio.c index 84d35b444..672b8f408 100644 --- a/drivers/sound/sb_audio.c +++ b/drivers/sound/sb_audio.c @@ -24,8 +24,6 @@ #include <linux/config.h> #include "sound_config.h" -#ifdef CONFIG_SBDSP - #include "sb_mixer.h" #include "sb.h" @@ -1126,5 +1124,3 @@ void sb_audio_init(sb_devc * devc, char *name) audio_devs[devc->dev]->mixer_dev = devc->my_mixerdev; audio_devs[devc->dev]->min_fragment = 5; } - -#endif diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c index 3a4a94247..49a55288f 100644 --- a/drivers/sound/sb_card.c +++ b/drivers/sound/sb_card.c @@ -37,8 +37,6 @@ #include "sound_config.h" #include "soundmodule.h" -#ifdef CONFIG_SBDSP - #include "sb_mixer.h" #include "sb.h" @@ -113,11 +111,11 @@ iobase=0x%x irq=%d lo_dma=%d hi_dma=%d\n", } #endif - /* This is useless since is done by sb_dsp_detect - azummo*/ + /* This is useless since is done by sb_dsp_detect - azummo */ if (check_region(hw_config->io_base, 16)) { - printk(KERN_ERR "sb_card: I/O port %x is already in use\n\n", hw_config->io_base); + printk(KERN_ERR "sb_card: I/O port 0x%x is already in use\n\n", hw_config->io_base); return 0; } return sb_dsp_detect(hw_config, 0, 0); @@ -138,11 +136,10 @@ static struct address_info config; static struct address_info config_mpu; struct pci_dev *sb_dev = NULL, - *wss_dev = NULL, - *jp_dev = NULL, -/* *ide_dev = NULL, */ - *mpu_dev = NULL, - *wt_dev = NULL; + *wss_dev = NULL, + *jp_dev = NULL, + *mpu_dev = NULL, + *wt_dev = NULL; /* * Note DMA2 of -1 has the right meaning in the SB16 driver as well * as here. It will cause either an error if it is needed or a fallback @@ -153,49 +150,49 @@ int mpu_io = 0; int io = -1; int irq = -1; int dma = -1; -int dma16 = -1; /* Set this for modules that need it */ -int type = 0; /* Can set this to a specific card type */ -int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ -int trix = 0; /* Set trix=1 to load this as support for trix */ -int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ -int support = 0; /* Set support to load this as a support module */ -int sm_games = 0; /* Mixer - see sb_mixer.c */ -int acer = 0; /* Do acer notebook init */ - -#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE -int isapnp = 1; -int isapnpjump = 0; -int nosbwave = 0; /* This option will be removed when the new awe_wave driver will be in the kernel tree */ +int dma16 = -1; /* Set this for modules that need it */ +int type = 0; /* Can set this to a specific card type */ +int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ +int trix = 0; /* Set trix=1 to load this as support for trix */ +int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ +int support = 0; /* Set support to load this as a support module */ +int sm_games = 0; /* Mixer - see sb_mixer.c */ +int acer = 0; /* Do acer notebook init */ + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +int isapnp = 1; +int isapnpjump = 0; +int nosbwave = 0; /* This option will be removed when the new awe_wave driver will be in the kernel tree */ #else -int isapnp = 0; +int isapnp = 0; #endif MODULE_DESCRIPTION("Soundblaster driver"); -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(dma, "i"); -MODULE_PARM(dma16, "i"); -MODULE_PARM(mpu_io, "i"); -MODULE_PARM(type, "i"); -MODULE_PARM(mad16, "i"); -MODULE_PARM(support, "i"); -MODULE_PARM(trix, "i"); -MODULE_PARM(pas2, "i"); -MODULE_PARM(sm_games, "i"); -MODULE_PARM(esstype, "i"); -MODULE_PARM(acer, "i"); +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(dma, "i"); +MODULE_PARM(dma16, "i"); +MODULE_PARM(mpu_io, "i"); +MODULE_PARM(type, "i"); +MODULE_PARM(mad16, "i"); +MODULE_PARM(support, "i"); +MODULE_PARM(trix, "i"); +MODULE_PARM(pas2, "i"); +MODULE_PARM(sm_games, "i"); +MODULE_PARM(esstype, "i"); +MODULE_PARM(acer, "i"); #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE -MODULE_PARM(isapnp, "i"); -MODULE_PARM(isapnpjump, "i"); +MODULE_PARM(isapnp, "i"); +MODULE_PARM(isapnpjump, "i"); MODULE_PARM(nosbwave, "i"); MODULE_PARM_DESC(isapnp, "When set to 0, Plug & Play support will be disabled"); -MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke."); -MODULE_PARM_DESC(nosbwave, "Disable SB AWE 32/64 Wavetable initialization. Use this option with the new awe_wave driver."); +MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke."); +MODULE_PARM_DESC(nosbwave, "Disable SB AWE 32/64 Wavetable initialization. Use this option with the new awe_wave driver."); #endif -MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)"); +MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)"); MODULE_PARM_DESC(irq, "IRQ (5,7,9,10)"); MODULE_PARM_DESC(dma, "8-bit DMA channel (0,1,3)"); MODULE_PARM_DESC(dma16, "16-bit DMA channel (5,6,7)"); @@ -211,7 +208,7 @@ MODULE_PARM_DESC(acer, "Set this to detect cards in some ACER notebooks"); void *smw_free = NULL; -#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE /* That's useful. */ @@ -253,7 +250,7 @@ static struct pci_dev *sb_init_generic(struct pci_bus *bus, struct pci_dev *card hw_config->irq = sb_dev->irq_resource[0].start; hw_config->dma = sb_dev->dma_resource[0].start; hw_config->dma2 = sb_dev->dma_resource[1].start; - mpu_config->io_base = sb_dev->resource[1].start; + mpu_config->io_base = sb_dev->resource[1].start; } } return(sb_dev); @@ -270,8 +267,8 @@ static struct pci_dev *sb_init_ess(struct pci_bus *bus, struct pci_dev *card, st hw_config->io_base = sb_dev->resource[0].start; hw_config->irq = sb_dev->irq_resource[0].start; hw_config->dma = sb_dev->dma_resource[0].start; - hw_config->dma2 = sb_dev->dma_resource[1].start; - mpu_config->io_base = sb_dev->resource[2].start; + hw_config->dma2 = sb_dev->dma_resource[1].start; + mpu_config->io_base = sb_dev->resource[2].start; } } return(sb_dev); @@ -291,7 +288,7 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st */ if((sb_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL))) + ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL))) { #ifdef CMI8330_DMA0BAD int dmahack = 0; @@ -299,9 +296,9 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st sb_dev->prepare(sb_dev); /* This device doesn't work with DMA 0, so we must allocate - * it to prevent PnP routines to assign it to the card. + * it to prevent PnP routines to assign it to the card. * - * I know i could have inlined the following lines, but it's cleaner + * I know i could have inlined the following lines, but it's cleaner * this way. */ @@ -327,12 +324,9 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st } #ifdef CMI8330_DMA0BAD - if(dmahack) - free_dma(0); + if(dmahack) free_dma(0); #endif - if(!sb_dev) return(NULL); - } else printk(KERN_ERR "sb: CMI8330 panic: sb base not found\n"); @@ -340,9 +334,8 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st /* @H@0001:mpu */ -#ifdef CONFIG_MIDI if((mpu_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL))) + ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL))) { mpu_dev->prepare(mpu_dev); @@ -359,17 +352,15 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st } else printk(KERN_ERR "sb: CMI8330 panic: mpu not found\n"); -#endif /* @P@:Gameport */ if((jp_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL))) + ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL))) { jp_dev->prepare(jp_dev); - if((jp_dev = activate_dev("CMI8330", "gameport", jp_dev))) show_base("CMI8330", "gameport", &jp_dev->resource[0]); @@ -382,7 +373,7 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st #if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE) if((wss_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL))) + ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL))) { wss_dev->prepare(wss_dev); @@ -405,7 +396,7 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st /* Specific support for awe will be dropped when: * a) The new awe_wawe driver with PnP support will be introduced in the kernel - * b) The joystick driver will support PnP + * b) The joystick driver will support PnP - a little patch is available from me....hint, hint :-) */ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) @@ -430,7 +421,7 @@ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, st mpu_config->io_base = sb_dev->resource[1].start; - show_base("AWE", "sb", &sb_dev->resource[0]); + show_base("AWE", "sb", &sb_dev->resource[0]); show_base("AWE", "mpu", &sb_dev->resource[1]); show_base("AWE", "opl3", &sb_dev->resource[2]); } @@ -445,7 +436,7 @@ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, st * CTL7001:Game SB32 */ - if( (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)) || + if( (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)) || (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7001), NULL)) ) { jp_dev->prepare(jp_dev); @@ -459,12 +450,13 @@ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, st /* CTL0022:WaveTable SB64 * CTL0021:WaveTable SB32 + * CTL0023:WaveTable Sb64 */ if( nosbwave == 0 && - ( (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), NULL)) || - (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)) || - (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), NULL)) )) + ( ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), NULL)) || + ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)) || + ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), NULL)) )) { wt_dev->prepare(wt_dev); @@ -478,26 +470,6 @@ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, st else printk(KERN_ERR "sb: AWE panic: wavetable not found\n"); - - /* CTL2011:IDE SB32/64 - */ - -/* No reasons to enable this... or not? */ -/* - if( (ide_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x2011), NULL)) ) - { - ide_dev->prepare(ide_dev); - - if((ide_dev = activate_dev("AWE", "IDE", ide_dev))) - { - show_base("AWE", "IDE 1", &ide_dev->resource[0]); - show_base("AWE", "IDE 2", &ide_dev->resource[1]); - } - } - else - printk(KERN_ERR "sb: AWE panic: IDE not found\n"); -*/ - printk(KERN_INFO "sb: AWE mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n"); return(sb_dev); @@ -508,31 +480,31 @@ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, st static struct { unsigned short vendor, function, flags; struct pci_dev * (*initfunc)(struct pci_bus *, struct pci_dev *, struct address_info *, struct address_info *); char *name; } isapnp_sb_list[] __initdata = { - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0, &sb_init_awe, "Sound Blaster 32" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0039), 0, &sb_init_awe, "Sound Blaster AWE 32" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0, &sb_init_awe, "Sound Blaster AWE 64" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0, &sb_init_awe, "Sound Blaster AWE 64" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0, &sb_init_awe, "Sound Blaster AWE 64" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" }, - {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" }, - {0} + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0, &sb_init_awe, "Sound Blaster 32" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0039), 0, &sb_init_awe, "Sound Blaster AWE 32" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0, &sb_init_awe, "Sound Blaster AWE 64" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0, &sb_init_awe, "Sound Blaster AWE 64" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0, &sb_init_awe, "Sound Blaster AWE 64" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" }, + {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" }, + {0} }; static int __init sb_init_isapnp(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot) { struct pci_dev *idev = NULL; - /* You missed the init func? That's bad. */ + /* You missed the init func? That's bad. */ if(isapnp_sb_list[slot].initfunc) { char *busname = bus->name[0] ? bus->name : isapnp_sb_list[slot].name; @@ -587,9 +559,9 @@ static int __init sb_probe_isapnp(struct address_info *hw_config, struct address struct pci_bus *bus = NULL; while ((bus = isapnp_find_card( - isapnp_sb_list[i].vendor, - isapnp_sb_list[i].function, - bus))) { + isapnp_sb_list[i].vendor, + isapnp_sb_list[i].function, + bus))) { if(sb_init_isapnp(hw_config, mpu_config, bus, NULL, i)) return 0; @@ -608,9 +580,9 @@ static int __init sb_probe_isapnp(struct address_info *hw_config, struct address struct pci_dev *card = NULL; while ((card = isapnp_find_dev(NULL, - isapnp_sb_list[i].vendor, - isapnp_sb_list[i].function, - card))) { + isapnp_sb_list[i].vendor, + isapnp_sb_list[i].function, + card))) { if(sb_init_isapnp(hw_config, mpu_config, card->bus, card, i)) return 0; @@ -632,7 +604,7 @@ int init_module(void) able to disable PNP support for this single driver! */ -#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE if(isapnp && (sb_probe_isapnp(&config, &config_mpu) < 0) ) { printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n"); @@ -647,10 +619,10 @@ int init_module(void) return -EINVAL; } - config.io_base = io; - config.irq = irq; - config.dma = dma; - config.dma2 = dma16; + config.io_base = io; + config.irq = irq; + config.dma = dma; + config.dma2 = dma16; } config.card_subtype = type; @@ -686,7 +658,6 @@ void cleanup_module(void) if(sb_dev) sb_dev->deactivate(sb_dev); if(jp_dev) jp_dev->deactivate(jp_dev); if(wt_dev) wt_dev->deactivate(wt_dev); -/* if(ide_dev) wt_dev->deactivate(ide_dev); */ if(mpu_dev) mpu_dev->deactivate(mpu_dev); if(wss_dev) wss_dev->deactivate(wss_dev); } @@ -716,5 +687,3 @@ EXPORT_SYMBOL(sb_be_quiet); EXPORT_SYMBOL(attach_sbmpu); EXPORT_SYMBOL(probe_sbmpu); EXPORT_SYMBOL(unload_sbmpu); - -#endif diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c index 37dd03f4f..bda10bfad 100644 --- a/drivers/sound/sb_common.c +++ b/drivers/sound/sb_common.c @@ -23,12 +23,6 @@ #include "sound_config.h" #include "sound_firmware.h" -#ifdef CONFIG_SBDSP - -#ifndef CONFIG_AUDIO -#error You will need to configure the sound driver with CONFIG_AUDIO option. -#endif - #include "sb_mixer.h" #include "sb.h" @@ -114,11 +108,9 @@ static void sb_intr (sb_devc *devc) { src = sb_getmixer(devc, IRQ_STAT); /* Interrupt source register */ -#if defined(CONFIG_MIDI)&& defined(CONFIG_UART401) if (src & 4) /* MPU401 interrupt */ if(devc->midi_irq_cookie) uart401intr(devc->irq, devc->midi_irq_cookie, NULL); -#endif if (!(src & 3)) return; /* Not a DSP interrupt */ @@ -139,9 +131,7 @@ static void sb_intr (sb_devc *devc) break; case IMODE_MIDI: -#ifdef CONFIG_MIDI sb_midi_interrupt(devc); -#endif break; default: @@ -284,7 +274,6 @@ static int sb16_set_dma_hw(sb_devc * devc) return 1; } -#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) static void sb16_set_mpu_port(sb_devc * devc, struct address_info *hw_config) { /* @@ -307,7 +296,6 @@ static void sb16_set_mpu_port(sb_devc * devc, struct address_info *hw_config) printk(KERN_ERR "SB16: Invalid MIDI I/O port %x\n", hw_config->io_base); } } -#endif static int sb16_set_irq_hw(sb_devc * devc, int level) { @@ -807,10 +795,8 @@ int sb_dsp_init(struct address_info *hw_config) if (devc->major == 3 || devc->major == 4) sb_mixer_init(devc); -#ifdef CONFIG_MIDI if (!(devc->caps & SB_NO_MIDI)) sb_dsp_midi_init(devc); -#endif if (hw_config->name == NULL) hw_config->name = "Sound Blaster (8 BIT/MONO ONLY)"; @@ -971,8 +957,6 @@ void sb_chgmixer sb_setmixer(devc, reg, value); } -#ifdef CONFIG_MIDI - /* * MPU401 MIDI initialization. */ @@ -1200,10 +1184,8 @@ void attach_sbmpu(struct address_info *hw_config) #endif return; } -#if defined(CONFIG_UART401) attach_uart401(hw_config); last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc; -#endif } int probe_sbmpu(struct address_info *hw_config) @@ -1244,7 +1226,6 @@ int probe_sbmpu(struct address_info *hw_config) } #endif -#if defined(CONFIG_UART401) if (check_region(hw_config->io_base, 4)) { printk(KERN_ERR "sbmpu: I/O port conflict (%x)\n", hw_config->io_base); @@ -1279,9 +1260,6 @@ int probe_sbmpu(struct address_info *hw_config) return 0; } return probe_uart401(hw_config); -#else - return 0; -#endif } void unload_sbmpu(struct address_info *hw_config) @@ -1292,23 +1270,5 @@ void unload_sbmpu(struct address_info *hw_config) return; } #endif -#if defined(CONFIG_UART401) unload_uart401(hw_config); -#endif -} -#else /* !CONFIG_MIDI */ - -void unload_sbmpu(struct address_info *hw_config) -{ -} - -int probe_sbmpu(struct address_info *hw_config) -{ - return 0; } - -void attach_sbmpu(struct address_info *hw_config) -{ -} -#endif -#endif diff --git a/drivers/sound/sb_midi.c b/drivers/sound/sb_midi.c index 31a299a96..9c3cef2bb 100644 --- a/drivers/sound/sb_midi.c +++ b/drivers/sound/sb_midi.c @@ -14,9 +14,6 @@ #include <linux/config.h> #include "sound_config.h" -#ifdef CONFIG_SBDSP -#ifdef CONFIG_MIDI - #include "sb.h" #undef SB_TEST_IRQ @@ -210,6 +207,3 @@ void sb_dsp_midi_init(sb_devc * devc) midi_devs[dev]->converter->id = "SBMIDI"; sequencer_init(); } - -#endif -#endif diff --git a/drivers/sound/sb_mixer.c b/drivers/sound/sb_mixer.c index 0bad5eb58..f786b69b5 100644 --- a/drivers/sound/sb_mixer.c +++ b/drivers/sound/sb_mixer.c @@ -19,7 +19,6 @@ #include <linux/config.h> #include "sound_config.h" -#ifdef CONFIG_SBDSP #define __SB_MIXER_C__ #include "sb.h" @@ -78,27 +77,6 @@ MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0) }; -#ifdef __SGNXPRO__ -#if 0 -static mixer_tab sgnxpro_mix = { /* not used anywhere */ -MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4), -MIX_ENT(SOUND_MIXER_BASS, 0x46, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x42, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0) -}; -#endif -#endif - static mixer_tab sb16_mix = { MIX_ENT(SOUND_MIXER_VOLUME, 0x30, 7, 5, 0x31, 7, 5), MIX_ENT(SOUND_MIXER_BASS, 0x46, 7, 4, 0x47, 7, 4), @@ -763,5 +741,3 @@ int sb_mixer_init(sb_devc * devc) sb_mixer_reset(devc); return 1; } - -#endif diff --git a/drivers/sound/sb_mixer.h b/drivers/sound/sb_mixer.h index d53df66ff..1e1a1b8d2 100644 --- a/drivers/sound/sb_mixer.h +++ b/drivers/sound/sb_mixer.h @@ -24,9 +24,6 @@ * */ #include <linux/config.h> -#include "legacy.h" - -#ifdef CONFIG_SBDSP /* * Mixer registers @@ -108,6 +105,3 @@ #define ALS007_LINE 6 #define ALS007_CD 2 #define ALS007_SYNTH 7 - -#endif - diff --git a/drivers/sound/sequencer.c b/drivers/sound/sequencer.c index 8fee21c6b..0ef3b67ad 100644 --- a/drivers/sound/sequencer.c +++ b/drivers/sound/sequencer.c @@ -15,15 +15,12 @@ * Alan Cox : reformatted and fixed a pair of null pointer bugs */ #include <linux/config.h> - #include <linux/kmod.h> - #define SEQUENCER_C #include "sound_config.h" - -#ifdef CONFIG_SEQUENCER #include "softoss.h" + int (*softsynthp) (int cmd, int parm1, int parm2, unsigned long parm3) = NULL; #include "midi_ctrl.h" @@ -719,9 +716,7 @@ static void seq_local_event(unsigned char *event_rec) switch (cmd) { case LOCL_STARTAUDIO: -#ifdef CONFIG_AUDIO DMAbuf_start_devices(parm); -#endif break; default: @@ -1692,9 +1687,7 @@ void sequencer_init(void) if (sequencer_ok) return; -#ifdef CONFIG_MIDI MIDIbuf_init(); -#endif queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ); if (queue == NULL) { @@ -1724,5 +1717,3 @@ void sequencer_unload(void) iqueue=NULL; } } - -#endif diff --git a/drivers/sound/sequencer_syms.c b/drivers/sound/sequencer_syms.c index 053cd1e01..014d77841 100644 --- a/drivers/sound/sequencer_syms.c +++ b/drivers/sound/sequencer_syms.c @@ -9,7 +9,6 @@ char sequencer_syms_symbol; #include "sound_config.h" - #include "sound_calls.h" EXPORT_SYMBOL(note_to_freq); diff --git a/drivers/sound/sgalaxy.c b/drivers/sound/sgalaxy.c index 7bbd36657..1f23125a8 100644 --- a/drivers/sound/sgalaxy.c +++ b/drivers/sound/sgalaxy.c @@ -24,8 +24,6 @@ #include "sound_config.h" #include "soundmodule.h" -#if defined(CONFIG_SGALAXY) || defined (MODULE) - static void sleep( unsigned howlong ) { current->state = TASK_INTERRUPTIBLE; @@ -182,5 +180,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/softoss.c b/drivers/sound/softoss.c index 2a9302bbc..ac8e4034f 100644 --- a/drivers/sound/softoss.c +++ b/drivers/sound/softoss.c @@ -30,8 +30,6 @@ #include "sound_config.h" #include "soundmodule.h" - -#ifdef CONFIG_SOFTOSS #include "softoss.h" #include <linux/ultrasound.h> @@ -1529,5 +1527,4 @@ void cleanup_module(void) sound_unload_timerdev(devc->timerdev); SOUND_LOCK_END; } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/softoss_rs.c b/drivers/sound/softoss_rs.c index 2fa95f748..75f1bbb90 100644 --- a/drivers/sound/softoss_rs.c +++ b/drivers/sound/softoss_rs.c @@ -17,8 +17,6 @@ #include "sound_config.h" - -#ifdef CONFIG_SOFTOSS #include "softoss.h" void softsynth_resample_loop(short *buf, int loops) @@ -130,4 +128,3 @@ void softsynth_resample_loop(short *buf, int loops) } } /* Mix one sample */ } -#endif diff --git a/drivers/sound/sound_config.h b/drivers/sound/sound_config.h index 18ff32e34..7621f33be 100644 --- a/drivers/sound/sound_config.h +++ b/drivers/sound/sound_config.h @@ -18,7 +18,6 @@ #include <linux/fs.h> #include <linux/sound.h> -#include "legacy.h" #include "os.h" #include "soundvers.h" diff --git a/drivers/sound/sound_timer.c b/drivers/sound/sound_timer.c index 60f031ac8..b32759008 100644 --- a/drivers/sound/sound_timer.c +++ b/drivers/sound/sound_timer.c @@ -17,8 +17,6 @@ #include "sound_config.h" -#if defined(CONFIG_SEQUENCER) - static volatile int initialized = 0, opened = 0, tmr_running = 0; static volatile time_t tmr_offs, tmr_ctr; static volatile unsigned long ticks_offs; @@ -318,5 +316,3 @@ void sound_timer_init(struct sound_lowlev_timer *t, char *name) strcpy(sound_timer.info.name, name); sound_timer_devs[n] = &sound_timer; } - -#endif diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index a1d682969..81f9cdb19 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -45,8 +45,11 @@ #include <linux/delay.h> #include <linux/proc_fs.h> #include <linux/smp_lock.h> - #include "soundmodule.h" + +/* From obsolete legacy.h */ +#define SELECTED_SOUND_OPTIONS 0x0 + struct notifier_block *sound_locker=(struct notifier_block *)0; static int lock_depth = 0; @@ -219,9 +222,6 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len } if (!sound_started) len += sprintf(buffer + len, "\n\n***** Sound driver not started *****\n\n"); -#ifndef CONFIG_AUDIO - len += sprintf(buffer + len, "\nAudio devices: NOT ENABLED IN CONFIG\n"); -#else len += sprintf(buffer + len, "\nAudio devices:\n"); for (i = 0; (i < num_audiodevs) && (pos <= offset + length); i++) { if (audio_devs[i] == NULL) @@ -234,11 +234,7 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len begin = pos; } } -#endif -#ifndef CONFIG_SEQUENCER - len += sprintf(buffer + len, "\nSynth devices: NOT ENABLED IN CONFIG\n"); -#else len += sprintf(buffer + len, "\nSynth devices:\n"); for (i = 0; (i < num_synths) && (pos <= offset + length); i++) { if (synth_devs[i] == NULL) @@ -250,11 +246,7 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len begin = pos; } } -#endif -#ifndef CONFIG_MIDI - len += sprintf(buffer + len, "\nMidi devices: NOT ENABLED IN CONFIG\n"); -#else len += sprintf(buffer + len, "\nMidi devices:\n"); for (i = 0; (i < num_midis) && (pos <= offset + length); i++) { if (midi_devs[i] == NULL) @@ -266,9 +258,7 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len begin = pos; } } -#endif -#ifdef CONFIG_SEQUENCER len += sprintf(buffer + len, "\nTimers:\n"); for (i = 0; (i < num_sound_timers) && (pos <= offset + length); i++) { @@ -281,7 +271,6 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len begin = pos; } } -#endif len += sprintf(buffer + len, "\nMixers:\n"); for (i = 0; (i < num_mixers) && (pos <= offset + length); i++) { @@ -388,25 +377,19 @@ static ssize_t sound_read(struct file *file, char *buf, size_t count, loff_t *pp ret = sndstat_file_read(file, buf, count, ppos); break; -#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: ret = audio_read(dev, file, buf, count); break; -#endif -#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: ret = sequencer_read(dev, file, buf, count); break; -#endif -#ifdef CONFIG_MIDI case SND_DEV_MIDIN: ret = MIDIbuf_read(dev, file, buf, count); -#endif } unlock_kernel(); return ret; @@ -420,26 +403,20 @@ static ssize_t sound_write(struct file *file, const char *buf, size_t count, lof lock_kernel(); DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count)); switch (dev & 0x0f) { -#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: ret = sequencer_write(dev, file, buf, count); break; -#endif -#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: ret = audio_write(dev, file, buf, count); break; -#endif -#ifdef CONFIG_MIDI case SND_DEV_MIDIN: ret = MIDIbuf_write(dev, file, buf, count); break; -#endif } unlock_kernel(); return ret; @@ -483,29 +460,23 @@ static int sound_open(struct inode *inode, struct file *file) return -ENXIO; break; -#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: if ((retval = sequencer_open(dev, file)) < 0) return retval; break; -#endif -#ifdef CONFIG_MIDI case SND_DEV_MIDIN: if ((retval = MIDIbuf_open(dev, file)) < 0) return retval; break; -#endif -#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: if ((retval = audio_open(dev, file)) < 0) return retval; break; -#endif default: printk(KERN_ERR "Invalid minor device %d\n", dev); @@ -531,26 +502,20 @@ static int sound_release(struct inode *inode, struct file *file) case SND_DEV_CTL: break; -#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: sequencer_release(dev, file); break; -#endif -#ifdef CONFIG_MIDI case SND_DEV_MIDIN: MIDIbuf_release(dev, file); break; -#endif -#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: audio_release(dev, file); break; -#endif default: printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); @@ -641,13 +606,11 @@ static int sound_ioctl(struct inode *inode, struct file *file, (dev & 0x0f) != SND_DEV_CTL) { dtype = dev & 0x0f; switch (dtype) { -#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: return sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev, cmd, (caddr_t)arg); -#endif default: return sound_mixer_ioctl(dev >> 4, cmd, (caddr_t)arg); @@ -661,25 +624,19 @@ static int sound_ioctl(struct inode *inode, struct file *file, return set_mixer_levels((caddr_t)arg); return sound_mixer_ioctl(dev >> 4, cmd, (caddr_t)arg); -#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_ioctl(dev, file, cmd, (caddr_t)arg); -#endif -#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: return audio_ioctl(dev, file, cmd, (caddr_t)arg); break; -#endif -#ifdef CONFIG_MIDI case SND_DEV_MIDIN: return MIDIbuf_ioctl(dev, file, cmd, (caddr_t)arg); break; -#endif } return -EINVAL; @@ -692,23 +649,17 @@ static unsigned int sound_poll(struct file *file, poll_table * wait) DEB(printk("sound_poll(dev=%d)\n", dev)); switch (dev & 0x0f) { -#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_poll(dev, file, wait); -#endif -#ifdef CONFIG_MIDI case SND_DEV_MIDIN: return MIDIbuf_poll(dev, file, wait); -#endif -#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: return DMAbuf_poll(file, dev >> 4, wait); -#endif } return 0; } @@ -828,13 +779,11 @@ static const struct { umode_t mode; int *num; } dev_list[] = { /* list of minor devices */ -#ifdef CONFIG_AUDIO /* seems to be some confusion here -- this device is not in the device list */ {SND_DEV_DSP16, "dspW", S_IWUGO | S_IRUSR | S_IRGRP, &num_audiodevs}, {SND_DEV_AUDIO, "audio", S_IWUGO | S_IRUSR | S_IRGRP, &num_audiodevs}, -#endif /* CONFIG_AUDIO */ }; static char * @@ -903,12 +852,10 @@ soundcard_init(void) return; /* No cards detected */ #endif -#ifdef CONFIG_AUDIO if (num_audiodevs || modular) /* Audio devices present */ { audio_init_devices(); } -#endif #ifdef CONFIG_PROC_FS if (!create_proc_info_entry("sound", 0, NULL, sound_proc_get_info)) printk(KERN_ERR "sound: registering /proc/sound failed\n"); @@ -1000,9 +947,7 @@ void cleanup_module(void) if (chrdev_registered) destroy_special_devices(); -#ifdef CONFIG_SEQUENCER sound_stop_timer(); -#endif #ifdef CONFIG_LOWLEVEL_SOUND { @@ -1093,8 +1038,6 @@ void sound_close_dma(int chn) restore_flags(flags); } -#ifdef CONFIG_SEQUENCER - static void do_sequencer_timer(unsigned long dummy) { sequencer_timer(0); @@ -1129,7 +1072,6 @@ void sound_stop_timer(void) { del_timer(&seq_timer);; } -#endif void conf_printf(char *name, struct address_info *hw_config) { diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c index 4dce39e81..1c06b7c31 100644 --- a/drivers/sound/sscape.c +++ b/drivers/sound/sscape.c @@ -41,9 +41,6 @@ #include <linux/delay.h> #include <linux/proc_fs.h> - -#ifdef CONFIG_SSCAPE - #include "coproc.h" /* @@ -722,7 +719,6 @@ void attach_sscape(struct address_info *hw_config) } #endif -#if defined(CONFIG_MIDI) && defined(CONFIG_MPU_EMU) if (probe_mpu401(hw_config)) hw_config->always_detect = 1; hw_config->name = "SoundScape"; @@ -736,7 +732,6 @@ void attach_sscape(struct address_info *hw_config) sscape_mididev = hw_config->slots[1]; midi_devs[hw_config->slots[1]]->coproc = &sscape_coproc_operations; } -#endif sscape_write(devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ devc->ok = 1; devc->failed = 0; @@ -1421,9 +1416,7 @@ void attach_ss_ms_sound(struct address_info *hw_config) void unload_sscape(struct address_info *hw_config) { release_region(devc->base + 2, 6); -#if defined(CONFIG_MPU_EMU) && defined(CONFIG_MIDI) unload_mpu401(hw_config); -#endif } void unload_ss_ms_sound(struct address_info *hw_config) @@ -1516,5 +1509,4 @@ void cleanup_module(void) unload_sscape(&mpu_config); } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/sys_timer.c b/drivers/sound/sys_timer.c index e7ca0c84b..5a8a7787a 100644 --- a/drivers/sound/sys_timer.c +++ b/drivers/sound/sys_timer.c @@ -20,8 +20,6 @@ #include "sound_config.h" -#ifdef CONFIG_SEQUENCER - static volatile int opened = 0, tmr_running = 0; static volatile time_t tmr_offs, tmr_ctr; static volatile unsigned long ticks_offs; @@ -289,5 +287,3 @@ struct sound_timer_operations default_sound_timer = def_tmr_ioctl, def_tmr_arm }; - -#endif diff --git a/drivers/sound/trident.c b/drivers/sound/trident.c index bbe991eb2..de01c6cbe 100644 --- a/drivers/sound/trident.c +++ b/drivers/sound/trident.c @@ -79,11 +79,11 @@ #include <linux/init.h> #include <linux/poll.h> #include <linux/spinlock.h> +#include <linux/ac97_codec.h> #include <asm/uaccess.h> #include <asm/hardirq.h> #include "trident.h" -#include "ac97_codec.h" #undef DEBUG @@ -1131,7 +1131,7 @@ static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* Midi - TODO */ } - /* manually clear interrupt status, bad hardware design, balme T^2 */ + /* manually clear interrupt status, bad hardware design, blame T^2 */ outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW), TRID_REG(card, T4D_MISCINT)); spin_unlock(&card->lock); diff --git a/drivers/sound/trix.c b/drivers/sound/trix.c index b54d00992..107c6ca9e 100644 --- a/drivers/sound/trix.c +++ b/drivers/sound/trix.c @@ -23,15 +23,8 @@ #include "sb.h" #include "sound_firmware.h" -#ifdef CONFIG_TRIX - -#ifdef INCLUDE_TRIX_BOOT #include <linux/init.h> #include "trix_boot.h" -#else -static unsigned char *trix_boot = NULL; -static int trix_boot_len = 0; -#endif static int kilroy_was_here = 0; /* Don't detect twice */ @@ -327,11 +320,7 @@ int probe_trix_sb(struct address_info *hw_config) sb_initialized = 1; hw_config->name = "AudioTrix SB"; -#ifdef CONFIG_SBDSP return sb_dsp_detect(hw_config, 0, 0); -#else - return 0; -#endif } void attach_trix_sb(struct address_info *hw_config) @@ -339,7 +328,6 @@ void attach_trix_sb(struct address_info *hw_config) extern int sb_be_quiet; int old_quiet; -#ifdef CONFIG_SBDSP hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING; /* Prevent false alarms */ @@ -349,20 +337,16 @@ void attach_trix_sb(struct address_info *hw_config) sb_dsp_init(hw_config); sb_be_quiet = old_quiet; -#endif } void attach_trix_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) hw_config->name = "AudioTrix Pro"; attach_uart401(hw_config); -#endif } int probe_trix_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) unsigned char conf; static char irq_bits[] = { -1, -1, -1, 1, 2, 3, -1, 4, -1, 5 @@ -420,9 +404,6 @@ int probe_trix_mpu(struct address_info *hw_config) trix_write(0x19, (trix_read(0x19) & 0x83) | conf); mpu_initialized = 1; return probe_uart401(hw_config); -#else - return 0; -#endif } void unload_trix_wss(struct address_info *hw_config) @@ -445,16 +426,12 @@ void unload_trix_wss(struct address_info *hw_config) void unload_trix_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) unload_uart401(hw_config); -#endif } void unload_trix_sb(struct address_info *hw_config) { -#ifdef CONFIG_SBDSP sb_dsp_unload(hw_config, mpu); -#endif } #ifdef MODULE @@ -566,5 +543,4 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/uart401.c b/drivers/sound/uart401.c index 7ccc65a4f..a59fa7c99 100644 --- a/drivers/sound/uart401.c +++ b/drivers/sound/uart401.c @@ -25,9 +25,6 @@ #include "sound_config.h" #include "soundmodule.h" -#ifdef CONFIG_UART401 -#ifdef CONFIG_MIDI - typedef struct uart401_devc { int base; @@ -482,12 +479,9 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif +#endif /* MODULE */ EXPORT_SYMBOL(attach_uart401); EXPORT_SYMBOL(probe_uart401); EXPORT_SYMBOL(unload_uart401); EXPORT_SYMBOL(uart401intr); - -#endif -#endif diff --git a/drivers/sound/uart6850.c b/drivers/sound/uart6850.c index 13dcb5fc2..dfa6ed417 100644 --- a/drivers/sound/uart6850.c +++ b/drivers/sound/uart6850.c @@ -24,9 +24,6 @@ */ #include "sound_config.h" - -#ifdef CONFIG_SOUND_UART6850 -#ifdef CONFIG_MIDI #include "soundmodule.h" static int uart6850_base = 0x330; @@ -353,6 +350,4 @@ void cleanup_module(void) unload_uart6850(&cfg); SOUND_LOCK_END; } -#endif -#endif -#endif +#endif /* MODULE */ diff --git a/drivers/sound/v_midi.c b/drivers/sound/v_midi.c index c1d695c99..caeda1e41 100644 --- a/drivers/sound/v_midi.c +++ b/drivers/sound/v_midi.c @@ -24,8 +24,6 @@ #include "sound_config.h" #include "soundmodule.h" -#ifdef CONFIG_VMIDI - #include "v_midi.h" static vmidi_devc *v_devc[2] = { NULL, NULL}; @@ -52,7 +50,7 @@ void cleanup_module(void) SOUND_LOCK_END; } -#endif +#endif /* MODULE */ /* * The DSP channel can be used either for input or output. Variable @@ -297,5 +295,3 @@ void unload_v_midi(struct address_info *hw_config) sound_unload_mididev(midi2); kfree(midi_mem); } - -#endif diff --git a/drivers/sound/vidc.c b/drivers/sound/vidc.c index 04fcd3413..4fed93e06 100644 --- a/drivers/sound/vidc.c +++ b/drivers/sound/vidc.c @@ -1,128 +1,534 @@ /* - * drivers/sound/vidc.c + * drivers/sound/vidc.c * - * Detection routine for the VIDC. + * VIDC20 audio driver. * - * Copyright (C) 1997 by Russell King <rmk@arm.uk.linux.org> + * Copyright (C) 1997-2000 by Russell King <rmk@arm.linux.org.uk> + * + * The VIDC20 sound hardware consists of the VIDC20 itself, a DAC and a DMA + * engine. The DMA transfers fixed-format (16-bit little-endian linear) + * samples to the VIDC20, which then transfers this data serially to the + * DACs. The samplerate is controlled by the VIDC. + * + * We currently support a mixer device, but it is currently non-functional. */ #include <linux/module.h> #include <linux/kernel.h> -#include <asm/io.h> +#include <asm/hardware.h> #include <asm/dma.h> +#include <asm/io.h> +#include <asm/iomd.h> +#include <asm/system.h> + #include "sound_config.h" #include "soundmodule.h" #include "vidc.h" -int vidc_busy; +#ifndef _SIOC_TYPE +#define _SIOC_TYPE(x) _IOC_TYPE(x) +#endif +#ifndef _SIOC_NR +#define _SIOC_NR(x) _IOC_NR(x) +#endif -void vidc_update_filler(int format, int channels) +#define VIDC_SOUND_CLOCK (250000) + +/* + * When using SERIAL SOUND mode (external DAC), the number of physical + * channels is fixed at 2. + */ +static int vidc_busy; +static int vidc_adev; +static int vidc_audio_rate; +static char vidc_audio_format; +static char vidc_audio_channels; + +static unsigned char vidc_level_l[SOUND_MIXER_NRDEVICES] = { + 85, /* master */ + 50, /* bass */ + 50, /* treble */ + 0, /* synth */ + 75, /* pcm */ + 0, /* speaker */ + 100, /* ext line */ + 0, /* mic */ + 100, /* CD */ + 0, +}; + +static unsigned char vidc_level_r[SOUND_MIXER_NRDEVICES] = { + 85, /* master */ + 50, /* bass */ + 50, /* treble */ + 0, /* synth */ + 75, /* pcm */ + 0, /* speaker */ + 100, /* ext line */ + 0, /* mic */ + 100, /* CD */ + 0, +}; + +static unsigned int vidc_audio_volume_l; /* left PCM vol, 0 - 65536 */ +static unsigned int vidc_audio_volume_r; /* right PCM vol, 0 - 65536 */ + +static void (*old_mksound)(unsigned int hz, unsigned int ticks); +extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); +extern void vidc_update_filler(int bits, int channels); +extern int softoss_dev; + +static void +vidc_mksound(unsigned int hz, unsigned int ticks) { - int fillertype; + printk("BEEP - %d %d!\n", hz, ticks); +} -#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) +static void +vidc_mixer_set(int mdev, unsigned int level) +{ + unsigned int lev_l = level & 0x007f; + unsigned int lev_r = (level & 0x7f00) >> 8; + unsigned int mlev_l, mlev_r; + + if (lev_l > 100) + lev_l = 100; + if (lev_r > 100) + lev_r = 100; + +#define SCALE(lev,master) ((lev) * (master) * 65536 / 10000) + + mlev_l = vidc_level_l[SOUND_MIXER_VOLUME]; + mlev_r = vidc_level_r[SOUND_MIXER_VOLUME]; + + switch (mdev) { + case SOUND_MIXER_VOLUME: + case SOUND_MIXER_PCM: + vidc_level_l[mdev] = lev_l; + vidc_level_r[mdev] = lev_r; + + vidc_audio_volume_l = SCALE(lev_l, mlev_l); + vidc_audio_volume_r = SCALE(lev_r, mlev_r); +/*printk("VIDC: PCM vol %05X %05X\n", vidc_audio_volume_l, vidc_audio_volume_r);*/ + break; + } +#undef SCALE +} + +static int vidc_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) +{ + unsigned int val; + unsigned int mdev; + + if (_SIOC_TYPE(cmd) != 'M') + return -EINVAL; + + mdev = _SIOC_NR(cmd); + + if (_SIOC_DIR(cmd) & _SIOC_WRITE) { + if (get_user(val, (unsigned int *)arg)) + return -EFAULT; + + if (mdev < SOUND_MIXER_NRDEVICES) + vidc_mixer_set(mdev, val); + else + return -EINVAL; + } + + /* + * Return parameters + */ + switch (mdev) { + case SOUND_MIXER_RECSRC: + val = 0; + break; + + case SOUND_MIXER_DEVMASK: + val = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH; + break; - fillertype = TYPE(format, channels); + case SOUND_MIXER_STEREODEVS: + val = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH; + break; - switch (fillertype) - { - default: - case TYPE(AFMT_U8, 1): - vidc_filler = vidc_fill_1x8_u; - break; + case SOUND_MIXER_RECMASK: + val = 0; + break; - case TYPE(AFMT_U8, 2): - vidc_filler = vidc_fill_2x8_u; - break; + case SOUND_MIXER_CAPS: + val = 0; + break; - case TYPE(AFMT_S8, 1): - vidc_filler = vidc_fill_1x8_s; - break; + default: + if (mdev < SOUND_MIXER_NRDEVICES) + val = vidc_level_l[mdev] | vidc_level_r[mdev] << 8; + else + return -EINVAL; + } + + return put_user(val, (unsigned int *)arg) ? -EFAULT : 0; +} + +static unsigned int vidc_audio_set_format(int dev, unsigned int fmt) +{ + switch (fmt) { + default: + fmt = AFMT_S16_LE; + case AFMT_U8: + case AFMT_S8: + case AFMT_S16_LE: + vidc_audio_format = fmt; + vidc_update_filler(vidc_audio_format, vidc_audio_channels); + case AFMT_QUERY: + break; + } + return vidc_audio_format; +} + +static int vidc_audio_set_speed(int dev, int rate) +{ + if (rate) { + unsigned int hwctrl, hwrate; + unsigned int newsize, new2size; - case TYPE(AFMT_S8, 2): - vidc_filler = vidc_fill_2x8_s; - break; + /* + * If we have selected 44.1kHz, use the DAC clock. + */ + if (0 && rate == 44100) { + hwctrl = 0x00000002; + hwrate = 3; + } else { + hwctrl = 0x00000003; - case TYPE(AFMT_S16_LE, 1): - vidc_filler = vidc_fill_1x16_s; - break; + hwrate = (((VIDC_SOUND_CLOCK * 2) / rate) + 1) >> 1; + if (hwrate < 3) + hwrate = 3; + if (hwrate > 255) + hwrate = 255; - case TYPE(AFMT_S16_LE, 2): - vidc_filler = vidc_fill_2x16_s; - break; + rate = VIDC_SOUND_CLOCK / hwrate; + } + + outl(0xb0000000 | (hwrate - 2), IO_VIDC_BASE); + outl(0xb1000000 | hwctrl, IO_VIDC_BASE); + + newsize = (10000 / hwrate) & ~3; + if (newsize < 208) + newsize = 208; + if (newsize > 4096) + newsize = 4096; + for (new2size = 128; new2size < newsize; new2size <<= 1); + if (new2size - newsize > newsize - (new2size >> 1)) + new2size >>= 1; + if (new2size > 4096) { + printk(KERN_ERR "VIDC: error: dma buffer (%d) %d > 4K\n", + newsize, new2size); + new2size = 4096; + } + dma_bufsize = new2size; + vidc_audio_rate = rate; + } + return vidc_audio_rate; +} + +static short vidc_audio_set_channels(int dev, short channels) +{ + switch (channels) { + default: + channels = 2; + case 1: + case 2: + vidc_audio_channels = channels; + vidc_update_filler(vidc_audio_format, vidc_audio_channels); + case 0: + break; + } + return vidc_audio_channels; +} + +/* + * Open the device + */ +static int vidc_audio_open(int dev, int mode) +{ + /* This audio device does not have recording capability */ + if (mode == OPEN_READ) + return -EPERM; + + if (vidc_busy) + return -EBUSY; + + vidc_busy = 1; + return 0; +} + +/* + * Close the device + */ +static void vidc_audio_close(int dev) +{ + vidc_busy = 0; +} + +/* + * Output a block via DMA to sound device. + * + * We just set the DMA start and count; the DMA interrupt routine + * will take care of formatting the samples (via the appropriate + * vidc_filler routine), and flag via vidc_audio_dma_interrupt when + * more data is required. + */ +static void +vidc_audio_output_block(int dev, unsigned long buf, int total_count, int one) +{ + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + unsigned long flags; + + save_flags_cli(flags); + dma_start = buf - (unsigned long)dmap->raw_buf_phys + (unsigned long)dmap->raw_buf; + dma_count = total_count; + restore_flags(flags); +} + +static void +vidc_audio_start_input(int dev, unsigned long buf, int count, int intrflag) +{ +} + +static int vidc_audio_prepare_for_input(int dev, int bsize, int bcount) +{ + return -EINVAL; +} + +static void vidc_audio_dma_interrupt(void) +{ + DMAbuf_outputintr(vidc_adev, 1); +} + +/* + * Prepare for outputting samples. + * + * Each buffer that will be passed will be `bsize' bytes long, + * with a total of `bcount' buffers. + */ +static int vidc_audio_prepare_for_output(int dev, int bsize, int bcount) +{ + struct audio_operations *adev = audio_devs[dev]; + + dma_interrupt = NULL; + adev->dmap_out->flags |= DMA_NODMA; + + return 0; +} + +/* + * Stop our current operation. + */ +static void vidc_audio_reset(int dev) +{ + dma_interrupt = NULL; +} + +static int vidc_audio_local_qlen(int dev) +{ + return /*dma_count !=*/ 0; +} + +static void vidc_audio_trigger(int dev, int enable_bits) +{ + struct audio_operations *adev = audio_devs[dev]; + + if (enable_bits & PCM_ENABLE_OUTPUT) { + if (!(adev->flags & DMA_ACTIVE)) { + unsigned long flags; + + save_flags_cli(flags); + + /* prevent recusion */ + adev->flags |= DMA_ACTIVE; + + dma_interrupt = vidc_audio_dma_interrupt; + vidc_sound_dma_irq(0, NULL, NULL); + outb(DMA_CR_E | 0x10, IOMD_SD0CR); + + restore_flags(flags); + } + } +} + +static struct audio_driver vidc_audio_driver = +{ + open: vidc_audio_open, + close: vidc_audio_close, + output_block: vidc_audio_output_block, + start_input: vidc_audio_start_input, + prepare_for_input: vidc_audio_prepare_for_input, + prepare_for_output: vidc_audio_prepare_for_output, + halt_io: vidc_audio_reset, + local_qlen: vidc_audio_local_qlen, + trigger: vidc_audio_trigger, + set_speed: vidc_audio_set_speed, + set_bits: vidc_audio_set_format, + set_channels: vidc_audio_set_channels +}; + +static struct mixer_operations vidc_mixer_operations = { + id: "VIDC", + name: "VIDCsound", + ioctl: vidc_mixer_ioctl +}; + +void vidc_update_filler(int format, int channels) +{ +#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) + + switch (TYPE(format, channels)) { + default: + case TYPE(AFMT_U8, 1): + vidc_filler = vidc_fill_1x8_u; + break; + + case TYPE(AFMT_U8, 2): + vidc_filler = vidc_fill_2x8_u; + break; + + case TYPE(AFMT_S8, 1): + vidc_filler = vidc_fill_1x8_s; + break; + + case TYPE(AFMT_S8, 2): + vidc_filler = vidc_fill_2x8_s; + break; + + case TYPE(AFMT_S16_LE, 1): + vidc_filler = vidc_fill_1x16_s; + break; + + case TYPE(AFMT_S16_LE, 2): + vidc_filler = vidc_fill_2x16_s; + break; } } void attach_vidc(struct address_info *hw_config) { char name[32]; - int i; + int i, adev; sprintf(name, "VIDC %d-bit sound", hw_config->card_subtype); conf_printf(name, hw_config); memset(dma_buf, 0, sizeof(dma_buf)); - for (i = 0; i < 2; i++) - { + adev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, name, + &vidc_audio_driver, sizeof(vidc_audio_driver), + DMA_AUTOMODE, AFMT_U8 | AFMT_S8 | AFMT_S16_LE, + NULL, hw_config->dma, hw_config->dma2); + + if (adev < 0) + goto audio_failed; + + /* + * 1024 bytes => 64 buffers + */ + audio_devs[adev]->min_fragment = 10; + audio_devs[adev]->mixer_dev = num_mixers; + + audio_devs[adev]->mixer_dev = + sound_install_mixer(MIXER_DRIVER_VERSION, + name, &vidc_mixer_operations, + sizeof(vidc_mixer_operations), NULL); + + if (audio_devs[adev]->mixer_dev < 0) + goto mixer_failed; + + for (i = 0; i < 2; i++) { dma_buf[i] = get_free_page(GFP_KERNEL); - if (!dma_buf[i]) - goto nomem; - dma_pbuf[i] = virt_to_phys(dma_buf[i]); + if (!dma_buf[i]) { + printk(KERN_ERR "%s: can't allocate required buffers\n", + name); + goto mem_failed; + } + dma_pbuf[i] = virt_to_phys((void *)dma_buf[i]); } - if (sound_alloc_dma(hw_config->dma, "VIDCsound")) - { - printk(KERN_ERR "VIDCsound: can't allocate virtual DMA channel\n"); - return; + if (sound_alloc_dma(hw_config->dma, hw_config->name)) { + printk(KERN_ERR "%s: DMA %d is in use\n", name, hw_config->dma); + goto dma_failed; } - if (request_irq(hw_config->irq, vidc_sound_dma_irq, 0, "VIDCsound", &dma_start)) - { - printk(KERN_ERR "VIDCsound: can't allocate DMA interrupt\n"); - return; + + if (request_irq(hw_config->irq, vidc_sound_dma_irq, 0, + hw_config->name, &dma_start)) { + printk(KERN_ERR "%s: IRQ %d is in use\n", name, hw_config->irq); + goto irq_failed; } + old_mksound = kd_mksound; + kd_mksound = vidc_mksound; + vidc_adev = adev; + vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8)); -// vidc_synth_init(hw_config); - vidc_audio_init(hw_config); - vidc_mixer_init(hw_config); +#if defined(CONFIG_SOUND_SOFTOSS) || defined(CONFIG_SOUND_SOFTOSS_MODULE) + softoss_dev = adev; +#endif return; -nomem: +irq_failed: + sound_free_dma(hw_config->dma); +dma_failed: +mem_failed: for (i = 0; i < 2; i++) free_page(dma_buf[i]); - printk(KERN_ERR "VIDCsound: can't allocate required buffers\n"); + sound_unload_mixerdev(audio_devs[adev]->mixer_dev); +mixer_failed: + sound_unload_audiodev(adev); +audio_failed: + return; } int probe_vidc(struct address_info *hw_config) { - hw_config->irq = IRQ_DMAS0; - hw_config->dma = DMA_VIRTUAL_SOUND; - hw_config->dma2 = -1; - hw_config->card_subtype = 16; + hw_config->irq = IRQ_DMAS0; + hw_config->dma = DMA_VIRTUAL_SOUND; + hw_config->dma2 = -1; + hw_config->card_subtype = 16; + hw_config->name = "VIDC20"; return 1; } void unload_vidc(struct address_info *hw_config) { - int i; + int i, adev = vidc_adev; + + vidc_adev = -1; - free_irq(hw_config->irq, NULL); + if (old_mksound) + kd_mksound = old_mksound; + + free_irq(hw_config->irq, &dma_start); sound_free_dma(hw_config->dma); - for (i = 0; i < 2; i++) - free_page(dma_buf[i]); + if (adev >= 0) { + sound_unload_mixerdev(audio_devs[adev]->mixer_dev); + sound_unload_audiodev(adev); + for (i = 0; i < 2; i++) + free_page(dma_buf[i]); + } } #ifdef MODULE static struct address_info config; +/* + * Note! Module use count is handled by SOUNDLOCK/SOUND_LOCK_END + */ int init_module(void) { if (probe_vidc(&config) == 0) return -ENODEV; - printk("VIDC 16-bit serial sound\n"); + SOUND_LOCK; attach_vidc(&config); + return 0; } diff --git a/drivers/sound/vidc.h b/drivers/sound/vidc.h index a79bdc85d..0b56e8b7a 100644 --- a/drivers/sound/vidc.h +++ b/drivers/sound/vidc.h @@ -55,18 +55,9 @@ extern void (*dma_interrupt) (void); extern unsigned long dma_start, dma_count, dma_bufsize; extern unsigned long dma_buf[2], dma_pbuf[2]; -/* vidc_audio.c */ - -extern void vidc_audio_init(struct address_info *hw_config); -extern int vidc_audio_get_volume(void); -extern int vidc_audio_set_volume(int vol); - -/* vidc_mixer.c */ - -extern void vidc_mixer_init(struct address_info *hw_config); - /* vidc_synth.c */ extern void vidc_synth_init(struct address_info *hw_config); +extern void vidc_synth_exit(struct address_info *hw_config); extern int vidc_synth_get_volume(void); extern int vidc_synth_set_volume(int vol); diff --git a/drivers/sound/vidc_audio.c b/drivers/sound/vidc_audio.c deleted file mode 100644 index 3a1f162fb..000000000 --- a/drivers/sound/vidc_audio.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * drivers/sound/vidc_audio.c - * - * Audio routines for the VIDC - * - * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org> - */ - -#include <asm/hardware.h> -#include <asm/io.h> -#include <asm/system.h> -#include <asm/iomd.h> - -#include "sound_config.h" -#include "vidc.h" - -/* - * VIDC sound - * - * When using SERIAL SOUND mode (external DAC), the number of physical - * channels is fixed at 2. Therefore, the sample rate = vidc sample rate. - */ - -static int vidc_adev; - -static int vidc_audio_volume; -static int vidc_audio_rate; -static char vidc_audio_format; -static char vidc_audio_channels; - -extern void vidc_update_filler(int bits, int channels); - -int vidc_audio_get_volume(void) -{ - return vidc_audio_volume; -} - -int vidc_audio_set_volume(int newvol) -{ - vidc_audio_volume = newvol; - return vidc_audio_volume; -} - -static int vidc_audio_set_bits(int fmt) -{ - switch (fmt) - { - case AFMT_QUERY: - break; - case AFMT_U8: - case AFMT_S8: - case AFMT_S16_LE: - vidc_audio_format = fmt; - vidc_update_filler(vidc_audio_format, vidc_audio_channels); - break; - default: - vidc_audio_format = AFMT_S16_LE; - vidc_update_filler(vidc_audio_format, vidc_audio_channels); - break; - } - return vidc_audio_format; -} - -static int vidc_audio_set_rate(int rate) -{ - if (rate) - { - int newsize, new2size; - - vidc_audio_rate = ((500000 / rate) + 1) >> 1; - if (vidc_audio_rate < 3) - vidc_audio_rate = 3; - if (vidc_audio_rate > 255) - vidc_audio_rate = 255; - outl((vidc_audio_rate - 2) | 0xb0000000, IO_VIDC_BASE); - outl(0xb1000003, IO_VIDC_BASE); - newsize = (10000 / vidc_audio_rate) & ~3; - if (newsize < 208) - newsize = 208; - if (newsize > 4096) - newsize = 4096; - for (new2size = 128; new2size < newsize; new2size <<= 1); - if (new2size - newsize > newsize - (new2size >> 1)) - new2size >>= 1; - dma_bufsize = new2size; - } - return 250000 / vidc_audio_rate; -} - -static int vidc_audio_set_channels(int channels) -{ - switch (channels) - { - case 0: - break; - case 1: - case 2: - vidc_audio_channels = channels; - vidc_update_filler(vidc_audio_format, vidc_audio_channels); - break; - default: - vidc_audio_channels = 2; - vidc_update_filler(vidc_audio_format, vidc_audio_channels); - break; - } - return vidc_audio_channels; -} - -/* - * Open the device - * - * dev - device - * mode - mode to open device (logical OR of OPEN_READ and OPEN_WRITE) - * - * Called when opening the DMAbuf (dmabuf.c:259) - */ -static int vidc_audio_open(int dev, int mode) -{ - if (vidc_busy) - return -EBUSY; - - if ((mode & OPEN_READ) && (!mode & OPEN_WRITE)) - { - /* This audio device doesn't have recording capability */ - return -EIO; - } - vidc_busy = 1; - return 0; -} - -/* - * Close the device - * - * dev - device - * - * Called when closing the DMAbuf (dmabuf.c:477) - * after halt_xfer - */ -static void vidc_audio_close(int dev) -{ - vidc_busy = 0; -} - -static int vidc_audio_ioctl(int dev, unsigned int cmd, caddr_t arg) -{ - int ret; - - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - if (get_user(ret, (int *) arg)) - return -EFAULT; - ret = vidc_audio_set_rate(ret); - break; - - case SOUND_PCM_READ_RATE: - ret = vidc_audio_set_rate(0); - break; - - case SNDCTL_DSP_STEREO: - if (get_user(ret, (int *) arg)) - return -EFAULT; - ret = vidc_audio_set_channels(ret + 1) - 1; - break; - - case SOUND_PCM_WRITE_CHANNELS: - if (get_user(ret, (int *) arg)) - return -EFAULT; - ret = vidc_audio_set_channels(ret); - break; - - case SOUND_PCM_READ_CHANNELS: - ret = vidc_audio_set_channels(0); - break; - - case SNDCTL_DSP_SETFMT: - if (get_user(ret, (int *) arg)) - return -EFAULT; - ret = vidc_audio_set_bits(ret); - break; - - case SOUND_PCM_READ_BITS: - ret = vidc_audio_set_bits(0); - break; - - case SOUND_PCM_WRITE_FILTER: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - - default: - return -EINVAL; - } - return put_user(ret, (int *) arg); -} - -/* - * Output a block via DMA to sound device - * - * dev - device number - * buf - physical address of buffer - * total_count - total byte count in buffer - * intrflag - set if this has been called from an interrupt (via DMAbuf_outputintr) - * restart_dma - set if DMA needs to be re-initialised - * - * Called when: - * 1. Starting output (dmabuf.c:1327) - * 2. (dmabuf.c:1504) - * 3. A new buffer needs to be sent to the device (dmabuf.c:1579) - */ -static void vidc_audio_output_block(int dev, unsigned long buf, int total_count, - int intrflag) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_out; - - dma_start = buf - (unsigned long)dmap->raw_buf_phys + (unsigned long)dmap->raw_buf; - dma_count = total_count; - - if (!(adev->flags & DMA_ACTIVE)) - { - unsigned long flags; - save_flags_cli(flags); - - vidc_sound_dma_irq(0, NULL, NULL); - outb(DMA_CR_E | 0x10, IOMD_SD0CR); - - restore_flags(flags); - } -} - -static void vidc_audio_start_input(int dev, unsigned long buf, int count, - int intrflag) -{ -} - -static int vidc_audio_prepare_for_input(int dev, int bsize, int bcount) -{ - return -EINVAL; -} - -static void vidc_audio_dma_interrupt(void) -{ - DMAbuf_outputintr(vidc_adev, 1); -} - -/* - * Prepare for outputting samples to `dev' - * - * Each buffer that will be passed will be `bsize' bytes long, - * with a total of `bcount' buffers. - * - * Called when: - * 1. A trigger enables audio output (dmabuf.c:978) - * 2. We get a write buffer without dma_mode setup (dmabuf.c:1152) - * 3. We restart a transfer (dmabuf.c:1324) - */ -static int vidc_audio_prepare_for_output(int dev, int bsize, int bcount) -{ - audio_devs[dev]->dmap_out->flags |= DMA_NODMA; - dma_interrupt = vidc_audio_dma_interrupt; - return 0; -} - -/* - * Stop our current operation. - */ -static void vidc_audio_reset(int dev) -{ - /* stop interrupts. Our real interrupt routine - * will close DMA down for us - */ - dma_interrupt = NULL; -} - -static int vidc_audio_local_qlen(int dev) -{ - return /*dma_count !=*/ 0; -} - -static struct audio_driver vidc_audio_driver = -{ - vidc_audio_open, /* open */ - vidc_audio_close, /* close */ - vidc_audio_output_block, /* output_block */ - vidc_audio_start_input, /* start_input */ - vidc_audio_ioctl, /* ioctl */ - vidc_audio_prepare_for_input, /* prepare_for_input */ - vidc_audio_prepare_for_output, /* prepare_for_output */ - vidc_audio_reset, /* reset */ - vidc_audio_local_qlen, /*+local_qlen */ - NULL, /*+copy_from_user */ - NULL, /*+halt_input */ - NULL, /* halt_output */ - NULL, /*+trigger */ - NULL, /*+set_speed */ - NULL, /*+set_bits */ - NULL, /*+set_channels */ -}; - -void vidc_audio_init(struct address_info *hw_config) -{ - vidc_audio_volume = 100 | (100 << 8); - - if ((vidc_adev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, - "VIDCsound", &vidc_audio_driver, - sizeof(struct audio_driver), - DMA_AUTOMODE, AFMT_U8 | AFMT_S8 | AFMT_S16_LE, - NULL, hw_config->dma, hw_config->dma2)) >= 0) - { - audio_devs[vidc_adev]->min_fragment = 10; /* 1024 bytes => 64 buffers */ - audio_devs[vidc_adev]->mixer_dev = num_mixers; - } - else printk(KERN_ERR "VIDCsound: Too many PCM devices available\n"); -} diff --git a/drivers/sound/vidc_fill.S b/drivers/sound/vidc_fill.S index 53fc2ed01..c198b72c6 100644 --- a/drivers/sound/vidc_fill.S +++ b/drivers/sound/vidc_fill.S @@ -191,24 +191,24 @@ ENTRY(vidc_sound_dma_irq) .data .globl SYMBOL_NAME(dma_interrupt) SYMBOL_NAME(dma_interrupt): - .long 0 + .long 0 @ r3 .globl SYMBOL_NAME(dma_pbuf) SYMBOL_NAME(dma_pbuf): - .long 0 - .long 0 + .long 0 @ r4 + .long 0 @ r5 .globl SYMBOL_NAME(dma_start) SYMBOL_NAME(dma_start): - .long 0 + .long 0 @ r0 .globl SYMBOL_NAME(dma_count) SYMBOL_NAME(dma_count): - .long 0 + .long 0 @ r1 .globl SYMBOL_NAME(dma_buf) SYMBOL_NAME(dma_buf): - .long 0 - .long 0 + .long 0 @ r2 + .long 0 @ r3 .globl SYMBOL_NAME(vidc_filler) SYMBOL_NAME(vidc_filler): - .long SYMBOL_NAME(vidc_fill_noaudio) + .long SYMBOL_NAME(vidc_fill_noaudio) @ r4 .globl SYMBOL_NAME(dma_bufsize) SYMBOL_NAME(dma_bufsize): - .long 0x1000 + .long 0x1000 @ r5 diff --git a/drivers/sound/vidc_mixer.c b/drivers/sound/vidc_mixer.c deleted file mode 100644 index 01be4925c..000000000 --- a/drivers/sound/vidc_mixer.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * drivers/sound/vidc_mixer.c - * - * Mixer routines for VIDC - * - * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org> - */ - -#include "sound_config.h" -#include "vidc.h" - -int vidc_volume; - -static int vidc_get_volume(void) -{ - return vidc_volume; -} - -static int vidc_set_volume(int newvol) -{ - vidc_volume = newvol; -/* printk ("vidc_set_volume: %X\n", newvol); */ - return newvol; -} - -static int vidc_default_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) -{ - int ret; - - switch (cmd) - { - case SOUND_MIXER_READ_VOLUME: - ret = vidc_get_volume(); - break; - - case SOUND_MIXER_WRITE_VOLUME: - if (get_user(ret, (int *) arg)) - return -EINVAL; - ret = vidc_set_volume(ret); - break; - - case SOUND_MIXER_READ_BASS: - case SOUND_MIXER_WRITE_BASS: - case SOUND_MIXER_READ_TREBLE: - case SOUND_MIXER_WRITE_TREBLE: - ret = 50; - break; - - case SOUND_MIXER_READ_SYNTH: -// ret = vidc_synth_get_volume(); - ret = 0; - break; - - case SOUND_MIXER_WRITE_SYNTH: - if (get_user(ret, (int *) arg)) - return -EINVAL; -// ret = vidc_synth_set_volume(ret); - ret = 0; - break; - - case SOUND_MIXER_READ_PCM: - ret = vidc_audio_get_volume(); - break; - - case SOUND_MIXER_WRITE_PCM: - if (get_user(ret, (int *) arg)) - return -EINVAL; - ret = vidc_audio_set_volume(ret); - break; - - case SOUND_MIXER_READ_SPEAKER: - ret = 100; - break; - - case SOUND_MIXER_WRITE_SPEAKER: - ret = 100; - break; - - case SOUND_MIXER_READ_LINE: - case SOUND_MIXER_WRITE_LINE: - case SOUND_MIXER_READ_MIC: - case SOUND_MIXER_WRITE_MIC: - ret = 0; - break; - - case SOUND_MIXER_READ_CD: - case SOUND_MIXER_WRITE_CD: - ret = 100 | (100 << 8); - break; - - case SOUND_MIXER_READ_IMIX: - case SOUND_MIXER_WRITE_IMIX: - case SOUND_MIXER_READ_ALTPCM: - case SOUND_MIXER_WRITE_ALTPCM: - case SOUND_MIXER_READ_LINE1: - case SOUND_MIXER_WRITE_LINE1: - case SOUND_MIXER_READ_LINE2: - case SOUND_MIXER_WRITE_LINE2: - case SOUND_MIXER_READ_LINE3: - case SOUND_MIXER_WRITE_LINE3: - ret = 0; - break; - - case SOUND_MIXER_READ_RECSRC: - ret = 0; - break; - - case SOUND_MIXER_WRITE_RECSRC: - return -EINVAL; - break; - - case SOUND_MIXER_READ_DEVMASK: - ret = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH; - break; - - case SOUND_MIXER_READ_RECMASK: - ret = 0; - break; - - case SOUND_MIXER_READ_STEREODEVS: - ret = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH; - break; - - case SOUND_MIXER_READ_CAPS: - ret = 0; - break; - - case SOUND_MIXER_READ_MUTE: - return -EINVAL; - break; - - default: - return -EINVAL; - break; - } - return put_user(ret, (int *) arg); -} - -static struct mixer_operations vidc_mixer_operations = { - "VIDC", - "VIDCsound", - vidc_default_mixer_ioctl /* ioctl */ -}; - -void vidc_mixer_init(struct address_info *hw_config) -{ - int vidc_mixer = sound_alloc_mixerdev(); - vidc_volume = 100 | (100 << 8); - if (num_mixers < MAX_MIXER_DEV) - mixer_devs[vidc_mixer] = &vidc_mixer_operations; -} diff --git a/drivers/sound/vidc_synth.c b/drivers/sound/vidc_synth.c deleted file mode 100644 index ba94f0bc6..000000000 --- a/drivers/sound/vidc_synth.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * drivers/sound/vidc_synth.c - * - * Synthesizer routines for the VIDC - * - * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org> - */ - -#include "sound_config.h" -#include "vidc.h" -#if 0 -static struct synth_info vidc_info = -{ - "VIDCsound", /* name */ - 0, /* device */ - SYNTH_TYPE_SAMPLE, /* synth_type */ - 0, /* synth_subtype */ - 0, /* perc_mode */ - 16, /* nr_voices */ - 0, /* nr_drums */ - 0, /* instr_bank_size */ - 0, /* capabilities */ -}; - -int vidc_sdev; -int vidc_synth_volume; - -static int vidc_synth_open(int dev, int mode) -{ - if (vidc_busy) - return -EBUSY; - - vidc_busy = 1; - return 0; -} - -static void vidc_synth_close(int dev) -{ - vidc_busy = 0; -} - - -static struct synth_operations vidc_synth_operations = -{ - "VIDC Synth", /* name */ - &vidc_info, /* info */ - 0, /* midi_dev */ - SYNTH_TYPE_SAMPLE, /* synth_type */ - /*SAMPLE_TYPE_XXX */ 0, /* synth_subtype */ - vidc_synth_open, /* open */ - vidc_synth_close, /* close */ - NULL, /* ioctl */ - NULL, /* kill_note */ - NULL, /* start_note */ - NULL, /* set_instr */ - NULL, /* reset */ - NULL, /* hw_control */ - NULL, /* load_patch */ - NULL, /* aftertouch */ - NULL, /* controller */ - NULL, /* panning */ - NULL, /* volume_method */ - NULL, /* bender */ - NULL, /* alloc_voice */ - NULL, /* setup_voice */ - NULL, /* send_sysex */ - /* alloc */ - /* chn_info[16] */ - /* syex_buf */ - /* syex_ptr */ -}; - -int vidc_synth_get_volume(void) -{ - return vidc_synth_volume; -} - -int vidc_synth_set_volume(int newvol) -{ - return vidc_synth_volume = newvol; -} - -void vidc_synth_init(struct address_info *hw_config) -{ - vidc_synth_volume = 100 | (100 << 8); - if ((vidc_sdev=sound_alloc_synthdev())!=-1) - synth_devs[vidc_sdev] = &vidc_synth_operations; - else - printk(KERN_ERR "VIDCsound: Too many synthesizers\n"); -} -#endif diff --git a/drivers/sound/waveartist.c b/drivers/sound/waveartist.c index 143512ea4..905b9cff6 100644 --- a/drivers/sound/waveartist.c +++ b/drivers/sound/waveartist.c @@ -838,7 +838,6 @@ waveartist_intr(int irq, void *dev_id, struct pt_regs *regs) else printk(KERN_WARNING "waveartist: unexpected interrupt\n"); -#ifdef CONFIG_AUDIO if (irqstatus & 0x01) { int temp = 1; @@ -855,7 +854,6 @@ waveartist_intr(int irq, void *dev_id, struct pt_regs *regs) if (temp) //default: printk(KERN_WARNING "waveartist: Unknown interrupt\n"); } -#endif if (irqstatus & 0x2) // We do not use SB mode natively... printk(KERN_WARNING "waveartist: Unexpected SB interrupt...\n"); diff --git a/drivers/sound/wavfront.c b/drivers/sound/wavfront.c index d7df1790b..2967fdf18 100644 --- a/drivers/sound/wavfront.c +++ b/drivers/sound/wavfront.c @@ -86,7 +86,7 @@ */ #if defined(__alpha__) -#ifdef __SMP__ +#ifdef CONFIG_SMP #define LOOPS_PER_SEC cpu_data[smp_processor_id()].loops_per_sec #else #define LOOPS_PER_SEC loops_per_sec @@ -1686,13 +1686,11 @@ wavefront_load_gus_patch (int devno, int format, const char *addr, master otherwise. */ -#ifdef CONFIG_MIDI if (dev.mididev > 0) { midi_synth_controller (dev.mididev, guspatch.instr_no, 10, ((guspatch.panning << 4) > 127) ? 127 : (guspatch.panning << 4)); } -#endif CONFIG_MIDI return(0); } diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c index cc03acb09..d93391340 100644 --- a/drivers/usb/acm.c +++ b/drivers/usb/acm.c @@ -643,16 +643,10 @@ static struct tty_driver acm_tty_driver = { }; /* - * Init / cleanup. + * Init / exit. */ -static void __exit usb_acm_cleanup(void) -{ - usb_deregister(&acm_driver); - tty_unregister_driver(&acm_tty_driver); -} - -static int __init usb_acm_init(void) +static int __init acm_init(void) { acm_tty_driver.init_termios = tty_std_termios; acm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; @@ -668,5 +662,11 @@ static int __init usb_acm_init(void) return 0; } -module_init(usb_acm_init); -module_exit(usb_acm_cleanup); +static void __exit acm_exit(void) +{ + usb_deregister(&acm_driver); + tty_unregister_driver(&acm_tty_driver); +} + +module_init(acm_init); +module_exit(acm_exit); diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c index 82a55ec8e..c4ae62d4c 100644 --- a/drivers/usb/devio.c +++ b/drivers/usb/devio.c @@ -1002,7 +1002,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai return mask; } -static struct file_operations usbdevfs_device_file_operations = { +struct file_operations usbdevfs_device_file_operations = { llseek: usbdev_lseek, read: usbdev_read, poll: usbdev_poll, @@ -1010,7 +1010,3 @@ static struct file_operations usbdevfs_device_file_operations = { open: usbdev_open, release: usbdev_release, }; - -struct inode_operations usbdevfs_device_inode_operations = { - &usbdevfs_device_file_operations, /* file-ops */ -}; diff --git a/drivers/usb/evdev.c b/drivers/usb/evdev.c index 44d7cfec4..9cca9fdf6 100644 --- a/drivers/usb/evdev.c +++ b/drivers/usb/evdev.c @@ -256,20 +256,16 @@ static struct input_handler evdev_handler = { disconnect: evdev_disconnect, }; -#ifdef MODULE -int init_module(void) -#else -int __init evdev_init(void) -#endif +static int __init evdev_init(void) { input_register_handler(&evdev_handler); - return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit evdev_exit(void) { input_unregister_handler(&evdev_handler); } -#endif + +module_init(evdev_init); +module_exit(evdev_exit); diff --git a/drivers/usb/ftdi_sio.h b/drivers/usb/ftdi_sio.h new file mode 100644 index 000000000..36fa7bb3e --- /dev/null +++ b/drivers/usb/ftdi_sio.h @@ -0,0 +1,380 @@ +/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */ +/* The device is based on the FTDI FT8U100AX chip, DB25 on one side, USB on the other */ +/* Thanx to FTDI for so kindly providing details of the protocol required */ +/* http://www.ftdi.co.uk */ + +/* The implementation of the device I have is called a USC-1000 */ +/* which is available from http://www.dse.co.nz - cat no XH4214 */ +/* It looks similar to this: http://www.dansdata.com/usbser.htm but I can't be sure */ +/* There are other USC-1000s which don't look like my device though so beware */ + +/* Definitions for the FTDI USB Single Port Serial Converter */ +/* known as FTDI_SIO (Serial Input/Output application of the chipset) */ + +#define FTDI_VID 0x0403 /* Vendor Id */ +#define FTDI_SIO_PID 0x8372 /* Product Id */ + +/* Vendor Request Interface */ +#define FTDI_SIO_RESET 0 /* Reset the port */ +#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ +#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */ +#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */ +#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */ +#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modern status register */ +#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ +#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ + +/* Port Identifier Table */ +#define PIT_DEFAULT 0 /* SIOA */ +#define PIT_SIOA 1 /* SIOA */ +/* The device this is tested with one has one port */ +#define PIT_SIOB 2 /* SIOB */ +#define PIT_PARALLEL 3 /* Parallel */ + +/* FTDI_SIO_RESET */ +#define FTDI_SIO_RESET_REQUEST FTDI_SIO_RESET +#define FTDI_SIO_RESET_REQUEST_TYPE 0x40 +#define FTDI_SIO_RESET_SIO 0 +#define FTDI_SIO_RESET_PURGE_RX 1 +#define FTDI_SIO_RESET_PURGE_TX 2 +/* + BmRequestType: 0100 0000B + bRequest: FTDI_SIO_RESET + wValue: Control Value + 0 = Reset SIO + 1 = Purge RX buffer + 2 = Purge TX buffer + wIndex: Port + wLength: 0 + Data: None + + */ + +/* FTDI_SIO_SET_BAUDRATE */ +#define FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_BAUDRATE_REQUEST 3 + +/* + BmRequestType: 0100 0000B + bRequest: FTDI_SIO_SET_BAUDRATE + wValue: BaudRate value - see below + wIndex: Port + wLength: 0 + Data: None +*/ + +typedef enum { + ftdi_sio_b300 = 0, + ftdi_sio_b600 = 1, + ftdi_sio_b1200 = 2, + ftdi_sio_b2400 = 3, + ftdi_sio_b4800 = 4, + ftdi_sio_b9600 = 5, + ftdi_sio_b19200 = 6, + ftdi_sio_b38400 = 7, + ftdi_sio_b57600 = 8, + ftdi_sio_b115200 = 9 +} FTDI_SIO_baudrate_t ; + +#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA +#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8 ) +#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8 ) +#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8 ) +#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8 ) +#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8 ) +#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11 ) +#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11 ) +#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11 ) + +/* FTDI_SIO_SET_DATA */ + +/* BmRequestType: 0100 0000B */ +/* bRequest: FTDI_SIO_SET_DATA */ +/* wValue: Data characteristics (see below) */ +/* wIndex: Port */ +/* wLength: 0 */ +/* Data: None */ +/* + Data characteristics + +B0..7 Number of data bits +B8..10 Parity + 0 = None + 1 = Odd + 2 = Even + 3 = Mark + 4 = Space + B11..13 Stop Bits + 0 = 1 + 1 = 1.5 + 2 = 2 + B14..15 Reserved +*/ + + + +/* FTDI_SIO_MODEM_CTRL */ +#define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL + +/* + BmRequestType: 0100 0000B + bRequest: FTDI_SIO_MODEM_CTRL + wValue: ControlValue (see below) + wIndex: Port + wLength: 0 + Data: None + + NOTE: If the device is in RTS/CTS flow control, the RTS set by this + command will be IGNORED without an error being returned +*/ + +#define FTDI_SIO_SET_DTR_MASK 0x1 +#define FTDI_SIO_SET_DTR_HIGH ( 1 | ( FTDI_SIO_SET_DTR_MASK << 8)) +#define FTDI_SIO_SET_DTR_LOW ( 0 | ( FTDI_SIO_SET_DTR_MASK << 8)) +#define FTDI_SIO_SET_RTS_MASK 0x2 +#define FTDI_SIO_SET_RTS_HIGH ( 2 | ( FTDI_SIO_SET_RTS_MASK << 8 )) +#define FTDI_SIO_SET_RTS_LOW ( 0 | ( FTDI_SIO_SET_RTS_MASK << 8 )) + +/* ControlValue + B0 DTR state + 0 = reset + 1 = set + B1 RTS state + 0 = reset + 1 = set + B2..7 Reserved + B8 DTR state enable + 0 = ignore + 1 = use DTR state + B9 RTS state enable + 0 = ignore + 1 = use RTS state + B10..15 Reserved +*/ + +/* FTDI_SIO_SET_FLOW_CTRL */ +#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL +#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 +#define FTDI_SIO_RTS_CTS_HS 0x1 +#define FTDI_SIO_DTR_DSR_HS 0x2 +#define FTDI_SIO_XON_XOFF_HS 0x4 +/* + BmRequestType: 0100 0000b + bRequest: FTDI_SIO_SET_FLOW_CTRL + wValue: Xoff/Xon + wIndex: Protocol/Port - hIndex is protocl / lIndex is port + wLength: 0 + Data: None + +hIndex - protocol has + B0 Output handshaking using RTS/CTS + 0 = disabled + 1 = enabled + B1 Output handshaking using DTR/DSR + 0 = disabled + 1 = enabled + B2 Xon/Xoff handshaking + 0 = disabled + 1 = enabled + +A value of zero in the hIndex field selects no handshaking + +If Xon/Xoff handshaking is specified, the hValue field contains the Xoff character +and the lValue field contains the Xon character. + +*/ + +/* FTDI_SIO_SET_EVENT_CHAR */ +/* Set the special event character for the specified communications port */ +/* If the device sees this character it will immediately return the */ +/* data read so far - rather than wait 40ms or until 62 bytes is read */ +#define FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR +#define FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40 + + +/* + BmRequestType: 0100 0000b + bRequest: FTDI_SIO_SET_EVENT_CHAR + wValue: EventChar + wIndex: Port + wLength: 0 + Data: None + +wValue: + B0..7 Event Character + B8 Event Character Processing + 0 = disabled + 1 = enabled + B9..15 Reserved + +*/ + +/* FTDI_SIO_SET_ERROR_CHAR */ +/* Set the parity error replacement character for the specified communications port */ + +/* + BmRequestType: 0100 0000b + bRequest: FTDI_SIO_SET_EVENT_CHAR + wValue: Error Char + wIndex: Port + wLength: 0 + Data: None + +Error Char + B0..7 Error Character + B8 Error Character Processing + 0 = disabled + 1 = enabled + B9..15 Reserved + +*/ + +/* FTDI_SIO_GET_MODEM_STATUS */ +/* Retreive the current value of the modem status register */ + +#define FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE 0xc0 +#define FTDI_SIO_GET_MODEM_STATUS_REQUEST FTDI_SIO_GET_MODEM_STATUS +#define FTDI_SIO_CTS_MASK 0x10 +#define FTDI_SIO_DSR_MASK 0x20 +#define FTDI_SIO_RI_MASK 0x40 +#define FTDI_SIO_RLSD_MASK 0x80 +/* + BmRequestType: 1100 0000b + bRequest: FTDI_SIO_GET_MODEM_STATUS + wValue: zero + wIndex: Port + wLength: 1 + Data: Status + +One byte of data is returned +B0..3 0 +B4 CTS + 0 = inactive + 1 = active +B5 DSR + 0 = inactive + 1 = active +B6 Ring Indicator (RI) + 0 = inactive + 1 = active +B7 Receive Line Signal Detect (RLSD) + 0 = inactive + 1 = active +*/ + + + +/* Descriptors returned by the device + + Device Descriptor + +Offset Field Size Value Description +0 bLength 1 0x12 Size of descriptor in bytes +1 bDescriptorType 1 0x01 DEVICE Descriptor Type +2 bcdUSB 2 0x0110 USB Spec Release Number +4 bDeviceClass 1 0x00 Class Code +5 bDeviceSubClass 1 0x00 SubClass Code +6 bDeviceProtocol 1 0x00 Protocol Code +7 bMaxPacketSize0 1 0x08 Maximum packet size for endpoint 0 +8 idVendor 2 0x0403 Vendor ID +10 idProduct 2 0x8372 Product ID (FTDI_SIO_PID) +12 bcdDevice 2 0x0001 Device release number +14 iManufacturer 1 0x01 Index of man. string desc +15 iProduct 1 0x02 Index of prod string desc +16 iSerialNumber 1 0x02 Index of serial nmr string desc +17 bNumConfigurations 1 0x01 Number of possible configurations + +Configuration Descriptor + +Offset Field Size Value +0 bLength 1 0x09 Size of descriptor in bytes +1 bDescriptorType 1 0x02 CONFIGURATION Descriptor Type +2 wTotalLength 2 0x0020 Total length of data +4 bNumInterfaces 1 0x01 Number of interfaces supported +5 bConfigurationValue 1 0x01 Argument for SetCOnfiguration() req +6 iConfiguration 1 0x02 Index of config string descriptor +7 bmAttributes 1 0x20 Config characteristics Remote Wakeup +8 MaxPower 1 0x1E Max power consumption + +Interface Descriptor + +Offset Field Size Value +0 bLength 1 0x09 Size of descriptor in bytes +1 bDescriptorType 1 0x04 INTERFACE Descriptor Type +2 bInterfaceNumber 1 0x00 Number of interface +3 bAlternateSetting 1 0x00 Value used to select alternate +4 bNumEndpoints 1 0x02 Number of endpoints +5 bInterfaceClass 1 0xFF Class Code +6 bInterfaceSubClass 1 0xFF Subclass Code +7 bInterfaceProtocol 1 0xFF Protocol Code +8 iInterface 1 0x02 Index of interface string description + +IN Endpoint Descriptor + +Offset Field Size Value +0 bLength 1 0x07 Size of descriptor in bytes +1 bDescriptorType 1 0x05 ENDPOINT descriptor type +2 bEndpointAddress 1 0x82 Address of endpoint +3 bmAttributes 1 0x02 Endpoint attributes - Bulk +4 bNumEndpoints 2 0x0040 maximum packet size +5 bInterval 1 0x00 Interval for polling endpoint + +OUT Endpoint Descriptor + +Offset Field Size Value +0 bLength 1 0x07 Size of descriptor in bytes +1 bDescriptorType 1 0x05 ENDPOINT descriptor type +2 bEndpointAddress 1 0x02 Address of endpoint +3 bmAttributes 1 0x02 Endpoint attributes - Bulk +4 bNumEndpoints 2 0x0040 maximum packet size +5 bInterval 1 0x00 Interval for polling endpoint + +DATA FORMAT + +IN Endpoint + +The device reserves the first two bytes of data on this endpoint to contain the current +values of the modem and line status registers. In the absence of data, the device +generates a message consisting of these two status bytes every 40 ms + +Byte 0: Modem Status + +Offset Description +B0 Reserved - must be 1 +B1 Reserved - must be 0 +B2 Reserved - must be 0 +B3 Reserved - must be 0 +B4 Clear to Send (CTS) +B5 Data Set Ready (DSR) +B6 Ring Indicator (RI) +B7 Receive Line Signal Detect (RLSD) + +Byte 1: Line Status + +Offset Description +B0 Data Ready (DR) +B1 Overrun Error (OE) +B2 Parity Error (PE) +B3 Framing Error (FE) +B4 Break Interrupt (BI) +B5 Transmitter Holding Register (THRE) +B6 Transmitter Empty (TEMT) +B7 Error in RCVR FIFO + +OUT Endpoint + +This device reserves the first bytes of data on this endpoint contain the length +and port identifier of the message. For the FTDI USB Serial converter the port +identifier is always 1. + +Byte 0: Line Status + +Offset Description +B0 Reserved - must be 1 +B1 Reserved - must be 0 +B2..7 Length of message - (not including Byte 0) + +*/ diff --git a/drivers/usb/graphire.c b/drivers/usb/graphire.c index 8921c7db8..3537c8607 100644 --- a/drivers/usb/graphire.c +++ b/drivers/usb/graphire.c @@ -37,6 +37,7 @@ #include <linux/malloc.h> #include <linux/input.h> #include <linux/module.h> +#include <linux/init.h> #include "usb.h" MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); @@ -179,17 +180,16 @@ static struct usb_driver graphire_driver = { disconnect: graphire_disconnect, }; -#ifdef MODULE -void cleanup_module(void) +static int __init graphire_init(void) { - usb_deregister(&graphire_driver); + usb_register(&graphire_driver); + return 0; } -int init_module(void) -#else -int graphire_init(void) -#endif +static void __exit graphire_exit(void) { - usb_register(&graphire_driver); - return 0; + usb_deregister(&graphire_driver); } + +module_init(graphire_init); +module_exit(graphire_exit); diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c index 85b44010c..778bb3532 100644 --- a/drivers/usb/hid.c +++ b/drivers/usb/hid.c @@ -40,6 +40,8 @@ #include <linux/smp_lock.h> #include <linux/spinlock.h> +#include <asm/unaligned.h> + #undef DEBUG #undef DEBUG_DATA @@ -573,14 +575,14 @@ static __u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) case 2: if ((end - start) >= 2) { - item->data.u16 = le16_to_cpu( *((__u16*)start)++); + item->data.u16 = le16_to_cpu( get_unaligned(((__u16*)start)++)); return start; } case 3: item->size++; if ((end - start) >= 4) { - item->data.u32 = le32_to_cpu( *((__u32*)start)++); + item->data.u32 = le32_to_cpu( get_unaligned(((__u32*)start)++)); return start; } } @@ -706,7 +708,7 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n) static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) { report += (offset >> 5) << 2; offset &= 31; - return (le64_to_cpu(*(__u64*)report) >> offset) & ((1 << n) - 1); + return (le64_to_cpu(get_unaligned((__u64*)report)) >> offset) & ((1 << n) - 1); } static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) @@ -1408,19 +1410,16 @@ static struct usb_driver hid_driver = { disconnect: hid_disconnect }; -#ifdef MODULE -void cleanup_module(void) +static int __init hid_init(void) { - usb_deregister(&hid_driver); + usb_register(&hid_driver); + return 0; } -int init_module(void) -#else -int hid_init(void) -#endif +static void __exit hid_exit(void) { - usb_register(&hid_driver); - return 0; + usb_deregister(&hid_driver); } -__initcall(hid_init); +module_init(hid_init); +module_exit(hid_exit); diff --git a/drivers/usb/inode.c b/drivers/usb/inode.c index 3c80bb8be..2306615f0 100644 --- a/drivers/usb/inode.c +++ b/drivers/usb/inode.c @@ -46,24 +46,17 @@ static LIST_HEAD(superlist); extern struct inode_operations usbdevfs_bus_inode_operations; - -static struct inode_operations devices_inode_operations = { - &usbdevfs_devices_fops -}; - -static struct inode_operations drivers_inode_operations = { - &usbdevfs_drivers_fops -}; +extern struct file_operations usbdevfs_bus_file_operations; struct special { const char *name; - struct inode_operations *iops; + struct file_operations *fops; struct list_head inodes; }; static struct special special[] = { - { "devices", &devices_inode_operations, }, - { "drivers", &drivers_inode_operations, } + { "devices", &usbdevfs_devices_fops, }, + { "drivers", &usbdevfs_drivers_fops, } }; #define NRSPECIAL (sizeof(special)/sizeof(special[0])) @@ -110,7 +103,7 @@ static void new_dev_inode(struct usb_device *dev, struct super_block *sb) inode->i_uid = sb->u.usbdevfs_sb.devuid; inode->i_gid = sb->u.usbdevfs_sb.devgid; inode->i_mode = sb->u.usbdevfs_sb.devmode | S_IFREG; - inode->i_op = &usbdevfs_device_inode_operations; + inode->i_fop = &usbdevfs_device_file_operations; inode->i_size = sizeof(struct usb_device_descriptor); inode->u.usbdev_i.p.dev = dev; list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist); @@ -148,6 +141,7 @@ static void new_bus_inode(struct usb_bus *bus, struct super_block *sb) inode->i_gid = sb->u.usbdevfs_sb.busgid; inode->i_mode = sb->u.usbdevfs_sb.busmode | S_IFDIR; inode->i_op = &usbdevfs_bus_inode_operations; + inode->i_fop = &usbdevfs_bus_file_operations; inode->u.usbdev_i.p.bus = bus; list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist); list_add_tail(&inode->u.usbdev_i.dlist, &bus->inodes); @@ -159,7 +153,6 @@ static void free_inode(struct inode *inode) inode->u.usbdev_i.p.dev = NULL; inode->i_mode &= ~S_IRWXUGO; inode->i_uid = inode->i_gid = 0; - inode->i_op = NULL; inode->i_size = 0; list_del(&inode->u.usbdev_i.slist); INIT_LIST_HEAD(&inode->u.usbdev_i.slist); @@ -405,7 +398,6 @@ static struct file_operations usbdevfs_root_file_operations = { }; static struct inode_operations usbdevfs_root_inode_operations = { - default_file_ops: &usbdevfs_root_file_operations, lookup: usbdevfs_root_lookup, }; @@ -414,7 +406,6 @@ static struct file_operations usbdevfs_bus_file_operations = { }; static struct inode_operations usbdevfs_bus_inode_operations = { - default_file_ops: &usbdevfs_bus_file_operations, lookup: usbdevfs_bus_lookup, }; @@ -433,13 +424,14 @@ static void usbdevfs_read_inode(struct inode *inode) case ISPECIAL: if (inode->i_ino == IROOT) { inode->i_op = &usbdevfs_root_inode_operations; + inode->i_fop = &usbdevfs_root_file_operations; inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; return; } if (inode->i_ino <= IROOT || inode->i_ino > IROOT+NRSPECIAL) return; spec = &special[inode->i_ino-(IROOT+1)]; - inode->i_op = spec->iops; + inode->i_fop = spec->fops; return; case IDEVICE: @@ -453,10 +445,6 @@ static void usbdevfs_read_inode(struct inode *inode) } } -static void usbdevfs_put_inode(struct inode *inode) -{ -} - static void usbdevfs_put_super(struct super_block *sb) { list_del(&sb->u.usbdevfs_sb.slist); @@ -482,15 +470,9 @@ static int usbdevfs_statfs(struct super_block *sb, struct statfs *buf, int bufsi } static struct super_operations usbdevfs_sops = { - usbdevfs_read_inode, - NULL, - usbdevfs_put_inode, - NULL, - NULL, - usbdevfs_put_super, - NULL, - usbdevfs_statfs, - NULL + read_inode: usbdevfs_read_inode, + put_super: usbdevfs_put_super, + statfs: usbdevfs_statfs, }; struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int silent) diff --git a/drivers/usb/input.c b/drivers/usb/input.c index d613976f5..e370927b3 100644 --- a/drivers/usb/input.c +++ b/drivers/usb/input.c @@ -31,7 +31,6 @@ #include <linux/init.h> #include <linux/input.h> #include <linux/module.h> -#include <linux/config.h> #include <linux/random.h> MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); @@ -303,35 +302,3 @@ void input_close_device(struct input_handle *handle) handleptr = &((*handleptr)->hnext); *handleptr = (*handleptr)->hnext; } - - -#ifdef MODULE -int init_module(void) -#else -int __init input_init(void) -#endif -{ -#ifndef MODULE -#ifdef CONFIG_INPUT_KEYBDEV - keybdev_init(); -#endif -#ifdef CONFIG_INPUT_MOUSEDEV - mousedev_init(); -#endif -#ifdef CONFIG_INPUT_JOYDEV - joydev_init(); -#endif -#ifdef CONFIG_INPUT_EVDEV - evdev_init(); -#endif -#endif - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ -} -#endif - -__initcall(input_init); diff --git a/drivers/usb/joydev.c b/drivers/usb/joydev.c index 9f1c94fc0..e2e1d2961 100644 --- a/drivers/usb/joydev.c +++ b/drivers/usb/joydev.c @@ -82,7 +82,7 @@ static struct joydev *joydev_base[BITS_PER_LONG]; MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_SUPPORTED_DEVICE("js"); -static int js_correct(int value, struct js_corr *corr) +static int joydev_correct(int value, struct js_corr *corr) { switch (corr->type) { case JS_CORR_NONE: @@ -102,7 +102,7 @@ static int js_correct(int value, struct js_corr *corr) return value; } -static void js_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct joydev *joydev = handle->private; struct joydev_list *list = joydev->list; @@ -120,7 +120,7 @@ static void js_event(struct input_handle *handle, unsigned int type, unsigned in case EV_ABS: event.type = JS_EVENT_AXIS; event.number = joydev->absmap[code]; - event.value = js_correct(value, &joydev->corr[event.number]); + event.value = joydev_correct(value, &joydev->corr[event.number]); break; default: @@ -226,8 +226,8 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p data.buttons = (joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0 | (joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0; - data.x = ((js_correct(input->abs[ABS_X], &joydev->corr[0]) / 256) + 128) >> joydev->glue.JS_CORR.x; - data.y = ((js_correct(input->abs[ABS_Y], &joydev->corr[1]) / 256) + 128) >> joydev->glue.JS_CORR.y; + data.x = ((joydev_correct(input->abs[ABS_X], &joydev->corr[0]) / 256) + 128) >> joydev->glue.JS_CORR.x; + data.y = ((joydev_correct(input->abs[ABS_Y], &joydev->corr[1]) / 256) + 128) >> joydev->glue.JS_CORR.y; if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) return -EFAULT; @@ -276,7 +276,7 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p event.number = list->startup; } else { event.type = JS_EVENT_AXIS | JS_EVENT_INIT; - event.value = js_correct(input->abs[joydev->abspam[list->startup - joydev->nkey]], + event.value = joydev_correct(input->abs[joydev->abspam[list->startup - joydev->nkey]], &joydev->corr[list->startup - joydev->nkey]); event.number = list->startup - joydev->nkey; } @@ -459,29 +459,27 @@ static void joydev_disconnect(struct input_handle *handle) } static struct input_handler joydev_handler = { - event: js_event, + event: joydev_event, connect: joydev_connect, disconnect: joydev_disconnect, }; -#ifdef MODULE -void cleanup_module(void) -{ - input_unregister_handler(&joydev_handler); - if (unregister_chrdev(JOYSTICK_MAJOR, "js")) - printk(KERN_ERR "js: can't unregister device\n"); -} - -int init_module(void) -#else -int __init joydev_init(void) -#endif +static int joydev_init(void) { if (register_chrdev(JOYDEV_MAJOR, "js", &joydev_fops)) { printk(KERN_ERR "joydev: unable to get major %d for joystick\n", JOYDEV_MAJOR); return -EBUSY; } input_register_handler(&joydev_handler); - return 0; } + +static void joydev_exit(void) +{ + input_unregister_handler(&joydev_handler); + if (unregister_chrdev(JOYSTICK_MAJOR, "js")) + printk(KERN_ERR "js: can't unregister device\n"); +} + +module_init(joydev_init); +module_exit(joydev_exit); diff --git a/drivers/usb/keybdev.c b/drivers/usb/keybdev.c index 1e00b7e49..2aef212cb 100644 --- a/drivers/usb/keybdev.c +++ b/drivers/usb/keybdev.c @@ -158,18 +158,18 @@ struct input_handler keybdev_handler = { disconnect: keybdev_disconnect, }; -#ifdef MODULE -void cleanup_module(void) -{ - kbd_ledfunc = NULL; - input_unregister_handler(&keybdev_handler); -} -int init_module(void) -#else -int __init keybdev_init(void) -#endif +static int __init keybdev_init(void) { input_register_handler(&keybdev_handler); kbd_ledfunc = keybdev_ledfunc; return 0; } + +static void __exit keybdev_exit(void) +{ + kbd_ledfunc = NULL; + input_unregister_handler(&keybdev_handler); +} + +module_init(keybdev_init); +module_exit(keybdev_exit); diff --git a/drivers/usb/mousedev.c b/drivers/usb/mousedev.c index 95623c986..0984e48fd 100644 --- a/drivers/usb/mousedev.c +++ b/drivers/usb/mousedev.c @@ -447,12 +447,7 @@ static struct input_handler mousedev_handler = { disconnect: mousedev_disconnect, }; - -#ifdef MODULE -int init_module(void) -#else -int __init mousedev_init(void) -#endif +static int __init mousedev_init(void) { input_register_handler(&mousedev_handler); @@ -472,13 +467,13 @@ int __init mousedev_init(void) return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit mousedev_exit(void) { #ifdef CONFIG_INPUT_MOUSEDEV_MIX misc_deregister(&mousedev_single.misc); #endif - input_unregister_handler(&mousedev_handler); } -#endif + +module_init(mousedev_init); +module_exit(mousedev_exit); diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c index 07220ad9b..182915a19 100644 --- a/drivers/usb/printer.c +++ b/drivers/usb/printer.c @@ -432,18 +432,17 @@ static struct usb_driver usblp_driver = { minor: USBLP_MINOR_BASE }; -static void __exit usb_printer_cleanup(void) -{ - usb_deregister(&usblp_driver); -} - -static int __init usb_printer_init(void) +static int __init usblp_init(void) { if (usb_register(&usblp_driver)) return -1; - return 0; } -module_init(usb_printer_init); -module_exit(usb_printer_cleanup); +static void __exit usblp_exit(void) +{ + usb_deregister(&usblp_driver); +} + +module_init(usblp_init); +module_exit(usblp_exit); diff --git a/drivers/usb/scanner.c b/drivers/usb/scanner.c index d55e54206..aa0531a89 100644 --- a/drivers/usb/scanner.c +++ b/drivers/usb/scanner.c @@ -817,15 +817,12 @@ usb_driver scanner_driver = { SCN_BASE_MNR }; -#ifdef MODULE -void cleanup_module(void) +void __exit usb_scanner_exit(void) { usb_deregister(&scanner_driver); } -int init_module(void) -#else -int usb_scanner_init(void) -#endif + +int __init usb_scanner_init(void) { if (usb_register(&scanner_driver) < 0) return -1; @@ -834,4 +831,5 @@ int usb_scanner_init(void) return 0; } -__initcall(usb_scanner_init); +module_init(usb_scanner_init); +module_exit(usb_scanner_exit); diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c index 60b411761..0d6457965 100644 --- a/drivers/usb/usb-core.c +++ b/drivers/usb/usb-core.c @@ -33,12 +33,8 @@ int usb_audio_init(void); int usb_cpia_init(void); int usb_ibmcam_init(void); int usb_ov511_init(void); -int usb_stor_init(void); int dabusb_init(void); int plusb_init(void); -int usb_mouse_init(void); -int usb_kbd_init(void); -int graphire_init(void); /* * HCI drivers @@ -86,24 +82,12 @@ int usb_init(void) #ifdef CONFIG_USB_OV511 usb_ov511_init(); #endif -#ifdef CONFIG_USB_STORAGE - usb_stor_init(); -#endif #ifdef CONFIG_USB_DABUSB dabusb_init(); #endif #ifdef CONFIG_USB_PLUSB plusb_init(); #endif -#ifdef CONFIG_USB_MOUSE - usb_mouse_init(); -#endif -#ifdef CONFIG_USB_KBD - usb_kbd_init(); -#endif -#ifdef CONFIG_USB_GRAPHIRE - graphire_init(); -#endif #ifdef CONFIG_USB_UHCI uhci_init(); #endif diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c index 7ca3b5b59..bb017e60c 100644 --- a/drivers/usb/usb-ohci.c +++ b/drivers/usb/usb-ohci.c @@ -45,6 +45,7 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/system.h> +#include <asm/unaligned.h> #undef DEBUG #define OHCI_USE_NPS @@ -62,7 +63,7 @@ static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data); static DECLARE_WAIT_QUEUE_HEAD (op_wakeup); static LIST_HEAD (ohci_hcd_list); -spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED; /*-------------------------------------------------------------------------* * URB support functions @@ -319,6 +320,7 @@ static int sohci_submit_urb (urb_t * urb) if (ed->state == ED_NEW || (ed->state & ED_DEL)) { urb_rm_priv(urb); usb_dec_dev_use (urb->dev); + spin_unlock_irqrestore(&usb_ed_lock, flags); return -EINVAL; } @@ -1261,7 +1263,7 @@ static int rh_submit_urb (urb_t * urb) int len = 0; int status = TD_CC_NOERROR; - __u8 datab[16]; + __u32 datab[4]; __u8 * data_buf = datab; __u16 bmRType_bReq; @@ -1371,7 +1373,8 @@ static int rh_submit_urb (urb_t * urb) case RH_GET_DESCRIPTOR | RH_CLASS: *(__u8 *) (data_buf+1) = 0x29; - *(__u32 *) (data_buf+2) = cpu_to_le32 (readl (&ohci->regs->roothub.a)); + put_unaligned(cpu_to_le32 (readl (&ohci->regs->roothub.a)), + (__u32 *) (data_buf + 2)); *(__u8 *) data_buf = (*(__u8 *) (data_buf + 2) / 8) * 2 + 9; /* length of descriptor */ len = min (leni, min(*(__u8 *) data_buf, wLength)); @@ -1380,7 +1383,8 @@ static int rh_submit_urb (urb_t * urb) *(__u8 *) (data_buf+7) = readl (&ohci->regs->roothub.b) & 0xff; *(__u8 *) (data_buf+8) = (readl (&ohci->regs->roothub.b) & 0xff0000) >> 16; } else { - *(__u32 *) (data_buf+7) = cpu_to_le32 (readl(&ohci->regs->roothub.b)); + put_unaligned(cpu_to_le32 (readl(&ohci->regs->roothub.b)), + (__u32 *) (data_buf + 7)); } OK (len); diff --git a/drivers/usb/usb-serial.c b/drivers/usb/usb-serial.c index f87600e83..6b9615e72 100644 --- a/drivers/usb/usb-serial.c +++ b/drivers/usb/usb-serial.c @@ -14,6 +14,17 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (02/21/2000) gkh + * Made it so that any serial devices only have to specify which functions + * they want to overload from the generic function calls (great, + * inheritance in C, in a driver, just what I wanted...) + * Added support for set_termios and ioctl function calls. No drivers take + * advantage of this yet. + * Removed the #ifdef MODULE, now there is no module specific code. + * Cleaned up a few comments in usb-serial.h that were wrong (thanks again + * to Miles Lott). + * Small fix to get_free_serial. + * * (02/14/2000) gkh * Removed the Belkin and Peracom functionality from the driver due to * the lack of support from the vendor, and me not wanting people to @@ -169,6 +180,19 @@ #include "usb-serial.h" +/* parity check flag */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + +/* local function prototypes */ +static int serial_open (struct tty_struct *tty, struct file * filp); +static void serial_close (struct tty_struct *tty, struct file * filp); +static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count); +static int serial_write_room (struct tty_struct *tty); +static int serial_chars_in_buffer (struct tty_struct *tty); +static void serial_throttle (struct tty_struct * tty); +static void serial_unthrottle (struct tty_struct * tty); +static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); +static void serial_set_termios (struct tty_struct *tty, struct termios * old); static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum); static void usb_serial_disconnect(struct usb_device *dev, void *ptr); @@ -224,7 +248,7 @@ static struct usb_serial *get_free_serial (int num_ports, int *minor) continue; good_spot = 1; - for (j = 0; j < num_ports-1; ++j) + for (j = 1; j <= num_ports-1; ++j) if (serial_table[i+j]) good_spot = 0; if (good_spot == 0) @@ -328,12 +352,12 @@ static int serial_open (struct tty_struct *tty, struct file * filp) tty->driver_data = serial; serial->tty = tty; - /* pass on to the driver specific version of this function */ + /* pass on to the driver specific version of this function if it is available */ if (serial->type->open) { return (serial->type->open(tty, filp)); + } else { + return (generic_serial_open(tty, filp)); } - - return (0); } @@ -363,9 +387,11 @@ static void serial_close(struct tty_struct *tty, struct file * filp) return; } - /* pass on to the driver specific version of this function */ + /* pass on to the driver specific version of this function if it is available */ if (serial->type->close) { serial->type->close(tty, filp); + } else { + generic_serial_close(tty, filp); } } @@ -391,13 +417,12 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned return (-EINVAL); } - /* pass on to the driver specific version of this function */ + /* pass on to the driver specific version of this function if it is available */ if (serial->type->write) { return (serial->type->write(tty, from_user, buf, count)); + } else { + return (generic_serial_write(tty, from_user, buf, count)); } - - /* no specific driver, so return that we didn't write anything */ - return (0); } @@ -422,12 +447,12 @@ static int serial_write_room (struct tty_struct *tty) return (-EINVAL); } - /* pass on to the driver specific version of this function */ + /* pass on to the driver specific version of this function if it is available */ if (serial->type->write_room) { return (serial->type->write_room(tty)); + } else { + return (generic_write_room(tty)); } - - return (0); } @@ -452,12 +477,12 @@ static int serial_chars_in_buffer (struct tty_struct *tty) return (-EINVAL); } - /* pass on to the driver specific version of this function */ + /* pass on to the driver specific version of this function if it is available */ if (serial->type->chars_in_buffer) { return (serial->type->chars_in_buffer(tty)); + } else { + return (generic_chars_in_buffer(tty)); } - - return (0); } @@ -485,6 +510,8 @@ static void serial_throttle (struct tty_struct * tty) /* pass on to the driver specific version of this function */ if (serial->type->throttle) { serial->type->throttle(tty); + } else { + generic_throttle(tty); } return; @@ -515,12 +542,86 @@ static void serial_unthrottle (struct tty_struct * tty) /* pass on to the driver specific version of this function */ if (serial->type->unthrottle) { serial->type->unthrottle(tty); + } else { + generic_unthrottle(tty); } return; } +static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port; + + dbg("serial_ioctl"); + + if (!serial) { + dbg("serial == NULL!"); + return -ENODEV; + } + + port = MINOR(tty->device) - serial->minor; + + dbg("serial_ioctl port %d", port); + + /* do some sanity checking that we really have a device present */ + if (!serial->type) { + dbg("serial->type == NULL!"); + return -ENODEV; + } + if (!serial->active[port]) { + dbg ("device not open"); + return -ENODEV; + } + + /* pass on to the driver specific version of this function if it is available */ + if (serial->type->ioctl) { + return (serial->type->ioctl(tty, file, cmd, arg)); + } else { + return (generic_ioctl (tty, file, cmd, arg)); + } +} + + +static void serial_set_termios (struct tty_struct *tty, struct termios * old) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port; + + dbg("serial_set_termios"); + + if (!serial) { + dbg("serial == NULL!"); + return; + } + + port = MINOR(tty->device) - serial->minor; + + dbg("serial_set_termios port %d", port); + + /* do some sanity checking that we really have a device present */ + if (!serial->type) { + dbg("serial->type == NULL!"); + return; + } + if (!serial->active[port]) { + dbg ("device not open"); + return; + } + + /* pass on to the driver specific version of this function if it is available */ + if (serial->type->set_termios) { + serial->type->set_termios(tty, old); + } else { + generic_set_termios (tty, old); + } + + return; +} + + #ifdef CONFIG_USB_SERIAL_WHITEHEAT /***************************************************************************** * Connect Tech's White Heat specific driver functions @@ -566,6 +667,29 @@ static void whiteheat_serial_close(struct tty_struct *tty, struct file * filp) } +static void whiteheat_set_termios (struct tty_struct *tty, struct termios *old_termios) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + unsigned int cflag = tty->termios->c_cflag; + + dbg("whiteheat_set_termios port %d", port); + + /* check that they really want us to change something */ + if (old_termios) { + if ((cflag == old_termios->c_cflag) && + (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { + dbg("nothing to change..."); + return; + } + } + + /* do the parsing of the cflag to see what to set the line to */ + /* FIXME!! */ + + return; +} + static void whiteheat_throttle (struct tty_struct * tty) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; @@ -813,25 +937,96 @@ static int visor_startup (struct usb_serial *serial) /****************************************************************************** * FTDI SIO Serial Converter specific driver functions ******************************************************************************/ + +/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */ +/* Thanx to FTDI for so kindly providing details of the protocol required */ +/* to talk to the device */ + +#include "ftdi_sio.h" + static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + char buf[1]; /* Needed for the usb_control_msg I think */ int port = MINOR(tty->device) - serial->minor; - dbg("ftdi_serial_open port %d", port); + dbg("ftdi_sio_serial_open port %d", port); if (serial->active[port]) { dbg ("device already open"); return -EINVAL; } serial->active[port] = 1; - + + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, + FTDI_SIO_RESET_SIO, + 0, buf, 0, HZ * 5); + + /* FIXME - Should I really purge the buffers? */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, + FTDI_SIO_RESET_PURGE_RX, + 0, buf, 0, HZ * 5); + + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, + FTDI_SIO_RESET_PURGE_TX, + 0, buf, 0, HZ * 5); + + + /* As per usb_serial_init s/be CS8, B9600, 1 STOP BIT */ + if ( usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_BAUDRATE_REQUEST, + FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, + ftdi_sio_b9600, 0, + buf, 0, HZ * 5) < 0){ + dbg("Error from baudrate urb"); + return(-EINVAL); + } + + if ( usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_DATA_REQUEST, + FTDI_SIO_SET_DATA_REQUEST_TYPE, + 8 | FTDI_SIO_SET_DATA_PARITY_NONE | + FTDI_SIO_SET_DATA_STOP_BITS_1, 0, + buf, 0, HZ * 5) < 0){ + dbg("Error from cs8/noparity/1 stopbit urb"); + return(-EINVAL); + } + + /* Disable flow control */ + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, + 0, 0, + buf, 0, HZ * 5) < 0) { + dbg("error from flowcontrol urb"); + return(-EINVAL); + } + + /* Turn on RTS and DTR since we are not flow controlling*/ + /* FIXME - check for correct behaviour clocal vs non clocal */ + /* FIXME - might be able to do both simultaneously */ + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + (unsigned)FTDI_SIO_SET_DTR_HIGH, 0, + buf, 0, HZ * 5) < 0) { + dbg("Error from DTR HIGH urb"); + } + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + (unsigned)FTDI_SIO_SET_RTS_HIGH, 0, + buf, 0, HZ * 5) < 0) { + dbg("Error from RTS HIGH urb"); + } + /*Start reading from the device*/ if (usb_submit_urb(&serial->read_urb[port])) dbg("usb_submit_urb(read bulk) failed"); - /* Need to do device specific setup here (control lines, baud rate, etc.) */ - /* FIXME!!! */ return (0); } @@ -840,13 +1035,29 @@ static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp) static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + char buf[1]; int port = MINOR(tty->device) - serial->minor; - dbg("ftdi_serial_close port %d", port); - - /* Need to change the control lines here */ - /* FIXME */ + dbg("ftdi_sio_serial_close port %d", port); + /* FIXME - might be able to do both simultaneously */ + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + (unsigned)FTDI_SIO_SET_DTR_LOW, 0, + buf, 0, HZ * 5) < 0) { + dbg("Error from DTR LOW urb"); + } + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + (unsigned)FTDI_SIO_SET_RTS_LOW, 0, + buf, 0, HZ * 5) < 0) { + dbg("Error from RTS LOW urb"); + } + + /* FIXME Should I flush the device here? - not doing it for now */ + /* shutdown our bulk reads and writes */ usb_unlink_urb (&serial->write_urb[port]); usb_unlink_urb (&serial->read_urb[port]); @@ -854,6 +1065,290 @@ static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp) } + +/* The ftdi_sio requires the first byte to have: + B0 1 + B1 0 + B2..7 length of message excluding byte 0 +*/ +static int ftdi_sio_serial_write (struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + const int data_offset = 1; + + dbg("ftdi_sio_serial_write port %d, %d bytes", port, count); + + if (count == 0) { + dbg("write request of 0 bytes"); + return (0); + } + + /* only do something if we have a bulk out endpoint */ + if (serial->num_bulk_out) { + unsigned char *first_byte = serial->write_urb[port].transfer_buffer; + + if (serial->write_urb[port].status == -EINPROGRESS) { + dbg ("already writing"); + return (0); + } + + count += data_offset; + count = (count > serial->bulk_out_size[port]) ? + serial->bulk_out_size[port] : count; + + + /* Copy in the data to send */ + if (from_user) { + copy_from_user(serial->write_urb[port].transfer_buffer + data_offset , + buf, count - data_offset ); + } + else { + memcpy(serial->write_urb[port].transfer_buffer + data_offset, + buf, count - data_offset ); + } + + /* Write the control byte at the front of the packet*/ + first_byte = serial->write_urb[port].transfer_buffer; + *first_byte = 1 | ((count-data_offset) << 2) ; + +#ifdef DEBUG + dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]); + + if (count) { + int i; + printk (KERN_DEBUG __FILE__ ": data written - length = %d, data = ", count); + for (i = 0; i < count; ++i) { + printk ("0x%02x ", first_byte[i]); + if (first_byte[i] > ' ' && first_byte[i] < '~') { + printk("%c ", first_byte[i]); + } else { + printk(" "); + } + } + + + printk ("\n"); + } + +#endif + + + /* send the data out the bulk port */ + serial->write_urb[port].transfer_buffer_length = count; + + if (usb_submit_urb(&serial->write_urb[port])) + dbg("usb_submit_urb(write bulk) failed"); + + dbg("write returning: %d",count - data_offset); + return (count - data_offset); + } + + /* no bulk out, so return 0 bytes written */ + return (0); +} + + +static void ftdi_sio_read_bulk_callback (struct urb *urb) +{ /* ftdi_sio_serial_buld_callback */ + struct usb_serial *serial = (struct usb_serial *)urb->context; + struct tty_struct *tty = serial->tty; + unsigned char *data = urb->transfer_buffer; + const int data_offset = 2; + int i; + + dbg("ftdi_sio_read_bulk_callback"); + + if (urb->status) { + dbg("nonzero read bulk status received: %d", urb->status); + return; + } + +#ifdef DEBUG + if (urb->actual_length > 2) { + printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length); + for (i = 0; i < urb->actual_length; ++i) { + printk ("0x%.2x ", data[i]); + if (data[i] > ' ' && data[i] < '~') { + printk("%c ", data[i]); + } else { + printk(" "); + } + } + printk ("\n"); + } +#endif + + + if (urb->actual_length > data_offset) { + for (i = data_offset ; i < urb->actual_length ; ++i) { + tty_insert_flip_char(tty, data[i], 0); + } + tty_flip_buffer_push(tty); + } + + /* Continue trying to always read */ + if (usb_submit_urb(urb)) + dbg("failed resubmitting read urb"); + + return; +} /* ftdi_sio_serial_read_bulk_callback */ + +static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios *old_termios) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + unsigned int cflag = tty->termios->c_cflag; + __u16 urb_value; /* Will hold the new flags */ + char buf[1]; /* Perhaps I should dynamically alloc this? */ + dbg("ftdi_sio_set_termios port %d", port); + + /* FIXME - we should keep the old termios really */ + /* FIXME -For this cut I don't care if the line is really changing or + not - so just do the change regardless */ + + /* Set number of data bits, parity, stop bits */ + + urb_value = 0; + urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 : + FTDI_SIO_SET_DATA_STOP_BITS_1); + urb_value |= (cflag & PARENB ? + (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : + FTDI_SIO_SET_DATA_PARITY_EVEN) : + FTDI_SIO_SET_DATA_PARITY_NONE); + if (cflag & CSIZE) { + switch (cflag & CSIZE) { + case CS5: urb_value |= 5; dbg("Setting CS5"); break; + case CS6: urb_value |= 6; dbg("Setting CS6"); break; + case CS7: urb_value |= 7; dbg("Setting CS7"); break; + case CS8: urb_value |= 8; dbg("Setting CS8"); break; + default: + dbg("CSIZE was set but not CS5-CS8"); + } + } + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_DATA_REQUEST, + FTDI_SIO_SET_DATA_REQUEST_TYPE, + urb_value , 0, + buf, 0, 100) < 0) { + dbg("FAILED to set databits/stopbits/parity"); + } + + /* Now do the baudrate */ + /* FIXME - should drop lines on B0 */ + /* FIXME Should also handle CLOCAL here */ + + switch(cflag & CBAUD){ + case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break; + case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break; + case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break; + case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break; + case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break; + case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break; + case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break; + case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break; + case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break; + case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break; + default: dbg("FTDI_SIO does not support the baudrate requested"); + /* FIXME - how to return an error for this? */ break; + } + /* Send the URB */ + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_BAUDRATE_REQUEST, + FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, + urb_value, 0, + buf, 0, 100) < 0) { + dbg("urb failed to set baurdrate"); + } + return; +} + +/*FIXME - the beginnings of this implementation - not even hooked into the driver yet */ +static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + __u16 urb_value=0; /* Will hold the new flags */ + char buf[1]; + int ret, mask; + dbg("ftdi_sio_ioctl port %d", port); + + /* Based on code from acm.c */ + switch (cmd) { + + case TIOCMGET: + /* Request the status from the device */ + if ((ret = usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_GET_MODEM_STATUS_REQUEST, + FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, + 0, 0, + buf, 1, HZ * 5)) < 0 ) { + dbg("Get not get modem status of device"); + return(ret); + } + + return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | + (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | + (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | + (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0), + (unsigned long *) arg); + break; + + case TIOCMSET: + case TIOCMBIS: + case TIOCMBIC: + if ((ret = get_user(mask, (unsigned long *) arg))) return ret; + + /* FIXME Need to remember if we have set DTR or RTS since we + can't ask the device */ + /* FIXME - also need to find the meaning of TIOCMBIS/BIC/SET */ + if (mask & TIOCM_DTR) { + switch(cmd) { + case TIOCMSET: + urb_value = FTDI_SIO_SET_DTR_HIGH | FTDI_SIO_SET_RTS_LOW; + break; + + case TIOCMBIS: + /* Will leave RTS alone and set DTR */ + urb_value = FTDI_SIO_SET_DTR_HIGH; + break; + + case TIOCMBIC: + urb_value = FTDI_SIO_SET_DTR_LOW; + break; + } + } + + if (mask & TIOCM_RTS) { + switch(cmd) { + case TIOCMSET: + urb_value = FTDI_SIO_SET_DTR_LOW | FTDI_SIO_SET_RTS_HIGH; + break; + + case TIOCMBIS: + /* Will leave DTR and set RTS */ + urb_value = FTDI_SIO_SET_RTS_HIGH; + break; + + case TIOCMBIC: + /* Will unset RTS */ + urb_value = FTDI_SIO_SET_RTS_LOW; + break; + } + } + + + return(usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + urb_value , 0, + buf, 0, HZ * 5)); + } +} + #endif /* CONFIG_USB_SERIAL_FTDI_SIO */ @@ -1041,6 +1536,34 @@ static int generic_chars_in_buffer (struct tty_struct *tty) } +static void generic_throttle (struct tty_struct *tty) +{ + /* do nothing for the generic device */ + return; +} + + +static void generic_unthrottle (struct tty_struct *tty) +{ + /* do nothing for the generic device */ + return; +} + + +static int generic_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) +{ + /* generic driver doesn't support any ioctls yet */ + return -ENOIOCTLCMD; +} + + +static void generic_set_termios (struct tty_struct *tty, struct termios * old) +{ + /* generic driver doesn't really care about setting any line settings */ + return; +} + + static void generic_read_bulk_callback (struct urb *urb) { struct usb_serial *serial = (struct usb_serial *)urb->context; @@ -1059,7 +1582,7 @@ static void generic_read_bulk_callback (struct urb *urb) if (urb->actual_length) { printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length); for (i = 0; i < urb->actual_length; ++i) { - printk ("0x%.2x ", data[i]); + printk ("%.2x ", data[i]); } printk ("\n"); } @@ -1352,8 +1875,8 @@ static struct tty_driver serial_tty_driver = { put_char: NULL, flush_chars: NULL, write_room: serial_write_room, - ioctl: NULL, - set_termios: NULL, + ioctl: serial_ioctl, + set_termios: serial_set_termios, set_ldisc: NULL, throttle: serial_throttle, unthrottle: serial_unthrottle, @@ -1397,19 +1920,14 @@ int usb_serial_init(void) } -#ifdef MODULE -int init_module(void) -{ - return usb_serial_init(); -} - -void cleanup_module(void) +void usb_serial_exit(void) { tty_unregister_driver(&serial_tty_driver); usb_deregister(&usb_serial_driver); } -#else -__initcall(usb_serial_init); -#endif + +module_init(usb_serial_init); +module_exit(usb_serial_exit); + diff --git a/drivers/usb/usb-serial.h b/drivers/usb/usb-serial.h index 6d8e978b5..c62bae569 100644 --- a/drivers/usb/usb-serial.h +++ b/drivers/usb/usb-serial.h @@ -87,15 +87,6 @@ struct usb_serial { #define NUM_DONT_CARE (-1) -/* local function prototypes */ -static int serial_open (struct tty_struct *tty, struct file * filp); -static void serial_close (struct tty_struct *tty, struct file * filp); -static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count); -static int serial_write_room (struct tty_struct *tty); -static int serial_chars_in_buffer (struct tty_struct *tty); -static void serial_throttle (struct tty_struct * tty); -static void serial_unthrottle (struct tty_struct * tty); - /* This structure defines the individual serial converter. */ struct usb_serial_device_type { @@ -110,6 +101,8 @@ struct usb_serial_device_type { char num_bulk_out; char num_ports; /* number of serial ports this device has */ + void *private; /* data private to the specific driver */ + /* function call to make before accepting driver */ int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */ @@ -118,21 +111,30 @@ struct usb_serial_device_type { void (*close)(struct tty_struct * tty, struct file * filp); int (*write)(struct tty_struct * tty, int from_user,const unsigned char *buf, int count); int (*write_room)(struct tty_struct *tty); + int (*ioctl)(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); + void (*set_termios)(struct tty_struct *tty, struct termios * old); int (*chars_in_buffer)(struct tty_struct *tty); void (*throttle)(struct tty_struct * tty); void (*unthrottle)(struct tty_struct * tty); + void (*read_bulk_callback)(struct urb *urb); void (*write_bulk_callback)(struct urb *urb); + }; /* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */ /* need to always compile these in, as some of the other devices use these functions as their own. */ +/* if a driver does not provide a function pointer, the generic function will be called. */ static int generic_serial_open (struct tty_struct *tty, struct file *filp); static void generic_serial_close (struct tty_struct *tty, struct file *filp); static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); static int generic_write_room (struct tty_struct *tty); +static int generic_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); +static void generic_set_termios (struct tty_struct *tty, struct termios * old); static int generic_chars_in_buffer (struct tty_struct *tty); +static void generic_throttle (struct tty_struct *tty); +static void generic_unthrottle (struct tty_struct *tty); static void generic_read_bulk_callback (struct urb *urb); static void generic_write_bulk_callback (struct urb *urb); @@ -150,13 +152,6 @@ static struct usb_serial_device_type generic_device = { num_bulk_in: NUM_DONT_CARE, num_bulk_out: NUM_DONT_CARE, num_ports: 1, - open: generic_serial_open, - close: generic_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, - read_bulk_callback: generic_read_bulk_callback, - write_bulk_callback: generic_write_bulk_callback }; #endif @@ -165,6 +160,7 @@ static struct usb_serial_device_type generic_device = { /* function prototypes for the Connect Tech WhiteHEAT serial converter */ static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp); static void whiteheat_serial_close (struct tty_struct *tty, struct file *filp); +static void whiteheat_set_termios (struct tty_struct *tty, struct termios * old); static void whiteheat_throttle (struct tty_struct *tty); static void whiteheat_unthrottle (struct tty_struct *tty); static int whiteheat_startup (struct usb_serial *serial); @@ -198,11 +194,9 @@ static struct usb_serial_device_type whiteheat_device = { num_ports: 4, open: whiteheat_serial_open, close: whiteheat_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, throttle: whiteheat_throttle, - unthrottle: whiteheat_unthrottle + unthrottle: whiteheat_unthrottle, + set_termios: whiteheat_set_termios, }; #endif @@ -283,14 +277,9 @@ static struct usb_serial_device_type handspring_device = { num_ports: 2, open: visor_serial_open, close: visor_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, throttle: visor_throttle, unthrottle: visor_unthrottle, startup: visor_startup, - read_bulk_callback: generic_read_bulk_callback, - write_bulk_callback: generic_write_bulk_callback }; #endif @@ -299,8 +288,12 @@ static struct usb_serial_device_type handspring_device = { /* function prototypes for a FTDI serial converter */ static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp); static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp); +static int ftdi_sio_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); +static void ftdi_sio_read_bulk_callback (struct urb *urb); +static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios * old); +static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); -/* All of the device info needed for the Handspring Visor */ +/* All of the device info needed for the FTDI SIO serial converter */ static __u16 ftdi_vendor_id = FTDI_VENDOR_ID; static __u16 ftdi_sio_product_id = FTDI_SIO_SERIAL_CONVERTER_ID; static struct usb_serial_device_type ftdi_sio_device = { @@ -316,11 +309,9 @@ static struct usb_serial_device_type ftdi_sio_device = { num_ports: 1, open: ftdi_sio_serial_open, close: ftdi_sio_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, - read_bulk_callback: generic_read_bulk_callback, - write_bulk_callback: generic_write_bulk_callback + write: ftdi_sio_serial_write, + read_bulk_callback: ftdi_sio_read_bulk_callback, + set_termios: ftdi_sio_set_termios }; #endif @@ -331,7 +322,7 @@ static int keyspan_pda_serial_open (struct tty_struct *tty, struct file *filp); static void keyspan_pda_serial_close (struct tty_struct *tty, struct file *filp); static int keyspan_pda_startup (struct usb_serial *serial); -/* All of the device info needed for the Handspring Visor */ +/* All of the device info needed for the Keyspan PDA serial converter */ static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID; static __u16 keyspan_pda_fake_product_id = KEYSPAN_PDA_FAKE_ID; static __u16 keyspan_pda_product_id = KEYSPAN_PDA_ID; @@ -360,17 +351,12 @@ static struct usb_serial_device_type keyspan_pda_device = { num_ports: 1, open: keyspan_pda_serial_open, close: keyspan_pda_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, - read_bulk_callback: generic_read_bulk_callback, - write_bulk_callback: generic_write_bulk_callback }; #endif /* To add support for another serial converter, create a usb_serial_device_type - structure for that device, and add it to this list, making sure that the last - entry is NULL. */ + structure for that device, and add it to this list, making sure that the + last entry is NULL. */ static struct usb_serial_device_type *usb_serial_devices[] = { #ifdef CONFIG_USB_SERIAL_GENERIC &generic_device, diff --git a/drivers/usb/usb-storage-debug.h b/drivers/usb/usb-storage-debug.h index 8994c06ba..1c5fcc0e2 100644 --- a/drivers/usb/usb-storage-debug.h +++ b/drivers/usb/usb-storage-debug.h @@ -1,3 +1,4 @@ +#include <linux/config.h> #ifdef CONFIG_USB_STORAGE_DEBUG /* Debug output for Driver for USB mass storage (scsi-like) devices diff --git a/drivers/usb/usbkbd.c b/drivers/usb/usbkbd.c index f3358ddfe..00fecea9d 100644 --- a/drivers/usb/usbkbd.c +++ b/drivers/usb/usbkbd.c @@ -32,6 +32,7 @@ #include <linux/malloc.h> #include <linux/module.h> #include <linux/input.h> +#include <linux/init.h> #include "usb.h" MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); @@ -202,17 +203,16 @@ static struct usb_driver usb_kbd_driver = { disconnect: usb_kbd_disconnect }; -#ifdef MODULE -void cleanup_module(void) +static int __init usb_kbd_init(void) { - usb_deregister(&usb_kbd_driver); + usb_register(&usb_kbd_driver); + return 0; } -int init_module(void) -#else -int usb_kbd_init(void) -#endif +static void __exit usb_kbd_exit(void) { - usb_register(&usb_kbd_driver); - return 0; + usb_deregister(&usb_kbd_driver); } + +module_init(usb_kbd_init); +module_exit(usb_kbd_exit); diff --git a/drivers/usb/usbmouse.c b/drivers/usb/usbmouse.c index 7276ca670..75e834649 100644 --- a/drivers/usb/usbmouse.c +++ b/drivers/usb/usbmouse.c @@ -32,6 +32,7 @@ #include <linux/malloc.h> #include <linux/input.h> #include <linux/module.h> +#include <linux/init.h> #include "usb.h" MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); @@ -132,18 +133,16 @@ static struct usb_driver usb_mouse_driver = { disconnect: usb_mouse_disconnect, }; -#ifdef MODULE -void cleanup_module(void) +static int __init usb_mouse_init(void) { - usb_deregister(&usb_mouse_driver); + usb_register(&usb_mouse_driver); + return 0; } -int init_module(void) -#else -int usb_mouse_init(void) -#endif +static void __exit usb_mouse_exit(void) { - usb_register(&usb_mouse_driver); - return 0; + usb_deregister(&usb_mouse_driver); } +module_init(usb_mouse_init); +module_exit(usb_mouse_exit); diff --git a/drivers/usb/wmforce.c b/drivers/usb/wmforce.c index fa2d1b465..06ddeb5b2 100644 --- a/drivers/usb/wmforce.c +++ b/drivers/usb/wmforce.c @@ -32,6 +32,7 @@ #include <linux/malloc.h> #include <linux/input.h> #include <linux/module.h> +#include <linux/init.h> #include "usb.h" MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); @@ -149,17 +150,16 @@ static struct usb_driver wmforce_driver = { disconnect: wmforce_disconnect, }; -#ifdef MODULE -void cleanup_module(void) +static int __init wmforce_init(void) { - usb_deregister(&wmforce_driver); + usb_register(&wmforce_driver); + return 0; } -int init_module(void) -#else -int wmforce_init(void) -#endif +static void __exit wmforce_exit(void) { - usb_register(&wmforce_driver); - return 0; + usb_deregister(&wmforce_driver); } + +module_init(wmforce_init); +module_exit(wmforce_exit); diff --git a/drivers/video/Config.in b/drivers/video/Config.in index b7a855b77..9d12bf42a 100644 --- a/drivers/video/Config.in +++ b/drivers/video/Config.in @@ -105,6 +105,10 @@ if [ "$CONFIG_FB" = "y" ]; then bool ' Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM bool ' Mystique support' CONFIG_FB_MATROX_MYSTIQUE bool ' G100/G200/G400 support' CONFIG_FB_MATROX_G100 + dep_tristate ' Matrox I2C support' CONFIG_FB_MATROX_I2C $CONFIG_FB_MATROX $CONFIG_I2C_ALGOBIT + if [ "$CONFIG_FB_MATROX_G100" = "y" ]; then + dep_tristate ' G400 second head support' CONFIG_FB_MATROX_MAVEN $CONFIG_FB_MATROX_I2C + fi bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD fi tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY diff --git a/drivers/video/Makefile b/drivers/video/Makefile index e52eee833..75896bbf8 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -3,9 +3,9 @@ # Rewritten to use lists instead of if-statements. SUB_DIRS := -MOD_SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) MOD_IN_SUB_DIRS := -ALL_SUB_DIRS := +ALL_SUB_DIRS := $(SUB_DIRS) matrox O_TARGET := video.o O_OBJS := @@ -16,7 +16,11 @@ M_OBJS := # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := fbmem.o fbcmap.o fbcon.o fbcon-afb.o fbcon-ilbm.o fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o fbcon-vga.o +export-objs := fbmem.o fbcmap.o fbcon.o fbcon-afb.o fbcon-ilbm.o fbcon-vga.o \ + fbcon-iplan2p2.o fbcon-iplan2p4.o fbcon-iplan2p8.o fbcon-vga-planes.o \ + fbcon-cfb16.o fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o fbcon-cfb8.o \ + fbcon-mac.o fbcon-mfb.o fbcon-vga8-planes.o \ + matrox/matroxfb.o # Object file lists. obj-y := @@ -81,11 +85,20 @@ obj-$(CONFIG_FB_TCX) += tcxfb.o sbusfb.o obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o -obj-$(CONFIG_FB_MATROX) += matroxfb.o obj-$(CONFIG_FB_SUN3) += sun3fb.o obj-$(CONFIG_FB_BWTWO) += bwtwofb.o obj-$(CONFIG_FB_VIRTUAL) += vfb.o +ifeq ($(CONFIG_FB_MATROX),y) +SUB_DIRS += matrox +obj-y += matrox/matrox.o +MOD_SUB_DIRS += matrox +else + ifeq ($(CONFIG_FB_MATROX),m) + MOD_SUB_DIRS += matrox + endif +endif + # Generic Low Level Drivers obj-$(CONFIG_FBCON_AFB) += fbcon-afb.o diff --git a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c index da084b045..388b0e1d2 100644 --- a/drivers/video/aty128fb.c +++ b/drivers/video/aty128fb.c @@ -118,20 +118,19 @@ static struct fb_videomode defaultmode __initdata = { /* chip description information */ struct aty128_chip_info { const char *name; - unsigned short vendor; unsigned short device; }; /* supported Rage128 chipsets */ -static const struct aty128_chip_info aty128_pci_probe_list[] = -{ - {"PCI_DEVICE_ID_ATI_RAGE128_RE", PCI_VENDOR_ID_ATI, 0x5245}, - {"PCI_DEVICE_ID_ATI_RAGE128_RF", PCI_VENDOR_ID_ATI, 0x5246}, - {"PCI_DEVICE_ID_ATI_RAGE128_RK", PCI_VENDOR_ID_ATI, 0x524b}, - {"PCI_DEVICE_ID_ATI_RAGE128_RL", PCI_VENDOR_ID_ATI, 0x524c}, - {"PCI_DEVICE_ID_ATI_RAGE128_PF", PCI_VENDOR_ID_ATI, 0x5046}, - {"PCI_DEVICE_ID_ATI_RAGE128_PR", PCI_VENDOR_ID_ATI, 0x5052}, - {NULL, 0, 0} +static const struct aty128_chip_info aty128_pci_probe_list[] __initdata = +{ + {"Rage128 RE (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RE}, + {"Rage128 RF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RF}, + {"Rage128 RK (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RK}, + {"Rage128 RL (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RL}, + {"Rage128 Pro PF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_PF}, + {"Rage128 Pro PR (PCI)", PCI_DEVICE_ID_ATI_RAGE128_PR}, + {NULL, 0} }; /* packed BIOS settings */ @@ -186,7 +185,8 @@ static int currcon = 0; static char *aty128fb_name = "ATY Rage128"; static char fontname[40] __initdata = { 0 }; -static char noaccel __initdata = 0; +static char noaccel __initdata = 1; +static unsigned int initdepth __initdata = 8; #ifndef MODULE static const char *mode_option __initdata = NULL; @@ -253,7 +253,9 @@ struct fb_info_aty128 { void *regbase; const struct aty128_meminfo *mem; /* onboard mem info */ u32 vram_size; /* onboard video ram */ - void *BIOS_SEG; /* BIOS segment */ +#ifndef CONFIG_PPC + void *bios_seg; /* video BIOS segment */ +#endif unsigned short card_revision; /* video card revision */ struct aty128fb_par default_par, current_par; struct display disp; @@ -362,12 +364,27 @@ static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p, #endif #ifdef FBCON_HAS_CFB16 static struct display_switch fbcon_aty128_16; +static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, + int c, int yy, int xx); +static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, + int yy, int xx); #endif #ifdef FBCON_HAS_CFB24 static struct display_switch fbcon_aty128_24; +static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, + int c, int yy, int xx); +static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, + int yy, int xx); #endif #ifdef FBCON_HAS_CFB32 static struct display_switch fbcon_aty128_32; +static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, + int c, int yy, int xx); +static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, + int yy, int xx); #endif static struct fb_ops aty128fb_ops = { @@ -651,7 +668,7 @@ aty128_init_engine(const struct aty128fb_par *par, GMC_SRC_CLIP_DEFAULT | GMC_DST_CLIP_DEFAULT | GMC_BRUSH_SOLIDCOLOR | - (bpp_to_depth(par->crtc.bpp) << 8) | + (bpp_to_depth(par->crtc.bpp << 8)) | GMC_SRC_DSTCOLOR | GMC_BYTE_ORDER_MSB_TO_LSB | GMC_DP_CONVERSION_TEMP_6500 | @@ -911,6 +928,7 @@ aty128_crtc_to_var(const struct aty128_crtc *crtc, u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; u32 pix_width; + /* fun with masking */ h_total = crtc->h_total & 0x1ff; h_disp = (crtc->h_total>>16) & 0xff; h_sync_strt = (crtc->h_sync_strt_wid>>3) & 0x1ff; @@ -1094,7 +1112,7 @@ aty128_ddafifo(struct aty128_ddafifo *dsp, x; #ifdef DEBUG - printk(KERN_DEBUG "x %x\n", x); + printk(KERN_DEBUG "aty128fb: x %x\n", x); #endif b = 0; while (x) { @@ -1109,13 +1127,13 @@ aty128_ddafifo(struct aty128_ddafifo *dsp, x = round_div(n, d); roff = x * (fifo_depth - 4); if ((ron + m->Rloop) >= roff) { - printk(KERN_ERR "Mode out of range\n"); + printk(KERN_ERR "aty128fb: Mode out of range!\n"); return -EINVAL; } #ifdef DEBUG - printk(KERN_DEBUG "p: %x rloop: %x x: %x ron: %x roff: %x\n", p, - m->Rloop, x, ron, roff); + printk(KERN_DEBUG "aty128fb: p: %x rloop: %x x: %x ron: %x roff: %x\n", + p, m->Rloop, x, ron, roff); #endif dsp->dda_config = p << 16 | m->Rloop << 20 | x; dsp->dda_on_off = ron << 16 | roff; @@ -1203,10 +1221,10 @@ aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par, { int err; - if ((err = aty128_var_to_crtc(var, &(par->crtc), info))) + if ((err = aty128_var_to_crtc(var, &par->crtc, info))) return err; - if ((err = aty128_var_to_pll(var->pixclock, &(par->pll), info))) + if ((err = aty128_var_to_pll(var->pixclock, &par->pll, info))) return err; if ((err = aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.bpp, info))) @@ -1587,7 +1605,25 @@ aty128fb_setup(char *options) fontname[i] = 0; } else if (!strncmp(this_opt, "noaccel", 7)) { noaccel = 1; - } + } else if (!strncmp(this_opt, "depth:", 6)) { + unsigned int depth = simple_strtoul(this_opt+6, NULL, 0); + switch (depth) { + case 0 ... 8: + initdepth = 8; + break; + case 9 ... 16: + initdepth = 16; + break; + case 17 ... 24: + initdepth = 24; + break; + case 25 ... 32: + initdepth = 32; + break; + default: + initdepth = 8; + } + } #ifdef CONFIG_MTRR else if(!strncmp(this_opt, "nomtrr", 6)) { mtrr = 0; @@ -1636,9 +1672,11 @@ aty128_init(struct fb_info_aty128 *info, const char *name) u32 dac; int j, k; u8 chip_rev; + const struct aty128_chip_info *aci = &aty128_pci_probe_list[0]; + char *video_card = NULL; if (!register_test(info)) { - printk(KERN_ERR "Can't write to video registers\n"); + printk(KERN_ERR "aty128fb: Can't write to video registers\n"); return 0; } @@ -1647,14 +1685,17 @@ aty128_init(struct fb_info_aty128 *info, const char *name) chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F; - /* TODO: be more verbose */ - printk(KERN_INFO "aty128fb: Rage128 [chip rev 0x%x] [card rev %x] ", - chip_rev, info->card_revision); + /* put a name with the face */ + while (info->pdev->device != aci->device) { aci++; } + video_card = (char *)aci->name; + + printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] [card rev %x] ", + video_card, chip_rev, info->card_revision); if (info->vram_size % (1024 * 1024) == 0) - printk("%dM \n", info->vram_size / (1024*1024)); + printk("%dM\n", info->vram_size / (1024*1024)); else - printk("%dk \n", info->vram_size / 1024); + printk("%dk\n", info->vram_size / 1024); /* fill in info */ strcpy(info->fb_info.modename, aty128fb_name); @@ -1678,7 +1719,7 @@ aty128_init(struct fb_info_aty128 *info, const char *name) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1) if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, - &defaultmode, 8)) + &defaultmode, initdepth)) var = default_var; #endif @@ -1767,13 +1808,13 @@ aty128pci_probe(void) struct pci_dev *pdev = NULL; const struct aty128_chip_info *aci = &aty128_pci_probe_list[0]; - while(aci->name != NULL) { - pdev = pci_find_device(aci->vendor, aci->device, NULL); - while(pdev != NULL) { - if(aty128_pci_register(pdev, aci) > 0) + while (aci->name != NULL) { + pdev = pci_find_device(PCI_VENDOR_ID_ATI, aci->device, pdev); + while (pdev != NULL) { + if (aty128_pci_register(pdev, aci) == 0) return; - pdev = pci_find_device(aci->vendor, aci->device, pdev); - } + pdev = pci_find_device(PCI_VENDOR_ID_ATI, aci->device, pdev); + } aci++; } @@ -1797,16 +1838,16 @@ aty128_pci_register(struct pci_dev *pdev, fb_addr = rp->start; fb_addr &= PCI_BASE_ADDRESS_MEM_MASK; - request_mem_region (rp->start, rp->end - rp->start + 1, "aty128fb"); + request_mem_region(rp->start, rp->end - rp->start + 1, "aty128fb"); rp = &pdev->resource[2]; reg_addr = rp->start; reg_addr &= PCI_BASE_ADDRESS_MEM_MASK; if (!reg_addr) { - release_mem_region (pdev->resource[0].start, - pdev->resource[0].end - - pdev->resource[0].start + 1); + release_mem_region(pdev->resource[0].start, + pdev->resource[0].end - + pdev->resource[0].start + 1); return -1; } #else @@ -1874,13 +1915,13 @@ aty128_pci_register(struct pci_dev *pdev, return 0; err_out: - kfree (info); + kfree(info); unmap_out: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1) - release_mem_region (pdev->resource[0].start, + release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1); - release_mem_region (pdev->resource[2].start, + release_mem_region(pdev->resource[2].start, pdev->resource[2].end - pdev->resource[2].start + 1); #endif @@ -1949,7 +1990,7 @@ aty128find_ROM(struct fb_info_aty128 *info) printk(KERN_INFO "aty128fb: Rage128 BIOS located at segment %4.4X\n", (u32)rom_base); - info->BIOS_SEG = rom_base; + info->bios_seg = rom_base; flag = 1; break; } @@ -1965,16 +2006,16 @@ aty128_get_pllinfo(struct fb_info_aty128 *info) u16 bios_header_offset, pll_info_offset; PLL_BLOCK pll; - bios_header = info->BIOS_SEG + 0x48L; + bios_header = info->bios_seg + 0x48L; header_ptr = bios_header; bios_header_offset = readw(header_ptr); - bios_header = info->BIOS_SEG + bios_header_offset; + bios_header = info->bios_seg + bios_header_offset; bios_header += 0x30; header_ptr = bios_header; pll_info_offset = readw(header_ptr); - header_ptr = info->BIOS_SEG + pll_info_offset; + header_ptr = info->bios_seg + pll_info_offset; memcpy_fromio(&pll, header_ptr, 50); @@ -2013,8 +2054,8 @@ aty128_get_pllinfo(struct fb_info_aty128 *info) } /* free up to-be unused resources */ - if (info->BIOS_SEG) - iounmap(info->BIOS_SEG); + if (info->bios_seg) + iounmap(info->bios_seg); return; } @@ -2346,7 +2387,6 @@ fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx, } -/* TODO: Fix accel and add to these structs */ #ifdef FBCON_HAS_CFB8 static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx) diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c index 57ae6e15e..5b78c939c 100644 --- a/drivers/video/atyfb.c +++ b/drivers/video/atyfb.c @@ -1,4 +1,4 @@ -/* $Id: atyfb.c,v 1.139 2000/02/12 22:47:04 davem Exp $ +/* $Id: atyfb.c,v 1.140 2000/02/25 05:46:27 davem Exp $ * linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64 * * Copyright (C) 1997-1998 Geert Uytterhoeven @@ -63,11 +63,13 @@ #ifdef __powerpc__ #include <linux/adb.h> -#include <linux/pmu.h> #include <asm/prom.h> #include <asm/pci-bridge.h> #include <video/macmodes.h> #endif +#ifdef CONFIG_ADB_PMU +#include <linux/pmu.h> +#endif #ifdef CONFIG_NVRAM #include <linux/nvram.h> #endif @@ -121,10 +123,6 @@ #define GUI_RESERVE (1 * PAGE_SIZE) -#ifndef __powerpc__ -#define eieio() /* Enforce In-order Execution of I/O */ -#endif - /* FIXME: remove the FAIL definition */ #define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0) @@ -3205,25 +3203,18 @@ static void atyfb_save_palette(struct fb_info *fb, int enter) tmp |= 0x2; aty_st_8(DAC_CNTL, tmp, info); aty_st_8(DAC_MASK, 0xff, info); - eieio(); + scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) && (info->current_par.crtc.bpp == 16)) ? 3 : 0; - info->aty_cmap_regs->rindex = i << scale; - eieio(); - atyfb_save.r[enter][i] = info->aty_cmap_regs->lut; - eieio(); - atyfb_save.g[enter][i] = info->aty_cmap_regs->lut; - eieio(); - atyfb_save.b[enter][i] = info->aty_cmap_regs->lut; - eieio(); - info->aty_cmap_regs->windex = i << scale; - eieio(); - info->aty_cmap_regs->lut = atyfb_save.r[1-enter][i]; - eieio(); - info->aty_cmap_regs->lut = atyfb_save.g[1-enter][i]; - eieio(); - info->aty_cmap_regs->lut = atyfb_save.b[1-enter][i]; - eieio(); + writeb(i << scale, &info->aty_cmap_regs->rindex); + + atyfb_save.r[enter][i] = readb(&info->aty_cmap_regs->lut); + atyfb_save.g[enter][i] = readb(&info->aty_cmap_regs->lut); + atyfb_save.b[enter][i] = readb(&info->aty_cmap_regs->lut); + writeb(i << scale, &info->aty_cmap_regs->windex); + writeb(atyfb_save.r[1-enter][i], &info->aty_cmap_regs->lut); + writeb(atyfb_save.g[1-enter][i], &info->aty_cmap_regs->lut); + writeb(atyfb_save.b[1-enter][i], &info->aty_cmap_regs->lut); } } @@ -3276,9 +3267,6 @@ static int __init aty_init(struct fb_info_aty *info, const char *name) u8 pll_ref_div; info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0); -#ifdef __sparc_v9__ - info->aty_cmap_regs = __va(info->aty_cmap_regs); -#endif chip_id = aty_ld_le32(CONFIG_CHIP_ID, info); Gx = chip_id & CFG_CHIP_TYPE; Rev = (chip_id & CFG_CHIP_REV)>>24; @@ -3519,6 +3507,9 @@ static int __init aty_init(struct fb_info_aty *info, const char *name) info->total_vram -= GUI_RESERVE; } + /* Clear the video memory */ + memset_io(info->frame_buffer, 0, info->total_vram); + disp = &info->disp; strcpy(info->fb_info.modename, atyfb_name); @@ -3692,7 +3683,7 @@ int __init atyfb_init(void) /* * Map in big-endian aperture. */ - info->frame_buffer = (unsigned long) __va(addr + 0x800000UL); + info->frame_buffer = (unsigned long) addr + 0x800000UL; info->frame_buffer_phys = addr + 0x800000UL; /* @@ -3937,7 +3928,7 @@ int __init atyfb_init(void) * Add /dev/fb mmap values. */ info->mmap_map[0].voff = 0x8000000000000000UL; - info->mmap_map[0].poff = __pa(info->frame_buffer & PAGE_MASK); + info->mmap_map[0].poff = info->frame_buffer & PAGE_MASK; info->mmap_map[0].size = info->total_vram; info->mmap_map[0].prot_mask = _PAGE_CACHE; info->mmap_map[0].prot_flag = _PAGE_E; @@ -4186,7 +4177,7 @@ static void atyfbcon_blank(int blank, struct fb_info *fb) struct fb_info_aty *info = (struct fb_info_aty *)fb; u8 gen_cntl; -#ifdef CONFIG_PPC +#ifdef CONFIG_ADB_PMU if ((_machine == _MACH_Pmac) && blank) pmu_enable_backlight(0); #endif @@ -4211,7 +4202,7 @@ static void atyfbcon_blank(int blank, struct fb_info *fb) gen_cntl &= ~(0x4c); aty_st_8(CRTC_GEN_CNTL, gen_cntl, info); -#ifdef CONFIG_PPC +#ifdef CONFIG_ADB_PMU if ((_machine == _MACH_Pmac) && !blank) pmu_enable_backlight(1); #endif @@ -4268,14 +4259,10 @@ static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, aty_st_8(DAC_MASK, 0xff, info); scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) && (info->current_par.crtc.bpp == 16)) ? 3 : 0; - info->aty_cmap_regs->windex = regno << scale; - eieio(); - info->aty_cmap_regs->lut = red; - eieio(); - info->aty_cmap_regs->lut = green; - eieio(); - info->aty_cmap_regs->lut = blue; - eieio(); + writeb(regno << scale, &info->aty_cmap_regs->windex); + writeb(red, &info->aty_cmap_regs->lut); + writeb(green, &info->aty_cmap_regs->lut); + writeb(blue, &info->aty_cmap_regs->lut); if (regno < 16) switch (info->current_par.crtc.bpp) { #ifdef FBCON_HAS_CFB16 diff --git a/drivers/video/matrox/Makefile b/drivers/video/matrox/Makefile new file mode 100644 index 000000000..6de9be372 --- /dev/null +++ b/drivers/video/matrox/Makefile @@ -0,0 +1,60 @@ +# Makefile for the Linux video drivers. +# 5 Aug 1999, James Simmons, <mailto:jsimmons@edgeglobal.com> +# Rewritten to use lists instead of if-statements. + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +MOD_IN_SUB_DIRS := +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := matrox.o +O_OBJS := +M_OBJS := +# This is a nice idea but needs depmod altering +# MOD_LIST_NAME := VIDEO_MODULES + +# All of the (potential) objects that export symbols. +# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. + +export-objs := matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o + +# Object file lists. +obj-y := +obj-m := +obj-n := +obj- := + +# Each configuration option enables a list of files. + +obj-$(CONFIG_FB_MATROX) += matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o +obj-$(CONFIG_FB_MATROX_I2C) += i2c-matroxfb.o +obj-$(CONFIG_FB_MATROX_MAVEN) += matroxfb_maven.o matroxfb_crtc2.o + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. + +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Take multi-part drivers out of obj-y and put components in. + +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +# Translate to Rules.make lists. + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c new file mode 100644 index 000000000..bbb695223 --- /dev/null +++ b/drivers/video/matrox/i2c-matroxfb.c @@ -0,0 +1,348 @@ +#include "matroxfb_base.h" +#include "matroxfb_maven.h" +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> + +/* MGA-TVO I2C for G200, G400 */ +#define MAT_CLK 0x20 +#define MAT_DATA 0x10 +/* primary head DDC for Mystique(?), G100, G200, G400 */ +#define DDC1_CLK 0x08 +#define DDC1_DATA 0x02 +/* primary head DDC for Millennium, Millennium II */ +#define DDC1B_CLK 0x10 +#define DDC1B_DATA 0x04 +/* secondary head DDC for G400 */ +#define DDC2_CLK 0x04 +#define DDC2_DATA 0x01 + +/******************************************************/ + +static int matroxfb_read_gpio(struct matrox_fb_info* minfo) { + unsigned long flags; + int v; + + matroxfb_DAC_lock_irqsave(flags); + v = matroxfb_DAC_in(PMINFO DAC_XGENIODATA); + matroxfb_DAC_unlock_irqrestore(flags); + return v; +} + +static inline void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) { + unsigned long flags; + int v; + + matroxfb_DAC_lock_irqsave(flags); + v = (matroxfb_DAC_in(PMINFO DAC_XGENIOCTRL) & mask) | val; + matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, v); + /* We must reset GENIODATA very often... XFree plays with this register */ + matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0x00); + matroxfb_DAC_unlock_irqrestore(flags); +} + +/* software I2C functions */ +static void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) { + if (state) + state = 0; + else + state = mask; + matroxfb_set_gpio(minfo, ~mask, state); +} + +static void matroxfb_maven_setsda(void* data, int state) { + matroxfb_i2c_set(data, MAT_DATA, state); +} + +static void matroxfb_maven_setscl(void* data, int state) { + matroxfb_i2c_set(data, MAT_CLK, state); +} + +static int matroxfb_maven_getsda(void* data) { + return (matroxfb_read_gpio(data) & MAT_DATA) ? 1 : 0; +} + +static int matroxfb_maven_getscl(void* data) { + return (matroxfb_read_gpio(data) & MAT_CLK) ? 1 : 0; +} + +static void matroxfb_ddc1_setsda(void* data, int state) { + matroxfb_i2c_set(data, DDC1_DATA, state); +} + +static void matroxfb_ddc1_setscl(void* data, int state) { + matroxfb_i2c_set(data, DDC1_CLK, state); +} + +static int matroxfb_ddc1_getsda(void* data) { + return (matroxfb_read_gpio(data) & DDC1_DATA) ? 1 : 0; +} + +static int matroxfb_ddc1_getscl(void* data) { + return (matroxfb_read_gpio(data) & DDC1_CLK) ? 1 : 0; +} + +static void matroxfb_ddc1b_setsda(void* data, int state) { + matroxfb_i2c_set(data, DDC1B_DATA, state); +} + +static void matroxfb_ddc1b_setscl(void* data, int state) { + matroxfb_i2c_set(data, DDC1B_CLK, state); +} + +static int matroxfb_ddc1b_getsda(void* data) { + return (matroxfb_read_gpio(data) & DDC1B_DATA) ? 1 : 0; +} + +static int matroxfb_ddc1b_getscl(void* data) { + return (matroxfb_read_gpio(data) & DDC1B_CLK) ? 1 : 0; +} + +static void matroxfb_ddc2_setsda(void* data, int state) { + matroxfb_i2c_set(data, DDC2_DATA, state); +} + +static void matroxfb_ddc2_setscl(void* data, int state) { + matroxfb_i2c_set(data, DDC2_CLK, state); +} + +static int matroxfb_ddc2_getsda(void* data) { + return (matroxfb_read_gpio(data) & DDC2_DATA) ? 1 : 0; +} + +static int matroxfb_ddc2_getscl(void* data) { + return (matroxfb_read_gpio(data) & DDC2_CLK) ? 1 : 0; +} + +static void matroxfb_dh_inc_use(struct i2c_adapter* dummy) { + MOD_INC_USE_COUNT; +} + +static void matroxfb_dh_dec_use(struct i2c_adapter* dummy) { + MOD_DEC_USE_COUNT; +} + +static struct i2c_adapter matroxmaven_i2c_adapter_template = +{ + "", + I2C_HW_B_G400, + + NULL, + NULL, + + matroxfb_dh_inc_use, + matroxfb_dh_dec_use, + NULL, + NULL, + NULL, +}; + +static struct i2c_algo_bit_data matroxmaven_i2c_algo_template = +{ + NULL, + matroxfb_maven_setsda, + matroxfb_maven_setscl, + matroxfb_maven_getsda, + matroxfb_maven_getscl, + 10, 10, 100, +}; + +static struct i2c_adapter matrox_ddc1_adapter_template = +{ + "", + I2C_HW_B_G400, /* DDC */ + + NULL, + NULL, + + matroxfb_dh_inc_use, + matroxfb_dh_dec_use, + NULL, + NULL, + NULL, +}; + +static struct i2c_algo_bit_data matrox_ddc1_algo_template = +{ + NULL, + matroxfb_ddc1_setsda, + matroxfb_ddc1_setscl, + matroxfb_ddc1_getsda, + matroxfb_ddc1_getscl, + 10, 10, 100, +}; + +static struct i2c_algo_bit_data matrox_ddc1b_algo_template = +{ + NULL, + matroxfb_ddc1b_setsda, + matroxfb_ddc1b_setscl, + matroxfb_ddc1b_getsda, + matroxfb_ddc1b_getscl, + 10, 10, 100, +}; + +static struct i2c_adapter matrox_ddc2_adapter_template = +{ + "", + I2C_HW_B_G400, /* DDC */ + + NULL, + NULL, + + matroxfb_dh_inc_use, /* should increment matroxfb_maven usage too, this DDC is coupled with maven_client */ + matroxfb_dh_dec_use, /* should decrement matroxfb_maven usage too */ + NULL, + NULL, + NULL, +}; + +static struct i2c_algo_bit_data matrox_ddc2_algo_template = +{ + NULL, + matroxfb_ddc2_setsda, + matroxfb_ddc2_setscl, + matroxfb_ddc2_getsda, + matroxfb_ddc2_getscl, + 10, 10, 100, +}; + +static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo) { + int err; + + b->adapter.data = minfo; + b->adapter.algo_data = &b->bac; + b->bac.data = minfo; + err = i2c_bit_add_bus(&b->adapter); + b->initialized = !err; + return err; +} + +static void i2c_bit_bus_del(struct i2c_bit_adapter* b) { + if (b->initialized) { + i2c_bit_del_bus(&b->adapter); + b->initialized = 0; + } +} + +static inline int i2c_maven_init(struct matroxfb_dh_maven_info* minfo2) { + struct i2c_bit_adapter *b = &minfo2->maven; + + b->adapter = matroxmaven_i2c_adapter_template; + b->bac = matroxmaven_i2c_algo_template; + sprintf(b->adapter.name, "MAVEN:fb%u on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node)); + return i2c_bus_reg(b, minfo2->primary_dev); +} + +static inline void i2c_maven_done(struct matroxfb_dh_maven_info* minfo2) { + i2c_bit_bus_del(&minfo2->maven); +} + +static inline int i2c_ddc1_init(struct matroxfb_dh_maven_info* minfo2) { + struct i2c_bit_adapter *b = &minfo2->ddc1; + + b->adapter = matrox_ddc1_adapter_template; + b->bac = matrox_ddc1_algo_template; + sprintf(b->adapter.name, "DDC:fb%u #0 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node)); + return i2c_bus_reg(b, minfo2->primary_dev); +} + +static inline int i2c_ddc1b_init(struct matroxfb_dh_maven_info* minfo2) { + struct i2c_bit_adapter *b = &minfo2->ddc1; + + b->adapter = matrox_ddc1_adapter_template; + b->bac = matrox_ddc1b_algo_template; + sprintf(b->adapter.name, "DDC:fb%u #0 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node)); + return i2c_bus_reg(b, minfo2->primary_dev); +} + +static inline void i2c_ddc1_done(struct matroxfb_dh_maven_info* minfo2) { + i2c_bit_bus_del(&minfo2->ddc1); +} + +static inline int i2c_ddc2_init(struct matroxfb_dh_maven_info* minfo2) { + struct i2c_bit_adapter *b = &minfo2->ddc2; + + b->adapter = matrox_ddc2_adapter_template; + b->bac = matrox_ddc2_algo_template; + sprintf(b->adapter.name, "DDC:fb%u #1 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node)); + return i2c_bus_reg(b, minfo2->primary_dev); +} + +static inline void i2c_ddc2_done(struct matroxfb_dh_maven_info* minfo2) { + i2c_bit_bus_del(&minfo2->ddc2); +} + +static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) { + int err; + unsigned long flags; + struct matroxfb_dh_maven_info* m2info; + + m2info = (struct matroxfb_dh_maven_info*)kmalloc(sizeof(*m2info), GFP_KERNEL); + if (!m2info) + return NULL; + + matroxfb_DAC_lock_irqsave(flags); + matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0x00); + matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, 0xFF); + matroxfb_DAC_unlock_irqrestore(flags); + + memset(m2info, 0, sizeof(*m2info)); + m2info->primary_dev = minfo; + + if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2064W || + ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2164W || + ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2164W_AGP) + err = i2c_ddc1b_init(m2info); + else + err = i2c_ddc1_init(m2info); + if (err) + goto fail_ddc1; + if (ACCESS_FBINFO(devflags.maven_capable)) { + err = i2c_ddc2_init(m2info); + if (err) + printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n"); + err = i2c_maven_init(m2info); + if (err) + printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n"); + } + return m2info; +fail_ddc1:; + kfree(m2info); + printk(KERN_ERR "i2c-matroxfb: Could not register primary adapter DDC bus.\n"); + return NULL; +} + +static void i2c_matroxfb_remove(struct matrox_fb_info* minfo, void* data) { + struct matroxfb_dh_maven_info* m2info = data; + + i2c_maven_done(m2info); + i2c_ddc2_done(m2info); + i2c_ddc1_done(m2info); + kfree(m2info); +} + +static struct matroxfb_driver i2c_matroxfb = { + LIST_HEAD_INIT(i2c_matroxfb.node), + "i2c-matroxfb", + i2c_matroxfb_probe, + i2c_matroxfb_remove, +}; + +static int __init i2c_matroxfb_init(void) { + if (matroxfb_register_driver(&i2c_matroxfb)) { + printk(KERN_ERR "i2c-matroxfb: failed to register driver\n"); + return -ENXIO; + } + return 0; +} + +static void __exit i2c_matroxfb_exit(void) { + matroxfb_unregister_driver(&i2c_matroxfb); +} + +MODULE_AUTHOR("(c) 1999 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards"); + +module_init(i2c_matroxfb_init); +module_exit(i2c_matroxfb_exit); +/* no __setup required */ diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c new file mode 100644 index 000000000..db84a3000 --- /dev/null +++ b/drivers/video/matrox/matroxfb_DAC1064.c @@ -0,0 +1,924 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 + * + * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Version: 1.21 1999/01/09 + * + * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> + * + * Contributors: "menion?" <menion@mindless.com> + * Betatesting, fixes, ideas + * + * "Kurt Garloff" <garloff@kg1.ping.de> + * Betatesting, fixes, ideas, videomodes, videomodes timmings + * + * "Tom Rini" <trini@kernel.crashing.org> + * MTRR stuff, PPC cleanups, betatesting, fixes, ideas + * + * "Bibek Sahu" <scorpio@dodds.net> + * Access device through readb|w|l and write b|w|l + * Extensive debugging stuff + * + * "Daniel Haun" <haund@usa.net> + * Testing, hardware cursor fixes + * + * "Scott Wood" <sawst46+@pitt.edu> + * Fixes + * + * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> + * Betatesting + * + * "Kelly French" <targon@hazmat.com> + * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> + * Betatesting, bug reporting + * + * "Pablo Bianucci" <pbian@pccp.com.ar> + * Fixes, ideas, betatesting + * + * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> + * Fixes, enhandcements, ideas, betatesting + * + * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> + * PPC betatesting, PPC support, backward compatibility + * + * "Paul Womar" <Paul@pwomar.demon.co.uk> + * "Owen Waller" <O.Waller@ee.qub.ac.uk> + * PPC betatesting + * + * "Thomas Pornin" <pornin@bolet.ens.fr> + * Alpha betatesting + * + * "Pieter van Leuven" <pvl@iae.nl> + * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> + * G100 testing + * + * "H. Peter Arvin" <hpa@transmeta.com> + * Ideas + * + * "Cort Dougan" <cort@cs.nmt.edu> + * CHRP fixes and PReP cleanup + * + * "Mark Vojkovich" <mvojkovi@ucsd.edu> + * G400 support + * + * (following author is not in any relation with this code, but his code + * is included in this driver) + * + * Based on framebuffer driver for VBE 2.0 compliant graphic boards + * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> + * + * (following author is not in any relation with this code, but his ideas + * were used when writting this driver) + * + * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> + * + */ + +/* make checkconfig does not walk through include tree :-( */ +#include <linux/config.h> + +#include "matroxfb_DAC1064.h" +#include "matroxfb_misc.h" +#include "matroxfb_accel.h" +#include <linux/matroxfb.h> + +#ifdef NEED_DAC1064 +#define outDAC1064 matroxfb_DAC_out +#define inDAC1064 matroxfb_DAC_in + +#define DAC1064_OPT_SCLK_PCI 0x00 +#define DAC1064_OPT_SCLK_PLL 0x01 +#define DAC1064_OPT_SCLK_EXT 0x02 +#define DAC1064_OPT_SCLK_MASK 0x03 +#define DAC1064_OPT_GDIV1 0x04 /* maybe it is GDIV2 on G100 ?! */ +#define DAC1064_OPT_GDIV3 0x00 +#define DAC1064_OPT_MDIV1 0x08 +#define DAC1064_OPT_MDIV2 0x00 +#define DAC1064_OPT_RESERVED 0x10 + +static void matroxfb_DAC1064_flashcursor(unsigned long ptr) { +#define minfo ((struct matrox_fb_info*)ptr) + matroxfb_DAC_lock(); + outDAC1064(PMINFO M1064_XCURCTRL, inDAC1064(PMINFO M1064_XCURCTRL) ^ M1064_XCURCTRL_DIS ^ M1064_XCURCTRL_XGA); + ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2; + add_timer(&ACCESS_FBINFO(cursor.timer)); + matroxfb_DAC_unlock(); +#undef minfo +} + +static void matroxfb_DAC1064_createcursor(WPMINFO struct display* p) { + vaddr_t cursorbase; + u_int32_t xline; + unsigned int i; + unsigned int h, to; + CRITFLAGS + + if (ACCESS_FBINFO(currcon_display) != p) + return; + + matroxfb_createcursorshape(PMINFO p, p->var.vmode); + + xline = (~0) << (32 - ACCESS_FBINFO(cursor.w)); + cursorbase = ACCESS_FBINFO(video.vbase); + h = ACCESS_FBINFO(features.DAC1064.cursorimage); + + CRITBEGIN + +#ifdef __BIG_ENDIAN + WaitTillIdle(); + mga_outl(M_OPMODE, M_OPMODE_32BPP); +#endif + to = ACCESS_FBINFO(cursor.u); + for (i = 0; i < to; i++) { + mga_writel(cursorbase, h, 0); + mga_writel(cursorbase, h+4, 0); + mga_writel(cursorbase, h+8, ~0); + mga_writel(cursorbase, h+12, ~0); + h += 16; + } + to = ACCESS_FBINFO(cursor.d); + for (; i < to; i++) { + mga_writel(cursorbase, h, 0); + mga_writel(cursorbase, h+4, xline); + mga_writel(cursorbase, h+8, ~0); + mga_writel(cursorbase, h+12, ~0); + h += 16; + } + for (; i < 64; i++) { + mga_writel(cursorbase, h, 0); + mga_writel(cursorbase, h+4, 0); + mga_writel(cursorbase, h+8, ~0); + mga_writel(cursorbase, h+12, ~0); + h += 16; + } +#ifdef __BIG_ENDIAN + mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); +#endif + + CRITEND +} + +static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) { + unsigned long flags; + MINFO_FROM_DISP(p); + + if (ACCESS_FBINFO(currcon_display) != p) + return; + + if (mode == CM_ERASE) { + if (ACCESS_FBINFO(cursor.state) != CM_ERASE) { + matroxfb_DAC_lock_irqsave(flags); + ACCESS_FBINFO(cursor.state) = CM_ERASE; + del_timer(&ACCESS_FBINFO(cursor.timer)); + outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS); + matroxfb_DAC_unlock_irqrestore(flags); + } + return; + } + if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type)) + matroxfb_DAC1064_createcursor(PMINFO p); + x *= fontwidth(p); + y *= fontheight(p); + y -= p->var.yoffset; + if (p->var.vmode & FB_VMODE_DOUBLE) + y *= 2; + matroxfb_DAC_lock_irqsave(flags); + if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y)) || ACCESS_FBINFO(cursor.redraw)) { + ACCESS_FBINFO(cursor.redraw) = 0; + ACCESS_FBINFO(cursor.x) = x; + ACCESS_FBINFO(cursor.y) = y; + x += 64; + y += 64; + outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS); + mga_outb(M_RAMDAC_BASE+M1064_CURPOSXL, x); + mga_outb(M_RAMDAC_BASE+M1064_CURPOSXH, x >> 8); + mga_outb(M_RAMDAC_BASE+M1064_CURPOSYL, y); + mga_outb(M_RAMDAC_BASE+M1064_CURPOSYH, y >> 8); + } + ACCESS_FBINFO(cursor.state) = CM_DRAW; + if (ACCESS_FBINFO(devflags.blink)) + mod_timer(&ACCESS_FBINFO(cursor.timer), jiffies + HZ/2); + outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_XGA); + matroxfb_DAC_unlock_irqrestore(flags); +} + +static int matroxfb_DAC1064_setfont(struct display* p, int width, int height) { + if (p && p->conp) + matroxfb_DAC1064_createcursor(PMXINFO(p) p); + return 0; +} + +static int DAC1064_selhwcursor(WPMINFO struct display* p) { + ACCESS_FBINFO(dispsw.cursor) = matroxfb_DAC1064_cursor; + ACCESS_FBINFO(dispsw.set_font) = matroxfb_DAC1064_setfont; + return 0; +} + +static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) { + unsigned int fvco; + unsigned int p; + + DBG("DAC1064_calcclock") + + fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p); + p = (1 << p) - 1; + if (fvco <= 100000) + ; + else if (fvco <= 140000) + p |= 0x08; + else if (fvco <= 180000) + p |= 0x10; + else + p |= 0x18; + *post = p; +} + +/* they must be in POS order */ +static const unsigned char MGA1064_DAC_regs[] = { + M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL, + M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE, + M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE, + M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE, + DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL, + M1064_XMISCCTRL, + M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST, + M1064_XCRCBITSEL, + M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH }; + +static const unsigned char MGA1064_DAC[] = { + 0x00, 0x00, M1064_XCURCTRL_DIS, + 0x00, 0x00, 0x00, /* black */ + 0xFF, 0xFF, 0xFF, /* white */ + 0xFF, 0x00, 0x00, /* red */ + 0x00, 0, + M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL, + M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN, + M1064_XMISCCTRL_DAC_8BIT, + 0x00, 0x00, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN, + 0x00, + 0x00, 0x00, 0xFF, 0xFF}; + +static void DAC1064_setpclk(CPMINFO struct matrox_hw_state* hw, unsigned long fout) { + unsigned int m, n, p; + + DBG("DAC1064_setpclk") + + DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); + hw->DACclk[0] = m; + hw->DACclk[1] = n; + hw->DACclk[2] = p; +} + +static void DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem){ + u_int32_t mx; + + DBG("DAC1064_setmclk") + + if (ACCESS_FBINFO(devflags.noinit)) { + /* read MCLK and give up... */ + hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM); + hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN); + hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP); + return; + } + mx = hw->MXoptionReg | 0x00000004; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); + mx &= ~0x000000BB; + if (oscinfo & DAC1064_OPT_GDIV1) + mx |= 0x00000008; + if (oscinfo & DAC1064_OPT_MDIV1) + mx |= 0x00000010; + if (oscinfo & DAC1064_OPT_RESERVED) + mx |= 0x00000080; + if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) { + /* select PCI clock until we have setup oscilator... */ + int clk; + unsigned int m, n, p; + + /* powerup system PLL, select PCI clock */ + mx |= 0x00000020; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); + mx &= ~0x00000004; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); + + /* !!! you must not access device if MCLK is not running !!! + Doing so cause immediate PCI lockup :-( Maybe they should + generate ABORT or I/O (parity...) error and Linux should + recover from this... (kill driver/process). But world is not + perfect... */ + /* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not + select PLL... because of PLL can be stopped at this time) */ + DAC1064_calcclock(PMINFO fmem, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); + outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3] = m); + outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4] = n); + outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5] = p); + for (clk = 65536; clk; --clk) { + if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40) + break; + } + if (!clk) + printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n"); + /* select PLL */ + mx |= 0x00000005; + } else { + /* select specified system clock source */ + mx |= oscinfo & DAC1064_OPT_SCLK_MASK; + } + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); + mx &= ~0x00000004; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); + hw->MXoptionReg = mx; +} + +void DAC1064_global_init(CPMINFO struct matrox_hw_state* hw) { + hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK; + hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN; + hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL; +#if defined(CONFIG_FB_MATROX_MAVEN) || defined(CONFIG_FB_MATROX_MAVEN_MODULE) + if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) { + hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT; + hw->DACreg[POS1064_XMISCCTRL] |= G400_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12; + } else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) + hw->DACreg[POS1064_XMISCCTRL] |= G400_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12; + else + hw->DACreg[POS1064_XMISCCTRL] |= G400_XMISCCTRL_MFC_DIS; + if ((ACCESS_FBINFO(output.ph) | ACCESS_FBINFO(output.sh)) & MATROXFB_OUTPUT_CONN_PRIMARY) + hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN; +#else + hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_MFC_DIS | M1064_XMISCCTRL_DAC_EN; +#endif +} + +void DAC1064_global_restore(CPMINFO const struct matrox_hw_state* hw) { + outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]); + outDAC1064(PMINFO M1064_XMISCCTRL, hw->DACreg[POS1064_XMISCCTRL]); + if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) { + outDAC1064(PMINFO 0x20, 0x04); + outDAC1064(PMINFO 0x1F, 0x00); + } +} + +static int DAC1064_init_1(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display *p) { + DBG("DAC1064_init_1") + + memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs)); + if (p->type == FB_TYPE_TEXT) { + hw->DACreg[POS1064_XMISCCTRL] = M1064_XMISCCTRL_DAC_6BIT; + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP + | M1064_XMULCTRL_GRAPHICS_PALETIZED; + } else { + switch (p->var.bits_per_pixel) { + /* case 4: not supported by MGA1064 DAC */ + case 8: + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; + break; + case 16: + if (p->var.green.length == 5) + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; + else + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; + break; + case 24: + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; + break; + case 32: + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; + break; + default: + return 1; /* unsupported depth */ + } + } + + DAC1064_global_init(PMINFO hw); + hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl); + hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK; + hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN; + hw->DACreg[POS1064_XCURADDL] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 10; + hw->DACreg[POS1064_XCURADDH] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 18; + return 0; +} + +static int DAC1064_init_2(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) { + + DBG("DAC1064_init_2") + + if (p->var.bits_per_pixel > 16) { /* 256 entries */ + int i; + + for (i = 0; i < 256; i++) { + hw->DACpal[i * 3 + 0] = i; + hw->DACpal[i * 3 + 1] = i; + hw->DACpal[i * 3 + 2] = i; + } + } else if (p->var.bits_per_pixel > 8) { + if (p->var.green.length == 5) { /* 0..31, 128..159 */ + int i; + + for (i = 0; i < 32; i++) { + /* with p15 == 0 */ + hw->DACpal[i * 3 + 0] = i << 3; + hw->DACpal[i * 3 + 1] = i << 3; + hw->DACpal[i * 3 + 2] = i << 3; + /* with p15 == 1 */ + hw->DACpal[(i + 128) * 3 + 0] = i << 3; + hw->DACpal[(i + 128) * 3 + 1] = i << 3; + hw->DACpal[(i + 128) * 3 + 2] = i << 3; + } + } else { + int i; + + for (i = 0; i < 64; i++) { /* 0..63 */ + hw->DACpal[i * 3 + 0] = i << 3; + hw->DACpal[i * 3 + 1] = i << 2; + hw->DACpal[i * 3 + 2] = i << 3; + } + } + } else { + memset(hw->DACpal, 0, 768); + } + return 0; +} + +static void DAC1064_restore_1(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) { + CRITFLAGS + + DBG("DAC1064_restore_1") + + CRITBEGIN + + outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]); + outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]); + outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]); + if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) { + unsigned int i; + + for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) { + if ((i != POS1064_XPIXCLKCTRL) && (i != POS1064_XMISCCTRL)) + outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]); + } + } + + DAC1064_global_restore(PMINFO hw); + + CRITEND +}; + +static void DAC1064_restore_2(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw, struct display* p) { +#ifdef DEBUG + unsigned int i; +#endif + + DBG("DAC1064_restore_2") + + matrox_init_putc(PMINFO p, matroxfb_DAC1064_createcursor); +#ifdef DEBUG + dprintk(KERN_DEBUG "DAC1064regs "); + for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) { + dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], hw->DACreg[i]); + if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... "); + } + dprintk("\n" KERN_DEBUG "DAC1064clk "); + for (i = 0; i < 6; i++) + dprintk("C%02X=%02X ", i, hw->DACclk[i]); + dprintk("\n"); +#endif +} + +static int m1064_compute(void* outdev, struct my_timming* m, struct matrox_hw_state* hw) { +#define minfo ((struct matrox_fb_info*)outdev) + DAC1064_setpclk(PMINFO hw, m->pixclock); +#undef minfo + return 0; +} + +static int m1064_program(void* outdev, const struct matrox_hw_state* hw) { +#define minfo ((struct matrox_fb_info*)outdev) + int i; + int tmout; + CRITFLAGS + + CRITBEGIN + + for (i = 0; i < 3; i++) + outDAC1064(PMINFO M1064_XPIXPLLCM + i, hw->DACclk[i]); + for (tmout = 500000; tmout; tmout--) { + if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40) + break; + udelay(10); + }; + + CRITEND + + if (!tmout) + printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n"); + +#undef minfo + return 0; +} + +static int m1064_start(void* outdev) { + /* nothing */ + return 0; +} + +static void m1064_incuse(void* outdev) { + /* nothing yet; MODULE_INC_USE in future... */ +} + +static void m1064_decuse(void* outdev) { + /* nothing yet; MODULE_DEC_USE in future... */ +} + +static int m1064_setmode(void* outdev, u_int32_t mode) { + if (mode != MATROXFB_OUTPUT_MODE_MONITOR) + return -EINVAL; + return 0; +} + +static struct matrox_altout m1064 = { + m1064_compute, + m1064_program, + m1064_start, + m1064_incuse, + m1064_decuse, + m1064_setmode +}; + +#endif /* NEED_DAC1064 */ + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +static int MGA1064_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) { + + DBG("MGA1064_init") + + if (DAC1064_init_1(PMINFO hw, m, p)) return 1; + if (matroxfb_vgaHWinit(PMINFO hw, m, p)) return 1; + + hw->MiscOutReg = 0xCB; + if (m->sync & FB_SYNC_HOR_HIGH_ACT) + hw->MiscOutReg &= ~0x40; + if (m->sync & FB_SYNC_VERT_HIGH_ACT) + hw->MiscOutReg &= ~0x80; + if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */ + hw->CRTCEXT[3] |= 0x40; + + if (DAC1064_init_2(PMINFO hw, m, p)) return 1; + return 0; +} +#endif + +#ifdef CONFIG_FB_MATROX_G100 +static int MGAG100_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) { + + DBG("MGAG100_init") + + if (DAC1064_init_1(PMINFO hw, m, p)) return 1; + hw->MXoptionReg &= ~0x2000; + if (matroxfb_vgaHWinit(PMINFO hw, m, p)) return 1; + + hw->MiscOutReg = 0xEF; + if (m->sync & FB_SYNC_HOR_HIGH_ACT) + hw->MiscOutReg &= ~0x40; + if (m->sync & FB_SYNC_VERT_HIGH_ACT) + hw->MiscOutReg &= ~0x80; + if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */ + hw->CRTCEXT[3] |= 0x40; + + if (DAC1064_init_2(PMINFO hw, m, p)) return 1; + return 0; +} +#endif /* G100 */ + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +static void MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw){ + + DBG("MGA1064_ramdac_init"); + + /* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */ + ACCESS_FBINFO(features.pll.vco_freq_min) = 62000; + ACCESS_FBINFO(features.pll.ref_freq) = 14318; + ACCESS_FBINFO(features.pll.feed_div_min) = 100; + ACCESS_FBINFO(features.pll.feed_div_max) = 127; + ACCESS_FBINFO(features.pll.in_div_min) = 1; + ACCESS_FBINFO(features.pll.in_div_max) = 31; + ACCESS_FBINFO(features.pll.post_shift_max) = 3; + ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_EXTERNAL; + /* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */ + DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333); +} +#endif + +#ifdef CONFIG_FB_MATROX_G100 +/* BIOS environ */ +static int x7AF4 = 0x10; /* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */ + /* G100 wants 0x10, G200 SGRAM does not care... */ +#if 0 +static int def50 = 0; /* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */ +#endif + +static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p){ + int reg; + int selClk; + int clk; + + DBG("MGAG100_progPixClock") + + outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS | + M1064_XPIXCLKCTRL_PLL_UP); + switch (flags & 3) { + case 0: reg = M1064_XPIXPLLAM; break; + case 1: reg = M1064_XPIXPLLBM; break; + default: reg = M1064_XPIXPLLCM; break; + } + outDAC1064(PMINFO reg++, m); + outDAC1064(PMINFO reg++, n); + outDAC1064(PMINFO reg, p); + selClk = mga_inb(M_MISC_REG_READ) & ~0xC; + /* there should be flags & 0x03 & case 0/1/else */ + /* and we should first select source and after that we should wait for PLL */ + /* and we are waiting for PLL with oscilator disabled... Is it right? */ + switch (flags & 0x03) { + case 0x00: break; + case 0x01: selClk |= 4; break; + default: selClk |= 0x0C; break; + } + mga_outb(M_MISC_REG, selClk); + for (clk = 500000; clk; clk--) { + if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40) + break; + udelay(10); + }; + if (!clk) + printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A'); + selClk = inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK; + switch (flags & 0x0C) { + case 0x00: selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break; + case 0x04: selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break; + default: selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break; + } + outDAC1064(PMINFO M1064_XPIXCLKCTRL, selClk); + outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS); +} + +static void MGAG100_setPixClock(CPMINFO int flags, int freq){ + unsigned int m, n, p; + + DBG("MGAG100_setPixClock") + + DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); + MGAG100_progPixClock(PMINFO flags, m, n, p); +} +#endif + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +static int MGA1064_preinit(WPMINFO struct matrox_hw_state* hw){ + static const int vxres_mystique[] = { 512, 640, 768, 800, 832, 960, + 1024, 1152, 1280, 1600, 1664, 1920, + 2048, 0}; + DBG("MGA1064_preinit") + + /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ + ACCESS_FBINFO(capable.text) = 1; + ACCESS_FBINFO(capable.vxres) = vxres_mystique; + ACCESS_FBINFO(features.accel.has_cacheflush) = 1; + ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor; + + ACCESS_FBINFO(primout) = &m1064; + + if (ACCESS_FBINFO(devflags.noinit)) + return 0; /* do not modify settings */ + hw->MXoptionReg &= 0xC0000100; + hw->MXoptionReg |= 0x00094E20; + if (ACCESS_FBINFO(devflags.novga)) + hw->MXoptionReg &= ~0x00000100; + if (ACCESS_FBINFO(devflags.nobios)) + hw->MXoptionReg &= ~0x40000000; + if (ACCESS_FBINFO(devflags.nopciretry)) + hw->MXoptionReg |= 0x20000000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + mga_setr(M_SEQ_INDEX, 0x01, 0x20); + mga_outl(M_CTLWTST, 0x00000000); + udelay(200); + mga_outl(M_MACCESS, 0x00008000); + udelay(100); + mga_outl(M_MACCESS, 0x0000C000); + return 0; +} + +static void MGA1064_reset(WPMINFO struct matrox_hw_state* hw){ + + DBG("MGA1064_reset"); + + ACCESS_FBINFO(features.DAC1064.cursorimage) = ACCESS_FBINFO(video.len_usable) - 1024; + if (ACCESS_FBINFO(devflags.hwcursor)) + ACCESS_FBINFO(video.len_usable) -= 1024; + matroxfb_fastfont_init(MINFO); + MGA1064_ramdac_init(PMINFO hw); +} +#endif + +#ifdef CONFIG_FB_MATROX_G100 +static int MGAG100_preinit(WPMINFO struct matrox_hw_state* hw){ + static const int vxres_g100[] = { 512, 640, 768, 800, 832, 960, + 1024, 1152, 1280, 1600, 1664, 1920, + 2048, 0}; + u_int32_t reg50; +#if 0 + u_int32_t q; +#endif + + DBG("MGAG100_preinit") + + /* there are some instabilities if in_div > 19 && vco < 61000 */ + ACCESS_FBINFO(features.pll.vco_freq_min) = 62000; + ACCESS_FBINFO(features.pll.ref_freq) = 27000; + ACCESS_FBINFO(features.pll.feed_div_min) = 7; + ACCESS_FBINFO(features.pll.feed_div_max) = 127; + ACCESS_FBINFO(features.pll.in_div_min) = 1; + ACCESS_FBINFO(features.pll.in_div_max) = 31; + ACCESS_FBINFO(features.pll.post_shift_max) = 3; + ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_G100_DEFAULT; + /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ + ACCESS_FBINFO(capable.text) = 1; + ACCESS_FBINFO(capable.vxres) = vxres_g100; + ACCESS_FBINFO(features.accel.has_cacheflush) = 1; + ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor; + ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) != FB_ACCEL_MATROX_MGAG100; + + ACCESS_FBINFO(primout) = &m1064; + + if (ACCESS_FBINFO(devflags.noinit)) + return 0; + hw->MXoptionReg &= 0xC0000100; + hw->MXoptionReg |= 0x00078020; + if (ACCESS_FBINFO(devflags.novga)) + hw->MXoptionReg &= ~0x00000100; + if (ACCESS_FBINFO(devflags.nobios)) + hw->MXoptionReg &= ~0x40000000; + if (ACCESS_FBINFO(devflags.nopciretry)) + hw->MXoptionReg |= 0x20000000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, ®50); + reg50 &= ~0x3000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50); + + DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333); + + if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100) { + hw->MXoptionReg |= 0x1080; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + mga_outl(M_CTLWTST, 0x00000300); + /* mga_outl(M_CTLWTST, 0x03258A31); */ + udelay(100); + mga_outb(0x1C05, 0x00); + mga_outb(0x1C05, 0x80); + udelay(100); + mga_outb(0x1C05, 0x40); + mga_outb(0x1C05, 0xC0); + udelay(100); + reg50 &= ~0xFF; + reg50 |= 0x07; + pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50); + /* it should help with G100 */ + mga_outb(M_GRAPHICS_INDEX, 6); + mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4); + mga_setr(M_EXTVGA_INDEX, 0x03, 0x81); + mga_setr(M_EXTVGA_INDEX, 0x04, 0x00); + mga_writeb(ACCESS_FBINFO(video.vbase), 0x0000, 0xAA); + mga_writeb(ACCESS_FBINFO(video.vbase), 0x0800, 0x55); + mga_writeb(ACCESS_FBINFO(video.vbase), 0x4000, 0x55); +#if 0 + if (mga_readb(ACCESS_FBINFO(video.vbase), 0x0000) != 0xAA) { + hw->MXoptionReg &= ~0x1000; + } +#endif + } else { + hw->MXoptionReg |= 0x00000C00; + if (ACCESS_FBINFO(devflags.sgram)) + hw->MXoptionReg |= 0x4000; + mga_outl(M_CTLWTST, 0x042450A1); + mga_outb(0x1E47, 0x00); + mga_outb(0x1E46, 0x00); + udelay(10); + mga_outb(0x1C05, 0x00); + mga_outb(0x1C05, 0x80); + udelay(100); + mga_outw(0x1E44, 0x0108); + } + hw->MXoptionReg = (hw->MXoptionReg & ~0x1F8000) | 0x78000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + return 0; +} + +static void MGAG100_reset(WPMINFO struct matrox_hw_state* hw){ + u_int8_t b; + + DBG("MGAG100_reset") + + ACCESS_FBINFO(features.DAC1064.cursorimage) = ACCESS_FBINFO(video.len_usable) - 1024; + if (ACCESS_FBINFO(devflags.hwcursor)) + ACCESS_FBINFO(video.len_usable) -= 1024; + matroxfb_fastfont_init(MINFO); + + { +#ifdef G100_BROKEN_IBM_82351 + u_int32_t d; + + find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */ + pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b); + if (b == ACCESS_FBINFO(pcidev)->bus->number) { + pci_write_config_byte(ibm, PCI_COMMAND+1, 0); /* disable back-to-back & SERR */ + pci_write_config_byte(ibm, 0x41, 0xF4); /* ??? */ + pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0); /* ??? */ + pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00); /* ??? */ + } +#endif + if (!ACCESS_FBINFO(devflags.noinit)) { + if (x7AF4 & 8) { + hw->MXoptionReg |= 0x40; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + } + mga_setr(M_EXTVGA_INDEX, 0x06, 0x50); + } + } + DAC1064_setmclk(PMINFO hw, DAC1064_OPT_RESERVED | DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV1 | DAC1064_OPT_SCLK_PLL, 133333); + if (ACCESS_FBINFO(devflags.noinit)) + return; + MGAG100_setPixClock(PMINFO 4, 25175); + MGAG100_setPixClock(PMINFO 5, 28322); + if (x7AF4 & 0x10) { + b = inDAC1064(PMINFO M1064_XGENIODATA) & ~1; + outDAC1064(PMINFO M1064_XGENIODATA, b); + b = inDAC1064(PMINFO M1064_XGENIOCTRL) | 1; + outDAC1064(PMINFO M1064_XGENIOCTRL, b); + } +} +#endif + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +static void MGA1064_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) { + int i; + CRITFLAGS + + DBG("MGA1064_restore") + + CRITBEGIN + + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + mga_outb(M_IEN, 0x00); + mga_outb(M_CACHEFLUSH, 0x00); + + CRITEND + + DAC1064_restore_1(PMINFO hw, oldhw); + matroxfb_vgaHWrestore(PMINFO hw, oldhw); + for (i = 0; i < 6; i++) + mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); + DAC1064_restore_2(PMINFO hw, oldhw, p); +} +#endif + +#ifdef CONFIG_FB_MATROX_G100 +static void MGAG100_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) { + int i; + CRITFLAGS + + DBG("MGAG100_restore") + + CRITBEGIN + + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + CRITEND + + DAC1064_restore_1(PMINFO hw, oldhw); + matroxfb_vgaHWrestore(PMINFO hw, oldhw); +#ifdef CONFIG_FB_MATROX_32MB + if (ACCESS_FBINFO(devflags.support32MB)) + mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]); +#endif + for (i = 0; i < 6; i++) + mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); + DAC1064_restore_2(PMINFO hw, oldhw, p); +} +#endif + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +struct matrox_switch matrox_mystique = { + MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore, DAC1064_selhwcursor +}; +EXPORT_SYMBOL(matrox_mystique); +#endif + +#ifdef CONFIG_FB_MATROX_G100 +struct matrox_switch matrox_G100 = { + MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore, DAC1064_selhwcursor +}; +EXPORT_SYMBOL(matrox_G100); +#endif + +#ifdef NEED_DAC1064 +EXPORT_SYMBOL(DAC1064_global_init); +EXPORT_SYMBOL(DAC1064_global_restore); +#endif diff --git a/drivers/video/matrox/matroxfb_DAC1064.h b/drivers/video/matrox/matroxfb_DAC1064.h new file mode 100644 index 000000000..4a8fdb801 --- /dev/null +++ b/drivers/video/matrox/matroxfb_DAC1064.h @@ -0,0 +1,147 @@ +#ifndef __MATROXFB_DAC1064_H__ +#define __MATROXFB_DAC1064_H__ + +/* make checkconfig does not walk through include tree */ +#include <linux/config.h> + +#include "matroxfb_base.h" + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +extern struct matrox_switch matrox_mystique; +#endif +#ifdef CONFIG_FB_MATROX_G100 +extern struct matrox_switch matrox_G100; +#endif +#ifdef NEED_DAC1064 +void DAC1064_global_init(CPMINFO struct matrox_hw_state*); +void DAC1064_global_restore(CPMINFO const struct matrox_hw_state*); +#endif + +#define M1064_INDEX 0x00 +#define M1064_PALWRADD 0x00 +#define M1064_PALDATA 0x01 +#define M1064_PIXRDMSK 0x02 +#define M1064_PALRDADD 0x03 +#define M1064_X_DATAREG 0x0A +#define M1064_CURPOSXL 0x0C /* can be accessed as DWORD */ +#define M1064_CURPOSXH 0x0D +#define M1064_CURPOSYL 0x0E +#define M1064_CURPOSYH 0x0F + +#define M1064_XCURADDL 0x04 +#define M1064_XCURADDH 0x05 +#define M1064_XCURCTRL 0x06 +#define M1064_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */ +#define M1064_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */ +#define M1064_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */ +#define M1064_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */ +#define M1064_XCURCOL0RED 0x08 +#define M1064_XCURCOL0GREEN 0x09 +#define M1064_XCURCOL0BLUE 0x0A +#define M1064_XCURCOL1RED 0x0C +#define M1064_XCURCOL1GREEN 0x0D +#define M1064_XCURCOL1BLUE 0x0E +#define M1064_XCURCOL2RED 0x10 +#define M1064_XCURCOL2GREEN 0x11 +#define M1064_XCURCOL2BLUE 0x12 +#define DAC1064_XVREFCTRL 0x18 +#define DAC1064_XVREFCTRL_INTERNAL 0x3F +#define DAC1064_XVREFCTRL_EXTERNAL 0x00 +#define DAC1064_XVREFCTRL_G100_DEFAULT 0x03 +#define M1064_XMULCTRL 0x19 +#define M1064_XMULCTRL_DEPTH_8BPP 0x00 /* 8 bpp paletized */ +#define M1064_XMULCTRL_DEPTH_15BPP_1BPP 0x01 /* 15 bpp paletized + 1 bpp overlay */ +#define M1064_XMULCTRL_DEPTH_16BPP 0x02 /* 16 bpp paletized */ +#define M1064_XMULCTRL_DEPTH_24BPP 0x03 /* 24 bpp paletized */ +#define M1064_XMULCTRL_DEPTH_24BPP_8BPP 0x04 /* 24 bpp direct + 8 bpp overlay paletized */ +#define M1064_XMULCTRL_2G8V16 0x05 /* 15 bpp video direct, half xres, 8bpp paletized */ +#define M1064_XMULCTRL_G16V16 0x06 /* 15 bpp video, 15bpp graphics, one of them paletized */ +#define M1064_XMULCTRL_DEPTH_32BPP 0x07 /* 24 bpp paletized + 8 bpp unused */ +#define M1064_XMULCTRL_GRAPHICS_PALETIZED 0x00 +#define M1064_XMULCTRL_VIDEO_PALETIZED 0x08 +#define M1064_XPIXCLKCTRL 0x1A +#define M1064_XPIXCLKCTRL_SRC_PCI 0x00 +#define M1064_XPIXCLKCTRL_SRC_PLL 0x01 +#define M1064_XPIXCLKCTRL_SRC_EXT 0x02 +#define M1064_XPIXCLKCTRL_SRC_MASK 0x03 +#define M1064_XPIXCLKCTRL_EN 0x00 +#define M1064_XPIXCLKCTRL_DIS 0x04 +#define M1064_XPIXCLKCTRL_PLL_DOWN 0x00 +#define M1064_XPIXCLKCTRL_PLL_UP 0x08 +#define M1064_XGENCTRL 0x1D +#define M1064_XGENCTRL_VS_0 0x00 +#define M1064_XGENCTRL_VS_1 0x01 +#define M1064_XGENCTRL_ALPHA_DIS 0x00 +#define M1064_XGENCTRL_ALPHA_EN 0x02 +#define M1064_XGENCTRL_BLACK_0IRE 0x00 +#define M1064_XGENCTRL_BLACK_75IRE 0x10 +#define M1064_XGENCTRL_SYNC_ON_GREEN 0x00 +#define M1064_XGENCTRL_NO_SYNC_ON_GREEN 0x20 +#define M1064_XGENCTRL_SYNC_ON_GREEN_MASK 0x20 +#define M1064_XMISCCTRL 0x1E +#define M1064_XMISCCTRL_DAC_DIS 0x00 +#define M1064_XMISCCTRL_DAC_EN 0x01 +#define M1064_XMISCCTRL_MFC_VGA 0x00 +#define M1064_XMISCCTRL_MFC_MAFC 0x02 +#define M1064_XMISCCTRL_MFC_DIS 0x06 +#define G400_XMISCCTRL_MFC_MAFC 0x02 +#define G400_XMISCCTRL_MFC_PANELLINK 0x04 +#define G400_XMISCCTRL_MFC_DIS 0x06 +#define G400_XMISCCTRL_MFC_MASK 0x06 +#define M1064_XMISCCTRL_DAC_6BIT 0x00 +#define M1064_XMISCCTRL_DAC_8BIT 0x08 +#define M1064_XMISCCTRL_DAC_WIDTHMASK 0x08 +#define M1064_XMISCCTRL_LUT_DIS 0x00 +#define M1064_XMISCCTRL_LUT_EN 0x10 +#define G400_XMISCCTRL_VDO_MAFC12 0x00 +#define G400_XMISCCTRL_VDO_BYPASS656 0x40 +#define G400_XMISCCTRL_VDO_C2_MAFC12 0x80 +#define G400_XMISCCTRL_VDO_C2_BYPASS656 0xC0 +#define G400_XMISCCTRL_VDO_MASK 0xE0 +#define M1064_XGENIOCTRL 0x2A +#define M1064_XGENIODATA 0x2B +#define DAC1064_XSYSPLLM 0x2C +#define DAC1064_XSYSPLLN 0x2D +#define DAC1064_XSYSPLLP 0x2E +#define DAC1064_XSYSPLLSTAT 0x2F +#define M1064_XZOOMCTRL 0x38 +#define M1064_XZOOMCTRL_1 0x00 +#define M1064_XZOOMCTRL_2 0x01 +#define M1064_XZOOMCTRL_4 0x03 +#define M1064_XSENSETEST 0x3A +#define M1064_XSENSETEST_BCOMP 0x01 +#define M1064_XSENSETEST_GCOMP 0x02 +#define M1064_XSENSETEST_RCOMP 0x04 +#define M1064_XSENSETEST_PDOWN 0x00 +#define M1064_XSENSETEST_PUP 0x80 +#define M1064_XCRCREML 0x3C +#define M1064_XCRCREMH 0x3D +#define M1064_XCRCBITSEL 0x3E +#define M1064_XCOLKEYMASKL 0x40 +#define M1064_XCOLKEYMASKH 0x41 +#define M1064_XCOLKEYL 0x42 +#define M1064_XCOLKEYH 0x43 +#define M1064_XPIXPLLAM 0x44 +#define M1064_XPIXPLLAN 0x45 +#define M1064_XPIXPLLAP 0x46 +#define M1064_XPIXPLLBM 0x48 +#define M1064_XPIXPLLBN 0x49 +#define M1064_XPIXPLLBP 0x4A +#define M1064_XPIXPLLCM 0x4C +#define M1064_XPIXPLLCN 0x4D +#define M1064_XPIXPLLCP 0x4E +#define M1064_XPIXPLLSTAT 0x4F + +enum POS1064 { + POS1064_XCURADDL=0, POS1064_XCURADDH, POS1064_XCURCTRL, + POS1064_XCURCOL0RED, POS1064_XCURCOL0GREEN, POS1064_XCURCOL0BLUE, + POS1064_XCURCOL1RED, POS1064_XCURCOL1GREEN, POS1064_XCURCOL1BLUE, + POS1064_XCURCOL2RED, POS1064_XCURCOL2GREEN, POS1064_XCURCOL2BLUE, + POS1064_XVREFCTRL, POS1064_XMULCTRL, POS1064_XPIXCLKCTRL, POS1064_XGENCTRL, + POS1064_XMISCCTRL, + POS1064_XGENIOCTRL, POS1064_XGENIODATA, POS1064_XZOOMCTRL, POS1064_XSENSETEST, + POS1064_XCRCBITSEL, + POS1064_XCOLKEYMASKL, POS1064_XCOLKEYMASKH, POS1064_XCOLKEYL, POS1064_XCOLKEYH }; + + +#endif /* __MATROXFB_DAC1064_H__ */ diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c new file mode 100644 index 000000000..6bc3cea64 --- /dev/null +++ b/drivers/video/matrox/matroxfb_Ti3026.c @@ -0,0 +1,862 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 + * + * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Version: 1.21 2000/01/09 + * + * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> + * + * Contributors: "menion?" <menion@mindless.com> + * Betatesting, fixes, ideas + * + * "Kurt Garloff" <garloff@kg1.ping.de> + * Betatesting, fixes, ideas, videomodes, videomodes timmings + * + * "Tom Rini" <trini@kernel.crashing.org> + * MTRR stuff, PPC cleanups, betatesting, fixes, ideas + * + * "Bibek Sahu" <scorpio@dodds.net> + * Access device through readb|w|l and write b|w|l + * Extensive debugging stuff + * + * "Daniel Haun" <haund@usa.net> + * Testing, hardware cursor fixes + * + * "Scott Wood" <sawst46+@pitt.edu> + * Fixes + * + * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> + * Betatesting + * + * "Kelly French" <targon@hazmat.com> + * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> + * Betatesting, bug reporting + * + * "Pablo Bianucci" <pbian@pccp.com.ar> + * Fixes, ideas, betatesting + * + * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> + * Fixes, enhandcements, ideas, betatesting + * + * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> + * PPC betatesting, PPC support, backward compatibility + * + * "Paul Womar" <Paul@pwomar.demon.co.uk> + * "Owen Waller" <O.Waller@ee.qub.ac.uk> + * PPC betatesting + * + * "Thomas Pornin" <pornin@bolet.ens.fr> + * Alpha betatesting + * + * "Pieter van Leuven" <pvl@iae.nl> + * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> + * G100 testing + * + * "H. Peter Arvin" <hpa@transmeta.com> + * Ideas + * + * "Cort Dougan" <cort@cs.nmt.edu> + * CHRP fixes and PReP cleanup + * + * "Mark Vojkovich" <mvojkovi@ucsd.edu> + * G400 support + * + * (following author is not in any relation with this code, but his code + * is included in this driver) + * + * Based on framebuffer driver for VBE 2.0 compliant graphic boards + * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> + * + * (following author is not in any relation with this code, but his ideas + * were used when writting this driver) + * + * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> + * + */ + +/* make checkconfig does not verify included files... */ +#include <linux/config.h> + +#include "matroxfb_Ti3026.h" +#include "matroxfb_misc.h" +#include "matroxfb_accel.h" + +#ifdef CONFIG_FB_MATROX_MILLENIUM +#define outTi3026 matroxfb_DAC_out +#define inTi3026 matroxfb_DAC_in + +#define TVP3026_INDEX 0x00 +#define TVP3026_PALWRADD 0x00 +#define TVP3026_PALDATA 0x01 +#define TVP3026_PIXRDMSK 0x02 +#define TVP3026_PALRDADD 0x03 +#define TVP3026_CURCOLWRADD 0x04 +#define TVP3026_CLOVERSCAN 0x00 +#define TVP3026_CLCOLOR0 0x01 +#define TVP3026_CLCOLOR1 0x02 +#define TVP3026_CLCOLOR2 0x03 +#define TVP3026_CURCOLDATA 0x05 +#define TVP3026_CURCOLRDADD 0x07 +#define TVP3026_CURCTRL 0x09 +#define TVP3026_X_DATAREG 0x0A +#define TVP3026_CURRAMDATA 0x0B +#define TVP3026_CURPOSXL 0x0C +#define TVP3026_CURPOSXH 0x0D +#define TVP3026_CURPOSYL 0x0E +#define TVP3026_CURPOSYH 0x0F + +#define TVP3026_XSILICONREV 0x01 +#define TVP3026_XCURCTRL 0x06 +#define TVP3026_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */ +#define TVP3026_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */ +#define TVP3026_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */ +#define TVP3026_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */ +#define TVP3026_XCURCTRL_BLANK2048 0x00 +#define TVP3026_XCURCTRL_BLANK4096 0x10 +#define TVP3026_XCURCTRL_INTERLACED 0x20 +#define TVP3026_XCURCTRL_ODD 0x00 /* ext.signal ODD/\EVEN */ +#define TVP3026_XCURCTRL_EVEN 0x40 /* ext.signal EVEN/\ODD */ +#define TVP3026_XCURCTRL_INDIRECT 0x00 +#define TVP3026_XCURCTRL_DIRECT 0x80 +#define TVP3026_XLATCHCTRL 0x0F +#define TVP3026_XLATCHCTRL_1_1 0x06 +#define TVP3026_XLATCHCTRL_2_1 0x07 +#define TVP3026_XLATCHCTRL_4_1 0x06 +#define TVP3026_XLATCHCTRL_8_1 0x06 +#define TVP3026_XLATCHCTRL_16_1 0x06 +#define TVP3026A_XLATCHCTRL_4_3 0x06 /* ??? do not understand... but it works... !!! */ +#define TVP3026A_XLATCHCTRL_8_3 0x07 +#define TVP3026B_XLATCHCTRL_4_3 0x08 +#define TVP3026B_XLATCHCTRL_8_3 0x06 /* ??? do not understand... but it works... !!! */ +#define TVP3026_XTRUECOLORCTRL 0x18 +#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_ACCEL 0x00 +#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_TVP 0x20 +#define TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR 0x80 +#define TVP3026_XTRUECOLORCTRL_TRUECOLOR 0x40 /* paletized */ +#define TVP3026_XTRUECOLORCTRL_DIRECTCOLOR 0x00 +#define TVP3026_XTRUECOLORCTRL_24_ALTERNATE 0x08 /* 5:4/5:2 instead of 4:3/8:3 */ +#define TVP3026_XTRUECOLORCTRL_RGB_888 0x16 /* 4:3/8:3 (or 5:4/5:2) */ +#define TVP3026_XTRUECOLORCTRL_BGR_888 0x17 +#define TVP3026_XTRUECOLORCTRL_ORGB_8888 0x06 +#define TVP3026_XTRUECOLORCTRL_BGRO_8888 0x07 +#define TVP3026_XTRUECOLORCTRL_RGB_565 0x05 +#define TVP3026_XTRUECOLORCTRL_ORGB_1555 0x04 +#define TVP3026_XTRUECOLORCTRL_RGB_664 0x03 +#define TVP3026_XTRUECOLORCTRL_RGBO_4444 0x01 +#define TVP3026_XMUXCTRL 0x19 +#define TVP3026_XMUXCTRL_MEMORY_8BIT 0x01 /* - */ +#define TVP3026_XMUXCTRL_MEMORY_16BIT 0x02 /* - */ +#define TVP3026_XMUXCTRL_MEMORY_32BIT 0x03 /* 2MB RAM, 512K * 4 */ +#define TVP3026_XMUXCTRL_MEMORY_64BIT 0x04 /* >2MB RAM, 512K * 8 & more */ +#define TVP3026_XMUXCTRL_PIXEL_4BIT 0x40 /* L0,H0,L1,H1... */ +#define TVP3026_XMUXCTRL_PIXEL_4BIT_SWAPPED 0x60 /* H0,L0,H1,L1... */ +#define TVP3026_XMUXCTRL_PIXEL_8BIT 0x48 +#define TVP3026_XMUXCTRL_PIXEL_16BIT 0x50 +#define TVP3026_XMUXCTRL_PIXEL_32BIT 0x58 +#define TVP3026_XMUXCTRL_VGA 0x98 /* VGA MEMORY, 8BIT PIXEL */ +#define TVP3026_XCLKCTRL 0x1A +#define TVP3026_XCLKCTRL_DIV1 0x00 +#define TVP3026_XCLKCTRL_DIV2 0x10 +#define TVP3026_XCLKCTRL_DIV4 0x20 +#define TVP3026_XCLKCTRL_DIV8 0x30 +#define TVP3026_XCLKCTRL_DIV16 0x40 +#define TVP3026_XCLKCTRL_DIV32 0x50 +#define TVP3026_XCLKCTRL_DIV64 0x60 +#define TVP3026_XCLKCTRL_CLKSTOPPED 0x70 +#define TVP3026_XCLKCTRL_SRC_CLK0 0x00 +#define TVP3026_XCLKCTRL_SRC_CLK1 0x01 +#define TVP3026_XCLKCTRL_SRC_CLK2 0x02 /* CLK2 is TTL source*/ +#define TVP3026_XCLKCTRL_SRC_NCLK2 0x03 /* not CLK2 is TTL source */ +#define TVP3026_XCLKCTRL_SRC_ECLK2 0x04 /* CLK2 and not CLK2 is ECL source */ +#define TVP3026_XCLKCTRL_SRC_PLL 0x05 +#define TVP3026_XCLKCTRL_SRC_DIS 0x06 /* disable & poweroff internal clock */ +#define TVP3026_XCLKCTRL_SRC_CLK0VGA 0x07 +#define TVP3026_XPALETTEPAGE 0x1C +#define TVP3026_XGENCTRL 0x1D +#define TVP3026_XGENCTRL_HSYNC_POS 0x00 +#define TVP3026_XGENCTRL_HSYNC_NEG 0x01 +#define TVP3026_XGENCTRL_VSYNC_POS 0x00 +#define TVP3026_XGENCTRL_VSYNC_NEG 0x02 +#define TVP3026_XGENCTRL_LITTLE_ENDIAN 0x00 +#define TVP3026_XGENCTRL_BIG_ENDIAN 0x08 +#define TVP3026_XGENCTRL_BLACK_0IRE 0x00 +#define TVP3026_XGENCTRL_BLACK_75IRE 0x10 +#define TVP3026_XGENCTRL_NO_SYNC_ON_GREEN 0x00 +#define TVP3026_XGENCTRL_SYNC_ON_GREEN 0x20 +#define TVP3026_XGENCTRL_OVERSCAN_DIS 0x00 +#define TVP3026_XGENCTRL_OVERSCAN_EN 0x40 +#define TVP3026_XMISCCTRL 0x1E +#define TVP3026_XMISCCTRL_DAC_PUP 0x00 +#define TVP3026_XMISCCTRL_DAC_PDOWN 0x01 +#define TVP3026_XMISCCTRL_DAC_EXT 0x00 /* or 8, bit 3 is ignored */ +#define TVP3026_XMISCCTRL_DAC_6BIT 0x04 +#define TVP3026_XMISCCTRL_DAC_8BIT 0x0C +#define TVP3026_XMISCCTRL_PSEL_DIS 0x00 +#define TVP3026_XMISCCTRL_PSEL_EN 0x10 +#define TVP3026_XMISCCTRL_PSEL_LOW 0x00 /* PSEL high selects directcolor */ +#define TVP3026_XMISCCTRL_PSEL_HIGH 0x20 /* PSEL high selects truecolor or pseudocolor */ +#define TVP3026_XGENIOCTRL 0x2A +#define TVP3026_XGENIODATA 0x2B +#define TVP3026_XPLLADDR 0x2C +#define TVP3026_XPLLADDR_X(LOOP,MCLK,PIX) (((LOOP)<<4) | ((MCLK)<<2) | (PIX)) +#define TVP3026_XPLLDATA_N 0x00 +#define TVP3026_XPLLDATA_M 0x01 +#define TVP3026_XPLLDATA_P 0x02 +#define TVP3026_XPLLDATA_STAT 0x03 +#define TVP3026_XPIXPLLDATA 0x2D +#define TVP3026_XMEMPLLDATA 0x2E +#define TVP3026_XLOOPPLLDATA 0x2F +#define TVP3026_XCOLKEYOVRMIN 0x30 +#define TVP3026_XCOLKEYOVRMAX 0x31 +#define TVP3026_XCOLKEYREDMIN 0x32 +#define TVP3026_XCOLKEYREDMAX 0x33 +#define TVP3026_XCOLKEYGREENMIN 0x34 +#define TVP3026_XCOLKEYGREENMAX 0x35 +#define TVP3026_XCOLKEYBLUEMIN 0x36 +#define TVP3026_XCOLKEYBLUEMAX 0x37 +#define TVP3026_XCOLKEYCTRL 0x38 +#define TVP3026_XCOLKEYCTRL_OVR_EN 0x01 +#define TVP3026_XCOLKEYCTRL_RED_EN 0x02 +#define TVP3026_XCOLKEYCTRL_GREEN_EN 0x04 +#define TVP3026_XCOLKEYCTRL_BLUE_EN 0x08 +#define TVP3026_XCOLKEYCTRL_NEGATE 0x10 +#define TVP3026_XCOLKEYCTRL_ZOOM1 0x00 +#define TVP3026_XCOLKEYCTRL_ZOOM2 0x20 +#define TVP3026_XCOLKEYCTRL_ZOOM4 0x40 +#define TVP3026_XCOLKEYCTRL_ZOOM8 0x60 +#define TVP3026_XCOLKEYCTRL_ZOOM16 0x80 +#define TVP3026_XCOLKEYCTRL_ZOOM32 0xA0 +#define TVP3026_XMEMPLLCTRL 0x39 +#define TVP3026_XMEMPLLCTRL_DIV(X) (((X)-1)>>1) /* 2,4,6,8,10,12,14,16, division applied to LOOP PLL after divide by 2^P */ +#define TVP3026_XMEMPLLCTRL_STROBEMKC4 0x08 +#define TVP3026_XMEMPLLCTRL_MCLK_DOTCLOCK 0x00 /* MKC4 */ +#define TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL 0x10 /* MKC4 */ +#define TVP3026_XMEMPLLCTRL_RCLK_PIXPLL 0x00 +#define TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL 0x20 +#define TVP3026_XMEMPLLCTRL_RCLK_DOTDIVN 0x40 /* dot clock divided by loop pclk N prescaler */ +#define TVP3026_XSENSETEST 0x3A +#define TVP3026_XTESTMODEDATA 0x3B +#define TVP3026_XCRCREML 0x3C +#define TVP3026_XCRCREMH 0x3D +#define TVP3026_XCRCBITSEL 0x3E +#define TVP3026_XID 0x3F + +static const unsigned char DACseq[] = +{ TVP3026_XLATCHCTRL, TVP3026_XTRUECOLORCTRL, + TVP3026_XMUXCTRL, TVP3026_XCLKCTRL, + TVP3026_XPALETTEPAGE, + TVP3026_XGENCTRL, + TVP3026_XMISCCTRL, + TVP3026_XGENIOCTRL, + TVP3026_XGENIODATA, + TVP3026_XCOLKEYOVRMIN, TVP3026_XCOLKEYOVRMAX, TVP3026_XCOLKEYREDMIN, TVP3026_XCOLKEYREDMAX, + TVP3026_XCOLKEYGREENMIN, TVP3026_XCOLKEYGREENMAX, TVP3026_XCOLKEYBLUEMIN, TVP3026_XCOLKEYBLUEMAX, + TVP3026_XCOLKEYCTRL, + TVP3026_XMEMPLLCTRL, TVP3026_XSENSETEST, TVP3026_XCURCTRL }; + +#define POS3026_XLATCHCTRL 0 +#define POS3026_XTRUECOLORCTRL 1 +#define POS3026_XMUXCTRL 2 +#define POS3026_XCLKCTRL 3 +#define POS3026_XGENCTRL 5 +#define POS3026_XMISCCTRL 6 +#define POS3026_XMEMPLLCTRL 18 +#define POS3026_XCURCTRL 20 + +static const unsigned char MGADACbpp32[] = +{ TVP3026_XLATCHCTRL_2_1, TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_8888, + 0x00, TVP3026_XCLKCTRL_DIV1 | TVP3026_XCLKCTRL_SRC_PLL, + 0x00, + TVP3026_XGENCTRL_HSYNC_POS | TVP3026_XGENCTRL_VSYNC_POS | TVP3026_XGENCTRL_LITTLE_ENDIAN | TVP3026_XGENCTRL_BLACK_0IRE | TVP3026_XGENCTRL_NO_SYNC_ON_GREEN | TVP3026_XGENCTRL_OVERSCAN_DIS, + TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_HIGH, + 0x00, + 0x1E, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + TVP3026_XCOLKEYCTRL_ZOOM1, + 0x00, 0x00, TVP3026_XCURCTRL_DIS }; + +static void matroxfb_ti3026_flashcursor(unsigned long ptr) { +#define minfo ((struct matrox_fb_info*)ptr) + matroxfb_DAC_lock(); + outTi3026(PMINFO TVP3026_XCURCTRL, inTi3026(PMINFO TVP3026_XCURCTRL) ^ TVP3026_XCURCTRL_DIS ^ TVP3026_XCURCTRL_XGA); + ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2; + add_timer(&ACCESS_FBINFO(cursor.timer)); + matroxfb_DAC_unlock(); +#undef minfo +} + +static void matroxfb_ti3026_createcursor(WPMINFO struct display* p) { + unsigned long flags; + u_int32_t xline; + unsigned int i; + unsigned int to; + + if (ACCESS_FBINFO(currcon_display) != p) + return; + + DBG("matroxfb_ti3026_createcursor"); + + matroxfb_createcursorshape(PMINFO p, p->var.vmode); + + xline = (~0) << (32 - ACCESS_FBINFO(cursor.w)); + matroxfb_DAC_lock_irqsave(flags); + mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, 0); + to = ACCESS_FBINFO(cursor.u); + for (i = 0; i < to; i++) { + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + } + to = ACCESS_FBINFO(cursor.d); + for (; i < to; i++) { + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 24); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 16); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 8); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + } + for (; i < 64; i++) { + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + } + for (i = 0; i < 512; i++) + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0xFF); + matroxfb_DAC_unlock_irqrestore(flags); +} + +static void matroxfb_ti3026_cursor(struct display* p, int mode, int x, int y) { + unsigned long flags; + MINFO_FROM_DISP(p); + + DBG("matroxfb_ti3026_cursor") + + if (ACCESS_FBINFO(currcon_display) != p) + return; + + if (mode == CM_ERASE) { + if (ACCESS_FBINFO(cursor.state) != CM_ERASE) { + matroxfb_DAC_lock_irqsave(flags); + ACCESS_FBINFO(cursor.state) = CM_ERASE; + del_timer(&ACCESS_FBINFO(cursor.timer)); + outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL])); + matroxfb_DAC_unlock_irqrestore(flags); + } + return; + } + if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type)) + matroxfb_ti3026_createcursor(PMINFO p); + x *= fontwidth(p); + y *= fontheight(p); + y -= p->var.yoffset; + if (p->var.vmode & FB_VMODE_DOUBLE) + y *= 2; + matroxfb_DAC_lock_irqsave(flags); + if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y)) || ACCESS_FBINFO(cursor.redraw)) { + ACCESS_FBINFO(cursor.redraw) = 0; + ACCESS_FBINFO(cursor.x) = x; + ACCESS_FBINFO(cursor.y) = y; + x += 64; + y += 64; + outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL])); + mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXL, x); + mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXH, x >> 8); + mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYL, y); + mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYH, y >> 8); + } + ACCESS_FBINFO(cursor.state) = CM_DRAW; + if (ACCESS_FBINFO(devflags.blink)) + mod_timer(&ACCESS_FBINFO(cursor.timer), jiffies + HZ/2); + outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]) | TVP3026_XCURCTRL_XGA); + matroxfb_DAC_unlock_irqrestore(flags); +} + +static int matroxfb_ti3026_setfont(struct display* p, int width, int height) { + + DBG("matrox_ti3026_setfont"); + + if (p && p->conp) + matroxfb_ti3026_createcursor(PMXINFO(p) p); + return 0; +} + +static int matroxfb_ti3026_selhwcursor(WPMINFO struct display* p) { + ACCESS_FBINFO(dispsw.cursor) = matroxfb_ti3026_cursor; + ACCESS_FBINFO(dispsw.set_font) = matroxfb_ti3026_setfont; + return 0; +} + +static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* in, int* feed, int* post) { + unsigned int fvco; + unsigned int lin, lfeed, lpost; + + DBG("Ti3026_calcclock") + + fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost); + fvco >>= (*post = lpost); + *in = 64 - lin; + *feed = 64 - lfeed; + return fvco; +} + +static int Ti3026_setpclk(CPMINFO struct matrox_hw_state* hw, int clk, struct display* p) { + unsigned int f_pll; + unsigned int pixfeed, pixin, pixpost; + + DBG("Ti3026_setpclk") + + f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost); + + hw->DACclk[0] = pixin | 0xC0; + hw->DACclk[1] = pixfeed; + hw->DACclk[2] = pixpost | 0xB0; + + if (p->type == FB_TYPE_TEXT) { + hw->DACreg[POS3026_XMEMPLLCTRL] = TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_PIXPLL; + hw->DACclk[3] = 0xFD; + hw->DACclk[4] = 0x3D; + hw->DACclk[5] = 0x70; + } else { + unsigned int loopfeed, loopin, looppost, loopdiv, z; + unsigned int Bpp; + + Bpp = ACCESS_FBINFO(curr.final_bppShift); + + if (p->var.bits_per_pixel == 24) { + loopfeed = 3; /* set lm to any possible value */ + loopin = 3 * 32 / Bpp; + } else { + loopfeed = 4; + loopin = 4 * 32 / Bpp; + } + z = (110000 * loopin) / (f_pll * loopfeed); + loopdiv = 0; /* div 2 */ + if (z < 2) + looppost = 0; + else if (z < 4) + looppost = 1; + else if (z < 8) + looppost = 2; + else { + looppost = 3; + loopdiv = z/16; + } + if (p->var.bits_per_pixel == 24) { + hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0; + hw->DACclk[4] = (65 - loopfeed) | 0x80; + if (ACCESS_FBINFO(accel.ramdac_rev) > 0x20) { + if (isInterleave(MINFO)) + hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_8_3; + else { + hw->DACclk[4] &= ~0xC0; + hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_4_3; + } + } else { + if (isInterleave(MINFO)) + ; /* default... */ + else { + hw->DACclk[4] ^= 0xC0; /* change from 0x80 to 0x40 */ + hw->DACreg[POS3026_XLATCHCTRL] = TVP3026A_XLATCHCTRL_4_3; + } + } + hw->DACclk[5] = looppost | 0xF8; + if (ACCESS_FBINFO(devflags.mga_24bpp_fix)) + hw->DACclk[5] ^= 0x40; + } else { + hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0; + hw->DACclk[4] = 65 - loopfeed; + hw->DACclk[5] = looppost | 0xF0; + } + hw->DACreg[POS3026_XMEMPLLCTRL] = loopdiv | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL; + } + return 0; +} + +static int Ti3026_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) { + u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT; + + DBG("Ti3026_init") + + memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg)); + if (p->type == FB_TYPE_TEXT) { + hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1; + hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR; + hw->DACreg[POS3026_XMUXCTRL] = TVP3026_XMUXCTRL_VGA; + hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | + TVP3026_XCLKCTRL_DIV4; + hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_6BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW; + } else { + switch (p->var.bits_per_pixel) { + case 4: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1; /* or _8_1, they are same */ + hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR; + hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT; + hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV8; + hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW; + break; + case 8: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1; /* or _4_1, they are same */ + hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR; + hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_8BIT; + hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4; + hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW; + break; + case 16: + /* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used everytime) */ + hw->DACreg[POS3026_XTRUECOLORCTRL] = (p->var.green.length == 5)? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555 ) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565); + hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT; + hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2; + break; + case 24: + /* XLATCHCTRL is: for (A) use _4_3 (?_8_3 is same? TBD), for (B) it is set in setpclk */ + hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_888; + hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT; + hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4; + break; + case 32: + /* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used everytime) */ + hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT; + break; + default: + return 1; /* TODO: failed */ + } + } + if (matroxfb_vgaHWinit(PMINFO hw, m, p)) return 1; + + /* set SYNC */ + hw->MiscOutReg = 0xCB; + if (m->sync & FB_SYNC_HOR_HIGH_ACT) + hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_HSYNC_NEG; + if (m->sync & FB_SYNC_VERT_HIGH_ACT) + hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_VSYNC_NEG; + if (m->sync & FB_SYNC_ON_GREEN) + hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_SYNC_ON_GREEN; + + /* set DELAY */ + if (ACCESS_FBINFO(video.len) < 0x400000) + hw->CRTCEXT[3] |= 0x08; + else if (ACCESS_FBINFO(video.len) > 0x400000) + hw->CRTCEXT[3] |= 0x10; + + /* set HWCURSOR */ + if (m->interlaced) { + hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_INTERLACED; + } + if (m->HTotal >= 1536) + hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_BLANK4096; + + /* set interleaving */ + hw->MXoptionReg &= ~0x00001000; + if ((p->type != FB_TYPE_TEXT) && isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000; + + /* set DAC */ + Ti3026_setpclk(PMINFO hw, m->pixclock, p); + return 0; +} + +static void ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout){ + unsigned int f_pll; + unsigned int pclk_m, pclk_n, pclk_p; + unsigned int mclk_m, mclk_n, mclk_p; + unsigned int rfhcnt, mclk_ctl; + int tmout; + + DBG("ti3026_setMCLK") + + f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p); + + /* save pclk */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC); + pclk_n = inTi3026(PMINFO TVP3026_XPIXPLLDATA); + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFD); + pclk_m = inTi3026(PMINFO TVP3026_XPIXPLLDATA); + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE); + pclk_p = inTi3026(PMINFO TVP3026_XPIXPLLDATA); + + /* stop pclk */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00); + + /* set pclk to new mclk */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_n | 0xC0); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_m); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_p | 0xB0); + + /* wait for PLL to lock */ + for (tmout = 500000; tmout; tmout--) { + if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40) + break; + udelay(10); + }; + if (!tmout) + printk(KERN_ERR "matroxfb: Temporary pixel PLL not locked after 5 secs\n"); + + /* output pclk on mclk pin */ + mclk_ctl = inTi3026(PMINFO TVP3026_XMEMPLLCTRL); + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, mclk_ctl & 0xE7); + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_STROBEMKC4); + + /* stop MCLK */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFB); + outTi3026(PMINFO TVP3026_XMEMPLLDATA, 0x00); + + /* set mclk to new freq */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xF3); + outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_n | 0xC0); + outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_m); + outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_p | 0xB0); + + /* wait for PLL to lock */ + for (tmout = 500000; tmout; tmout--) { + if (inTi3026(PMINFO TVP3026_XMEMPLLDATA) & 0x40) + break; + udelay(10); + } + if (!tmout) + printk(KERN_ERR "matroxfb: Memory PLL not locked after 5 secs\n"); + + f_pll = f_pll * 333 / (10000 << mclk_p); + if (isMilleniumII(MINFO)) { + rfhcnt = (f_pll - 128) / 256; + if (rfhcnt > 15) + rfhcnt = 15; + } else { + rfhcnt = (f_pll - 64) / 128; + if (rfhcnt > 15) + rfhcnt = 0; + } + hw->MXoptionReg = (hw->MXoptionReg & ~0x000F0000) | (rfhcnt << 16); + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + + /* output MCLK to MCLK pin */ + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL); + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl ) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_STROBEMKC4); + + /* stop PCLK */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00); + + /* restore pclk */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_n); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_m); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_p); + + /* wait for PLL to lock */ + for (tmout = 500000; tmout; tmout--) { + if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40) + break; + udelay(10); + } + if (!tmout) + printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n"); +} + +static void ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw){ + + DBG("ti3026_ramdac_init") + + ACCESS_FBINFO(features.pll.vco_freq_min) = 110000; + ACCESS_FBINFO(features.pll.ref_freq) = 114545; + ACCESS_FBINFO(features.pll.feed_div_min) = 2; + ACCESS_FBINFO(features.pll.feed_div_max) = 24; + ACCESS_FBINFO(features.pll.in_div_min) = 2; + ACCESS_FBINFO(features.pll.in_div_max) = 63; + ACCESS_FBINFO(features.pll.post_shift_max) = 3; + if (ACCESS_FBINFO(devflags.noinit)) + return; + ti3026_setMCLK(PMINFO hw, 60000); +} + +static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) { + int i; + CRITFLAGS + + DBG("Ti3026_restore") + +#ifdef DEBUG + dprintk(KERN_INFO "EXTVGA regs: "); + for (i = 0; i < 6; i++) + dprintk("%02X:", hw->CRTCEXT[i]); + dprintk("\n"); +#endif + + CRITBEGIN + + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + + CRITEND + + matroxfb_vgaHWrestore(PMINFO hw, oldhw); + + CRITBEGIN + + for (i = 0; i < 6; i++) + mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); + + for (i = 0; i < 21; i++) { + outTi3026(PMINFO DACseq[i], hw->DACreg[i]); + } + if (oldhw) { + outTi3026(PMINFO TVP3026_XPLLADDR, 0x00); + oldhw->DACclk[0] = inTi3026(PMINFO TVP3026_XPIXPLLDATA); + oldhw->DACclk[3] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA); + outTi3026(PMINFO TVP3026_XPLLADDR, 0x15); + oldhw->DACclk[1] = inTi3026(PMINFO TVP3026_XPIXPLLDATA); + oldhw->DACclk[4] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA); + outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A); + oldhw->DACclk[2] = inTi3026(PMINFO TVP3026_XPIXPLLDATA); + oldhw->DACclk[5] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA); + } + CRITEND + if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) { + /* agrhh... setting up PLL is very slow on Millennium... */ + /* Mystique PLL is locked in few ms, but Millennium PLL lock takes about 0.15 s... */ + /* Maybe even we should call schedule() ? */ + + CRITBEGIN + outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]); + outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A); + outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0); + + outTi3026(PMINFO TVP3026_XPLLADDR, 0x00); + for (i = 0; i < 3; i++) + outTi3026(PMINFO TVP3026_XPIXPLLDATA, hw->DACclk[i]); + /* wait for PLL only if PLL clock requested (always for PowerMode, never for VGA) */ + if (hw->MiscOutReg & 0x08) { + int tmout; + outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F); + for (tmout = 500000; tmout; --tmout) { + if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40) + break; + udelay(10); + } + + CRITEND + + if (!tmout) + printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n"); + else + dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout); + CRITBEGIN + } + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]); + outTi3026(PMINFO TVP3026_XPLLADDR, 0x00); + for (i = 3; i < 6; i++) + outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]); + CRITEND + if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) { + int tmout; + + CRITBEGIN + outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F); + for (tmout = 500000; tmout; --tmout) { + if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40) + break; + udelay(10); + } + CRITEND + if (!tmout) + printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n"); + else + dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout); + } + } + matrox_init_putc(PMINFO p, matroxfb_ti3026_createcursor); + +#ifdef DEBUG + dprintk(KERN_DEBUG "3026DACregs "); + for (i = 0; i < 21; i++) { + dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]); + if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... "); + } + dprintk("\n" KERN_DEBUG "DACclk "); + for (i = 0; i < 6; i++) + dprintk("C%02X=%02X ", i, hw->DACclk[i]); + dprintk("\n"); +#endif +} + +static void Ti3026_reset(WPMINFO struct matrox_hw_state* hw){ + + DBG("Ti3026_reset") + + matroxfb_fastfont_init(MINFO); + + ti3026_ramdac_init(PMINFO hw); +} + +static int Ti3026_preinit(WPMINFO struct matrox_hw_state* hw){ + static const int vxres_mill2[] = { 512, 640, 768, 800, 832, 960, + 1024, 1152, 1280, 1600, 1664, 1920, + 2048, 0}; + static const int vxres_mill1[] = { 640, 768, 800, 960, + 1024, 1152, 1280, 1600, 1920, + 2048, 0}; + + DBG("Ti3026_preinit") + + ACCESS_FBINFO(millenium) = 1; + ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL); + ACCESS_FBINFO(capable.cfb4) = 1; + ACCESS_FBINFO(capable.text) = 1; /* isMilleniumII(MINFO); */ + ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1; + ACCESS_FBINFO(cursor.timer.function) = matroxfb_ti3026_flashcursor; + + if (ACCESS_FBINFO(devflags.noinit)) + return 0; + /* preserve VGA I/O, BIOS and PPC */ + hw->MXoptionReg &= 0xC0000100; + hw->MXoptionReg |= 0x002C0000; + if (ACCESS_FBINFO(devflags.novga)) + hw->MXoptionReg &= ~0x00000100; + if (ACCESS_FBINFO(devflags.nobios)) + hw->MXoptionReg &= ~0x40000000; + if (ACCESS_FBINFO(devflags.nopciretry)) + hw->MXoptionReg |= 0x20000000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + + ACCESS_FBINFO(accel.ramdac_rev) = inTi3026(PMINFO TVP3026_XSILICONREV); + + outTi3026(PMINFO TVP3026_XCLKCTRL, TVP3026_XCLKCTRL_SRC_CLK0VGA | TVP3026_XCLKCTRL_CLKSTOPPED); + outTi3026(PMINFO TVP3026_XTRUECOLORCTRL, TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR); + outTi3026(PMINFO TVP3026_XMUXCTRL, TVP3026_XMUXCTRL_VGA); + + outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A); + outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0x00); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00); + + mga_outb(M_MISC_REG, 0x67); + + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL); + + mga_outl(M_RESET, 1); + udelay(250); + mga_outl(M_RESET, 0); + udelay(250); + mga_outl(M_MACCESS, 0x00008000); + udelay(10); + return 0; +} + +struct matrox_switch matrox_millennium = { + Ti3026_preinit, Ti3026_reset, Ti3026_init, Ti3026_restore, matroxfb_ti3026_selhwcursor +}; +EXPORT_SYMBOL(matrox_millennium); +#endif diff --git a/drivers/video/matrox/matroxfb_Ti3026.h b/drivers/video/matrox/matroxfb_Ti3026.h new file mode 100644 index 000000000..541933d7e --- /dev/null +++ b/drivers/video/matrox/matroxfb_Ti3026.h @@ -0,0 +1,13 @@ +#ifndef __MATROXFB_TI3026_H__ +#define __MATROXFB_TI3026_H__ + +/* make checkconfig does not walk through whole include tree */ +#include <linux/config.h> + +#include "matroxfb_base.h" + +#ifdef CONFIG_FB_MATROX_MILLENIUM +extern struct matrox_switch matrox_millennium; +#endif + +#endif /* __MATROXFB_TI3026_H__ */ diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c new file mode 100644 index 000000000..2eb2cfd85 --- /dev/null +++ b/drivers/video/matrox/matroxfb_accel.c @@ -0,0 +1,1212 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 + * + * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Version: 1.21 2000/01/09 + * + * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> + * + * Contributors: "menion?" <menion@mindless.com> + * Betatesting, fixes, ideas + * + * "Kurt Garloff" <garloff@kg1.ping.de> + * Betatesting, fixes, ideas, videomodes, videomodes timmings + * + * "Tom Rini" <trini@kernel.crashing.org> + * MTRR stuff, PPC cleanups, betatesting, fixes, ideas + * + * "Bibek Sahu" <scorpio@dodds.net> + * Access device through readb|w|l and write b|w|l + * Extensive debugging stuff + * + * "Daniel Haun" <haund@usa.net> + * Testing, hardware cursor fixes + * + * "Scott Wood" <sawst46+@pitt.edu> + * Fixes + * + * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> + * Betatesting + * + * "Kelly French" <targon@hazmat.com> + * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> + * Betatesting, bug reporting + * + * "Pablo Bianucci" <pbian@pccp.com.ar> + * Fixes, ideas, betatesting + * + * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> + * Fixes, enhandcements, ideas, betatesting + * + * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> + * PPC betatesting, PPC support, backward compatibility + * + * "Paul Womar" <Paul@pwomar.demon.co.uk> + * "Owen Waller" <O.Waller@ee.qub.ac.uk> + * PPC betatesting + * + * "Thomas Pornin" <pornin@bolet.ens.fr> + * Alpha betatesting + * + * "Pieter van Leuven" <pvl@iae.nl> + * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> + * G100 testing + * + * "H. Peter Arvin" <hpa@transmeta.com> + * Ideas + * + * "Cort Dougan" <cort@cs.nmt.edu> + * CHRP fixes and PReP cleanup + * + * "Mark Vojkovich" <mvojkovi@ucsd.edu> + * G400 support + * + * (following author is not in any relation with this code, but his code + * is included in this driver) + * + * Based on framebuffer driver for VBE 2.0 compliant graphic boards + * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> + * + * (following author is not in any relation with this code, but his ideas + * were used when writting this driver) + * + * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> + * + */ + +#include "matroxfb_accel.h" +#include "matroxfb_DAC1064.h" +#include "matroxfb_Ti3026.h" +#include "matroxfb_misc.h" + +#define curr_ydstorg(x) ACCESS_FBINFO2(x, curr.ydstorg.pixels) + +#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l)) + +void matrox_cfbX_init(WPMINFO struct display* p) { + u_int32_t maccess; + u_int32_t mpitch; + u_int32_t mopmode; + + DBG("matrox_cfbX_init") + + mpitch = p->var.xres_virtual; + + if (p->type == FB_TYPE_TEXT) { + maccess = 0x00000000; + mpitch = (mpitch >> 4) | 0x8000; /* set something */ + mopmode = M_OPMODE_8BPP; + } else { + switch (p->var.bits_per_pixel) { + case 4: maccess = 0x00000000; /* accelerate as 8bpp video */ + mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */ + mopmode = M_OPMODE_4BPP; + break; + case 8: maccess = 0x00000000; + mopmode = M_OPMODE_8BPP; + break; + case 16: if (p->var.green.length == 5) + maccess = 0xC0000001; + else + maccess = 0x40000001; + mopmode = M_OPMODE_16BPP; + break; + case 24: maccess = 0x00000003; + mopmode = M_OPMODE_24BPP; + break; + case 32: maccess = 0x00000002; + mopmode = M_OPMODE_32BPP; + break; + default: maccess = 0x00000000; + mopmode = 0x00000000; + break; /* turn off acceleration!!! */ + } + } + mga_fifo(8); + mga_outl(M_PITCH, mpitch); + mga_outl(M_YDSTORG, curr_ydstorg(MINFO)); + if (ACCESS_FBINFO(capable.plnwt)) + mga_outl(M_PLNWT, -1); + mga_outl(M_OPMODE, mopmode); + mga_outl(M_CXBNDRY, 0xFFFF0000); + mga_outl(M_YTOP, 0); + mga_outl(M_YBOT, 0x01FFFFFF); + mga_outl(M_MACCESS, maccess); + ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO; + if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC; + ACCESS_FBINFO(accel.m_opmode) = mopmode; +} + +static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) { + int pixx = p->var.xres_virtual, start, end; + CRITFLAGS + MINFO_FROM_DISP(p); + + DBG("matrox_cfbX_bmove") + + CRITBEGIN + + sx *= fontwidth(p); + dx *= fontwidth(p); + width *= fontwidth(p); + height *= fontheight(p); + sy *= fontheight(p); + dy *= fontheight(p); + if ((dy < sy) || ((dy == sy) && (dx <= sx))) { + mga_fifo(2); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | + M_DWG_BFCOL | M_DWG_REPLACE); + mga_outl(M_AR5, pixx); + width--; + start = sy*pixx+sx+curr_ydstorg(MINFO); + end = start+width; + } else { + mga_fifo(3); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); + mga_outl(M_SGN, 5); + mga_outl(M_AR5, -pixx); + width--; + end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO); + start = end+width; + dy += height-1; + } + mga_fifo(4); + mga_outl(M_AR0, end); + mga_outl(M_AR3, start); + mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); + mga_ydstlen(dy, height); + WaitTillIdle(); + + CRITEND +} + +#ifdef FBCON_HAS_CFB4 +static void matrox_cfb4_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) { + int pixx, start, end; + CRITFLAGS + MINFO_FROM_DISP(p); + /* both (sx or dx or width) and fontwidth() are odd, so their multiply is + also odd, that means that we cannot use acceleration */ + + DBG("matrox_cfb4_bmove") + + CRITBEGIN + + if ((sx | dx | width) & fontwidth(p) & 1) { + fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width); + return; + } + sx *= fontwidth(p); + dx *= fontwidth(p); + width *= fontwidth(p); + height *= fontheight(p); + sy *= fontheight(p); + dy *= fontheight(p); + pixx = p->var.xres_virtual >> 1; + sx >>= 1; + dx >>= 1; + width >>= 1; + if ((dy < sy) || ((dy == sy) && (dx <= sx))) { + mga_fifo(2); + mga_outl(M_AR5, pixx); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | + M_DWG_BFCOL | M_DWG_REPLACE); + width--; + start = sy*pixx+sx+curr_ydstorg(MINFO); + end = start+width; + } else { + mga_fifo(3); + mga_outl(M_SGN, 5); + mga_outl(M_AR5, -pixx); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); + width--; + end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO); + start = end+width; + dy += height-1; + } + mga_fifo(5); + mga_outl(M_AR0, end); + mga_outl(M_AR3, start); + mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); + mga_outl(M_YDST, dy*pixx >> 5); + mga_outl(M_LEN | M_EXEC, height); + WaitTillIdle(); + + CRITEND +} +#endif + +static void matroxfb_accel_clear(WPMINFO u_int32_t color, int sy, int sx, int height, + int width) { + CRITFLAGS + + DBG("matroxfb_accel_clear") + + CRITBEGIN + + mga_fifo(5); + mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE); + mga_outl(M_FCOL, color); + mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); + mga_ydstlen(sy, height); + WaitTillIdle(); + + CRITEND +} + +static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) { + + DBG("matrox_cfbX_clear") + + matroxfb_accel_clear(PMXINFO(p) color, sy * fontheight(p), sx * fontwidth(p), + height * fontheight(p), width * fontwidth(p)); +} + +#ifdef FBCON_HAS_CFB4 +static void matrox_cfb4_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { + u_int32_t bgx; + int whattodo; + CRITFLAGS + MINFO_FROM_DISP(p); + + DBG("matrox_cfb4_clear") + + CRITBEGIN + + whattodo = 0; + bgx = attr_bgcol_ec(p, conp); + bgx |= bgx << 4; + bgx |= bgx << 8; + bgx |= bgx << 16; + sy *= fontheight(p); + sx *= fontwidth(p); + height *= fontheight(p); + width *= fontwidth(p); + if (sx & 1) { + sx ++; + if (!width) return; + width --; + whattodo = 1; + } + if (width & 1) { + whattodo |= 2; + } + width >>= 1; + sx >>= 1; + if (width) { + mga_fifo(5); + mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE2); + mga_outl(M_FCOL, bgx); + mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); + mga_outl(M_YDST, sy * p->var.xres_virtual >> 6); + mga_outl(M_LEN | M_EXEC, height); + WaitTillIdle(); + } + if (whattodo) { + u_int32_t step = p->var.xres_virtual >> 1; + vaddr_t vbase = ACCESS_FBINFO(video.vbase); + if (whattodo & 1) { + unsigned int uaddr = sy * step + sx - 1; + u_int32_t loop; + u_int8_t bgx2 = bgx & 0xF0; + for (loop = height; loop > 0; loop --) { + mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0x0F) | bgx2); + uaddr += step; + } + } + if (whattodo & 2) { + unsigned int uaddr = sy * step + sx + width; + u_int32_t loop; + u_int8_t bgx2 = bgx & 0x0F; + for (loop = height; loop > 0; loop --) { + mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0xF0) | bgx2); + uaddr += step; + } + } + } + + CRITEND +} +#endif + +#ifdef FBCON_HAS_CFB8 +static void matrox_cfb8_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { + u_int32_t bgx; + + DBG("matrox_cfb8_clear") + + bgx = attr_bgcol_ec(p, conp); + bgx |= bgx << 8; + bgx |= bgx << 16; + matrox_cfbX_clear(bgx, p, sy, sx, height, width); +} +#endif + +#ifdef FBCON_HAS_CFB16 +static void matrox_cfb16_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { + u_int32_t bgx; + + DBG("matrox_cfb16_clear") + + bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)]; + matrox_cfbX_clear((bgx << 16) | bgx, p, sy, sx, height, width); +} +#endif + +#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24) +static void matrox_cfb32_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { + u_int32_t bgx; + + DBG("matrox_cfb32_clear") + + bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)]; + matrox_cfbX_clear(bgx, p, sy, sx, height, width); +} +#endif + +static void matrox_cfbX_fastputc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) { + unsigned int charcell; + unsigned int ar3; + CRITFLAGS + MINFO_FROM_DISP(p); + + charcell = fontwidth(p) * fontheight(p); + yy *= fontheight(p); + xx *= fontwidth(p); + + CRITBEGIN + + mga_fifo(8); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); + + mga_outl(M_FCOL, fgx); + mga_outl(M_BCOL, bgx); + mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx); + ar3 = ACCESS_FBINFO(fastfont.mgabase) + (c & p->charmask) * charcell; + mga_outl(M_AR3, ar3); + mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF); + mga_ydstlen(yy, fontheight(p)); + WaitTillIdle(); + + CRITEND +} + +static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) { + u_int32_t ar0; + u_int32_t step; + CRITFLAGS + MINFO_FROM_DISP(p); + + DBG_HEAVY("matrox_cfbX_putc"); + + yy *= fontheight(p); + xx *= fontwidth(p); + + CRITBEGIN + +#ifdef __BIG_ENDIAN + WaitTillIdle(); + mga_outl(M_OPMODE, M_OPMODE_8BPP); +#else + mga_fifo(7); +#endif + ar0 = fontwidth(p) - 1; + mga_outl(M_FXBNDRY, ((xx+ar0)<<16) | xx); + if (fontwidth(p) <= 8) + step = 1; + else if (fontwidth(p) <= 16) + step = 2; + else + step = 4; + if (fontwidth(p) == step << 3) { + size_t charcell = fontheight(p)*step; + /* TODO: Align charcell to 4B for BE */ + mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); + mga_outl(M_FCOL, fgx); + mga_outl(M_BCOL, bgx); + mga_outl(M_AR3, 0); + mga_outl(M_AR0, fontheight(p)*fontwidth(p)-1); + mga_ydstlen(yy, fontheight(p)); + mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, p->fontdata+(c&p->charmask)*charcell, charcell); + } else { + u8* chardata = p->fontdata+(c&p->charmask)*fontheight(p)*step; + int i; + + mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE); + mga_outl(M_FCOL, fgx); + mga_outl(M_BCOL, bgx); + mga_outl(M_AR5, 0); + mga_outl(M_AR3, 0); + mga_outl(M_AR0, ar0); + mga_ydstlen(yy, fontheight(p)); + + switch (step) { + case 1: + for (i = fontheight(p); i > 0; i--) { +#ifdef __LITTLE_ENDIAN + mga_outl(0, *chardata++); +#else + mga_outl(0, (*chardata++) << 24); +#endif + } + break; + case 2: + for (i = fontheight(p); i > 0; i--) { +#ifdef __LITTLE_ENDIAN + mga_outl(0, *(u_int16_t*)chardata); +#else + mga_outl(0, (*(u_int16_t*)chardata) << 16); +#endif + chardata += 2; + } + break; + case 4: + mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, chardata, fontheight(p) * 4); + break; + } + } + WaitTillIdle(); +#ifdef __BIG_ENDIAN + mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); +#endif + CRITEND +} + +#ifdef FBCON_HAS_CFB8 +static void matrox_cfb8_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { + u_int32_t fgx, bgx; + MINFO_FROM_DISP(p); + + DBG_HEAVY("matroxfb_cfb8_putc"); + + fgx = attr_fgcol(p, c); + bgx = attr_bgcol(p, c); + fgx |= (fgx << 8); + fgx |= (fgx << 16); + bgx |= (bgx << 8); + bgx |= (bgx << 16); + ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx); +} +#endif + +#ifdef FBCON_HAS_CFB16 +static void matrox_cfb16_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { + u_int32_t fgx, bgx; + MINFO_FROM_DISP(p); + + DBG_HEAVY("matroxfb_cfb16_putc"); + + fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, c)]; + bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, c)]; + fgx |= (fgx << 16); + bgx |= (bgx << 16); + ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx); +} +#endif + +#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24) +static void matrox_cfb32_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { + u_int32_t fgx, bgx; + MINFO_FROM_DISP(p); + + DBG_HEAVY("matroxfb_cfb32_putc"); + + fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, c)]; + bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, c)]; + ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx); +} +#endif + +static void matrox_cfbX_fastputcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) { + unsigned int charcell; + CRITFLAGS + MINFO_FROM_DISP(p); + + yy *= fontheight(p); + xx *= fontwidth(p); + charcell = fontwidth(p) * fontheight(p); + + CRITBEGIN + + mga_fifo(3); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); + mga_outl(M_FCOL, fgx); + mga_outl(M_BCOL, bgx); + while (count--) { + u_int32_t ar3 = ACCESS_FBINFO(fastfont.mgabase) + (scr_readw(s++) & p->charmask)*charcell; + + mga_fifo(4); + mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx); + mga_outl(M_AR3, ar3); + mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF); + mga_ydstlen(yy, fontheight(p)); + xx += fontwidth(p); + } + WaitTillIdle(); + + CRITEND +} + +static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) { + u_int32_t step; + u_int32_t ydstlen; + u_int32_t xlen; + u_int32_t ar0; + u_int32_t charcell; + u_int32_t fxbndry; + vaddr_t mmio; + int easy; + CRITFLAGS + MINFO_FROM_DISP(p); + + DBG_HEAVY("matroxfb_cfbX_putcs"); + + yy *= fontheight(p); + xx *= fontwidth(p); + if (fontwidth(p) <= 8) + step = 1; + else if (fontwidth(p) <= 16) + step = 2; + else + step = 4; + charcell = fontheight(p)*step; + xlen = (charcell + 3) & ~3; + ydstlen = (yy << 16) | fontheight(p); + if (fontwidth(p) == step << 3) { + ar0 = fontheight(p)*fontwidth(p) - 1; + easy = 1; + } else { + ar0 = fontwidth(p) - 1; + easy = 0; + } + + CRITBEGIN + +#ifdef __BIG_ENDIAN + WaitTillIdle(); + mga_outl(M_OPMODE, M_OPMODE_8BPP); +#else + mga_fifo(3); +#endif + if (easy) + mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); + else + mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE); + mga_outl(M_FCOL, fgx); + mga_outl(M_BCOL, bgx); + fxbndry = ((xx + fontwidth(p) - 1) << 16) | xx; + mmio = ACCESS_FBINFO(mmio.vbase); + while (count--) { + u_int8_t* chardata = p->fontdata + (scr_readw(s++) & p->charmask)*charcell; + + mga_fifo(6); + mga_writel(mmio, M_FXBNDRY, fxbndry); + mga_writel(mmio, M_AR0, ar0); + mga_writel(mmio, M_AR3, 0); + if (easy) { + mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen); + mga_memcpy_toio(mmio, 0, chardata, xlen); + } else { + mga_writel(mmio, M_AR5, 0); + mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen); + switch (step) { + case 1: { + u_int8_t* charend = chardata + charcell; + for (; chardata != charend; chardata++) { +#ifdef __LITTLE_ENDIAN + mga_writel(mmio, 0, *chardata); +#else + mga_writel(mmio, 0, (*chardata) << 24); +#endif + } + } + break; + case 2: { + u_int8_t* charend = chardata + charcell; + for (; chardata != charend; chardata += 2) { +#ifdef __LITTLE_ENDIAN + mga_writel(mmio, 0, *(u_int16_t*)chardata); +#else + mga_writel(mmio, 0, (*(u_int16_t*)chardata) << 16); +#endif + } + } + break; + default: + mga_memcpy_toio(mmio, 0, chardata, charcell); + break; + } + } + fxbndry += fontwidth(p) + (fontwidth(p) << 16); + } + WaitTillIdle(); +#ifdef __BIG_ENDIAN + mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); +#endif + CRITEND +} + +#ifdef FBCON_HAS_CFB8 +static void matrox_cfb8_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) { + u_int32_t fgx, bgx; + MINFO_FROM_DISP(p); + + DBG_HEAVY("matroxfb_cfb8_putcs"); + + fgx = attr_fgcol(p, scr_readw(s)); + bgx = attr_bgcol(p, scr_readw(s)); + fgx |= (fgx << 8); + fgx |= (fgx << 16); + bgx |= (bgx << 8); + bgx |= (bgx << 16); + ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx); +} +#endif + +#ifdef FBCON_HAS_CFB16 +static void matrox_cfb16_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) { + u_int32_t fgx, bgx; + MINFO_FROM_DISP(p); + + DBG_HEAVY("matroxfb_cfb16_putcs"); + + fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, scr_readw(s))]; + bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, scr_readw(s))]; + fgx |= (fgx << 16); + bgx |= (bgx << 16); + ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx); +} +#endif + +#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24) +static void matrox_cfb32_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) { + u_int32_t fgx, bgx; + MINFO_FROM_DISP(p); + + DBG_HEAVY("matroxfb_cfb32_putcs"); + + fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, scr_readw(s))]; + bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, scr_readw(s))]; + ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx); +} +#endif + +#ifdef FBCON_HAS_CFB4 +static void matrox_cfb4_revc(struct display* p, int xx, int yy) { + CRITFLAGS + MINFO_FROM_DISP(p); + + DBG_LOOP("matroxfb_cfb4_revc"); + + if (fontwidth(p) & 1) { + fbcon_cfb4_revc(p, xx, yy); + return; + } + yy *= fontheight(p); + xx *= fontwidth(p); + xx |= (xx + fontwidth(p)) << 16; + xx >>= 1; + + CRITBEGIN + + mga_fifo(5); + mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR); + mga_outl(M_FCOL, 0xFFFFFFFF); + mga_outl(M_FXBNDRY, xx); + mga_outl(M_YDST, yy * p->var.xres_virtual >> 6); + mga_outl(M_LEN | M_EXEC, fontheight(p)); + WaitTillIdle(); + + CRITEND +} +#endif + +#ifdef FBCON_HAS_CFB8 +static void matrox_cfb8_revc(struct display* p, int xx, int yy) { + CRITFLAGS + MINFO_FROM_DISP(p); + + DBG_LOOP("matrox_cfb8_revc") + + yy *= fontheight(p); + xx *= fontwidth(p); + + CRITBEGIN + + mga_fifo(4); + mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR); + mga_outl(M_FCOL, 0x0F0F0F0F); + mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx); + mga_ydstlen(yy, fontheight(p)); + WaitTillIdle(); + + CRITEND +} +#endif + +static void matrox_cfbX_revc(struct display* p, int xx, int yy) { + CRITFLAGS + MINFO_FROM_DISP(p); + + DBG_LOOP("matrox_cfbX_revc") + + yy *= fontheight(p); + xx *= fontwidth(p); + + CRITBEGIN + + mga_fifo(4); + mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR); + mga_outl(M_FCOL, 0xFFFFFFFF); + mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx); + mga_ydstlen(yy, fontheight(p)); + WaitTillIdle(); + + CRITEND +} + +static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) { + unsigned int bottom_height, right_width; + unsigned int bottom_start, right_start; + unsigned int cell_h, cell_w; + + DBG("matrox_cfbX_clear_margins") + + cell_w = fontwidth(p); + if (!cell_w) return; /* PARANOID */ + right_width = p->var.xres % cell_w; + right_start = p->var.xres - right_width; + if (!bottom_only && right_width) { + /* clear whole right margin, not only visible portion */ + matroxfb_accel_clear( PMXINFO(p) + /* color */ 0x00000000, + /* y */ 0, + /* x */ p->var.xoffset + right_start, + /* height */ p->var.yres_virtual, + /* width */ right_width); + } + cell_h = fontheight(p); + if (!cell_h) return; /* PARANOID */ + bottom_height = p->var.yres % cell_h; + if (bottom_height) { + bottom_start = p->var.yres - bottom_height; + matroxfb_accel_clear( PMXINFO(p) + /* color */ 0x00000000, + /* y */ p->var.yoffset + bottom_start, + /* x */ p->var.xoffset, + /* height */ bottom_height, + /* width */ right_start); + } +} + +static void matrox_text_setup(struct display* p) { + MINFO_FROM_DISP(p); + + p->next_line = p->line_length ? p->line_length : ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep)); + p->next_plane = 0; +} + +static void matrox_text_bmove(struct display* p, int sy, int sx, int dy, int dx, + int height, int width) { + unsigned int srcoff; + unsigned int dstoff; + unsigned int step; + CRITFLAGS + MINFO_FROM_DISP(p); + + CRITBEGIN + + step = ACCESS_FBINFO(devflags.textstep); + srcoff = (sy * p->next_line) + (sx * step); + dstoff = (dy * p->next_line) + (dx * step); + if (dstoff < srcoff) { + while (height > 0) { + int i; + for (i = width; i > 0; dstoff += step, srcoff += step, i--) + mga_writew(ACCESS_FBINFO(video.vbase), dstoff, mga_readw(ACCESS_FBINFO(video.vbase), srcoff)); + height--; + dstoff += p->next_line - width * step; + srcoff += p->next_line - width * step; + } + } else { + unsigned int off; + + off = (height - 1) * p->next_line + (width - 1) * step; + srcoff += off; + dstoff += off; + while (height > 0) { + int i; + for (i = width; i > 0; dstoff -= step, srcoff -= step, i--) + mga_writew(ACCESS_FBINFO(video.vbase), dstoff, mga_readw(ACCESS_FBINFO(video.vbase), srcoff)); + dstoff -= p->next_line - width * step; + srcoff -= p->next_line - width * step; + height--; + } + } + CRITEND +} + +static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, int sx, + int height, int width) { + unsigned int offs; + unsigned int val; + unsigned int step; + CRITFLAGS + MINFO_FROM_DISP(p); + + step = ACCESS_FBINFO(devflags.textstep); + offs = sy * p->next_line + sx * step; + val = ntohs((attr_bgcol(p, conp->vc_video_erase_char) << 4) | attr_fgcol(p, conp->vc_video_erase_char) | (' ' << 8)); + + CRITBEGIN + + while (height > 0) { + int i; + for (i = width; i > 0; offs += step, i--) + mga_writew(ACCESS_FBINFO(video.vbase), offs, val); + offs += p->next_line - width * step; + height--; + } + CRITEND +} + +static void matrox_text_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { + unsigned int offs; + unsigned int chr; + unsigned int step; + CRITFLAGS + MINFO_FROM_DISP(p); + + step = ACCESS_FBINFO(devflags.textstep); + offs = yy * p->next_line + xx * step; + chr = attr_fgcol(p,c) | (attr_bgcol(p,c) << 4) | ((c & p->charmask) << 8); + if (chr & 0x10000) chr |= 0x08; + + CRITBEGIN + + mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(chr)); + + CRITEND +} + +static void matrox_text_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, + int count, int yy, int xx) { + unsigned int offs; + unsigned int attr; + unsigned int step; + CRITFLAGS + MINFO_FROM_DISP(p); + + step = ACCESS_FBINFO(devflags.textstep); + offs = yy * p->next_line + xx * step; + attr = attr_fgcol(p, scr_readw(s)) | (attr_bgcol(p, scr_readw(s)) << 4); + + CRITBEGIN + + while (count-- > 0) { + unsigned int chr = ((scr_readw(s++)) & p->charmask) << 8; + if (chr & 0x10000) chr ^= 0x10008; + mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(attr|chr)); + offs += step; + } + + CRITEND +} + +static void matrox_text_revc(struct display* p, int xx, int yy) { + unsigned int offs; + unsigned int step; + CRITFLAGS + MINFO_FROM_DISP(p); + + step = ACCESS_FBINFO(devflags.textstep); + offs = yy * p->next_line + xx * step + 1; + + CRITBEGIN + + mga_writeb(ACCESS_FBINFO(video.vbase), offs, mga_readb(ACCESS_FBINFO(video.vbase), offs) ^ 0x77); + + CRITEND +} + +void matrox_text_createcursor(WPMINFO struct display* p) { + CRITFLAGS + + if (ACCESS_FBINFO(currcon_display) != p) + return; + + matroxfb_createcursorshape(PMINFO p, 0); + + CRITBEGIN + + mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u)); + mga_setr(M_CRTC_INDEX, 0x0B, ACCESS_FBINFO(cursor.d) - 1); + + CRITEND +} + +static void matrox_text_cursor(struct display* p, int mode, int x, int y) { + unsigned int pos; + CRITFLAGS + MINFO_FROM_DISP(p); + + if (ACCESS_FBINFO(currcon_display) != p) + return; + + if (mode == CM_ERASE) { + if (ACCESS_FBINFO(cursor.state) != CM_ERASE) { + + CRITBEGIN + + mga_setr(M_CRTC_INDEX, 0x0A, 0x20); + + CRITEND + + ACCESS_FBINFO(cursor.state) = CM_ERASE; + } + return; + } + if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type)) + matrox_text_createcursor(PMINFO p); + + /* DO NOT CHECK cursor.x != x because of matroxfb_vgaHWinit moves cursor to 0,0 */ + ACCESS_FBINFO(cursor.x) = x; + ACCESS_FBINFO(cursor.y) = y; + pos = p->next_line / ACCESS_FBINFO(devflags.textstep) * y + x; + + CRITBEGIN + + mga_setr(M_CRTC_INDEX, 0x0F, pos); + mga_setr(M_CRTC_INDEX, 0x0E, pos >> 8); + + mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u)); + + CRITEND + + ACCESS_FBINFO(cursor.state) = CM_DRAW; +} + +void matrox_text_round(CPMINFO struct fb_var_screeninfo* var, struct display* p) { + unsigned hf; + unsigned vf; + unsigned vxres; + unsigned ych; + + hf = fontwidth(p); + if (!hf) hf = 8; + /* do not touch xres */ + vxres = (var->xres_virtual + hf - 1) / hf; + if (vxres >= 256) + vxres = 255; + if (vxres < 16) + vxres = 16; + vxres = (vxres + 1) & ~1; /* must be even */ + vf = fontheight(p); + if (!vf) vf = 16; + if (var->yres < var->yres_virtual) { + ych = ACCESS_FBINFO(devflags.textvram) / vxres; + var->yres_virtual = ych * vf; + } else + ych = var->yres_virtual / vf; + if (vxres * ych > ACCESS_FBINFO(devflags.textvram)) { + ych = ACCESS_FBINFO(devflags.textvram) / vxres; + var->yres_virtual = ych * vf; + } + var->xres_virtual = vxres * hf; +} + +static int matrox_text_setfont(struct display* p, int width, int height) { + DBG("matrox_text_setfont"); + + if (p) { + MINFO_FROM_DISP(p); + + matrox_text_round(PMINFO &p->var, p); + p->next_line = p->line_length = ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep)); + + if (p->conp) + matrox_text_createcursor(PMINFO p); + } + return 0; +} + +#define matrox_cfb16_revc matrox_cfbX_revc +#define matrox_cfb24_revc matrox_cfbX_revc +#define matrox_cfb32_revc matrox_cfbX_revc + +#define matrox_cfb24_clear matrox_cfb32_clear +#define matrox_cfb24_putc matrox_cfb32_putc +#define matrox_cfb24_putcs matrox_cfb32_putcs + +#ifdef FBCON_HAS_VGATEXT +static struct display_switch matroxfb_text = { + matrox_text_setup, matrox_text_bmove, matrox_text_clear, + matrox_text_putc, matrox_text_putcs, matrox_text_revc, + matrox_text_cursor, matrox_text_setfont, NULL, + FONTWIDTH(8)|FONTWIDTH(9) +}; +#endif + +#ifdef FBCON_HAS_CFB4 +static struct display_switch matroxfb_cfb4 = { + fbcon_cfb4_setup, matrox_cfb4_bmove, matrox_cfb4_clear, + fbcon_cfb4_putc, fbcon_cfb4_putcs, matrox_cfb4_revc, + NULL, NULL, NULL, + /* cursor... */ /* set_font... */ + FONTWIDTH(8) /* fix, fix, fix it */ +}; +#endif + +#ifdef FBCON_HAS_CFB8 +static struct display_switch matroxfb_cfb8 = { + fbcon_cfb8_setup, matrox_cfbX_bmove, matrox_cfb8_clear, + matrox_cfb8_putc, matrox_cfb8_putcs, matrox_cfb8_revc, + NULL, NULL, matrox_cfbX_clear_margins, + ~1 /* FONTWIDTHS */ +}; +#endif + +#ifdef FBCON_HAS_CFB16 +static struct display_switch matroxfb_cfb16 = { + fbcon_cfb16_setup, matrox_cfbX_bmove, matrox_cfb16_clear, + matrox_cfb16_putc, matrox_cfb16_putcs, matrox_cfb16_revc, + NULL, NULL, matrox_cfbX_clear_margins, + ~1 /* FONTWIDTHS */ +}; +#endif + +#ifdef FBCON_HAS_CFB24 +static struct display_switch matroxfb_cfb24 = { + fbcon_cfb24_setup, matrox_cfbX_bmove, matrox_cfb24_clear, + matrox_cfb24_putc, matrox_cfb24_putcs, matrox_cfb24_revc, + NULL, NULL, matrox_cfbX_clear_margins, + ~1 /* FONTWIDTHS */ /* TODO: and what about non-aligned access on BE? I think that there are no in my code */ +}; +#endif + +#ifdef FBCON_HAS_CFB32 +static struct display_switch matroxfb_cfb32 = { + fbcon_cfb32_setup, matrox_cfbX_bmove, matrox_cfb32_clear, + matrox_cfb32_putc, matrox_cfb32_putcs, matrox_cfb32_revc, + NULL, NULL, matrox_cfbX_clear_margins, + ~1 /* FONTWIDTHS */ +}; +#endif + +void initMatrox(WPMINFO struct display* p) { + struct display_switch *swtmp; + + DBG("initMatrox") + + if (ACCESS_FBINFO(currcon_display) != p) + return; + if (p->dispsw && p->conp) + fb_con.con_cursor(p->conp, CM_ERASE); + p->dispsw_data = NULL; + if ((p->var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) { + if (p->type == FB_TYPE_TEXT) { + swtmp = &matroxfb_text; + } else { + switch (p->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB4 + case 4: + swtmp = &fbcon_cfb4; + break; +#endif +#ifdef FBCON_HAS_CFB8 + case 8: + swtmp = &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16); + swtmp = &fbcon_cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24); + swtmp = &fbcon_cfb24; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32); + swtmp = &fbcon_cfb32; + break; +#endif + default: + p->dispsw = &fbcon_dummy; + return; + } + } + dprintk(KERN_INFO "matroxfb: acceleration disabled\n"); + } else if (p->type == FB_TYPE_TEXT) { + swtmp = &matroxfb_text; + } else { + switch (p->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB4 + case 4: + swtmp = &matroxfb_cfb4; + break; +#endif +#ifdef FBCON_HAS_CFB8 + case 8: + swtmp = &matroxfb_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16); + swtmp = &matroxfb_cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24); + swtmp = &matroxfb_cfb24; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32); + swtmp = &matroxfb_cfb32; + break; +#endif + default: + p->dispsw = &fbcon_dummy; + return; + } + } + memcpy(&ACCESS_FBINFO(dispsw), swtmp, sizeof(ACCESS_FBINFO(dispsw))); + p->dispsw = &ACCESS_FBINFO(dispsw); + if ((p->type != FB_TYPE_TEXT) && ACCESS_FBINFO(devflags.hwcursor)) { + ACCESS_FBINFO(hw_switch)->selhwcursor(PMINFO p); + } +} + +void matrox_init_putc(WPMINFO struct display* p, void (*dac_createcursor)(WPMINFO struct display* p)) { + int i; + + if (p && p->conp) { + if (p->type == FB_TYPE_TEXT) { + matrox_text_createcursor(PMINFO p); + matrox_text_loadfont(PMINFO p); + i = 0; + } else { + dac_createcursor(PMINFO p); + i = matroxfb_fastfont_tryset(PMINFO p); + } + } else + i = 0; + if (i) { + ACCESS_FBINFO(curr.putc) = matrox_cfbX_fastputc; + ACCESS_FBINFO(curr.putcs) = matrox_cfbX_fastputcs; + } else { + ACCESS_FBINFO(curr.putc) = matrox_cfbX_putc; + ACCESS_FBINFO(curr.putcs) = matrox_cfbX_putcs; + } +} diff --git a/drivers/video/matrox/matroxfb_accel.h b/drivers/video/matrox/matroxfb_accel.h new file mode 100644 index 000000000..a3165a0a2 --- /dev/null +++ b/drivers/video/matrox/matroxfb_accel.h @@ -0,0 +1,12 @@ +#ifndef __MATROXFB_ACCEL_H__ +#define __MATROXFB_ACCEL_H__ + +#include "matroxfb_base.h" + +void matrox_init_putc(WPMINFO struct display* p, void (*)(WPMINFO struct display *p)); +void matrox_cfbX_init(WPMINFO struct display* p); +void matrox_text_createcursor(WPMINFO struct display* p); +void matrox_text_round(CPMINFO struct fb_var_screeninfo* var, struct display* p); +void initMatrox(WPMINFO struct display* p); + +#endif diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c new file mode 100644 index 000000000..a8af1c68c --- /dev/null +++ b/drivers/video/matrox/matroxfb_base.c @@ -0,0 +1,2544 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 + * + * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Version: 1.21 1999/01/09 + * + * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> + * + * Contributors: "menion?" <menion@mindless.com> + * Betatesting, fixes, ideas + * + * "Kurt Garloff" <garloff@kg1.ping.de> + * Betatesting, fixes, ideas, videomodes, videomodes timmings + * + * "Tom Rini" <trini@kernel.crashing.org> + * MTRR stuff, PPC cleanups, betatesting, fixes, ideas + * + * "Bibek Sahu" <scorpio@dodds.net> + * Access device through readb|w|l and write b|w|l + * Extensive debugging stuff + * + * "Daniel Haun" <haund@usa.net> + * Testing, hardware cursor fixes + * + * "Scott Wood" <sawst46+@pitt.edu> + * Fixes + * + * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> + * Betatesting + * + * "Kelly French" <targon@hazmat.com> + * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> + * Betatesting, bug reporting + * + * "Pablo Bianucci" <pbian@pccp.com.ar> + * Fixes, ideas, betatesting + * + * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> + * Fixes, enhandcements, ideas, betatesting + * + * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> + * PPC betatesting, PPC support, backward compatibility + * + * "Paul Womar" <Paul@pwomar.demon.co.uk> + * "Owen Waller" <O.Waller@ee.qub.ac.uk> + * PPC betatesting + * + * "Thomas Pornin" <pornin@bolet.ens.fr> + * Alpha betatesting + * + * "Pieter van Leuven" <pvl@iae.nl> + * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> + * G100 testing + * + * "H. Peter Arvin" <hpa@transmeta.com> + * Ideas + * + * "Cort Dougan" <cort@cs.nmt.edu> + * CHRP fixes and PReP cleanup + * + * "Mark Vojkovich" <mvojkovi@ucsd.edu> + * G400 support + * + * "Samuel Hocevar" <sam@via.ecp.fr> + * Fixes + * + * "Anton Altaparmakov" <AntonA@bigfoot.com> + * G400 MAX/non-MAX distinction + * + * (following author is not in any relation with this code, but his code + * is included in this driver) + * + * Based on framebuffer driver for VBE 2.0 compliant graphic boards + * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> + * + * (following author is not in any relation with this code, but his ideas + * were used when writting this driver) + * + * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> + * + */ + +/* make checkconfig does not check included files... */ +#include <linux/config.h> + +#include "matroxfb_base.h" +#include "matroxfb_misc.h" +#include "matroxfb_accel.h" +#include "matroxfb_DAC1064.h" +#include "matroxfb_Ti3026.h" +#include "matroxfb_maven.h" +#include "matroxfb_crtc2.h" +#include <linux/matroxfb.h> +#include <asm/uaccess.h> + +#if defined(CONFIG_FB_OF) +unsigned char nvram_read_byte(int); +int matrox_of_init(struct device_node *dp); +static int default_vmode = VMODE_NVRAM; +static int default_cmode = CMODE_NVRAM; +#endif + +static void matroxfb_unregister_device(struct matrox_fb_info* minfo); + +/* --------------------------------------------------------------------- */ + +/* + * card parameters + */ + +/* --------------------------------------------------------------------- */ + +static struct fb_var_screeninfo vesafb_defined = { + 640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/ + 0,0, /* virtual -> visible no offset */ + 8, /* depth -> load bits_per_pixel */ + 0, /* greyscale ? */ + {0,0,0}, /* R */ + {0,0,0}, /* G */ + {0,0,0}, /* B */ + {0,0,0}, /* transparency */ + 0, /* standard pixel format */ + FB_ACTIVATE_NOW, + -1,-1, + FB_ACCELF_TEXT, /* accel flags */ + 39721L,48L,16L,33L,10L, + 96L,2L,~0, /* No sync info */ + FB_VMODE_NONINTERLACED, + {0,0,0,0,0,0} +}; + + + +/* --------------------------------------------------------------------- */ + +static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) { + unsigned int pos; + unsigned short p0, p1, p2; +#ifdef CONFIG_FB_MATROX_32MB + unsigned int p3; +#endif + struct display *disp; + CRITFLAGS + + DBG("matrox_pan_var") + + if (ACCESS_FBINFO(dead)) + return; + + disp = ACCESS_FBINFO(currcon_display); + if (disp->type == FB_TYPE_TEXT) { + pos = var->yoffset / fontheight(disp) * disp->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(disp)?fontwidth(disp):8); + } else { + pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32; + pos += ACCESS_FBINFO(curr.ydstorg.chunks); + } + p0 = ACCESS_FBINFO(currenthw)->CRTC[0x0D] = pos & 0xFF; + p1 = ACCESS_FBINFO(currenthw)->CRTC[0x0C] = (pos & 0xFF00) >> 8; + p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); +#ifdef CONFIG_FB_MATROX_32MB + p3 = ACCESS_FBINFO(currenthw)->CRTCEXT[8] = pos >> 21; +#endif + + CRITBEGIN + + mga_setr(M_CRTC_INDEX, 0x0D, p0); + mga_setr(M_CRTC_INDEX, 0x0C, p1); +#ifdef CONFIG_FB_MATROX_32MB + if (ACCESS_FBINFO(devflags.support32MB)) + mga_setr(M_EXTVGA_INDEX, 0x08, p3); +#endif + mga_setr(M_EXTVGA_INDEX, 0x00, p2); + + CRITEND +} + +static void matroxfb_remove(WPMINFO int dummy) { + /* Currently we are holding big kernel lock on all dead & usecount updates. + * Destroy everything after all users release it. Especially do not unregister + * framebuffer and iounmap memory, neither fbmem nor fbcon-cfb* does not check + * for device unplugged when in use. + * In future we should point mmio.vbase & video.vbase somewhere where we can + * write data without causing too much damage... + */ + + ACCESS_FBINFO(dead) = 1; + if (ACCESS_FBINFO(usecount)) { + /* destroy it later */ + return; + } + matroxfb_unregister_device(MINFO); + unregister_framebuffer(&ACCESS_FBINFO(fbcon)); + del_timer(&ACCESS_FBINFO(cursor.timer)); +#ifdef CONFIG_MTRR + if (ACCESS_FBINFO(mtrr.vram_valid)) + mtrr_del(ACCESS_FBINFO(mtrr.vram), ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len)); +#endif + mga_iounmap(ACCESS_FBINFO(mmio.vbase)); + mga_iounmap(ACCESS_FBINFO(video.vbase)); + release_mem_region(ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len_maximum)); + release_mem_region(ACCESS_FBINFO(mmio.base), 16384); +#ifdef CONFIG_FB_MATROX_MULTIHEAD + kfree_s(ACCESS_FBINFO(fbcon.disp), sizeof(struct display)); + kfree_s(minfo, sizeof(struct matrox_fb_info)); +#endif +} + + /* + * Open/Release the frame buffer device + */ + +static int matroxfb_open(struct fb_info *info, int user) +{ +#define minfo ((struct matrox_fb_info*)info) + DBG_LOOP("matroxfb_open") + + if (ACCESS_FBINFO(dead)) { + return -ENXIO; + } + MOD_INC_USE_COUNT; + ACCESS_FBINFO(usecount)++; +#undef minfo + return(0); +} + +static int matroxfb_release(struct fb_info *info, int user) +{ +#define minfo ((struct matrox_fb_info*)info) + DBG_LOOP("matroxfb_release") + + if (!(--ACCESS_FBINFO(usecount)) && ACCESS_FBINFO(dead)) { + matroxfb_remove(PMINFO 0); + } + MOD_DEC_USE_COUNT; +#undef minfo + return(0); +} + +static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info* info) { +#define minfo ((struct matrox_fb_info*)info) + + DBG("matroxfb_pan_display") + + if (var->vmode & FB_VMODE_YWRAP) { + if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset) + return -EINVAL; + } else { + if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual || + var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual) + return -EINVAL; + } + if (con == ACCESS_FBINFO(currcon)) + matrox_pan_var(PMINFO var); + fb_display[con].var.xoffset = var->xoffset; + fb_display[con].var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + fb_display[con].var.vmode |= FB_VMODE_YWRAP; + else + fb_display[con].var.vmode &= ~FB_VMODE_YWRAP; + return 0; +#undef minfo +} + +static int matroxfb_updatevar(int con, struct fb_info *info) +{ +#define minfo ((struct matrox_fb_info*)info) + DBG("matroxfb_updatevar"); + + matrox_pan_var(PMINFO &fb_display[con].var); + return 0; +#undef minfo +} + +static int matroxfb_get_final_bppShift(CPMINFO int bpp) { + int bppshft2; + + DBG("matroxfb_get_final_bppShift") + + bppshft2 = bpp; + if (!bppshft2) { + return 8; + } + if (isInterleave(MINFO)) + bppshft2 >>= 1; + if (ACCESS_FBINFO(devflags.video64bits)) + bppshft2 >>= 1; + return bppshft2; +} + +static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) { + int over; + int rounding; + + DBG("matroxfb_test_and_set_rounding") + + switch (bpp) { + case 0: return xres; + case 4: rounding = 128; + break; + case 8: rounding = 64; /* doc says 64; 32 is OK for G400 */ + break; + case 16: rounding = 32; + break; + case 24: rounding = 64; /* doc says 64; 32 is OK for G400 */ + break; + default: rounding = 16; + /* on G400, 16 really does not work */ + if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) + rounding = 32; + break; + } + if (isInterleave(MINFO)) { + rounding *= 2; + } + over = xres % rounding; + if (over) + xres += rounding-over; + return xres; +} + +static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) { + const int* width; + int xres_new; + + DBG("matroxfb_pitch_adjust") + + if (!bpp) return xres; + + width = ACCESS_FBINFO(capable.vxres); + + if (ACCESS_FBINFO(devflags.precise_width)) { + while (*width) { + if ((*width >= xres) && (matroxfb_test_and_set_rounding(PMINFO *width, bpp) == *width)) { + break; + } + width++; + } + xres_new = *width; + } else { + xres_new = matroxfb_test_and_set_rounding(PMINFO xres, bpp); + } + if (!xres_new) return 0; + if (xres != xres_new) { + printk(KERN_INFO "matroxfb: cannot set xres to %d, rounded up to %d\n", xres, xres_new); + } + return xres_new; +} + +static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) { + + DBG("matroxfb_get_cmap_len") + + switch (var->bits_per_pixel) { +#ifdef FBCON_HAS_VGATEXT + case 0: + return 16; /* pseudocolor... 16 entries HW palette */ +#endif +#ifdef FBCON_HAS_CFB4 + case 4: + return 16; /* pseudocolor... 16 entries HW palette */ +#endif +#ifdef FBCON_HAS_CFB8 + case 8: + return 256; /* pseudocolor... 256 entries HW palette */ +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + return 16; /* directcolor... 16 entries SW palette */ + /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + return 16; /* directcolor... 16 entries SW palette */ + /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + return 16; /* directcolor... 16 entries SW palette */ + /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ +#endif + } + return 16; /* return something reasonable... or panic()? */ +} + +static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) { + unsigned int vramlen; + unsigned int memlen; + + DBG("matroxfb_decode_var") + + switch (var->bits_per_pixel) { +#ifdef FBCON_HAS_VGATEXT + case 0: if (!ACCESS_FBINFO(capable.text)) return -EINVAL; + break; +#endif +#ifdef FBCON_HAS_CFB4 + case 4: if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL; + break; +#endif +#ifdef FBCON_HAS_CFB8 + case 8: break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: break; +#endif + default: return -EINVAL; + } + *ydstorg = 0; + vramlen = ACCESS_FBINFO(video.len_usable); + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->bits_per_pixel) { + var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, var->bits_per_pixel); + memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8; + if (memlen > vramlen) { + var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel); + memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8; + } + /* There is hardware bug that no line can cross 4MB boundary */ + /* give up for CFB24, it is impossible to easy workaround it */ + /* for other try to do something */ + if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) { + if (var->bits_per_pixel == 24) { + /* sorry */ + } else { + unsigned int linelen; + unsigned int m1 = linelen = var->xres_virtual * var->bits_per_pixel / 8; + unsigned int m2 = PAGE_SIZE; /* or 128 if you do not need PAGE ALIGNED address */ + unsigned int max_yres; + + while (m1) { + int t; + + while (m2 >= m1) m2 -= m1; + t = m1; + m1 = m2; + m2 = t; + } + m2 = linelen * PAGE_SIZE / m2; + *ydstorg = m2 = 0x400000 % m2; + max_yres = (vramlen - m2) / linelen; + if (var->yres_virtual > max_yres) + var->yres_virtual = max_yres; + } + } + } else { + matrox_text_round(PMINFO var, p); +#if 0 +/* we must limit pixclock by mclk... + Millennium I: 66 MHz = 15000 + Millennium II: 61 MHz = 16300 + Millennium G200: 83 MHz = 12000 */ + if (var->pixclock < 15000) + var->pixclock = 15000; /* limit for "normal" gclk & mclk */ +#endif + } + /* YDSTLEN contains only signed 16bit value */ + if (var->yres_virtual > 32767) + var->yres_virtual = 32767; + /* we must round yres/xres down, we already rounded y/xres_virtual up + if it was possible. We should return -EINVAL, but I disagree */ + if (var->yres_virtual < var->yres) + var->yres = var->yres_virtual; + if (var->xres_virtual < var->xres) + var->xres = var->xres_virtual; + if (var->xoffset + var->xres > var->xres_virtual) + var->xoffset = var->xres_virtual - var->xres; + if (var->yoffset + var->yres > var->yres_virtual) + var->yoffset = var->yres_virtual - var->yres; + + if (var->bits_per_pixel == 0) { + var->red.offset = 0; + var->red.length = 6; + var->green.offset = 0; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 6; + var->transp.offset = 0; + var->transp.length = 0; + *visual = MX_VISUAL_PSEUDOCOLOR; + } else if (var->bits_per_pixel == 4) { + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + *visual = MX_VISUAL_PSEUDOCOLOR; + } else if (var->bits_per_pixel <= 8) { + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + *visual = MX_VISUAL_PSEUDOCOLOR; + } else { + if (var->bits_per_pixel <= 16) { + if (var->green.length == 5) { + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + } else { + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + } + } else if (var->bits_per_pixel <= 24) { + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + } else { + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + } + dprintk("matroxfb: truecolor: " + "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", + var->transp.length, + var->red.length, + var->green.length, + var->blue.length, + var->transp.offset, + var->red.offset, + var->green.offset, + var->blue.offset); + *visual = MX_VISUAL_DIRECTCOLOR; + } + *video_cmap_len = matroxfb_get_cmap_len(var); + dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel, + var->xres_virtual, var->yres_virtual); + return 0; +} + +static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info) +{ + struct display* p; +#ifdef CONFIG_FB_MATROX_MULTIHEAD + struct matrox_fb_info* minfo = (struct matrox_fb_info*)fb_info; +#endif + + DBG("matrox_setcolreg") + + /* + * Set a single color register. The values supplied are + * already rounded down to the hardware's capabilities + * (according to the entries in the `var' structure). Return + * != 0 for invalid regno. + */ + + if (regno >= ACCESS_FBINFO(curr.cmap_len)) + return 1; + + ACCESS_FBINFO(palette[regno].red) = red; + ACCESS_FBINFO(palette[regno].green) = green; + ACCESS_FBINFO(palette[regno].blue) = blue; + ACCESS_FBINFO(palette[regno].transp) = transp; + + p = ACCESS_FBINFO(currcon_display); + if (p->var.grayscale) { + /* gray = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + red = CNVT_TOHW(red, p->var.red.length); + green = CNVT_TOHW(green, p->var.green.length); + blue = CNVT_TOHW(blue, p->var.blue.length); + transp = CNVT_TOHW(transp, p->var.transp.length); + + switch (p->var.bits_per_pixel) { +#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_VGATEXT) +#ifdef FBCON_HAS_VGATEXT + case 0: +#endif +#ifdef FBCON_HAS_CFB4 + case 4: +#endif +#ifdef FBCON_HAS_CFB8 + case 8: +#endif + mga_outb(M_DAC_REG, regno); + mga_outb(M_DAC_VAL, red); + mga_outb(M_DAC_VAL, green); + mga_outb(M_DAC_VAL, blue); + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + ACCESS_FBINFO(cmap.cfb16[regno]) = + (red << p->var.red.offset) | + (green << p->var.green.offset) | + (blue << p->var.blue.offset) | + (transp << p->var.transp.offset); /* for 1:5:5:5 */ + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + ACCESS_FBINFO(cmap.cfb24[regno]) = + (red << p->var.red.offset) | + (green << p->var.green.offset) | + (blue << p->var.blue.offset); + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + ACCESS_FBINFO(cmap.cfb32[regno]) = + (red << p->var.red.offset) | + (green << p->var.green.offset) | + (blue << p->var.blue.offset) | + (transp << p->var.transp.offset); /* 8:8:8:8 */ + break; +#endif + } + return 0; +} + +static void do_install_cmap(WPMINFO struct display* dsp) +{ + DBG("do_install_cmap") + + if (dsp->cmap.len) + fb_set_cmap(&dsp->cmap, 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon)); + else + fb_set_cmap(fb_default_cmap(ACCESS_FBINFO(curr.cmap_len)), + 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon)); +} + +static int matroxfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct display* p; + DBG("matroxfb_get_fix") + +#define minfo ((struct matrox_fb_info*)info) + + if (ACCESS_FBINFO(dead)) { + return -ENXIO; + } + + if (con >= 0) + p = fb_display + con; + else + p = ACCESS_FBINFO(fbcon.disp); + + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id,"MATROX"); + + fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); + fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes); + fix->type = p->type; + fix->type_aux = p->type_aux; + fix->visual = p->visual; + fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */ + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->line_length = p->line_length; + fix->mmio_start = ACCESS_FBINFO(mmio.base); + fix->mmio_len = ACCESS_FBINFO(mmio.len); + fix->accel = ACCESS_FBINFO(devflags.accelerator); + return 0; +#undef minfo +} + +static int matroxfb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ +#define minfo ((struct matrox_fb_info*)info) + DBG("matroxfb_get_var") + + if(con < 0) + *var=ACCESS_FBINFO(fbcon.disp)->var; + else + *var=fb_display[con].var; + return 0; +#undef minfo +} + +static int matroxfb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ +#define minfo ((struct matrox_fb_info*)info) + int err; + int visual; + int cmap_len; + unsigned int ydstorg; + struct display* display; + int chgvar; + + DBG("matroxfb_set_var") + + if (ACCESS_FBINFO(dead)) { + return -ENXIO; + } + + if (con >= 0) + display = fb_display + con; + else + display = ACCESS_FBINFO(fbcon.disp); + if ((err = matroxfb_decode_var(PMINFO display, var, &visual, &cmap_len, &ydstorg)) != 0) + return err; + switch (var->activate & FB_ACTIVATE_MASK) { + case FB_ACTIVATE_TEST: return 0; + case FB_ACTIVATE_NXTOPEN: /* ?? */ + case FB_ACTIVATE_NOW: break; /* continue */ + default: return -EINVAL; /* unknown */ + } + if (con >= 0) { + chgvar = ((display->var.xres != var->xres) || + (display->var.yres != var->yres) || + (display->var.xres_virtual != var->xres_virtual) || + (display->var.yres_virtual != var->yres_virtual) || + (display->var.bits_per_pixel != var->bits_per_pixel) || + memcmp(&display->var.red, &var->red, sizeof(var->red)) || + memcmp(&display->var.green, &var->green, sizeof(var->green)) || + memcmp(&display->var.blue, &var->blue, sizeof(var->blue))); + } else { + chgvar = 0; + } + display->var = *var; + /* cmap */ + display->screen_base = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg; + display->visual = visual; + display->ypanstep = 1; + display->ywrapstep = 0; + if (var->bits_per_pixel) { + display->type = FB_TYPE_PACKED_PIXELS; + display->type_aux = 0; + display->next_line = display->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; + } else { + display->type = FB_TYPE_TEXT; + display->type_aux = ACCESS_FBINFO(devflags.text_type_aux); + display->next_line = display->line_length = (var->xres_virtual / (fontwidth(display)?fontwidth(display):8)) * ACCESS_FBINFO(devflags.textstep); + } + display->can_soft_blank = 1; + display->inverse = ACCESS_FBINFO(devflags.inverse); + /* conp, fb_info, vrows, cursor_x, cursor_y, fgcol, bgcol */ + /* next_plane, fontdata, _font*, userfont */ + initMatrox(PMINFO display); /* dispsw */ + /* dispsw, scrollmode, yscroll */ + /* fgshift, bgshift, charmask */ + if (chgvar && info && info->changevar) + info->changevar(con); + if (con == ACCESS_FBINFO(currcon)) { + unsigned int pos; + + ACCESS_FBINFO(curr.cmap_len) = cmap_len; + if (display->type == FB_TYPE_TEXT) { + /* textmode must be in first megabyte, so no ydstorg allowed */ + ACCESS_FBINFO(curr.ydstorg.bytes) = 0; + ACCESS_FBINFO(curr.ydstorg.chunks) = 0; + ACCESS_FBINFO(curr.ydstorg.pixels) = 0; + } else { + ydstorg += ACCESS_FBINFO(devflags.ydstorg); + ACCESS_FBINFO(curr.ydstorg.bytes) = ydstorg; + ACCESS_FBINFO(curr.ydstorg.chunks) = ydstorg >> (isInterleave(MINFO)?3:2); + if (var->bits_per_pixel == 4) + ACCESS_FBINFO(curr.ydstorg.pixels) = ydstorg; + else + ACCESS_FBINFO(curr.ydstorg.pixels) = (ydstorg * 8) / var->bits_per_pixel; + } + ACCESS_FBINFO(curr.final_bppShift) = matroxfb_get_final_bppShift(PMINFO var->bits_per_pixel); + if (visual == MX_VISUAL_PSEUDOCOLOR) { + int i; + + for (i = 0; i < 16; i++) { + int j; + + j = color_table[i]; + ACCESS_FBINFO(palette[i].red) = default_red[j]; + ACCESS_FBINFO(palette[i].green) = default_grn[j]; + ACCESS_FBINFO(palette[i].blue) = default_blu[j]; + } + } + + { struct my_timming mt; + struct matrox_hw_state* hw; + struct matrox_hw_state* ohw; + + matroxfb_var2my(var, &mt); + /* CRTC1 delays */ + switch (var->bits_per_pixel) { + case 0: mt.delay = 31 + 0; break; + case 16: mt.delay = 21 + 8; break; + case 24: mt.delay = 17 + 8; break; + case 32: mt.delay = 16 + 8; break; + default: mt.delay = 31 + 8; break; + } + + hw = ACCESS_FBINFO(newhw); + ohw = ACCESS_FBINFO(currenthw); + + /* copy last setting... */ + memcpy(hw, ohw, sizeof(*hw)); + + del_timer(&ACCESS_FBINFO(cursor.timer)); + ACCESS_FBINFO(cursor.state) = CM_ERASE; + + ACCESS_FBINFO(hw_switch->init(PMINFO hw, &mt, display)); + if (display->type == FB_TYPE_TEXT) { + if (fontheight(display)) + pos = var->yoffset / fontheight(display) * display->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(display)?fontwidth(display):8); + else + pos = 0; + } else { + pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32; + pos += ACCESS_FBINFO(curr.ydstorg.chunks); + } + + hw->CRTC[0x0D] = pos & 0xFF; + hw->CRTC[0x0C] = (pos & 0xFF00) >> 8; + hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); + hw->CRTCEXT[8] = pos >> 21; + if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_PRIMARY) { + if (ACCESS_FBINFO(primout)) + ACCESS_FBINFO(primout)->compute(MINFO, &mt, hw); + } + if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) { + down_read(&ACCESS_FBINFO(altout.lock)); + if (ACCESS_FBINFO(altout.output)) + ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt, hw); + up_read(&ACCESS_FBINFO(altout.lock)); + } + ACCESS_FBINFO(hw_switch->restore(PMINFO hw, ohw, display)); + if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_PRIMARY) { + if (ACCESS_FBINFO(primout)) + ACCESS_FBINFO(primout)->program(MINFO, hw); + } + if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) { + down_read(&ACCESS_FBINFO(altout.lock)); + if (ACCESS_FBINFO(altout.output)) + ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device), hw); + up_read(&ACCESS_FBINFO(altout.lock)); + } + ACCESS_FBINFO(cursor.redraw) = 1; + ACCESS_FBINFO(currenthw) = hw; + ACCESS_FBINFO(newhw) = ohw; + if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_PRIMARY) { + if (ACCESS_FBINFO(primout)) + ACCESS_FBINFO(primout)->start(MINFO); + } + if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) { + down_read(&ACCESS_FBINFO(altout.lock)); + if (ACCESS_FBINFO(altout.output)) + ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device)); + up_read(&ACCESS_FBINFO(altout.lock)); + } + matrox_cfbX_init(PMINFO display); + do_install_cmap(PMINFO display); +#if defined(CONFIG_FB_OF) && defined(CONFIG_FB_COMPAT_XPMAC) + if (console_fb_info == &ACCESS_FBINFO(fbcon)) { + int vmode, cmode; + + display_info.width = var->xres; + display_info.height = var->yres; + display_info.depth = var->bits_per_pixel; + display_info.pitch = (var->xres_virtual)*(var->bits_per_pixel)/8; + if (mac_var_to_vmode(var, &vmode, &cmode)) + display_info.mode = 0; + else + display_info.mode = vmode; + strcpy(display_info.name, ACCESS_FBINFO(matrox_name)); + display_info.fb_address = ACCESS_FBINFO(video.base); + display_info.cmap_adr_address = 0; + display_info.cmap_data_address = 0; + display_info.disp_reg_address = ACCESS_FBINFO(mmio.base); + } +#endif /* CONFIG_FB_OF && CONFIG_FB_COMPAT_XPMAC */ + } + } + return 0; +#undef minfo +} + +static int matrox_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *info) +{ + + DBG("matrox_getcolreg") + +#define minfo ((struct matrox_fb_info*)info) + /* + * Read a single color register and split it into colors/transparent. + * Return != 0 for invalid regno. + */ + + if (regno >= ACCESS_FBINFO(curr.cmap_len)) + return 1; + + *red = ACCESS_FBINFO(palette[regno].red); + *green = ACCESS_FBINFO(palette[regno].green); + *blue = ACCESS_FBINFO(palette[regno].blue); + *transp = ACCESS_FBINFO(palette[regno].transp); + return 0; +#undef minfo +} + +static int matroxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ +#define minfo ((struct matrox_fb_info*)info) + struct display* dsp = (con < 0) ? ACCESS_FBINFO(fbcon.disp) + : fb_display + con; + + DBG("matroxfb_get_cmap") + + if (ACCESS_FBINFO(dead)) { + return -ENXIO; + } + + if (con == ACCESS_FBINFO(currcon)) /* current console? */ + return fb_get_cmap(cmap, kspc, matrox_getcolreg, info); + else if (dsp->cmap.len) /* non default colormap? */ + fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2); + else + fb_copy_cmap(fb_default_cmap(matroxfb_get_cmap_len(&dsp->var)), + cmap, kspc ? 0 : 2); + return 0; +#undef minfo +} + +static int matroxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + unsigned int cmap_len; + struct display* dsp = (con < 0) ? info->disp : (fb_display + con); +#define minfo ((struct matrox_fb_info*)info) + + DBG("matroxfb_set_cmap") + + if (ACCESS_FBINFO(dead)) { + return -ENXIO; + } + + cmap_len = matroxfb_get_cmap_len(&dsp->var); + if (dsp->cmap.len != cmap_len) { + int err; + + err = fb_alloc_cmap(&dsp->cmap, cmap_len, 0); + if (err) + return err; + } + if (con == ACCESS_FBINFO(currcon)) { /* current console? */ + return fb_set_cmap(cmap, kspc, matrox_setcolreg, info); + } else + fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1); + return 0; +#undef minfo +} + +static int matroxfb_switch(int con, struct fb_info *info); + +static int matroxfb_get_vblank(CPMINFO struct fb_vblank *vblank) +{ + unsigned int sts1; + + memset(vblank, 0, sizeof(*vblank)); + vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC | + FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_HBLANK; + sts1 = mga_inb(M_INSTS1); + vblank->vcount = mga_inl(M_VCOUNT); + /* BTW, on my PIII/450 with G400, reading M_INSTS1 + byte makes this call about 12% slower (1.70 vs. 2.05 us + per ioctl()) */ + if (sts1 & 1) + vblank->flags |= FB_VBLANK_HBLANKING; + if (sts1 & 8) + vblank->flags |= FB_VBLANK_VSYNCING; + if (vblank->count >= ACCESS_FBINFO(currcon_display)->var.yres) + vblank->flags |= FB_VBLANK_VBLANKING; + vblank->hcount = 0; + vblank->count = 0; + return 0; +} + +static int matroxfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info) +{ +#define minfo ((struct matrox_fb_info*)info) + DBG("matroxfb_ioctl") + + if (ACCESS_FBINFO(dead)) { + return -ENXIO; + } + + switch (cmd) { + case FBIOGET_VBLANK: + { + struct fb_vblank vblank; + int err; + + err = matroxfb_get_vblank(PMINFO &vblank); + if (err) + return err; + copy_to_user_ret((struct fb_vblank*)arg, &vblank, sizeof(vblank), -EFAULT); + return 0; + } + case MATROXFB_SET_OUTPUT_MODE: + { + struct matroxioc_output_mode mom; + int val; + + copy_from_user_ret(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom), -EFAULT); + if (mom.output >= sizeof(u_int32_t)) + return -EINVAL; + switch (mom.output) { + case MATROXFB_OUTPUT_PRIMARY: + if (mom.mode != MATROXFB_OUTPUT_MODE_MONITOR) + return -EINVAL; + /* mode did not change... */ + return 0; + case MATROXFB_OUTPUT_SECONDARY: + val = -EINVAL; + down_read(&ACCESS_FBINFO(altout.lock)); + if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.device)) + val = ACCESS_FBINFO(altout.output)->setmode(ACCESS_FBINFO(altout.device), mom.mode); + up_read(&ACCESS_FBINFO(altout.lock)); + if (val != 1) + return val; + if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) + matroxfb_switch(ACCESS_FBINFO(currcon), info); + if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { + struct matroxfb_dh_fb_info* crtc2; + + down_read(&ACCESS_FBINFO(crtc2.lock)); + crtc2 = (struct matroxfb_dh_fb_info*)(ACCESS_FBINFO(crtc2.info)); + if (crtc2) + crtc2->fbcon.switch_con(crtc2->currcon, &crtc2->fbcon); + up_read(&ACCESS_FBINFO(crtc2.lock)); + } + return 0; + default: + return -EINVAL; + } + return 0; + } + case MATROXFB_GET_OUTPUT_MODE: + { + struct matroxioc_output_mode mom; + int val; + + copy_from_user_ret(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom), -EFAULT); + if (mom.output >= sizeof(u_int32_t)) + return -EINVAL; + switch (mom.output) { + case MATROXFB_OUTPUT_PRIMARY: + mom.mode = MATROXFB_OUTPUT_MODE_MONITOR; + break; + case MATROXFB_OUTPUT_SECONDARY: + val = -EINVAL; + down_read(&ACCESS_FBINFO(altout.lock)); + if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.device)) + val = ACCESS_FBINFO(altout.output)->getmode(ACCESS_FBINFO(altout.device), &mom.mode); + up_read(&ACCESS_FBINFO(altout.lock)); + if (val) + return val; + break; + default: + return -EINVAL; + } + copy_to_user_ret((struct matroxioc_output_mode*)arg, &mom, sizeof(mom), -EFAULT); + return 0; + } + case MATROXFB_SET_OUTPUT_CONNECTION: + { + u_int32_t tmp; + + copy_from_user_ret(&tmp, (u_int32_t*)arg, sizeof(tmp), -EFAULT); + if (tmp & ~ACCESS_FBINFO(output.all)) + return -EINVAL; + if (tmp & ACCESS_FBINFO(output.sh)) + return -EINVAL; + if (tmp == ACCESS_FBINFO(output.ph)) + return 0; + ACCESS_FBINFO(output.ph) = tmp; + matroxfb_switch(ACCESS_FBINFO(currcon), info); + return 0; + } + case MATROXFB_GET_OUTPUT_CONNECTION: + { + put_user_ret(ACCESS_FBINFO(output.ph), (u_int32_t*)arg, -EFAULT); + return 0; + } + case MATROXFB_GET_AVAILABLE_OUTPUTS: + { + u_int32_t tmp; + + tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.sh); + put_user_ret(tmp, (u_int32_t*)arg, -EFAULT); + return 0; + } + case MATROXFB_GET_ALL_OUTPUTS: + { + put_user_ret(ACCESS_FBINFO(output.all), (u_int32_t*)arg, -EFAULT); + return 0; + } + } + return -EINVAL; +#undef minfo +} + +static struct fb_ops matroxfb_ops = { + matroxfb_open, + matroxfb_release, + matroxfb_get_fix, + matroxfb_get_var, + matroxfb_set_var, + matroxfb_get_cmap, + matroxfb_set_cmap, + matroxfb_pan_display, + matroxfb_ioctl, + NULL, /* mmap */ + NULL, /* rasterimg */ +}; + +static int matroxfb_switch(int con, struct fb_info *info) +{ +#define minfo ((struct matrox_fb_info*)info) + struct fb_cmap* cmap; + struct display *p; + + DBG("matroxfb_switch"); + + if (ACCESS_FBINFO(currcon) >= 0) { + /* Do we have to save the colormap? */ + cmap = &(ACCESS_FBINFO(currcon_display)->cmap); + dprintk(KERN_DEBUG "switch1: con = %d, cmap.len = %d\n", ACCESS_FBINFO(currcon), cmap->len); + + if (cmap->len) { + dprintk(KERN_DEBUG "switch1a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp); + fb_get_cmap(cmap, 1, matrox_getcolreg, info); +#ifdef DEBUG + if (cmap->red) { + dprintk(KERN_DEBUG "switch1r: %X\n", cmap->red[0]); + } +#endif + } + } + ACCESS_FBINFO(currcon) = con; + if (con < 0) + p = ACCESS_FBINFO(fbcon.disp); + else + p = fb_display + con; + ACCESS_FBINFO(currcon_display) = p; + p->var.activate = FB_ACTIVATE_NOW; +#ifdef DEBUG + cmap = &p->cmap; + dprintk(KERN_DEBUG "switch2: con = %d, cmap.len = %d\n", con, cmap->len); + dprintk(KERN_DEBUG "switch2a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp); + if (p->cmap.red) { + dprintk(KERN_DEBUG "switch2r: %X\n", cmap->red[0]); + } +#endif + matroxfb_set_var(&p->var, con, info); +#ifdef DEBUG + dprintk(KERN_DEBUG "switch3: con = %d, cmap.len = %d\n", con, cmap->len); + dprintk(KERN_DEBUG "switch3a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp); + if (p->cmap.red) { + dprintk(KERN_DEBUG "switch3r: %X\n", cmap->red[0]); + } +#endif + return 0; +#undef minfo +} + +/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ + +static void matroxfb_blank(int blank, struct fb_info *info) +{ +#define minfo ((struct matrox_fb_info*)info) + int seq; + int crtc; + CRITFLAGS + + DBG("matroxfb_blank") + + if (ACCESS_FBINFO(dead)) + return; + + switch (blank) { + case 1: seq = 0x20; crtc = 0x00; break; /* works ??? */ + case 2: seq = 0x20; crtc = 0x10; break; + case 3: seq = 0x20; crtc = 0x20; break; + case 4: seq = 0x20; crtc = 0x30; break; + default: seq = 0x00; crtc = 0x00; break; + } + + CRITBEGIN + + mga_outb(M_SEQ_INDEX, 1); + mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq); + mga_outb(M_EXTVGA_INDEX, 1); + mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc); + + CRITEND + +#undef minfo +} + +#define RSDepth(X) (((X) >> 8) & 0x0F) +#define RS8bpp 0x1 +#define RS15bpp 0x2 +#define RS16bpp 0x3 +#define RS32bpp 0x4 +#define RS4bpp 0x5 +#define RS24bpp 0x6 +#define RSText 0x7 +#define RSText8 0x8 +/* 9-F */ +static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] = { + { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 8 }, + { { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 }, + { { 11, 5, 0}, { 5, 6, 0}, { 0, 5, 0}, { 0, 0, 0}, 16 }, + { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 }, + { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 4 }, + { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 24 }, + { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode with (default) VGA8x16 */ + { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode hardwired to VGA8x8 */ +}; + +/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */ +static unsigned int mem = 0; /* "matrox:mem:xxxxxM" */ +static int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */ +static int inv24 = 0; /* "matrox:inv24" */ +static int cross4MB = -1; /* "matrox:cross4MB" */ +static int disabled = 0; /* "matrox:disabled" */ +static int noaccel = 0; /* "matrox:noaccel" */ +static int nopan = 0; /* "matrox:nopan" */ +static int no_pci_retry = 0; /* "matrox:nopciretry" */ +static int novga = 0; /* "matrox:novga" */ +static int nobios = 0; /* "matrox:nobios" */ +static int noinit = 1; /* "matrox:init" */ +static int inverse = 0; /* "matrox:inverse" */ +static int hwcursor = 1; /* "matrox:nohwcursor" */ +static int blink = 1; /* "matrox:noblink" */ +static int sgram = 0; /* "matrox:sgram" */ +#ifdef CONFIG_MTRR +static int mtrr = 1; /* "matrox:nomtrr" */ +#endif +static int grayscale = 0; /* "matrox:grayscale" */ +static unsigned int fastfont = 0; /* "matrox:fastfont:xxxxx" */ +static int dev = -1; /* "matrox:dev:xxxxx" */ +static unsigned int vesa = ~0; /* "matrox:vesa:xxxxx" */ +static int depth = -1; /* "matrox:depth:xxxxx" */ +static unsigned int xres = 0; /* "matrox:xres:xxxxx" */ +static unsigned int yres = 0; /* "matrox:yres:xxxxx" */ +static unsigned int upper = ~0; /* "matrox:upper:xxxxx" */ +static unsigned int lower = ~0; /* "matrox:lower:xxxxx" */ +static unsigned int vslen = 0; /* "matrox:vslen:xxxxx" */ +static unsigned int left = ~0; /* "matrox:left:xxxxx" */ +static unsigned int right = ~0; /* "matrox:right:xxxxx" */ +static unsigned int hslen = 0; /* "matrox:hslen:xxxxx" */ +static unsigned int pixclock = 0; /* "matrox:pixclock:xxxxx" */ +static int sync = -1; /* "matrox:sync:xxxxx" */ +static unsigned int fv = 0; /* "matrox:fv:xxxxx" */ +static unsigned int fh = 0; /* "matrox:fh:xxxxxk" */ +static unsigned int maxclk = 0; /* "matrox:maxclk:xxxxM" */ +static char fontname[64]; /* "matrox:font:xxxxx" */ + +#ifndef MODULE +static char videomode[64]; /* "matrox:mode:xxxxx" or "matrox:xxxxx" */ +#endif + +static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSize){ + vaddr_t vm; + unsigned int offs; + unsigned int offs2; + unsigned char store; + unsigned char bytes[32]; + unsigned char* tmp; + + DBG("matroxfb_getmemory") + + vm = ACCESS_FBINFO(video.vbase); + maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */ + /* at least 2MB */ + if (maxSize < 0x0200000) return 0; + if (maxSize > 0x2000000) maxSize = 0x2000000; + + mga_outb(M_EXTVGA_INDEX, 0x03); + mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80); + + store = mga_readb(vm, 0x1234); + tmp = bytes; + for (offs = 0x100000; offs < maxSize; offs += 0x200000) + *tmp++ = mga_readb(vm, offs); + for (offs = 0x100000; offs < maxSize; offs += 0x200000) + mga_writeb(vm, offs, 0x02); + if (ACCESS_FBINFO(features.accel.has_cacheflush)) + mga_outb(M_CACHEFLUSH, 0x00); + else + mga_writeb(vm, 0x1234, 0x99); + for (offs = 0x100000; offs < maxSize; offs += 0x200000) { + if (mga_readb(vm, offs) != 0x02) + break; + mga_writeb(vm, offs, mga_readb(vm, offs) - 0x02); + if (mga_readb(vm, offs)) + break; + } + tmp = bytes; + for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000) + mga_writeb(vm, offs2, *tmp++); + mga_writeb(vm, 0x1234, store); + + mga_outb(M_EXTVGA_INDEX, 0x03); + mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) & ~0x80); + + *realSize = offs - 0x100000; +#ifdef CONFIG_FB_MATROX_MILLENIUM + ACCESS_FBINFO(interleave) = !(!isMillenium(MINFO) || ((offs - 0x100000) & 0x3FFFFF)); +#endif + return 1; +} + +struct video_board { + int maxvram; + int maxdisplayable; + int accelID; + struct matrox_switch* lowlevel; + }; +#ifdef CONFIG_FB_MATROX_MILLENIUM +static struct video_board vbMillennium = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA2064W, &matrox_millennium}; +static struct video_board vbMillennium2 = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W, &matrox_millennium}; +static struct video_board vbMillennium2A = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W_AGP, &matrox_millennium}; +#endif /* CONFIG_FB_MATROX_MILLENIUM */ +#ifdef CONFIG_FB_MATROX_MYSTIQUE +static struct video_board vbMystique = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA1064SG, &matrox_mystique}; +#endif /* CONFIG_FB_MATROX_MYSTIQUE */ +#ifdef CONFIG_FB_MATROX_G100 +static struct video_board vbG100 = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGAG100, &matrox_G100}; +static struct video_board vbG200 = {0x1000000, 0x1000000, FB_ACCEL_MATROX_MGAG200, &matrox_G100}; +#ifdef CONFIG_FB_MATROX_32MB +/* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for + whole 32MB */ +static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100}; +#else +static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100}; +#endif +#endif + +#define DEVF_VIDEO64BIT 0x0001 +#define DEVF_SWAPS 0x0002 +#define DEVF_MILLENNIUM 0x0004 +#define DEVF_MILLENNIUM2 0x0008 +#define DEVF_CROSS4MB 0x0010 +#define DEVF_TEXT4B 0x0020 +#define DEVF_DDC_8_2 0x0040 +#define DEVF_DMA 0x0080 +#define DEVF_SUPPORT32MB 0x0100 +#define DEVF_ANY_VXRES 0x0200 +#define DEVF_TEXT16B 0x0400 +#define DEVF_CRTC2 0x0800 +#define DEVF_MAVEN_CAPABLE 0x1000 + +#define DEVF_GCORE (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2) +#define DEVF_G100 (DEVF_GCORE) /* no doc, no vxres... */ +#define DEVF_G200 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE) +#define DEVF_G400 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2) + +static struct board { + unsigned short vendor, device, rev, svid, sid; + unsigned int flags; + unsigned int maxclk; + struct video_board* base; + const char* name; + } dev_list[] = { +#ifdef CONFIG_FB_MATROX_MILLENIUM + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, 0xFF, + 0, 0, + DEVF_MILLENNIUM | DEVF_TEXT4B, + 230000, + &vbMillennium, + "Millennium (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, 0xFF, + 0, 0, + DEVF_MILLENNIUM | DEVF_MILLENNIUM2 | DEVF_SWAPS, + 220000, + &vbMillennium2, + "Millennium II (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, 0xFF, + 0, 0, + DEVF_MILLENNIUM | DEVF_MILLENNIUM2 | DEVF_SWAPS, + 250000, + &vbMillennium2A, + "Millennium II (AGP)"}, +#endif +#ifdef CONFIG_FB_MATROX_MYSTIQUE + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0x02, + 0, 0, + DEVF_VIDEO64BIT, + 180000, + &vbMystique, + "Mystique (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0xFF, + 0, 0, + DEVF_VIDEO64BIT | DEVF_SWAPS, + 220000, + &vbMystique, + "Mystique 220 (PCI)"}, +#endif +#ifdef CONFIG_FB_MATROX_G100 + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_PCI, + DEVF_G100, + 230000, + &vbG100, + "MGA-G100 (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF, + 0, 0, + DEVF_G100, + 230000, + &vbG100, + "unknown G100 (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC, + DEVF_G100, + 230000, + &vbG100, + "MGA-G100 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_AGP, + DEVF_G100, + 230000, + &vbG100, + "MGA-G100 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, + PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G100_AGP, + DEVF_G100, + 230000, + &vbG100, + "MGA-G100 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP, + DEVF_G100, + 230000, + &vbG100, + "Productiva G100 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, + 0, 0, + DEVF_G100, + 230000, + &vbG100, + "unknown G100 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 0xFF, + 0, 0, + DEVF_G200, + 250000, + &vbG200, + "unknown G200 (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC, + DEVF_G200, + 220000, + &vbG200, + "MGA-G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP, + DEVF_G200, + 230000, + &vbG200, + "Mystique G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENIUM_G200_AGP, + DEVF_G200, + 250000, + &vbG200, + "Millennium G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MARVEL_G200_AGP, + DEVF_G200, + 230000, + &vbG200, + "Marvel G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G200_AGP, + DEVF_G200, + 230000, + &vbG200, + "MGA-G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + 0, 0, + DEVF_G200, + 230000, + &vbG200, + "unknown G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP, + DEVF_G400, + 360000, + &vbG400, + "Millennium G400 MAX (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0xFF, + 0, 0, + DEVF_G400, + 300000, + &vbG400, + "unknown G400 (AGP)"}, +#endif + {0, 0, 0xFF, + 0, 0, + 0, + 0, + NULL, + NULL}}; + +#ifndef MODULE +static struct fb_videomode defaultmode = { + /* 640x480 @ 60Hz, 31.5 kHz */ + NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, + 0, FB_VMODE_NONINTERLACED +}; +#endif /* !MODULE */ + +static int hotplug = 0; + +static int initMatrox2(WPMINFO struct display* d, struct board* b){ + unsigned long ctrlptr_phys = 0; + unsigned long video_base_phys = 0; + unsigned int memsize; + struct matrox_hw_state* hw = ACCESS_FBINFO(currenthw); + int err; + + DBG("initMatrox2") + + /* set default values... */ + vesafb_defined.accel_flags = FB_ACCELF_TEXT; + + ACCESS_FBINFO(hw_switch) = b->base->lowlevel; + ACCESS_FBINFO(devflags.accelerator) = b->base->accelID; + ACCESS_FBINFO(max_pixel_clock) = b->maxclk; + + printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name); + ACCESS_FBINFO(capable.plnwt) = 1; + ACCESS_FBINFO(devflags.video64bits) = b->flags & DEVF_VIDEO64BIT; + if (b->flags & DEVF_TEXT4B) { + ACCESS_FBINFO(devflags.vgastep) = 4; + ACCESS_FBINFO(devflags.textmode) = 4; + ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16; + } else if (b->flags & DEVF_TEXT16B) { + ACCESS_FBINFO(devflags.vgastep) = 16; + ACCESS_FBINFO(devflags.textmode) = 1; + ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16; + } else { + ACCESS_FBINFO(devflags.vgastep) = 8; + ACCESS_FBINFO(devflags.textmode) = 1; + ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8; + } +#ifdef CONFIG_FB_MATROX_32MB + ACCESS_FBINFO(devflags.support32MB) = b->flags & DEVF_SUPPORT32MB; +#endif + ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES); + ACCESS_FBINFO(devflags.crtc2) = b->flags & DEVF_CRTC2; + ACCESS_FBINFO(devflags.maven_capable) = b->flags & DEVF_MAVEN_CAPABLE; + ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode); + ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode); + + if (ACCESS_FBINFO(capable.cross4MB) < 0) + ACCESS_FBINFO(capable.cross4MB) = b->flags & DEVF_CROSS4MB; + if (b->flags & DEVF_SWAPS) { + ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[1].start; + video_base_phys = ACCESS_FBINFO(pcidev)->resource[0].start; + } else { + ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[0].start; + video_base_phys = ACCESS_FBINFO(pcidev)->resource[1].start; + } + err = -EINVAL; + if (!ctrlptr_phys) { + printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n"); + goto fail; + } + if (!video_base_phys) { + printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n"); + goto fail; + } + memsize = b->base->maxvram; + if (!request_mem_region(ctrlptr_phys, 16384, "matroxfb MMIO")) { + goto fail; + } + if (!request_mem_region(video_base_phys, memsize, "matroxfb FB")) { + goto failCtrlMR; + } + ACCESS_FBINFO(video.len_maximum) = memsize; + /* convert mem (autodetect k, M) */ + if (mem < 1024) mem *= 1024; + if (mem < 0x00100000) mem *= 1024; + + if (mem && (mem < memsize)) + memsize = mem; + err = -ENOMEM; + if (mga_ioremap(ctrlptr_phys, 16384, MGA_IOREMAP_MMIO, &ACCESS_FBINFO(mmio.vbase))) { + printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys); + goto failVideoMR; + } + ACCESS_FBINFO(mmio.base) = ctrlptr_phys; + ACCESS_FBINFO(mmio.len) = 16384; + ACCESS_FBINFO(video.base) = video_base_phys; + if (mga_ioremap(video_base_phys, memsize, MGA_IOREMAP_FB, &ACCESS_FBINFO(video.vbase))) { + printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n", + video_base_phys, memsize); + goto failCtrlIO; + } + { + u_int32_t cmd; + u_int32_t mga_option; + + pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &mga_option); + pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd); + mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */ + mga_option |= MX_OPTION_BSWAP; + /* disable palette snooping */ + cmd &= ~PCI_COMMAND_VGA_PALETTE; + if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, NULL)) { + if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) { + printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n"); + } + mga_option |= 0x20000000; + ACCESS_FBINFO(devflags.nopciretry) = 1; + } + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, cmd); + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mga_option); + hw->MXoptionReg = mga_option; + + /* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */ + /* maybe preinit() candidate, but it is same... for all devices... at this time... */ + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MGA_INDEX, 0x00003C00); + } + + err = -ENXIO; + if (ACCESS_FBINFO(hw_switch)->preinit(PMINFO hw)) { + goto failVideoIO; + } + + err = -ENOMEM; + if (!matroxfb_getmemory(PMINFO memsize, &ACCESS_FBINFO(video.len)) || !ACCESS_FBINFO(video.len)) { + printk(KERN_ERR "matroxfb: cannot determine memory size\n"); + goto failVideoIO; + } + ACCESS_FBINFO(devflags.ydstorg) = 0; + + ACCESS_FBINFO(currcon) = -1; + ACCESS_FBINFO(currcon_display) = d; + mga_iounmap(ACCESS_FBINFO(video.vbase)); + ACCESS_FBINFO(video.base) = video_base_phys; + if (mga_ioremap(video_base_phys, ACCESS_FBINFO(video.len), MGA_IOREMAP_FB, &ACCESS_FBINFO(video.vbase))) { + printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n", + video_base_phys, ACCESS_FBINFO(video.len)); + goto failCtrlIO; + } + ACCESS_FBINFO(video.len_usable) = ACCESS_FBINFO(video.len); + if (ACCESS_FBINFO(video.len_usable) > b->base->maxdisplayable) + ACCESS_FBINFO(video.len_usable) = b->base->maxdisplayable; +#ifdef CONFIG_MTRR + if (mtrr) { + ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video.len), MTRR_TYPE_WRCOMB, 1); + ACCESS_FBINFO(mtrr.vram_valid) = 1; + printk(KERN_INFO "matroxfb: MTRR's turned on\n"); + } +#endif /* CONFIG_MTRR */ + + if (!ACCESS_FBINFO(devflags.novga)) + request_region(0x3C0, 32, "matrox"); + ACCESS_FBINFO(hw_switch->reset(PMINFO hw)); + + ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0; + ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh; + ACCESS_FBINFO(fbcon.monspecs.vfmin) = 0; + ACCESS_FBINFO(fbcon.monspecs.vfmax) = fv; + ACCESS_FBINFO(fbcon.monspecs.dpms) = 0; /* TBD */ + + /* static settings */ + if ((depth == RSText8) && (!*ACCESS_FBINFO(fbcon.fontname))) { + strcpy(ACCESS_FBINFO(fbcon.fontname), "VGA8x8"); + } + vesafb_defined.red = colors[depth-1].red; + vesafb_defined.green = colors[depth-1].green; + vesafb_defined.blue = colors[depth-1].blue; + vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel; + vesafb_defined.grayscale = grayscale; + vesafb_defined.vmode = 0; + if (noaccel) + vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT; + + strcpy(ACCESS_FBINFO(fbcon.modename), "MATROX VGA"); + ACCESS_FBINFO(fbcon.changevar) = NULL; + ACCESS_FBINFO(fbcon.node) = -1; + ACCESS_FBINFO(fbcon.fbops) = &matroxfb_ops; + ACCESS_FBINFO(fbcon.disp) = d; + ACCESS_FBINFO(fbcon.switch_con) = &matroxfb_switch; + ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar; + ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank; + /* after __init time we are like module... no logo */ + ACCESS_FBINFO(fbcon.flags) = hotplug ? FBINFO_FLAG_MODULE : FBINFO_FLAG_DEFAULT; + ACCESS_FBINFO(video.len_usable) &= PAGE_MASK; + +#ifndef MODULE + /* mode database is marked __init!!! */ + if (!hotplug) { + fb_find_mode(&vesafb_defined, &ACCESS_FBINFO(fbcon), videomode[0]?videomode:NULL, + NULL, 0, &defaultmode, vesafb_defined.bits_per_pixel); + } +#endif /* !MODULE */ + + /* mode modifiers */ + if (hslen) + vesafb_defined.hsync_len = hslen; + if (vslen) + vesafb_defined.vsync_len = vslen; + if (left != ~0) + vesafb_defined.left_margin = left; + if (right != ~0) + vesafb_defined.right_margin = right; + if (upper != ~0) + vesafb_defined.upper_margin = upper; + if (lower != ~0) + vesafb_defined.lower_margin = lower; + if (xres) + vesafb_defined.xres = xres; + if (yres) + vesafb_defined.yres = yres; + if (sync != -1) + vesafb_defined.sync = sync; + else if (vesafb_defined.sync == ~0) { + vesafb_defined.sync = 0; + if (yres < 400) + vesafb_defined.sync |= FB_SYNC_HOR_HIGH_ACT; + else if (yres < 480) + vesafb_defined.sync |= FB_SYNC_VERT_HIGH_ACT; + } + + /* fv, fh, maxclk limits was specified */ + { + unsigned int tmp; + + if (fv) { + tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres + + vesafb_defined.lower_margin + vesafb_defined.vsync_len); + if ((tmp < fh) || (fh == 0)) fh = tmp; + } + if (fh) { + tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres + + vesafb_defined.right_margin + vesafb_defined.hsync_len); + if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp; + } + maxclk = (maxclk + 499) / 500; + if (maxclk) { + tmp = (2000000000 + maxclk) / maxclk; + if (tmp > pixclock) pixclock = tmp; + } + } + if (pixclock) { + if (pixclock < 2000) /* > 500MHz */ + pixclock = 4000; /* 250MHz */ + if (pixclock > 1000000) + pixclock = 1000000; /* 1MHz */ + vesafb_defined.pixclock = pixclock; + } + + /* FIXME: Where to move this?! */ +#if defined(CONFIG_FB_OF) +#if defined(CONFIG_FB_COMPAT_XPMAC) + strcpy(ACCESS_FBINFO(matrox_name), "MTRX,"); /* OpenFirmware naming convension */ + strncat(ACCESS_FBINFO(matrox_name), b->name, 26); + if (!console_fb_info) + console_fb_info = &ACCESS_FBINFO(fbcon); +#endif + if ((xres <= 640) && (yres <= 480)) { + struct fb_var_screeninfo var; + if (default_vmode == VMODE_NVRAM) { + default_vmode = nvram_read_byte(NV_VMODE); + if (default_vmode <= 0 || default_vmode > VMODE_MAX) + default_vmode = VMODE_CHOOSE; + } + if (default_vmode <= 0 || default_vmode > VMODE_MAX) + default_vmode = VMODE_640_480_60; + if (default_cmode == CMODE_NVRAM) + default_cmode = nvram_read_byte(NV_CMODE); + if (default_cmode < CMODE_8 || default_cmode > CMODE_32) + default_cmode = CMODE_8; + if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) { + var.accel_flags = vesafb_defined.accel_flags; + var.xoffset = var.yoffset = 0; + vesafb_defined = var; /* Note: mac_vmode_to_var() doesnot set all parameters */ + } + } +#endif + vesafb_defined.xres_virtual = vesafb_defined.xres; + if (nopan) { + vesafb_defined.yres_virtual = vesafb_defined.yres; + } else { + vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough + to yres_virtual * xres_virtual < 2^32 */ + } + err = -EINVAL; + if (matroxfb_set_var(&vesafb_defined, -2, &ACCESS_FBINFO(fbcon))) { + printk(KERN_ERR "matroxfb: cannot set required parameters\n"); + goto failVideoIO; + } + + printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n", + vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, + vesafb_defined.xres_virtual, vesafb_defined.yres_virtual); + printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n", + ACCESS_FBINFO(video.base), vaddr_va(ACCESS_FBINFO(video.vbase)), ACCESS_FBINFO(video.len)); + +/* We do not have to set currcon to 0... register_framebuffer do it for us on first console + * and we do not want currcon == 0 for subsequent framebuffers */ + + if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0) { + goto failVideoIO; + } + printk("fb%d: %s frame buffer device\n", + GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), ACCESS_FBINFO(fbcon.modename)); + if (ACCESS_FBINFO(currcon) < 0) { + /* there is no console on this fb... but we have to initialize hardware + * until someone tells me what is proper thing to do */ + printk(KERN_INFO "fb%d: initializing hardware\n", + GET_FB_IDX(ACCESS_FBINFO(fbcon.node))); + matroxfb_set_var(&vesafb_defined, -1, &ACCESS_FBINFO(fbcon)); + } + return 0; +failVideoIO:; + mga_iounmap(ACCESS_FBINFO(video.vbase)); +failCtrlIO:; + mga_iounmap(ACCESS_FBINFO(mmio.vbase)); +failVideoMR:; + release_mem_region(video_base_phys, ACCESS_FBINFO(video.len_maximum)); +failCtrlMR:; + release_mem_region(ctrlptr_phys, 16384); +fail:; + return err; +} + +LIST_HEAD(matroxfb_list); +LIST_HEAD(matroxfb_driver_list); + +#define matroxfb_l(x) list_entry(x, struct matrox_fb_info, next_fb) +#define matroxfb_driver_l(x) list_entry(x, struct matroxfb_driver, node) +int matroxfb_register_driver(struct matroxfb_driver* drv) { + struct matrox_fb_info* minfo; + + list_add(&drv->node, &matroxfb_driver_list); + for (minfo = matroxfb_l(matroxfb_list.next); + minfo != matroxfb_l(&matroxfb_list); + minfo = matroxfb_l(minfo->next_fb.next)) { + void* p; + + if (minfo->drivers_count == MATROXFB_MAX_FB_DRIVERS) + continue; + p = drv->probe(minfo); + if (p) { + minfo->drivers_data[minfo->drivers_count] = p; + minfo->drivers[minfo->drivers_count++] = drv; + } + } + return 0; +} + +void matroxfb_unregister_driver(struct matroxfb_driver* drv) { + struct matrox_fb_info* minfo; + + list_del(&drv->node); + for (minfo = matroxfb_l(matroxfb_list.next); + minfo != matroxfb_l(&matroxfb_list); + minfo = matroxfb_l(minfo->next_fb.next)) { + int i; + + for (i = 0; i < minfo->drivers_count; ) { + if (minfo->drivers[i] == drv) { + if (drv && drv->remove) + drv->remove(minfo, minfo->drivers_data[i]); + minfo->drivers[i] = minfo->drivers[--minfo->drivers_count]; + minfo->drivers_data[i] = minfo->drivers_data[minfo->drivers_count]; + } else + i++; + } + } +} + +static void matroxfb_register_device(struct matrox_fb_info* minfo) { + struct matroxfb_driver* drv; + int i = 0; + list_add(&ACCESS_FBINFO(next_fb), &matroxfb_list); + for (drv = matroxfb_driver_l(matroxfb_driver_list.next); + drv != matroxfb_driver_l(&matroxfb_driver_list); + drv = matroxfb_driver_l(drv->node.next)) { + if (drv && drv->probe) { + void *p = drv->probe(minfo); + if (p) { + minfo->drivers_data[i] = p; + minfo->drivers[i++] = drv; + if (i == MATROXFB_MAX_FB_DRIVERS) + break; + } + } + } + minfo->drivers_count = i; +} + +static void matroxfb_unregister_device(struct matrox_fb_info* minfo) { + int i; + + list_del(&ACCESS_FBINFO(next_fb)); + for (i = 0; i < minfo->drivers_count; i++) { + struct matroxfb_driver* drv = minfo->drivers[i]; + + if (drv && drv->remove) + drv->remove(minfo, minfo->drivers_data[i]); + } +} + +static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dummy) { + struct board* b; + u_int8_t rev; + u_int16_t svid; + u_int16_t sid; + struct matrox_fb_info* minfo; + struct display* d; + int err; +#ifndef CONFIG_FB_MATROX_MULTIHEAD + static int registered = 0; +#endif + DBG("matroxfb_probe") + + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); + svid = pdev->subsystem_vendor; + sid = pdev->subsystem_device; + for (b = dev_list; b->vendor; b++) { + if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue; + if (b->svid) + if ((b->svid != svid) || (b->sid != sid)) continue; + break; + } + /* not match... */ + if (!b->vendor) + return -1; + if (dev > 0) { + /* not requested one... */ + dev--; + return -1; + } + if (pci_enable_device(pdev)) { + return -1; + } + +#ifdef CONFIG_FB_MATROX_MULTIHEAD + minfo = (struct matrox_fb_info*)kmalloc(sizeof(*minfo), GFP_KERNEL); + if (!minfo) + return -1; + d = (struct display*)kmalloc(sizeof(*d), GFP_KERNEL); + if (!d) { + kfree(minfo); + return -1; + } +#else + if (registered) /* singlehead driver... */ + return -1; + minfo = &matroxfb_global_mxinfo; + d = &global_disp; +#endif + memset(MINFO, 0, sizeof(*MINFO)); + memset(d, 0, sizeof(*d)); + + ACCESS_FBINFO(currenthw) = &ACCESS_FBINFO(hw1); + ACCESS_FBINFO(newhw) = &ACCESS_FBINFO(hw2); + ACCESS_FBINFO(pcidev) = pdev; + ACCESS_FBINFO(dead) = 0; + ACCESS_FBINFO(usecount) = 0; + pdev->driver_data = MINFO; + /* CMDLINE */ + memcpy(ACCESS_FBINFO(fbcon.fontname), fontname, sizeof(ACCESS_FBINFO(fbcon.fontname))); + /* DEVFLAGS */ + ACCESS_FBINFO(devflags.inverse) = inverse; + ACCESS_FBINFO(devflags.novga) = novga; + ACCESS_FBINFO(devflags.nobios) = nobios; + ACCESS_FBINFO(devflags.noinit) = noinit; + ACCESS_FBINFO(devflags.nopciretry) = no_pci_retry; + ACCESS_FBINFO(devflags.mga_24bpp_fix) = inv24; + ACCESS_FBINFO(devflags.precise_width) = option_precise_width; + ACCESS_FBINFO(devflags.hwcursor) = hwcursor; + ACCESS_FBINFO(devflags.blink) = blink; + ACCESS_FBINFO(devflags.sgram) = sgram; + ACCESS_FBINFO(capable.cross4MB) = cross4MB; + + ACCESS_FBINFO(fastfont.size) = fastfont; + + ACCESS_FBINFO(cursor.state) = CM_ERASE; + ACCESS_FBINFO(cursor.timer.prev) = ACCESS_FBINFO(cursor.timer.next) = NULL; + ACCESS_FBINFO(cursor.timer.data) = (unsigned long)MINFO; + spin_lock_init(&ACCESS_FBINFO(lock.DAC)); + spin_lock_init(&ACCESS_FBINFO(lock.accel)); + init_rwsem(&ACCESS_FBINFO(crtc2.lock)); + init_rwsem(&ACCESS_FBINFO(altout.lock)); + + ACCESS_FBINFO(output.all) = MATROXFB_OUTPUT_CONN_PRIMARY; + ACCESS_FBINFO(output.ph) = MATROXFB_OUTPUT_CONN_PRIMARY; + ACCESS_FBINFO(output.sh) = 0; + + /* subsequent heads always needs initialization and must not enable BIOS */ + noinit = 0; + nobios = 1; + novga = 1; + + err = initMatrox2(PMINFO d, b); + if (!err) { + matroxfb_register_device(MINFO); + return 0; + } +#ifdef CONFIG_FB_MATROX_MULTIHEAD + kfree(d); + kfree(minfo); +#endif + return -1; +} + +static void pci_remove_matrox(struct pci_dev* pdev) { + struct matrox_fb_info* minfo; + + minfo = pdev->driver_data; + matroxfb_remove(PMINFO 1); +} + +static struct pci_driver matroxfb_driver = { + name: "matroxfb", + probe: matroxfb_probe, + remove: pci_remove_matrox, +}; + +/* **************************** init-time only **************************** */ + +#define RSResolution(X) ((X) & 0x0F) +#define RS640x400 1 +#define RS640x480 2 +#define RS800x600 3 +#define RS1024x768 4 +#define RS1280x1024 5 +#define RS1600x1200 6 +#define RS768x576 7 +#define RS960x720 8 +#define RS1152x864 9 +#define RS1408x1056 10 +#define RS640x350 11 +#define RS1056x344 12 /* 132 x 43 text */ +#define RS1056x400 13 /* 132 x 50 text */ +#define RS1056x480 14 /* 132 x 60 text */ +#define RSNoxNo 15 +/* 10-FF */ +static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = { + { 640, 400, 48, 16, 39, 8, 96, 2, 70 }, + { 640, 480, 48, 16, 33, 10, 96, 2, 60 }, + { 800, 600, 144, 24, 28, 8, 112, 6, 60 }, + { 1024, 768, 160, 32, 30, 4, 128, 4, 60 }, + { 1280, 1024, 224, 32, 32, 4, 136, 4, 60 }, + { 1600, 1200, 272, 48, 32, 5, 152, 5, 60 }, + { 768, 576, 144, 16, 28, 6, 112, 4, 60 }, + { 960, 720, 144, 24, 28, 8, 112, 4, 60 }, + { 1152, 864, 192, 32, 30, 4, 128, 4, 60 }, + { 1408, 1056, 256, 40, 32, 5, 144, 5, 60 }, + { 640, 350, 48, 16, 39, 8, 96, 2, 70 }, + { 1056, 344, 96, 24, 59, 44, 160, 2, 70 }, + { 1056, 400, 96, 24, 39, 8, 160, 2, 70 }, + { 1056, 480, 96, 24, 36, 12, 160, 3, 60 }, + { 0, 0, ~0, ~0, ~0, ~0, 0, 0, 0 } +}; + +#define RSCreate(X,Y) ((X) | ((Y) << 8)) +static struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = { +/* default must be first */ +#ifdef FBCON_HAS_CFB8 + { ~0, RSCreate(RSNoxNo, RS8bpp ) }, + { 0x101, RSCreate(RS640x480, RS8bpp ) }, + { 0x100, RSCreate(RS640x400, RS8bpp ) }, + { 0x180, RSCreate(RS768x576, RS8bpp ) }, + { 0x103, RSCreate(RS800x600, RS8bpp ) }, + { 0x188, RSCreate(RS960x720, RS8bpp ) }, + { 0x105, RSCreate(RS1024x768, RS8bpp ) }, + { 0x190, RSCreate(RS1152x864, RS8bpp ) }, + { 0x107, RSCreate(RS1280x1024, RS8bpp ) }, + { 0x198, RSCreate(RS1408x1056, RS8bpp ) }, + { 0x11C, RSCreate(RS1600x1200, RS8bpp ) }, +#endif +#ifdef FBCON_HAS_CFB16 + { ~0, RSCreate(RSNoxNo, RS15bpp) }, + { 0x110, RSCreate(RS640x480, RS15bpp) }, + { 0x181, RSCreate(RS768x576, RS15bpp) }, + { 0x113, RSCreate(RS800x600, RS15bpp) }, + { 0x189, RSCreate(RS960x720, RS15bpp) }, + { 0x116, RSCreate(RS1024x768, RS15bpp) }, + { 0x191, RSCreate(RS1152x864, RS15bpp) }, + { 0x119, RSCreate(RS1280x1024, RS15bpp) }, + { 0x199, RSCreate(RS1408x1056, RS15bpp) }, + { 0x11D, RSCreate(RS1600x1200, RS15bpp) }, + { 0x111, RSCreate(RS640x480, RS16bpp) }, + { 0x182, RSCreate(RS768x576, RS16bpp) }, + { 0x114, RSCreate(RS800x600, RS16bpp) }, + { 0x18A, RSCreate(RS960x720, RS16bpp) }, + { 0x117, RSCreate(RS1024x768, RS16bpp) }, + { 0x192, RSCreate(RS1152x864, RS16bpp) }, + { 0x11A, RSCreate(RS1280x1024, RS16bpp) }, + { 0x19A, RSCreate(RS1408x1056, RS16bpp) }, + { 0x11E, RSCreate(RS1600x1200, RS16bpp) }, +#endif +#ifdef FBCON_HAS_CFB24 + { ~0, RSCreate(RSNoxNo, RS24bpp) }, + { 0x1B2, RSCreate(RS640x480, RS24bpp) }, + { 0x184, RSCreate(RS768x576, RS24bpp) }, + { 0x1B5, RSCreate(RS800x600, RS24bpp) }, + { 0x18C, RSCreate(RS960x720, RS24bpp) }, + { 0x1B8, RSCreate(RS1024x768, RS24bpp) }, + { 0x194, RSCreate(RS1152x864, RS24bpp) }, + { 0x1BB, RSCreate(RS1280x1024, RS24bpp) }, + { 0x19C, RSCreate(RS1408x1056, RS24bpp) }, + { 0x1BF, RSCreate(RS1600x1200, RS24bpp) }, +#endif +#ifdef FBCON_HAS_CFB32 + { ~0, RSCreate(RSNoxNo, RS32bpp) }, + { 0x112, RSCreate(RS640x480, RS32bpp) }, + { 0x183, RSCreate(RS768x576, RS32bpp) }, + { 0x115, RSCreate(RS800x600, RS32bpp) }, + { 0x18B, RSCreate(RS960x720, RS32bpp) }, + { 0x118, RSCreate(RS1024x768, RS32bpp) }, + { 0x193, RSCreate(RS1152x864, RS32bpp) }, + { 0x11B, RSCreate(RS1280x1024, RS32bpp) }, + { 0x19B, RSCreate(RS1408x1056, RS32bpp) }, + { 0x11F, RSCreate(RS1600x1200, RS32bpp) }, +#endif +#ifdef FBCON_HAS_VGATEXT + { ~0, RSCreate(RSNoxNo, RSText ) }, + { 0x002, RSCreate(RS640x400, RSText ) }, /* 80x25 */ + { 0x003, RSCreate(RS640x400, RSText ) }, /* 80x25 */ + { 0x007, RSCreate(RS640x400, RSText ) }, /* 80x25 */ + { 0x1C0, RSCreate(RS640x400, RSText8) }, /* 80x50 */ + { 0x108, RSCreate(RS640x480, RSText8) }, /* 80x60 */ + { 0x109, RSCreate(RS1056x400, RSText ) }, /* 132x25 */ + { 0x10A, RSCreate(RS1056x344, RSText8) }, /* 132x43 */ + { 0x10B, RSCreate(RS1056x400, RSText8) }, /* 132x50 */ + { 0x10C, RSCreate(RS1056x480, RSText8) }, /* 132x60 */ +#endif +#ifdef FBCON_HAS_CFB4 + { ~0, RSCreate(RSNoxNo, RS4bpp ) }, + { 0x010, RSCreate(RS640x350, RS4bpp ) }, + { 0x012, RSCreate(RS640x480, RS4bpp ) }, + { 0x102, RSCreate(RS800x600, RS4bpp ) }, + { 0x104, RSCreate(RS1024x768, RS4bpp ) }, + { 0x106, RSCreate(RS1280x1024, RS4bpp ) }, +#endif + { 0, 0 }}; + +static void __init matroxfb_init_params(void) { + /* fh from kHz to Hz */ + if (fh < 1000) + fh *= 1000; /* 1kHz minimum */ + /* maxclk */ + if (maxclk < 1000) maxclk *= 1000; /* kHz -> Hz, MHz -> kHz */ + if (maxclk < 1000000) maxclk *= 1000; /* kHz -> Hz, 1MHz minimum */ + /* fix VESA number */ + if (vesa != ~0) + vesa &= 0x1DFF; /* mask out clearscreen, acceleration and so on */ + + /* static settings */ + for (RSptr = vesamap; RSptr->vesa; RSptr++) { + if (RSptr->vesa == vesa) break; + } + if (!RSptr->vesa) { + printk(KERN_ERR "Invalid vesa mode 0x%04X\n", vesa); + RSptr = vesamap; + } + { + int res = RSResolution(RSptr->info)-1; + if (left == ~0) + left = timmings[res].left; + if (!xres) + xres = timmings[res].xres; + if (right == ~0) + right = timmings[res].right; + if (!hslen) + hslen = timmings[res].hslen; + if (upper == ~0) + upper = timmings[res].upper; + if (!yres) + yres = timmings[res].yres; + if (lower == ~0) + lower = timmings[res].lower; + if (!vslen) + vslen = timmings[res].vslen; + if (!(fv||fh||maxclk||pixclock)) + fv = timmings[res].vfreq; + if (depth == -1) + depth = RSDepth(RSptr->info); + } +} + +static void __init matrox_init(void) { + matroxfb_init_params(); + pci_register_driver(&matroxfb_driver); + dev = -1; /* accept all new devices... */ +} + +/* **************************** exit-time only **************************** */ + +static void __exit matrox_done(void) { + pci_unregister_driver(&matroxfb_driver); +} + +#ifndef MODULE + +/* ************************* init in-kernel code ************************** */ + +int __init matroxfb_setup(char *options) { + char *this_opt; + + DBG("matroxfb_setup") + + fontname[0] = '\0'; + + if (!options || !*options) + return 0; + + for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) { + if (!*this_opt) continue; + + dprintk("matroxfb_setup: option %s\n", this_opt); + + if (!strncmp(this_opt, "dev:", 4)) + dev = simple_strtoul(this_opt+4, NULL, 0); + else if (!strncmp(this_opt, "depth:", 6)) { + switch (simple_strtoul(this_opt+6, NULL, 0)) { + case 0: depth = RSText; break; + case 4: depth = RS4bpp; break; + case 8: depth = RS8bpp; break; + case 15:depth = RS15bpp; break; + case 16:depth = RS16bpp; break; + case 24:depth = RS24bpp; break; + case 32:depth = RS32bpp; break; + default: + printk(KERN_ERR "matroxfb: unsupported color depth\n"); + } + } else if (!strncmp(this_opt, "xres:", 5)) + xres = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "yres:", 5)) + yres = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "vslen:", 6)) + vslen = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "hslen:", 6)) + hslen = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "left:", 5)) + left = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "right:", 6)) + right = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "upper:", 6)) + upper = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "lower:", 6)) + lower = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "pixclock:", 9)) + pixclock = simple_strtoul(this_opt+9, NULL, 0); + else if (!strncmp(this_opt, "sync:", 5)) + sync = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "vesa:", 5)) + vesa = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "font:", 5)) + strncpy(fontname, this_opt+5, sizeof(fontname)-1); + else if (!strncmp(this_opt, "maxclk:", 7)) + maxclk = simple_strtoul(this_opt+7, NULL, 0); + else if (!strncmp(this_opt, "fh:", 3)) + fh = simple_strtoul(this_opt+3, NULL, 0); + else if (!strncmp(this_opt, "fv:", 3)) + fv = simple_strtoul(this_opt+3, NULL, 0); + else if (!strncmp(this_opt, "mem:", 4)) + mem = simple_strtoul(this_opt+4, NULL, 0); + else if (!strncmp(this_opt, "mode:", 5)) + strncpy(videomode, this_opt+5, sizeof(videomode)-1); +#ifdef CONFIG_FB_OF + else if (!strncmp(this_opt, "vmode:", 6)) { + unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX) + default_vmode = vmode; + } else if (!strncmp(this_opt, "cmode:", 6)) { + unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0); + switch (cmode) { + case 0: + case 8: + default_cmode = CMODE_8; + break; + case 15: + case 16: + default_cmode = CMODE_16; + break; + case 24: + case 32: + default_cmode = CMODE_32; + break; + } + } +#endif + else if (!strncmp(this_opt, "fastfont:", 9)) + fastfont = simple_strtoul(this_opt+9, NULL, 0); + else if (!strcmp(this_opt, "nofastfont")) /* fastfont:N and nofastfont (nofastfont = fastfont:0) */ + fastfont = 0; + else if (!strcmp(this_opt, "disabled")) /* nodisabled does not exist */ + disabled = 1; + else if (!strcmp(this_opt, "enabled")) /* noenabled does not exist */ + disabled = 0; + else if (!strcmp(this_opt, "sgram")) /* nosgram == sdram */ + sgram = 1; + else if (!strcmp(this_opt, "sdram")) + sgram = 0; + else { + int value = 1; + + if (!strncmp(this_opt, "no", 2)) { + value = 0; + this_opt += 2; + } + if (! strcmp(this_opt, "inverse")) + inverse = value; + else if (!strcmp(this_opt, "accel")) + noaccel = !value; + else if (!strcmp(this_opt, "pan")) + nopan = !value; + else if (!strcmp(this_opt, "pciretry")) + no_pci_retry = !value; + else if (!strcmp(this_opt, "vga")) + novga = !value; + else if (!strcmp(this_opt, "bios")) + nobios = !value; + else if (!strcmp(this_opt, "init")) + noinit = !value; +#ifdef CONFIG_MTRR + else if (!strcmp(this_opt, "mtrr")) + mtrr = value; +#endif + else if (!strcmp(this_opt, "inv24")) + inv24 = value; + else if (!strcmp(this_opt, "cross4MB")) + cross4MB = value; + else if (!strcmp(this_opt, "hwcursor")) + hwcursor = value; + else if (!strcmp(this_opt, "blink")) + blink = value; + else if (!strcmp(this_opt, "grayscale")) + grayscale = value; + else { + strncpy(videomode, this_opt, sizeof(videomode)-1); + } + } + } + return 0; +} + +static int __init initialized = 0; + +int __init matroxfb_init(void) +{ + DBG("matroxfb_init") + + if (disabled) + return -ENXIO; + if (!initialized) { + initialized = 1; + matrox_init(); + } + /* never return failure, user can hotplug matrox later... */ + return 0; +} + +#if defined(CONFIG_FB_OF) +int __init matrox_of_init(struct device_node *dp){ + DBG("matrox_of_init"); + + if (disabled) + return -ENXIO; + if (!initialized) { + initialized = 1; + matrox_init(); + } + /* failure? */ + return 0; +} +#endif /* CONFIG_FB_OF */ + +#else + +/* *************************** init module code **************************** */ + +MODULE_AUTHOR("(c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400"); +MODULE_PARM(mem, "i"); +MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)"); +MODULE_PARM(disabled, "i"); +MODULE_PARM_DESC(disabled, "Disabled (0 or 1=disabled) (default=0)"); +MODULE_PARM(noaccel, "i"); +MODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)"); +MODULE_PARM(nopan, "i"); +MODULE_PARM_DESC(nopan, "Disable pan on startup (0 or 1=disabled) (default=0)"); +MODULE_PARM(no_pci_retry, "i"); +MODULE_PARM_DESC(no_pci_retry, "PCI retries enabled (0 or 1=disabled) (default=0)"); +MODULE_PARM(novga, "i"); +MODULE_PARM_DESC(novga, "VGA I/O (0x3C0-0x3DF) disabled (0 or 1=disabled) (default=0)"); +MODULE_PARM(nobios, "i"); +MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)"); +MODULE_PARM(noinit, "i"); +MODULE_PARM_DESC(noinit, "Disables W/SG/SD-RAM and bus interface initialization (0 or 1=do not initialize) (default=0)"); +MODULE_PARM(mtrr, "i"); +MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)"); +MODULE_PARM(sgram, "i"); +MODULE_PARM_DESC(sgram, "Indicates that G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)"); +MODULE_PARM(inv24, "i"); +MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)"); +MODULE_PARM(inverse, "i"); +MODULE_PARM_DESC(inverse, "Inverse (0 or 1) (default=0)"); +#ifdef CONFIG_FB_MATROX_MULTIHEAD +MODULE_PARM(dev, "i"); +MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=all working)"); +#else +MODULE_PARM(dev, "i"); +MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=first working)"); +#endif +MODULE_PARM(vesa, "i"); +MODULE_PARM_DESC(vesa, "Startup videomode (0x000-0x1FF) (default=0x101)"); +MODULE_PARM(xres, "i"); +MODULE_PARM_DESC(xres, "Horizontal resolution (px), overrides xres from vesa (default=vesa)"); +MODULE_PARM(yres, "i"); +MODULE_PARM_DESC(yres, "Vertical resolution (scans), overrides yres from vesa (default=vesa)"); +MODULE_PARM(upper, "i"); +MODULE_PARM_DESC(upper, "Upper blank space (scans), overrides upper from vesa (default=vesa)"); +MODULE_PARM(lower, "i"); +MODULE_PARM_DESC(lower, "Lower blank space (scans), overrides lower from vesa (default=vesa)"); +MODULE_PARM(vslen, "i"); +MODULE_PARM_DESC(vslen, "Vertical sync length (scans), overrides lower from vesa (default=vesa)"); +MODULE_PARM(left, "i"); +MODULE_PARM_DESC(left, "Left blank space (px), overrides left from vesa (default=vesa)"); +MODULE_PARM(right, "i"); +MODULE_PARM_DESC(right, "Right blank space (px), overrides right from vesa (default=vesa)"); +MODULE_PARM(hslen, "i"); +MODULE_PARM_DESC(hslen, "Horizontal sync length (px), overrides hslen from vesa (default=vesa)"); +MODULE_PARM(pixclock, "i"); +MODULE_PARM_DESC(pixclock, "Pixelclock (ns), overrides pixclock from vesa (default=vesa)"); +MODULE_PARM(sync, "i"); +MODULE_PARM_DESC(sync, "Sync polarity, overrides sync from vesa (default=vesa)"); +MODULE_PARM(depth, "i"); +MODULE_PARM_DESC(depth, "Color depth (0=text,8,15,16,24,32) (default=vesa)"); +MODULE_PARM(maxclk, "i"); +MODULE_PARM_DESC(maxclk, "Startup maximal clock, 0-999MHz, 1000-999999kHz, 1000000-INF Hz"); +MODULE_PARM(fh, "i"); +MODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz"); +MODULE_PARM(fv, "i"); +MODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n" +"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\"\n"); +MODULE_PARM(hwcursor, "i"); +MODULE_PARM_DESC(hwcursor, "Enables hardware cursor (0 or 1) (default=0)"); +MODULE_PARM(blink, "i"); +MODULE_PARM_DESC(blink, "Enables hardware cursor blinking (0 or 1) (default=1)"); +MODULE_PARM(fastfont, "i"); +MODULE_PARM_DESC(fastfont, "Specifies, how much memory should be used for font data (0, 1024-65536 are reasonable) (default=0)"); +MODULE_PARM(grayscale, "i"); +MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)"); +MODULE_PARM(cross4MB, "i"); +MODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)"); +#ifdef CONFIG_FB_OF +MODULE_PARM(vmode, "i"); +MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)"); +MODULE_PARM(cmode, "i"); +MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)"); +#endif + +int __init init_module(void){ + + DBG("init_module") + + if (disabled) + return -ENXIO; + + if (depth == 0) + depth = RSText; + else if (depth == 4) + depth = RS4bpp; + else if (depth == 8) + depth = RS8bpp; + else if (depth == 15) + depth = RS15bpp; + else if (depth == 16) + depth = RS16bpp; + else if (depth == 24) + depth = RS24bpp; + else if (depth == 32) + depth = RS32bpp; + else if (depth != -1) { + printk(KERN_ERR "matroxfb: depth %d is not supported, using default\n", depth); + depth = -1; + } + matrox_init(); + /* never return failure; user can hotplug matrox later... */ + return 0; +} +#endif /* MODULE */ + +module_exit(matrox_done); +EXPORT_SYMBOL(matroxfb_register_driver); +EXPORT_SYMBOL(matroxfb_unregister_driver); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h new file mode 100644 index 000000000..0cb21b0f9 --- /dev/null +++ b/drivers/video/matrox/matroxfb_base.h @@ -0,0 +1,825 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 + * + * (c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz> + * + */ +#ifndef __MATROXFB_H__ +#define __MATROXFB_H__ + +/* general, but fairly heavy, debugging */ +#undef MATROXFB_DEBUG + +/* heavy debugging: */ +/* -- logs putc[s], so everytime a char is displayed, it's logged */ +#undef MATROXFB_DEBUG_HEAVY + +/* This one _could_ cause infinite loops */ +/* It _does_ cause lots and lots of messages during idle loops */ +#undef MATROXFB_DEBUG_LOOP + +/* Debug register calls, too? */ +#undef MATROXFB_DEBUG_REG + +/* Guard accelerator accesses with spin_lock_irqsave... */ +#undef MATROXFB_USE_SPINLOCKS + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/console.h> +#include <linux/selection.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/pci.h> +#include <linux/spinlock.h> + +#include <asm/io.h> +#include <asm/unaligned.h> +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include <video/fbcon.h> +#include <video/fbcon-cfb4.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> + +#if defined(CONFIG_FB_OF) +#if defined(CONFIG_FB_COMPAT_XPMAC) +#include <asm/vc_ioctl.h> +#endif +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#include <video/macmodes.h> +#endif + +/* always compile support for 32MB... It cost almost nothing */ +#define CONFIG_FB_MATROX_32MB + +#define FBCON_HAS_VGATEXT + +#ifdef MATROXFB_DEBUG + +#define DEBUG +#define DBG(x) printk(KERN_DEBUG "matroxfb: %s\n", (x)); + +#ifdef MATROXFB_DEBUG_HEAVY +#define DBG_HEAVY(x) DBG(x) +#else /* MATROXFB_DEBUG_HEAVY */ +#define DBG_HEAVY(x) /* DBG_HEAVY */ +#endif /* MATROXFB_DEBUG_HEAVY */ + +#ifdef MATROXFB_DEBUG_LOOP +#define DBG_LOOP(x) DBG(x) +#else /* MATROXFB_DEBUG_LOOP */ +#define DBG_LOOP(x) /* DBG_LOOP */ +#endif /* MATROXFB_DEBUG_LOOP */ + +#ifdef MATROXFB_DEBUG_REG +#define DBG_REG(x) DBG(x) +#else /* MATROXFB_DEBUG_REG */ +#define DBG_REG(x) /* DBG_REG */ +#endif /* MATROXFB_DEBUG_REG */ + +#else /* MATROXFB_DEBUG */ + +#define DBG(x) /* DBG */ +#define DBG_HEAVY(x) /* DBG_HEAVY */ +#define DBG_REG(x) /* DBG_REG */ +#define DBG_LOOP(x) /* DBG_LOOP */ + +#endif /* MATROXFB_DEBUG */ + +#ifndef __i386__ +#ifndef ioremap_nocache +#define ioremap_nocache(X,Y) ioremap(X,Y) +#endif +#endif + +#if defined(__alpha__) || defined(__m68k__) +#define READx_WORKS +#define MEMCPYTOIO_WORKS +#else +#define READx_FAILS +/* recheck __ppc__, maybe that __ppc__ needs MEMCPYTOIO_WRITEL */ +/* I benchmarked PII/350MHz with G200... MEMCPY, MEMCPYTOIO and WRITEL are on same speed ( <2% diff) */ +/* so that means that G200 speed (or AGP speed?) is our limit... I do not have benchmark to test, how */ +/* much of PCI bandwidth is used during transfers... */ +#if defined(__i386__) +#define MEMCPYTOIO_MEMCPY +#else +#define MEMCPYTOIO_WRITEL +#endif +#endif + +#ifdef __sparc__ +#error "Sorry, I have no idea how to do this on sparc... There is mapioaddr... With bus_type parameter..." +#endif + +#if defined(__m68k__) +#define MAP_BUSTOVIRT +#else +#define MAP_IOREMAP +#endif + +#ifdef DEBUG +#define dprintk(X...) printk(X) +#else +#define dprintk(X...) +#endif + +#ifndef PCI_SS_VENDOR_ID_SIEMENS_NIXDORF +#define PCI_SS_VENDOR_ID_SIEMENS_NIXDORF 0x110A +#endif +#ifndef PCI_SS_VENDOR_ID_MATROX +#define PCI_SS_VENDOR_ID_MATROX PCI_VENDOR_ID_MATROX +#endif +#ifndef PCI_DEVICE_ID_MATROX_G200_PCI +#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520 +#endif +#ifndef PCI_DEVICE_ID_MATROX_G200_AGP +#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521 +#endif +#ifndef PCI_DEVICE_ID_MATROX_G100 +#define PCI_DEVICE_ID_MATROX_G100 0x1000 +#endif +#ifndef PCI_DEVICE_ID_MATROX_G100_AGP +#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001 +#endif +#ifndef PCI_DEVICE_ID_MATROX_G400_AGP +#define PCI_DEVICE_ID_MATROX_G400_AGP 0x0525 +#endif + +#ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP +#define PCI_SS_ID_MATROX_GENERIC 0xFF00 +#define PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP 0xFF01 +#define PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP 0xFF02 +#define PCI_SS_ID_MATROX_MILLENIUM_G200_AGP 0xFF03 +#define PCI_SS_ID_MATROX_MARVEL_G200_AGP 0xFF04 +#define PCI_SS_ID_MATROX_MGA_G100_PCI 0xFF05 +#define PCI_SS_ID_MATROX_MGA_G100_AGP 0x1001 +#define PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP 0x2179 +#define PCI_SS_ID_SIEMENS_MGA_G100_AGP 0x001E /* 30 */ +#define PCI_SS_ID_SIEMENS_MGA_G200_AGP 0x0032 /* 50 */ +#endif + +#define MX_VISUAL_TRUECOLOR FB_VISUAL_DIRECTCOLOR +#define MX_VISUAL_DIRECTCOLOR FB_VISUAL_TRUECOLOR +#define MX_VISUAL_PSEUDOCOLOR FB_VISUAL_PSEUDOCOLOR + +#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) + +/* G100, G200 and Mystique have (almost) same DAC */ +#undef NEED_DAC1064 +#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G100) +#define NEED_DAC1064 1 +#endif + +typedef struct { + u_int8_t* vaddr; +} vaddr_t; + +#ifdef READx_WORKS +static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) { + return readb(va.vaddr + offs); +} + +static inline unsigned int mga_readw(vaddr_t va, unsigned int offs) { + return readw(va.vaddr + offs); +} + +static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) { + return readl(va.vaddr + offs); +} + +static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) { + writeb(value, va.vaddr + offs); +} + +static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) { + writew(value, va.vaddr + offs); +} + +static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) { + writel(value, va.vaddr + offs); +} +#else +static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) { + return *(volatile u_int8_t*)(va.vaddr + offs); +} + +static inline unsigned int mga_readw(vaddr_t va, unsigned int offs) { + return *(volatile u_int16_t*)(va.vaddr + offs); +} + +static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) { + return *(volatile u_int32_t*)(va.vaddr + offs); +} + +static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) { + *(volatile u_int8_t*)(va.vaddr + offs) = value; +} + +static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) { + *(volatile u_int16_t*)(va.vaddr + offs) = value; +} + +static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) { + *(volatile u_int32_t*)(va.vaddr + offs) = value; +} +#endif + +static inline void mga_memcpy_toio(vaddr_t va, unsigned int offs, const void* src, int len) { +#ifdef MEMCPYTOIO_WORKS + memcpy_toio(va.vaddr + offs, src, len); +#elif defined(MEMCPYTOIO_WRITEL) +#define srcd ((const u_int32_t*)src) + if (offs & 3) { + while (len >= 4) { + mga_writel(va, offs, get_unaligned(srcd++)); + offs += 4; + len -= 4; + } + } else { + while (len >= 4) { + mga_writel(va, offs, *srcd++); + offs += 4; + len -= 4; + } + } +#undef srcd + if (len) { + u_int32_t tmp; + + memcpy(&tmp, src, len); + mga_writel(va, offs, tmp); + } +#elif defined(MEMCPYTOIO_MEMCPY) + memcpy(va.vaddr + offs, src, len); +#else +#error "Sorry, do not know how to write block of data to device" +#endif +} + +static inline void vaddr_add(vaddr_t* va, unsigned long offs) { + va->vaddr += offs; +} + +static inline void* vaddr_va(vaddr_t va) { + return va.vaddr; +} + +#define MGA_IOREMAP_NORMAL 0 +#define MGA_IOREMAP_NOCACHE 1 + +#define MGA_IOREMAP_FB MGA_IOREMAP_NOCACHE +#define MGA_IOREMAP_MMIO MGA_IOREMAP_NOCACHE +static inline int mga_ioremap(unsigned long phys, unsigned long size, int flags, vaddr_t* virt) { +#ifdef MAP_IOREMAP + if (flags & MGA_IOREMAP_NOCACHE) + virt->vaddr = ioremap_nocache(phys, size); + else + virt->vaddr = ioremap(phys, size); +#else +#ifdef MAP_BUSTOVIRT + virt->vaddr = bus_to_virt(phys); +#else +#error "Your architecture does not have neither ioremap nor bus_to_virt... Giving up" +#endif +#endif + return (virt->vaddr == 0); /* 0, !0... 0, error_code in future */ +} + +static inline void mga_iounmap(vaddr_t va) { +#ifdef MAP_IOREMAP + iounmap(va.vaddr); +#endif +} + +struct my_timming { + unsigned int pixclock; + unsigned int HDisplay; + unsigned int HSyncStart; + unsigned int HSyncEnd; + unsigned int HTotal; + unsigned int VDisplay; + unsigned int VSyncStart; + unsigned int VSyncEnd; + unsigned int VTotal; + unsigned int sync; + int dblscan; + int interlaced; + unsigned int delay; /* CRTC delay */ +}; + +struct matrox_pll_features { + unsigned int vco_freq_min; + unsigned int ref_freq; + unsigned int feed_div_min; + unsigned int feed_div_max; + unsigned int in_div_min; + unsigned int in_div_max; + unsigned int post_shift_max; +}; + +struct matroxfb_par +{ + unsigned int final_bppShift; + unsigned int cmap_len; + struct { + unsigned int bytes; + unsigned int pixels; + unsigned int chunks; + } ydstorg; + void (*putc)(u_int32_t, u_int32_t, struct display*, int, int, int); + void (*putcs)(u_int32_t, u_int32_t, struct display*, const unsigned short*, int, int, int); +}; + +struct matrox_fb_info; + +struct matrox_DAC1064_features { + u_int8_t xvrefctrl; + u_int8_t xmiscctrl; + unsigned int cursorimage; +}; + +struct matrox_accel_features { + int has_cacheflush; +}; + +/* current hardware status */ +struct mavenregs { + u_int8_t regs[256]; + int mode; + int vlines; + int xtal; + int fv; + + u_int16_t htotal; + u_int16_t hcorr; +}; + +struct matrox_hw_state { + u_int32_t MXoptionReg; + unsigned char DACclk[6]; + unsigned char DACreg[64]; + unsigned char MiscOutReg; + unsigned char DACpal[768]; + unsigned char CRTC[25]; + unsigned char CRTCEXT[9]; + unsigned char SEQ[5]; + /* unused for MGA mode, but who knows... */ + unsigned char GCTL[9]; + /* unused for MGA mode, but who knows... */ + unsigned char ATTR[21]; + + /* TVOut only */ + struct mavenregs maven; + + /* CRTC2 only */ + /* u_int32_t TBD */ +}; + +struct matrox_accel_data { +#ifdef CONFIG_FB_MATROX_MILLENIUM + unsigned char ramdac_rev; +#endif + u_int32_t m_dwg_rect; + u_int32_t m_opmode; +}; + +struct matrox_altout { + int (*compute)(void* altout_dev, struct my_timming* input, struct matrox_hw_state* state); + int (*program)(void* altout_dev, const struct matrox_hw_state* state); + int (*start)(void* altout_dev); + void (*incuse)(void* altout_dev); + void (*decuse)(void* altout_dev); + int (*setmode)(void* altout_dev, u_int32_t mode); + int (*getmode)(void* altout_dev, u_int32_t* mode); +}; + +struct matrox_switch; +struct matroxfb_driver; + +struct matrox_fb_info { + /* fb_info must be first */ + struct fb_info fbcon; + + struct list_head next_fb; + + int dead; + unsigned int usecount; + + struct matroxfb_par curr; + struct matrox_hw_state hw1; + struct matrox_hw_state hw2; + struct matrox_hw_state* newhw; + struct matrox_hw_state* currenthw; + + struct matrox_accel_data accel; + + struct pci_dev* pcidev; + + struct { + u_int32_t all; + u_int32_t ph; + u_int32_t sh; + } output; + struct matrox_altout* primout; + struct { + struct fb_info* info; + struct rw_semaphore lock; + } crtc2; + struct { + struct matrox_altout* output; + void* device; + struct rw_semaphore lock; + } altout; + +#define MATROXFB_MAX_FB_DRIVERS 5 + struct matroxfb_driver* (drivers[MATROXFB_MAX_FB_DRIVERS]); + void* (drivers_data[MATROXFB_MAX_FB_DRIVERS]); + unsigned int drivers_count; + + struct { + unsigned long base; /* physical */ + vaddr_t vbase; /* CPU view */ + unsigned int len; + unsigned int len_usable; + unsigned int len_maximum; + } video; + + struct { + unsigned long base; /* physical */ + vaddr_t vbase; /* CPU view */ + unsigned int len; + } mmio; + + unsigned int max_pixel_clock; + + struct matrox_switch* hw_switch; + int currcon; + struct display* currcon_display; + + struct { + struct matrox_pll_features pll; + struct matrox_DAC1064_features DAC1064; + struct matrox_accel_features accel; + } features; + struct { + spinlock_t DAC; + spinlock_t accel; + } lock; + + int interleave; + int millenium; + int milleniumII; + struct { + int cfb4; + const int* vxres; + int cross4MB; + int text; + int plnwt; + } capable; + struct { + unsigned int size; + unsigned int mgabase; + vaddr_t vbase; + } fastfont; +#ifdef CONFIG_MTRR + struct { + int vram; + int vram_valid; + } mtrr; +#endif + struct { + int precise_width; + int mga_24bpp_fix; + int novga; + int nobios; + int nopciretry; + int noinit; + int inverse; + int hwcursor; + int blink; + int sgram; +#ifdef CONFIG_FB_MATROX_32MB + int support32MB; +#endif + + int accelerator; + int text_type_aux; + int video64bits; + int crtc2; + int maven_capable; + unsigned int vgastep; + unsigned int textmode; + unsigned int textstep; + unsigned int textvram; /* character cells */ + unsigned int ydstorg; /* offset in bytes from video start to usable memory */ + /* 0 except for 6MB Millenium */ + } devflags; + struct display_switch dispsw; + struct { + int x; + int y; + unsigned int w; + unsigned int u; + unsigned int d; + unsigned int type; + int state; + int redraw; + struct timer_list timer; + } cursor; + struct { unsigned red, green, blue, transp; } palette[256]; +#if defined(CONFIG_FB_OF) && defined(CONFIG_FB_COMPAT_XPMAC) + char matrox_name[32]; +#endif +/* These ifdefs must be last! They differ for module & non-module compiles */ +#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32) + union { +#ifdef FBCON_HAS_CFB16 + u_int16_t cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB24 + u_int32_t cfb24[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u_int32_t cfb32[16]; +#endif + } cmap; +#endif +}; + +#ifdef CONFIG_FB_MATROX_MULTIHEAD +#define ACCESS_FBINFO2(info, x) (info->x) +#define ACCESS_FBINFO(x) ACCESS_FBINFO2(minfo,x) + +#define MINFO minfo + +#define WPMINFO2 struct matrox_fb_info* minfo +#define WPMINFO WPMINFO2 , +#define CPMINFO2 const struct matrox_fb_info* minfo +#define CPMINFO CPMINFO2 , +#define PMINFO2 minfo +#define PMINFO PMINFO2 , + +static inline struct matrox_fb_info* mxinfo(const struct display* p) { + return (struct matrox_fb_info*)p->fb_info; +} + +#define PMXINFO(p) mxinfo(p), +#define MINFO_FROM(x) struct matrox_fb_info* minfo = x +#define MINFO_FROM_DISP(x) MINFO_FROM(mxinfo(x)) + +#else + +extern struct matrox_fb_info matroxfb_global_mxinfo; +struct display global_disp; + +#define ACCESS_FBINFO(x) (matroxfb_global_mxinfo.x) +#define ACCESS_FBINFO2(info, x) (matroxfb_global_mxinfo.x) + +#define MINFO (&matroxfb_global_mxinfo) + +#define WPMINFO2 void +#define WPMINFO +#define CPMINFO2 void +#define CPMINFO +#define PMINFO2 +#define PMINFO + +#if 0 +static inline struct matrox_fb_info* mxinfo(const struct display* p) { + return &matroxfb_global_mxinfo; +} +#endif + +#define PMXINFO(p) +#define MINFO_FROM(x) +#define MINFO_FROM_DISP(x) + +#endif + +struct matrox_switch { + int (*preinit)(WPMINFO struct matrox_hw_state*); + void (*reset)(WPMINFO struct matrox_hw_state*); + int (*init)(CPMINFO struct matrox_hw_state*, struct my_timming*, struct display*); + void (*restore)(WPMINFO struct matrox_hw_state*, struct matrox_hw_state*, struct display*); + int (*selhwcursor)(WPMINFO struct display*); +}; + +struct matroxfb_driver { + struct list_head node; + char* name; + void* (*probe)(struct matrox_fb_info* info); + void (*remove)(struct matrox_fb_info* info, void* data); +}; + +int matroxfb_register_driver(struct matroxfb_driver* drv); +void matroxfb_unregister_driver(struct matroxfb_driver* drv); + +#define PCI_OPTION_REG 0x40 +#define PCI_MGA_INDEX 0x44 +#define PCI_MGA_DATA 0x48 + +#define M_DWGCTL 0x1C00 +#define M_MACCESS 0x1C04 +#define M_CTLWTST 0x1C08 + +#define M_PLNWT 0x1C1C + +#define M_BCOL 0x1C20 +#define M_FCOL 0x1C24 + +#define M_SGN 0x1C58 +#define M_LEN 0x1C5C +#define M_AR0 0x1C60 +#define M_AR1 0x1C64 +#define M_AR2 0x1C68 +#define M_AR3 0x1C6C +#define M_AR4 0x1C70 +#define M_AR5 0x1C74 +#define M_AR6 0x1C78 + +#define M_CXBNDRY 0x1C80 +#define M_FXBNDRY 0x1C84 +#define M_YDSTLEN 0x1C88 +#define M_PITCH 0x1C8C +#define M_YDST 0x1C90 +#define M_YDSTORG 0x1C94 +#define M_YTOP 0x1C98 +#define M_YBOT 0x1C9C + +/* mystique only */ +#define M_CACHEFLUSH 0x1FFF + +#define M_EXEC 0x0100 + +#define M_DWG_TRAP 0x04 +#define M_DWG_BITBLT 0x08 +#define M_DWG_ILOAD 0x09 + +#define M_DWG_LINEAR 0x0080 +#define M_DWG_SOLID 0x0800 +#define M_DWG_ARZERO 0x1000 +#define M_DWG_SGNZERO 0x2000 +#define M_DWG_SHIFTZERO 0x4000 + +#define M_DWG_REPLACE 0x000C0000 +#define M_DWG_REPLACE2 (M_DWG_REPLACE | 0x40) +#define M_DWG_XOR 0x00060010 + +#define M_DWG_BFCOL 0x04000000 +#define M_DWG_BMONOWF 0x08000000 + +#define M_DWG_TRANSC 0x40000000 + +#define M_FIFOSTATUS 0x1E10 +#define M_STATUS 0x1E14 + +#define M_IEN 0x1E1C + +#define M_VCOUNT 0x1E20 + +#define M_RESET 0x1E40 + +#define M_AGP2PLL 0x1E4C + +#define M_OPMODE 0x1E54 +#define M_OPMODE_DMA_GEN_WRITE 0x00 +#define M_OPMODE_DMA_BLIT 0x04 +#define M_OPMODE_DMA_VECTOR_WRITE 0x08 +#define M_OPMODE_DMA_LE 0x0000 /* little endian - no transformation */ +#define M_OPMODE_DMA_BE_8BPP 0x0000 +#define M_OPMODE_DMA_BE_16BPP 0x0100 +#define M_OPMODE_DMA_BE_32BPP 0x0200 +#define M_OPMODE_DIR_LE 0x000000 /* little endian - no transformation */ +#define M_OPMODE_DIR_BE_8BPP 0x000000 +#define M_OPMODE_DIR_BE_16BPP 0x010000 +#define M_OPMODE_DIR_BE_32BPP 0x020000 + +#define M_ATTR_INDEX 0x1FC0 +#define M_ATTR_DATA 0x1FC1 + +#define M_MISC_REG 0x1FC2 +#define M_3C2_RD 0x1FC2 + +#define M_SEQ_INDEX 0x1FC4 +#define M_SEQ_DATA 0x1FC5 + +#define M_MISC_REG_READ 0x1FCC + +#define M_GRAPHICS_INDEX 0x1FCE +#define M_GRAPHICS_DATA 0x1FCF + +#define M_CRTC_INDEX 0x1FD4 + +#define M_ATTR_RESET 0x1FDA +#define M_3DA_WR 0x1FDA +#define M_INSTS1 0x1FDA + +#define M_EXTVGA_INDEX 0x1FDE +#define M_EXTVGA_DATA 0x1FDF + +/* G200 only */ +#define M_SRCORG 0x2CB4 + +#define M_RAMDAC_BASE 0x3C00 + +/* fortunately, same on TVP3026 and MGA1064 */ +#define M_DAC_REG (M_RAMDAC_BASE+0) +#define M_DAC_VAL (M_RAMDAC_BASE+1) +#define M_PALETTE_MASK (M_RAMDAC_BASE+2) + +#define M_X_INDEX 0x00 +#define M_X_DATAREG 0x0A + +#define DAC_XGENIOCTRL 0x2A +#define DAC_XGENIODATA 0x2B + +#ifdef __LITTLE_ENDIAN +#define MX_OPTION_BSWAP 0x00000000 + +#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) +#define M_OPMODE_8BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) +#define M_OPMODE_16BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) +#define M_OPMODE_24BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) +#define M_OPMODE_32BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) +#else +#ifdef __BIG_ENDIAN +#define MX_OPTION_BSWAP 0x80000000 + +#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) /* TODO */ +#define M_OPMODE_8BPP (M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT) +#define M_OPMODE_16BPP (M_OPMODE_DMA_BE_16BPP | M_OPMODE_DIR_BE_16BPP | M_OPMODE_DMA_BLIT) +#define M_OPMODE_24BPP (M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT) /* TODO, ?32 */ +#define M_OPMODE_32BPP (M_OPMODE_DMA_BE_32BPP | M_OPMODE_DIR_BE_32BPP | M_OPMODE_DMA_BLIT) +#else +#error "Byte ordering have to be defined. Cannot continue." +#endif +#endif + +#define mga_inb(addr) mga_readb(ACCESS_FBINFO(mmio.vbase), (addr)) +#define mga_inl(addr) mga_readl(ACCESS_FBINFO(mmio.vbase), (addr)) +#define mga_outb(addr,val) mga_writeb(ACCESS_FBINFO(mmio.vbase), (addr), (val)) +#define mga_outw(addr,val) mga_writew(ACCESS_FBINFO(mmio.vbase), (addr), (val)) +#define mga_outl(addr,val) mga_writel(ACCESS_FBINFO(mmio.vbase), (addr), (val)) +#define mga_readr(port,idx) (mga_outb((port),(idx)), mga_inb((port)+1)) +#ifdef __LITTLE_ENDIAN +#define mga_setr(addr,port,val) mga_outw(addr, ((val)<<8) | (port)) +#else +#define mga_setr(addr,port,val) do { mga_outb(addr, port); mga_outb((addr)+1, val); } while (0) +#endif + +#ifdef __LITTLE_ENDIAN +#define mga_fifo(n) do {} while (mga_inb(M_FIFOSTATUS) < (n)) +#else +#define mga_fifo(n) do {} while ((mga_inl(M_FIFOSTATUS) & 0xFF) < (n)) +#endif + +#define WaitTillIdle() do {} while (mga_inl(M_STATUS) & 0x10000) + +/* code speedup */ +#ifdef CONFIG_FB_MATROX_MILLENIUM +#define isInterleave(x) (x->interleave) +#define isMillenium(x) (x->millenium) +#define isMilleniumII(x) (x->milleniumII) +#else +#define isInterleave(x) (0) +#define isMillenium(x) (0) +#define isMilleniumII(x) (0) +#endif + +#define matroxfb_DAC_lock() spin_lock(&ACCESS_FBINFO(lock.DAC)) +#define matroxfb_DAC_unlock() spin_unlock(&ACCESS_FBINFO(lock.DAC)) +#define matroxfb_DAC_lock_irqsave(flags) spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC),flags) +#define matroxfb_DAC_unlock_irqrestore(flags) spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC),flags) +extern void matroxfb_DAC_out(CPMINFO int reg, int val); +extern int matroxfb_DAC_in(CPMINFO int reg); +extern struct list_head matroxfb_list; +extern void matroxfb_var2my(struct fb_var_screeninfo* fvsi, struct my_timming* mt); + +#ifdef MATROXFB_USE_SPINLOCKS +#define CRITBEGIN spin_lock_irqsave(&ACCESS_FBINFO(lock.accel), critflags); +#define CRITEND spin_unlock_irqrestore(&ACCESS_FBINFO(lock.accel), critflags); +#define CRITFLAGS unsigned long critflags; +#else +#define CRITBEGIN +#define CRITEND +#define CRITFLAGS +#endif + +#endif /* __MATROXFB_H__ */ diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c new file mode 100644 index 000000000..46fdb5fad --- /dev/null +++ b/drivers/video/matrox/matroxfb_crtc2.c @@ -0,0 +1,788 @@ +#include "matroxfb_maven.h" +#include "matroxfb_crtc2.h" +#include "matroxfb_misc.h" +#include "matroxfb_DAC1064.h" +#include <linux/matroxfb.h> +#include <asm/uaccess.h> + +/* **************************************************** */ + +static int mem = 8192; + +MODULE_PARM(mem, "i"); +MODULE_PARM_DESC(mem, "Memory size reserved for dualhead (default=8MB)"); + +/* **************************************************** */ + +static int matroxfb_dh_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, struct fb_info* info) { +#define m2info ((struct matroxfb_dh_fb_info*)info) + if (regno > 16) + return 1; + *red = m2info->palette[regno].red; + *blue = m2info->palette[regno].blue; + *green = m2info->palette[regno].green; + *transp = m2info->palette[regno].transp; + return 0; +#undef m2info +} + +static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info* info) { +#define m2info ((struct matroxfb_dh_fb_info*)info) + struct display* p; + + if (regno > 16) + return 1; + m2info->palette[regno].red = red; + m2info->palette[regno].blue = blue; + m2info->palette[regno].green = green; + m2info->palette[regno].transp = transp; + p = m2info->currcon_display; + if (p->var.grayscale) { + /* gray = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + red = CNVT_TOHW(red, p->var.red.length); + green = CNVT_TOHW(green, p->var.green.length); + blue = CNVT_TOHW(blue, p->var.blue.length); + transp = CNVT_TOHW(transp, p->var.transp.length); + + switch (p->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB16 + case 16: + m2info->cmap.cfb16[regno] = + (red << p->var.red.offset) | + (green << p->var.green.offset) | + (blue << p->var.blue.offset) | + (transp << p->var.transp.offset); + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + m2info->cmap.cfb32[regno] = + (red << p->var.red.offset) | + (green << p->var.green.offset) | + (blue << p->var.blue.offset) | + (transp << p->var.transp.offset); + break; +#endif + } + return 0; +#undef m2info +} + +static void do_install_cmap(struct matroxfb_dh_fb_info* m2info, struct display* p) { + if (p->cmap.len) + fb_set_cmap(&p->cmap, 1, matroxfb_dh_setcolreg, &m2info->fbcon); + else + fb_set_cmap(fb_default_cmap(16), 1, matroxfb_dh_setcolreg, &m2info->fbcon); +} + +static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info, + struct my_timming* mt, + struct display* p, + int mode, + unsigned int pos) { + u_int32_t tmp; + struct matrox_fb_info* minfo = m2info->primary_dev; + + switch (mode) { + case 15: + tmp = 0x00200000; + break; + case 16: + tmp = 0x00400000; + break; +/* case 32: */ + default: + tmp = 0x00800000; + break; + } + + if (ACCESS_FBINFO(output.sh)) { + tmp |= 0x00000001; /* enable CRTC2 */ + + if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { + tmp |= 0x00000002; /* source from VDOCLK */ + tmp |= 0xC0000000; /* enable vvidrst & hvidrst */ + /* MGA TVO is our clock source */ + } else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) { + tmp |= 0x00000004; /* source from pixclock */ + /* PIXPLL is our clock source */ + } + + if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) + tmp |= 0x00100000; /* connect CRTC2 to DAC */ + } + mga_outl(0x3C10, tmp | 0x10000000); /* depth and so on... 0x10000000 is VIDRST polarity */ + mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8)); + mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8)); + mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1)); + mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1)); + mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart)); /* preload */ + mga_outl(0x3C28, pos); /* vmemory start */ + mga_outl(0x3C40, p->var.xres_virtual * (p->var.bits_per_pixel >> 3)); + tmp = 0x0FFF0000; /* line compare */ + if (mt->sync & FB_SYNC_HOR_HIGH_ACT) + tmp |= 0x00000100; + if (mt->sync & FB_SYNC_VERT_HIGH_ACT) + tmp |= 0x00000200; + mga_outl(0x3C44, tmp); + mga_outl(0x3C4C, 0); /* data control */ +} + +static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info, + struct display* p) { + /* no acceleration for secondary head... */ +} + +static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info, + struct fb_var_screeninfo* var) { + unsigned int pos; + +#define minfo (m2info->primary_dev) + pos = (var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel >> 3; + pos += m2info->video.offbase; + mga_outl(0x3C28, pos); +#undef minfo +} + +static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info, + struct display* p, + struct fb_var_screeninfo* var, + int *visual, + int *video_cmap_len, + int *mode) { + unsigned int mask; + unsigned int memlen; + unsigned int vramlen; + + switch (var->bits_per_pixel) { +#ifdef FBCON_HAS_CFB16 + case 16: mask = 0x1F; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: mask = 0x0F; + break; +#endif + default: return -EINVAL; + } + vramlen = m2info->video.len_usable; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + var->xres_virtual = (var->xres_virtual + mask) & ~mask; + if (var->yres_virtual > 32767) + return -EINVAL; + memlen = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel >> 3); + if (memlen > vramlen) + return -EINVAL; + if (var->xoffset + var->xres > var->xres_virtual) + var->xoffset = var->xres_virtual - var->xres; + if (var->yoffset + var->yres > var->yres_virtual) + var->yoffset = var->yres_virtual - var->yres; + + var->xres &= ~7; + var->left_margin &= ~7; + var->right_margin &= ~7; + var->hsync_len &= ~7; + + *mode = var->bits_per_pixel; + if (var->bits_per_pixel == 16) { + if (var->green.length == 5) { + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + *mode = 15; + } else { + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + } + } else { + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + } + *visual = FB_VISUAL_TRUECOLOR; + *video_cmap_len = 16; + return 0; +} + +static void initMatroxDH(struct matroxfb_dh_fb_info* m2info, struct display* p) { + switch (p->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB16 + case 16: + p->dispsw_data = m2info->cmap.cfb16; + p->dispsw = &fbcon_cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + p->dispsw_data = m2info->cmap.cfb32; + p->dispsw = &fbcon_cfb32; + break; +#endif + default: + p->dispsw_data = NULL; + p->dispsw = &fbcon_dummy; + break; + } +} + +static int matroxfb_dh_open(struct fb_info* info, int user) { +#define m2info ((struct matroxfb_dh_fb_info*)info) + struct matrox_fb_info* minfo = m2info->primary_dev; + MOD_INC_USE_COUNT; + + if (minfo) { + if (ACCESS_FBINFO(dead)) { + return -ENXIO; + } + } + return 0; +#undef m2info +} + +static int matroxfb_dh_release(struct fb_info* info, int user) { +#define m2info ((struct matroxfb_dh_fb_info*)info) + struct matrox_fb_info* minfo = m2info->primary_dev; + + if (minfo) { + } + MOD_DEC_USE_COUNT; + return 0; +#undef m2info +} + +static int matroxfb_dh_get_fix(struct fb_fix_screeninfo* fix, int con, + struct fb_info* info) { +#define m2info ((struct matroxfb_dh_fb_info*)info) + struct display* p; + + if (con >= 0) + p = fb_display + con; + else + p = m2info->fbcon.disp; + + memset(fix, 0, sizeof(*fix)); + strcpy(fix->id, "MATROX DH"); + + fix->smem_start = m2info->video.base; + fix->smem_len = m2info->video.len_usable; + fix->type = p->type; + fix->type_aux = p->type_aux; + fix->visual = p->visual; + fix->xpanstep = 8; /* TBD */ + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->line_length = p->line_length; + fix->mmio_start = m2info->mmio.base; + fix->mmio_len = m2info->mmio.len; + fix->accel = 0; /* no accel... */ + return 0; +#undef m2info +} + +static int matroxfb_dh_get_var(struct fb_var_screeninfo* var, int con, + struct fb_info* info) { +#define m2info ((struct matroxfb_dh_fb_info*)info) + if (con < 0) + *var = m2info->fbcon.disp->var; + else + *var = fb_display[con].var; + return 0; +#undef m2info +} + +static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con, + struct fb_info* info) { +#define m2info ((struct matroxfb_dh_fb_info*)info) + struct display* p; + int chgvar; + int visual; + int cmap_len; + int mode; + int err; + struct matrox_fb_info* minfo = m2info->primary_dev; + + if (con < 0) + p = m2info->fbcon.disp; + else + p = fb_display + con; + if ((err = matroxfb_dh_decode_var(m2info, p, var, &visual, &cmap_len, &mode)) != 0) + return err; + switch (var->activate & FB_ACTIVATE_MASK) { + case FB_ACTIVATE_TEST: return 0; + case FB_ACTIVATE_NXTOPEN: + case FB_ACTIVATE_NOW: break; + default: return -EINVAL; + } + if (con >= 0) { + chgvar = (p->var.xres != var->xres) || + (p->var.yres != var->yres) || + (p->var.xres_virtual != var->xres_virtual) || + (p->var.yres_virtual != var->yres_virtual) || + (p->var.bits_per_pixel != var->bits_per_pixel) || + memcmp(&p->var.red, &var->red, sizeof(var->red)) || + memcmp(&p->var.green, &var->green, sizeof(var->green)) || + memcmp(&p->var.blue, &var->blue, sizeof(var->blue)); + } else + chgvar = 0; + p->var = *var; + /* cmap */ + p->screen_base = vaddr_va(m2info->video.vbase); + p->visual = visual; + p->ypanstep = 1; + p->ywrapstep = 0; + p->type = FB_TYPE_PACKED_PIXELS; + p->type_aux = 0; + p->next_line = p->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; + p->can_soft_blank = 0; + p->inverse = 0; /* TBD */ + initMatroxDH(m2info, p); + if (chgvar && info && info->changevar) + info->changevar(con); + if (con == m2info->currcon) { + struct my_timming mt; + struct matrox_hw_state* hw; + struct matrox_hw_state* ohw; + unsigned int pos; + + matroxfb_var2my(var, &mt); + /* CRTC2 delay */ + mt.delay = 34; + + hw = ACCESS_FBINFO(newhw); + ohw = ACCESS_FBINFO(currenthw); + + /* copy last setting... */ + memcpy(hw, ohw, sizeof(*hw)); + + pos = (var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel >> 3; + pos += m2info->video.offbase; + DAC1064_global_init(PMINFO hw); + if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) { + if (ACCESS_FBINFO(primout)) + ACCESS_FBINFO(primout)->compute(MINFO, &mt, hw); + } + if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { + down_read(&ACCESS_FBINFO(altout.lock)); + if (ACCESS_FBINFO(altout.output)) + ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt, hw); + up_read(&ACCESS_FBINFO(altout.lock)); + } + matroxfb_dh_restore(m2info, &mt, p, mode, pos); + DAC1064_global_restore(PMINFO hw); + if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) { + if (ACCESS_FBINFO(primout)) + ACCESS_FBINFO(primout)->program(MINFO, hw); + } + if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { + down_read(&ACCESS_FBINFO(altout.lock)); + if (ACCESS_FBINFO(altout.output)) + ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device), hw); + up_read(&ACCESS_FBINFO(altout.lock)); + } + if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) { + if (ACCESS_FBINFO(primout)) + ACCESS_FBINFO(primout)->start(MINFO); + } + if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { + down_read(&ACCESS_FBINFO(altout.lock)); + if (ACCESS_FBINFO(altout.output)) + ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device)); + up_read(&ACCESS_FBINFO(altout.lock)); + } + matroxfb_dh_cfbX_init(m2info, p); + do_install_cmap(m2info, p); + } + return 0; +#undef m2info +} + +static int matroxfb_dh_get_cmap(struct fb_cmap* cmap, int kspc, int con, + struct fb_info* info) { +#define m2info ((struct matroxfb_dh_fb_info*)info) + struct display* dsp; + + if (con < 0) + dsp = m2info->fbcon.disp; + else + dsp = fb_display + con; + if (con == m2info->currcon) + return fb_get_cmap(cmap, kspc, matroxfb_dh_getcolreg, info); + else if (dsp->cmap.len) + fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2); + else + fb_copy_cmap(fb_default_cmap(16), cmap, kspc ? 0 : 2); + return 0; +#undef m2info +} + +static int matroxfb_dh_set_cmap(struct fb_cmap* cmap, int kspc, int con, + struct fb_info* info) { +#define m2info ((struct matroxfb_dh_fb_info*)info) + struct display* dsp; + + if (con < 0) + dsp = m2info->fbcon.disp; + else + dsp = fb_display + con; + if (dsp->cmap.len != 16) { + int err; + + err = fb_alloc_cmap(&dsp->cmap, 16, 0); + if (err) + return err; + } + if (con == m2info->currcon) + return fb_set_cmap(cmap, kspc, matroxfb_dh_setcolreg, info); + else + fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1); + return 0; +#undef m2info +} + +static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, int con, + struct fb_info* info) { +#define m2info ((struct matroxfb_dh_fb_info*)info) + if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual || + var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual) + return -EINVAL; + if (con == m2info->currcon) + matroxfb_dh_pan_var(m2info, var); + fb_display[con].var.xoffset = var->xoffset; + fb_display[con].var.yoffset = var->yoffset; + return 0; +#undef m2info +} + +static int matroxfb_dh_switch(int con, struct fb_info* info); + +static int matroxfb_dh_get_vblank(const struct matroxfb_dh_fb_info* m2info, struct fb_vblank* vblank) { + struct matrox_fb_info* minfo = m2info->primary_dev; + + memset(vblank, 0, sizeof(*vblank)); + vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VBLANK; + /* mask out reserved bits + field number (odd/even) */ + vblank->vcount = mga_inl(0x3C48) & 0x000007FF; + /* compatibility stuff */ + if (vblank->vcount >= m2info->currcon_display->var.yres) + vblank->flags |= FB_VBLANK_VBLANKING; + return 0; +} + +static int matroxfb_dh_ioctl(struct inode* inode, + struct file* file, + unsigned int cmd, + unsigned long arg, + int con, + struct fb_info* info) { +#define m2info ((struct matroxfb_dh_fb_info*)info) + struct matrox_fb_info* minfo = m2info->primary_dev; + + DBG("matroxfb_crtc2_ioctl") + + switch (cmd) { + case FBIOGET_VBLANK: + { + struct fb_vblank vblank; + int err; + + err = matroxfb_dh_get_vblank(m2info, &vblank); + if (err) + return err; + copy_to_user_ret((struct fb_vblank*)arg, &vblank, sizeof(vblank), -EFAULT); + return 0; + } + case MATROXFB_SET_OUTPUT_MODE: + case MATROXFB_GET_OUTPUT_MODE: + case MATROXFB_GET_ALL_OUTPUTS: + { + return ACCESS_FBINFO(fbcon.fbops)->fb_ioctl(inode, file, cmd, arg, con, &minfo->fbcon); + } + case MATROXFB_SET_OUTPUT_CONNECTION: + { + u_int32_t tmp; + + get_user_ret(tmp, (u_int32_t*)arg, -EFAULT); + if (tmp & ~ACCESS_FBINFO(output.all)) + return -EINVAL; + if (tmp & ACCESS_FBINFO(output.ph)) + return -EINVAL; + if (tmp == ACCESS_FBINFO(output.sh)) + return 0; + ACCESS_FBINFO(output.sh) = tmp; + matroxfb_dh_switch(m2info->currcon, info); + return 0; + } + case MATROXFB_GET_OUTPUT_CONNECTION: + { + put_user_ret(ACCESS_FBINFO(output.sh), (u_int32_t*)arg, -EFAULT); + return 0; + } + case MATROXFB_GET_AVAILABLE_OUTPUTS: + { + u_int32_t tmp; + + tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.ph); + put_user_ret(tmp, (u_int32_t*)arg, -EFAULT); + return 0; + } + } + return -EINVAL; +#undef m2info +} + +static struct fb_ops matroxfb_dh_ops = { + matroxfb_dh_open, + matroxfb_dh_release, + matroxfb_dh_get_fix, + matroxfb_dh_get_var, + matroxfb_dh_set_var, + matroxfb_dh_get_cmap, + matroxfb_dh_set_cmap, + matroxfb_dh_pan_display, + matroxfb_dh_ioctl, + NULL /* mmap */ +}; + +static int matroxfb_dh_switch(int con, struct fb_info* info) { +#define m2info ((struct matroxfb_dh_fb_info*)info) + struct fb_cmap* cmap; + struct display* p; + + if (m2info->currcon >= 0) { + cmap = &m2info->currcon_display->cmap; + if (cmap->len) { + fb_get_cmap(cmap, 1, matroxfb_dh_getcolreg, info); + } + } + m2info->currcon = con; + if (con < 0) + p = m2info->fbcon.disp; + else + p = fb_display + con; + m2info->currcon_display = p; + p->var.activate = FB_ACTIVATE_NOW; + matroxfb_dh_set_var(&p->var, con, info); + return 0; +#undef m2info +} + +static int matroxfb_dh_updatevar(int con, struct fb_info* info) { +#define m2info ((struct matroxfb_dh_fb_info*)info) + matroxfb_dh_pan_var(m2info, &fb_display[con].var); + return 0; +#undef m2info +} + +static void matroxfb_dh_blank(int blank, struct fb_info* info) { +#define m2info ((struct matroxfb_dh_fb_info*)info) + switch (blank) { + case 1: + case 2: + case 3: + case 4: + default:; + } + /* do something... */ +#undef m2info +} + +static struct fb_var_screeninfo matroxfb_dh_defined = { + 640,480,640,480,/* W,H, virtual W,H */ + 0,0, /* offset */ + 32, /* depth */ + 0, /* gray */ + {0,0,0}, /* R */ + {0,0,0}, /* G */ + {0,0,0}, /* B */ + {0,0,0}, /* alpha */ + 0, /* nonstd */ + FB_ACTIVATE_NOW, + -1,-1, /* display size */ + 0, /* accel flags */ + 39721L,48L,16L,33L,10L, + 96L,2,0, /* no sync info */ + FB_VMODE_NONINTERLACED, + {0,0,0,0,0,0} +}; + +static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) { +#define minfo (m2info->primary_dev) + struct display* d; + void* oldcrtc2; + + d = kmalloc(sizeof(*d), GFP_KERNEL); + + memset(d, 0, sizeof(*d)); + + strcpy(m2info->fbcon.modename, "MATROX CRTC2"); + m2info->fbcon.changevar = NULL; + m2info->fbcon.node = -1; + m2info->fbcon.fbops = &matroxfb_dh_ops; + m2info->fbcon.disp = d; + m2info->fbcon.switch_con = &matroxfb_dh_switch; + m2info->fbcon.updatevar = &matroxfb_dh_updatevar; + m2info->fbcon.blank = &matroxfb_dh_blank; + m2info->fbcon.flags = FBINFO_FLAG_DEFAULT; + m2info->currcon = -1; + m2info->currcon_display = d; + + if (mem < 64) + mem *= 1024; + if (mem < 64*1024) + mem *= 1024; + mem &= ~0x00000FFF; /* PAGE_MASK? */ + if (minfo->video.len_usable + mem <= minfo->video.len) + m2info->video.offbase = minfo->video.len - mem; + else if (minfo->video.len < mem) { + kfree(d); + return -ENOMEM; + } else { /* check yres on first head... */ + m2info->video.borrowed = mem; + minfo->video.len_usable -= mem; + m2info->video.offbase = minfo->video.len_usable; + } + m2info->video.base = ACCESS_FBINFO(video.base) + m2info->video.offbase; + m2info->video.len = m2info->video.len_usable = m2info->video.len_maximum = mem; + m2info->video.vbase.vaddr = vaddr_va(ACCESS_FBINFO(video.vbase)) + m2info->video.offbase; + m2info->mmio.base = ACCESS_FBINFO(mmio.base); + m2info->mmio.vbase = ACCESS_FBINFO(mmio.vbase); + m2info->mmio.len = ACCESS_FBINFO(mmio.len); + + /* + * If we have two outputs, connect CRTC2 to it... + */ + if (ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) { + ACCESS_FBINFO(output.sh) |= MATROXFB_OUTPUT_CONN_SECONDARY; + ACCESS_FBINFO(output.ph) &= ~MATROXFB_OUTPUT_CONN_SECONDARY; + } + + matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon); + if (register_framebuffer(&m2info->fbcon)) { + kfree(d); + return -ENXIO; + } + if (m2info->currcon < 0) { + matroxfb_dh_set_var(&matroxfb_dh_defined, -1, &m2info->fbcon); + } + down_write(&ACCESS_FBINFO(crtc2.lock)); + oldcrtc2 = minfo->crtc2.info; + minfo->crtc2.info = &m2info->fbcon; + up_write(&ACCESS_FBINFO(crtc2.lock)); + if (oldcrtc2) { + printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 already present: %p\n", + oldcrtc2); + } + return 0; +#undef minfo +} + +/* ************************** */ + +static int matroxfb_dh_registerfb(struct matroxfb_dh_fb_info* m2info) { +#define minfo (m2info->primary_dev) + if (matroxfb_dh_regit(PMINFO m2info)) { + printk(KERN_ERR "matroxfb_crtc2: secondary head failed to register\n"); + return -1; + } + printk(KERN_INFO "matroxfb_crtc2: secondary head of fb%u was registered as fb%u\n", + GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), GET_FB_IDX(m2info->fbcon.node)); + m2info->fbcon_registered = 1; + return 0; +#undef minfo +} + +static void matroxfb_dh_deregisterfb(struct matroxfb_dh_fb_info* m2info) { +#define minfo (m2info->primary_dev) + if (m2info->fbcon_registered) { + int id; + struct fb_info* crtc2; + + down_write(&ACCESS_FBINFO(crtc2.lock)); + crtc2 = minfo->crtc2.info; + if (crtc2 == &m2info->fbcon) + minfo->crtc2.info = NULL; + up_write(&ACCESS_FBINFO(crtc2.lock)); + if (crtc2 != &m2info->fbcon) { + printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 mismatch at unload: %p != %p\n", + crtc2, &m2info->fbcon); + printk(KERN_ERR "matroxfb_crtc2: Expect kernel crash after module unload.\n"); + return; + } + id = GET_FB_IDX(m2info->fbcon.node); + unregister_framebuffer(&m2info->fbcon); + kfree(m2info->fbcon.disp); + /* return memory back to primary head */ + ACCESS_FBINFO(video.len_usable) += m2info->video.borrowed; + printk(KERN_INFO "matroxfb_crtc2: fb%u unregistered\n", id); + m2info->fbcon_registered = 0; + } +#undef minfo +} + +static void* matroxfb_crtc2_probe(struct matrox_fb_info* minfo) { + struct matroxfb_dh_fb_info* m2info; + + /* hardware is CRTC2 incapable... */ + if (!minfo->devflags.crtc2) + return NULL; + m2info = (struct matroxfb_dh_fb_info*)kmalloc(sizeof(*m2info), GFP_KERNEL); + if (!m2info) { + printk(KERN_ERR "matroxfb_crtc2: Not enough memory for CRTC2 control structs\n"); + return NULL; + } + memset(m2info, 0, sizeof(*m2info)); + m2info->primary_dev = minfo; + if (matroxfb_dh_registerfb(m2info)) { + kfree(m2info); + printk(KERN_ERR "matroxfb_crtc2: CRTC2 framebuffer failed to register\n"); + return NULL; + } + return m2info; +} + +static void matroxfb_crtc2_remove(struct matrox_fb_info* minfo, void* crtc2) { + matroxfb_dh_deregisterfb(crtc2); +} + +static struct matroxfb_driver crtc2 = { + name: "Matrox G400 CRTC2", + probe: matroxfb_crtc2_probe, + remove: matroxfb_crtc2_remove }; + +static int matroxfb_crtc2_init(void) { + matroxfb_register_driver(&crtc2); + return 0; +} + +static void matroxfb_crtc2_exit(void) { + matroxfb_unregister_driver(&crtc2); +} + +MODULE_AUTHOR("(c) 1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_DESCRIPTION("Matrox G400 CRTC2 driver"); +module_init(matroxfb_crtc2_init); +module_exit(matroxfb_crtc2_exit); +/* we do not have __setup() yet */ diff --git a/drivers/video/matrox/matroxfb_crtc2.h b/drivers/video/matrox/matroxfb_crtc2.h new file mode 100644 index 000000000..e625053bc --- /dev/null +++ b/drivers/video/matrox/matroxfb_crtc2.h @@ -0,0 +1,44 @@ +#ifndef __MATROXFB_CRTC2_H__ +#define __MATROXFB_CRTC2_H__ + +#include <linux/ioctl.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#include "matroxfb_base.h" + +struct matroxfb_dh_fb_info { + struct fb_info fbcon; + int fbcon_registered; + + struct matrox_fb_info* primary_dev; + + struct { + unsigned long base; /* physical */ + vaddr_t vbase; /* virtual */ + unsigned int len; + unsigned int len_usable; + unsigned int len_maximum; + unsigned int offbase; + unsigned int borrowed; + } video; + struct { + unsigned long base; + vaddr_t vbase; + unsigned int len; + } mmio; + + int currcon; + struct display* currcon_display; + + union { +#ifdef FBCON_HAS_CFB16 + u_int16_t cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u_int32_t cfb32[16]; +#endif + } cmap; + struct { unsigned red, green, blue, transp; } palette[16]; +}; + +#endif /* __MATROXFB_CRTC2_H__ */ diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c new file mode 100644 index 000000000..978dba156 --- /dev/null +++ b/drivers/video/matrox/matroxfb_maven.c @@ -0,0 +1,1040 @@ +#include "matroxfb_maven.h" +#include "matroxfb_misc.h" +#include "matroxfb_DAC1064.h" +#include <linux/i2c.h> +#include <linux/matroxfb.h> +#include <asm/div64.h> +#include <asm/uaccess.h> + +#define MAVEN_I2CID (0x1B) + +#define MODE_PAL MATROXFB_OUTPUT_MODE_PAL +#define MODE_NTSC MATROXFB_OUTPUT_MODE_NTSC +#define MODE_TV(x) (((x) == MODE_PAL) || ((x) == MODE_NTSC)) +#define MODE_MONITOR MATROXFB_OUTPUT_MODE_MONITOR + +struct maven_data { + struct matrox_fb_info* primary_head; + struct i2c_client* client; + int mode; +}; + +static int maven_get_reg(struct i2c_client* c, char reg) { + char dst; + struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), ® }, + { c->addr, I2C_M_RD | I2C_M_NOSTART, sizeof(dst), &dst }}; + s32 err; + + err = i2c_transfer(c->adapter, msgs, 2); + if (err < 0) + printk(KERN_INFO "ReadReg(%d) failed\n", reg); + return dst & 0xFF; +} + +static int maven_set_reg(struct i2c_client* c, int reg, int val) { + s32 err; + + err = i2c_smbus_write_byte_data(c, reg, val); + if (err) + printk(KERN_INFO "WriteReg(%d) failed\n", reg); + return err; +} + +static int maven_set_reg_pair(struct i2c_client* c, int reg, int val) { + s32 err; + + err = i2c_smbus_write_word_data(c, reg, val); + if (err) + printk(KERN_INFO "WriteRegPair(%d) failed\n", reg); + return err; +} + +static const struct matrox_pll_features maven_pll = { + 50000, + 27000, + 4, 127, + 2, 31, + 3 +}; + +struct matrox_pll_features2 { + unsigned int vco_freq_min; + unsigned int vco_freq_max; + unsigned int feed_div_min; + unsigned int feed_div_max; + unsigned int in_div_min; + unsigned int in_div_max; + unsigned int post_shift_max; +}; + +struct matrox_pll_ctl { + unsigned int ref_freq; + unsigned int den; +}; + +static const struct matrox_pll_features2 maven1000_pll = { + 50000000, + 300000000, + 5, 128, + 3, 32, + 3 +}; + +static const struct matrox_pll_ctl maven_PAL = { + 540000, + 50 +}; + +static const struct matrox_pll_ctl maven_NTSC = { + 450450, /* 27027000/60 == 27000000/59.94005994 */ + 60 +}; + +static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, + const struct matrox_pll_ctl* ctl, + unsigned int htotal, unsigned int vtotal, + unsigned int* in, unsigned int* feed, unsigned int* post, + unsigned int* h2) { + unsigned int besth2 = 0; + unsigned int fxtal = ctl->ref_freq; + unsigned int fmin = pll->vco_freq_min / ctl->den; + unsigned int fwant; + unsigned int p; + unsigned int scrlen; + unsigned int fmax; + + DBG("PLL_calcclock") + + scrlen = htotal * (vtotal - 1); + fwant = htotal * vtotal; + fmax = pll->vco_freq_max / ctl->den; + + printk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n", + fwant, fxtal, htotal, vtotal, fmax); + for (p = 1; p <= pll->post_shift_max; p++) { + if (fwant * 2 > fmax) + break; + fwant *= 2; + } + if (fwant > fmax) + return 0; + for (; p-- > 0; fwant >>= 1) { + unsigned int m; + + if (fwant < fmin) break; + for (m = pll->in_div_min; m <= pll->in_div_max; m++) { + unsigned int n; + unsigned int dvd; + unsigned int ln; + + n = (fwant * m) / fxtal; + if (n < pll->feed_div_min) + continue; + if (n > pll->feed_div_max) + break; + + ln = fxtal * n; + dvd = m << p; + + if (ln % dvd) + continue; + ln = ln / dvd; + + if (ln < scrlen + 2) + continue; + ln = ln - scrlen; + if (ln > htotal) + continue; + printk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln); + if (ln > besth2) { + printk(KERN_DEBUG "Better...\n"); + *h2 = besth2 = ln; + *post = p; + *in = m; + *feed = n; + } + } + } + if (besth2 < 2) + return 0; + dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant); + return fxtal * (*feed) / (*in) * ctl->den; +} + +static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl, + unsigned int htotal, unsigned int vtotal, + unsigned int* in, unsigned int* feed, unsigned int* post, + unsigned int* htotal2) { + unsigned int fvco; + unsigned int p; + + fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2); + if (!fvco) + return -EINVAL; + p = (1 << p) - 1; + if (fvco <= 100000000) + ; + else if (fvco <= 140000000) + p |= 0x08; + else if (fvco <= 180000000) + p |= 0x10; + else + p |= 0x18; + *post = p; + return 0; +} + +static void DAC1064_calcclock(unsigned int freq, unsigned int fmax, + unsigned int* in, unsigned int* feed, unsigned int* post) { + unsigned int fvco; + unsigned int p; + + fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p); + p = (1 << p) - 1; + if (fvco <= 100000) + ; + else if (fvco <= 140000) + p |= 0x08; + else if (fvco <= 180000) + p |= 0x10; + else + p |= 0x18; + *post = p; + return; +} + +static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) { + static struct mavenregs palregs = { { + 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */ + 0x00, + 0x00, /* ? not written */ + 0x00, /* modified by code (F9 written...) */ + 0x00, /* ? not written */ + 0x7E, /* 08 */ + 0x44, /* 09 */ + 0x9C, /* 0A */ + 0x2E, /* 0B */ + 0x21, /* 0C */ + 0x00, /* ? not written */ + 0x3F, 0x03, /* 0E-0F */ + 0x3F, 0x03, /* 10-11 */ + 0x1A, /* 12 */ + 0x2A, /* 13 */ + 0x1C, 0x3D, 0x14, /* 14-16 */ + 0x9C, 0x01, /* 17-18 */ + 0x00, /* 19 */ + 0xFE, /* 1A */ + 0x7E, /* 1B */ + 0x60, /* 1C */ + 0x05, /* 1D */ + 0x89, 0x03, /* 1E-1F */ + 0x72, /* 20 */ + 0x07, /* 21 */ + 0x72, /* 22 */ + 0x00, /* 23 */ + 0x00, /* 24 */ + 0x00, /* 25 */ + 0x08, /* 26 */ + 0x04, /* 27 */ + 0x00, /* 28 */ + 0x1A, /* 29 */ + 0x55, 0x01, /* 2A-2B */ + 0x26, /* 2C */ + 0x07, 0x7E, /* 2D-2E */ + 0x02, 0x54, /* 2F-30 */ + 0xB0, 0x00, /* 31-32 */ + 0x14, /* 33 */ + 0x49, /* 34 */ + 0x00, /* 35 written multiple times */ + 0x00, /* 36 not written */ + 0xA3, /* 37 */ + 0xC8, /* 38 */ + 0x22, /* 39 */ + 0x02, /* 3A */ + 0x22, /* 3B */ + 0x3F, 0x03, /* 3C-3D */ + 0x00, /* 3E written multiple times */ + 0x00, /* 3F not written */ + }, MODE_PAL, 625, 50 }; + static struct mavenregs ntscregs = { { + 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */ + 0x00, + 0x00, /* ? not written */ + 0x00, /* modified by code (F9 written...) */ + 0x00, /* ? not written */ + 0x7E, /* 08 */ + 0x43, /* 09 */ + 0x7E, /* 0A */ + 0x3D, /* 0B */ + 0x00, /* 0C */ + 0x00, /* ? not written */ + 0x41, 0x00, /* 0E-0F */ + 0x3C, 0x00, /* 10-11 */ + 0x17, /* 12 */ + 0x21, /* 13 */ + 0x1B, 0x1B, 0x24, /* 14-16 */ + 0x83, 0x01, /* 17-18 */ + 0x00, /* 19 */ + 0x0F, /* 1A */ + 0x0F, /* 1B */ + 0x60, /* 1C */ + 0x05, /* 1D */ + 0x89, 0x02, /* 1E-1F */ + 0x5F, /* 20 */ + 0x04, /* 21 */ + 0x5F, /* 22 */ + 0x01, /* 23 */ + 0x02, /* 24 */ + 0x00, /* 25 */ + 0x0A, /* 26 */ + 0x05, /* 27 */ + 0x00, /* 28 */ + 0x10, /* 29 */ + 0xFF, 0x03, /* 2A-2B */ + 0x24, /* 2C */ + 0x0F, 0x78, /* 2D-2E */ + 0x00, 0x00, /* 2F-30 */ + 0xB2, 0x04, /* 31-32 */ + 0x14, /* 33 */ + 0x02, /* 34 */ + 0x00, /* 35 written multiple times */ + 0x00, /* 36 not written */ + 0xA3, /* 37 */ + 0xC8, /* 38 */ + 0x15, /* 39 */ + 0x05, /* 3A */ + 0x3B, /* 3B */ + 0x3C, 0x00, /* 3C-3D */ + 0x00, /* 3E written multiple times */ + 0x00, /* never written */ + }, MODE_NTSC, 525, 60 }; + + if (md->mode & MODE_PAL) + *data = palregs; + else + *data = ntscregs; + + data->regs[0x93] = 0xA2; + + /* gamma correction registers */ + data->regs[0x83] = 0x00; + data->regs[0x84] = 0x00; + data->regs[0x85] = 0x00; + data->regs[0x86] = 0x1F; + data->regs[0x87] = 0x10; + data->regs[0x88] = 0x10; + data->regs[0x89] = 0x10; + data->regs[0x8A] = 0x64; /* 100 */ + data->regs[0x8B] = 0xC8; /* 200 */ + + return; +} + +#define LR(x) maven_set_reg(c, (x), m->regs[(x)]) +#define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8)) +static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) { + int val; + + + maven_set_reg(c, 0x3E, 0x01); + maven_get_reg(c, 0x82); /* fetch oscillator state? */ + maven_set_reg(c, 0x8C, 0x00); + maven_get_reg(c, 0x94); /* get 0x82 */ + maven_set_reg(c, 0x94, 0xA2); + /* xmiscctrl */ + + maven_set_reg_pair(c, 0x8E, 0x1EFF); + maven_set_reg(c, 0xC6, 0x01); + + /* removed code... */ + + maven_get_reg(c, 0x06); + maven_set_reg(c, 0x06, 0xF9); /* or read |= 0xF0 ? */ + + /* removed code here... */ + + /* real code begins here? */ + /* chroma subcarrier */ + LR(0x00); LR(0x01); LR(0x02); LR(0x03); + + LR(0x04); + + LR(0x2C); + LR(0x08); + LR(0x0A); + LR(0x09); + LR(0x29); + LRP(0x31); + LRP(0x17); + LR(0x0B); + LR(0x0C); + if (m->mode & MODE_PAL) { + maven_set_reg(c, 0x35, 0x10); /* ... */ + } else { + maven_set_reg(c, 0x35, 0x0F); /* ... */ + } + + LRP(0x10); + + LRP(0x0E); + LRP(0x1E); + + LR(0x20); /* saturation #1 */ + LR(0x22); /* saturation #2 */ + LR(0x25); /* hue */ + LR(0x34); + LR(0x33); + LR(0x19); + LR(0x12); + LR(0x3B); + LR(0x13); + LR(0x39); + LR(0x1D); + LR(0x3A); + LR(0x24); + LR(0x14); + LR(0x15); + LR(0x16); + LRP(0x2D); + LRP(0x2F); + LR(0x1A); + LR(0x1B); + LR(0x1C); + LR(0x23); + LR(0x26); + LR(0x28); + LR(0x27); + LR(0x21); + LRP(0x2A); + if (m->mode & MODE_PAL) + maven_set_reg(c, 0x35, 0x1D); /* ... */ + else + maven_set_reg(c, 0x35, 0x1C); + + LRP(0x3C); + LR(0x37); + LR(0x38); + maven_set_reg(c, 0xB3, 0x01); + + maven_get_reg(c, 0xB0); /* read 0x80 */ + maven_set_reg(c, 0xB0, 0x08); /* ugh... */ + maven_get_reg(c, 0xB9); /* read 0x7C */ + maven_set_reg(c, 0xB9, 0x78); + maven_get_reg(c, 0xBF); /* read 0x00 */ + maven_set_reg(c, 0xBF, 0x02); + maven_get_reg(c, 0x94); /* read 0x82 */ + maven_set_reg(c, 0x94, 0xB3); + + LR(0x80); /* 04 1A 91 or 05 21 91 */ + LR(0x81); + LR(0x82); + + maven_set_reg(c, 0x8C, 0x20); + maven_get_reg(c, 0x8D); + maven_set_reg(c, 0x8D, 0x10); + + LR(0x90); /* 4D 50 52 or 4E 05 45 */ + LR(0x91); + LR(0x92); + + LRP(0x9A); /* 0049 or 004F */ + LRP(0x9C); /* 0004 or 0004 */ + LRP(0x9E); /* 0458 or 045E */ + LRP(0xA0); /* 05DA or 051B */ + LRP(0xA2); /* 00CC or 00CF */ + LRP(0xA4); /* 007D or 007F */ + LRP(0xA6); /* 007C or 007E */ + LRP(0xA8); /* 03CB or 03CE */ + LRP(0x98); /* 0000 or 0000 */ + LRP(0xAE); /* 0044 or 003A */ + LRP(0x96); /* 05DA or 051B */ + LRP(0xAA); /* 04BC or 046A */ + LRP(0xAC); /* 004D or 004E */ + + LR(0xBE); + LR(0xC2); + + maven_get_reg(c, 0x8D); + maven_set_reg(c, 0x8D, 0x00); + + LR(0x20); /* saturation #1 */ + LR(0x22); /* saturation #2 */ + LR(0x93); /* whoops */ + LR(0x20); /* oh, saturation #1 again */ + LR(0x22); /* oh, saturation #2 again */ + LR(0x25); /* hue */ + LRP(0x0E); + LRP(0x1E); + LRP(0x0E); /* problems with memory? */ + LRP(0x1E); /* yes, matrox must have problems in memory area... */ + + /* load gamma correction stuff */ + LR(0x83); + LR(0x84); + LR(0x85); + LR(0x86); + LR(0x87); + LR(0x88); + LR(0x89); + LR(0x8A); + LR(0x8B); + + val = maven_get_reg(c, 0x8D); + val &= 0x10; /* 0x10 or anything ored with it */ + maven_set_reg(c, 0x8D, val); + + LR(0x33); + LR(0x19); + LR(0x12); + LR(0x3B); + LR(0x13); + LR(0x39); + LR(0x1D); + LR(0x3A); + LR(0x24); + LR(0x14); + LR(0x15); + LR(0x16); + LRP(0x2D); + LRP(0x2F); + LR(0x1A); + LR(0x1B); + LR(0x1C); + LR(0x23); + LR(0x26); + LR(0x28); + LR(0x27); + LR(0x21); + LRP(0x2A); + if (m->mode & MODE_PAL) + maven_set_reg(c, 0x35, 0x1D); + else + maven_set_reg(c, 0x35, 0x1C); + LRP(0x3C); + LR(0x37); + LR(0x38); + + maven_get_reg(c, 0xB0); + LR(0xB0); /* output mode */ + LR(0x90); + LR(0xBE); + LR(0xC2); + + LRP(0x9A); + LRP(0xA2); + LRP(0x9E); + LRP(0xA6); + LRP(0xAA); + LRP(0xAC); + maven_set_reg(c, 0x3E, 0x00); + maven_set_reg(c, 0x95, 0x20); +} + +static int maven_find_exact_clocks(unsigned int ht, unsigned int vt, + struct mavenregs* m) { + unsigned int x; + unsigned int err = ~0; + + /* 1:1 */ + m->regs[0x80] = 0x0F; + m->regs[0x81] = 0x07; + m->regs[0x82] = 0x81; + + for (x = 0; x < 8; x++) { + unsigned int a, b, c, h2; + unsigned int h = ht + 2 + x; + + if (!matroxfb_mavenclock((m->mode & MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) { + unsigned int diff = h - h2; + + if (diff < err) { + err = diff; + m->regs[0x80] = a - 1; + m->regs[0x81] = b - 1; + m->regs[0x82] = c | 0x80; + m->hcorr = h2 - 2; + m->htotal = h - 2; + } + } + } + return err != ~0U; +} + +static inline int maven_compute_timming(struct maven_data* md, + struct my_timming* mt, + struct mavenregs* m) { + unsigned int tmpi; + unsigned int a, bv, c; + + m->mode = md->mode; + if (MODE_TV(md->mode)) { + unsigned int lmargin; + unsigned int umargin; + unsigned int vslen; + unsigned int hcrt; + unsigned int slen; + + maven_init_TVdata(md, m); + + if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0) + return -EINVAL; + + lmargin = mt->HTotal - mt->HSyncEnd; + slen = mt->HSyncEnd - mt->HSyncStart; + hcrt = mt->HTotal - slen - mt->delay; + umargin = mt->VTotal - mt->VSyncEnd; + vslen = mt->VSyncEnd - mt->VSyncStart; + + if (m->hcorr < mt->HTotal) + hcrt += m->hcorr; + if (hcrt > mt->HTotal) + hcrt -= mt->HTotal; + if (hcrt + 2 > mt->HTotal) + hcrt = 0; /* or issue warning? */ + + /* last (first? middle?) line in picture can have different length */ + /* hlen - 2 */ + m->regs[0x96] = m->hcorr; + m->regs[0x97] = m->hcorr >> 8; + /* ... */ + m->regs[0x98] = 0x00; m->regs[0x99] = 0x00; + /* hblanking end */ + m->regs[0x9A] = lmargin; /* 100% */ + m->regs[0x9B] = lmargin >> 8; /* 100% */ + /* who knows */ + m->regs[0x9C] = 0x04; + m->regs[0x9D] = 0x00; + /* htotal - 2 */ + m->regs[0xA0] = m->htotal; + m->regs[0xA1] = m->htotal >> 8; + /* vblanking end */ + m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1; /* stop vblanking */ + m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8; + /* something end... [A6]+1..[A8] */ + m->regs[0xA4] = 0x01; + m->regs[0xA5] = 0x00; + /* something start... 0..[A4]-1 */ + m->regs[0xA6] = 0x00; + m->regs[0xA7] = 0x00; + /* vertical line count - 1 */ + m->regs[0xA8] = mt->VTotal - 1; + m->regs[0xA9] = (mt->VTotal - 1) >> 8; + /* horizontal vidrst pos */ + m->regs[0xAA] = hcrt; /* 0 <= hcrt <= htotal - 2 */ + m->regs[0xAB] = hcrt >> 8; + /* vertical vidrst pos */ + m->regs[0xAC] = mt->VTotal - 2; + m->regs[0xAD] = (mt->VTotal - 2) >> 8; + /* moves picture up/down and so on... */ + m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */ + m->regs[0xAF] = 0x00; + { + int hdec; + int hlen; + unsigned int ibmin = 4 + lmargin + mt->HDisplay; + unsigned int ib; + int i; + + /* Verify! */ + /* Where 94208 came from? */ + if (mt->HTotal) + hdec = 94208 / (mt->HTotal); + else + hdec = 0x81; + if (hdec > 0x81) + hdec = 0x81; + if (hdec < 0x41) + hdec = 0x41; + hdec--; + hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec); + if (hlen < 0) + hlen = 0; + hlen = hlen >> 8; + if (hlen > 0xFF) + hlen = 0xFF; + /* Now we have to compute input buffer length. + If you want any picture, it must be between + 4 + lmargin + xres + and + 94208 / hdec + If you want perfect picture even on the top + of screen, it must be also + 0x3C0000 * i / hdec + Q - R / hdec + where + R Qmin Qmax + 0x07000 0x5AE 0x5BF + 0x08000 0x5CF 0x5FF + 0x0C000 0x653 0x67F + 0x10000 0x6F8 0x6FF + */ + i = 1; + do { + ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8; + i++; + } while (ib < ibmin); + if (ib >= m->htotal + 2) { + ib = ibmin; + } + + m->regs[0x90] = hdec; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */ + m->regs[0xC2] = hlen; + /* 'valid' input line length */ + m->regs[0x9E] = ib; + m->regs[0x9F] = ib >> 8; + } + { + int vdec; + int vlen; + +#define MATROX_USE64BIT_DIVIDE + if (mt->VTotal) { +#ifdef MATROX_USE64BIT_DIVIDE + u64 f1; + u32 a; + u32 b; + + a = m->vlines * (m->htotal + 2); + b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2; + + f1 = ((u64)a) << 15; /* *32768 */ + do_div(f1, b); + vdec = f1; +#else + vdec = m->vlines * 32768 / mt->VTotal; +#endif + } else + vdec = 0x8000; + if (vdec > 0x8000) + vdec = 0x8000; + vlen = (vslen + umargin + mt->VDisplay) * vdec; + vlen = (vlen >> 16) - 146; /* FIXME: 146?! */ + if (vlen < 0) + vlen = 0; + if (vlen > 0xFF) + vlen = 0xFF; + vdec--; + m->regs[0x91] = vdec; + m->regs[0x92] = vdec >> 8; + m->regs[0xBE] = vlen; + } + m->regs[0xB0] = 0x08; /* output: SVideo/Composite */ + return 0; + } + + DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c); + m->regs[0x80] = a; + m->regs[0x81] = bv; + m->regs[0x82] = c | 0x80; + + m->regs[0xB3] = 0x01; + m->regs[0x94] = 0xB2; + + /* htotal... */ + m->regs[0x96] = mt->HTotal; + m->regs[0x97] = mt->HTotal >> 8; + /* ?? */ + m->regs[0x98] = 0x00; + m->regs[0x99] = 0x00; + /* hsync len */ + tmpi = mt->HSyncEnd - mt->HSyncStart; + m->regs[0x9A] = tmpi; + m->regs[0x9B] = tmpi >> 8; + /* hblank end */ + tmpi = mt->HTotal - mt->HSyncStart; + m->regs[0x9C] = tmpi; + m->regs[0x9D] = tmpi >> 8; + /* hblank start */ + tmpi += mt->HDisplay; + m->regs[0x9E] = tmpi; + m->regs[0x9F] = tmpi >> 8; + /* htotal + 1 */ + tmpi = mt->HTotal + 1; + m->regs[0xA0] = tmpi; + m->regs[0xA1] = tmpi >> 8; + /* vsync?! */ + tmpi = mt->VSyncEnd - mt->VSyncStart - 1; + m->regs[0xA2] = tmpi; + m->regs[0xA3] = tmpi >> 8; + /* ignored? */ + tmpi = mt->VTotal - mt->VSyncStart; + m->regs[0xA4] = tmpi; + m->regs[0xA5] = tmpi >> 8; + /* ignored? */ + tmpi = mt->VTotal - 1; + m->regs[0xA6] = tmpi; + m->regs[0xA7] = tmpi >> 8; + /* vtotal - 1 */ + m->regs[0xA8] = tmpi; + m->regs[0xA9] = tmpi >> 8; + /* hor vidrst */ + tmpi = mt->HTotal - mt->delay; + m->regs[0xAA] = tmpi; + m->regs[0xAB] = tmpi >> 8; + /* vert vidrst */ + tmpi = mt->VTotal - 2; + m->regs[0xAC] = tmpi; + m->regs[0xAD] = tmpi >> 8; + /* ignored? */ + m->regs[0xAE] = 0x00; + m->regs[0xAF] = 0x00; + + m->regs[0xB0] = 0x03; /* output: monitor */ + m->regs[0xB1] = 0xA0; /* ??? */ + m->regs[0x8C] = 0x20; /* must be set... */ + m->regs[0x8D] = 0x00; /* defaults to 0x10: test signal */ + m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */ + m->regs[0xBF] = 0x22; /* makes picture stable */ + + return 0; +} + +static inline int maven_program_timming(struct maven_data* md, + const struct mavenregs* m) { + struct i2c_client* c = md->client; + + if (m->mode & MODE_MONITOR) { + LR(0x80); + LR(0x81); + LR(0x82); + + LR(0xB3); + LR(0x94); + + LRP(0x96); + LRP(0x98); + LRP(0x9A); + LRP(0x9C); + LRP(0x9E); + LRP(0xA0); + LRP(0xA2); + LRP(0xA4); + LRP(0xA6); + LRP(0xA8); + LRP(0xAA); + LRP(0xAC); + LRP(0xAE); + + LR(0xB0); /* output: monitor */ + LR(0xB1); /* ??? */ + LR(0x8C); /* must be set... */ + LR(0x8D); /* defaults to 0x10: test signal */ + LR(0xB9); /* defaults to 0x2C: too bright */ + LR(0xBF); /* makes picture stable */ + } else { + maven_init_TV(c, m); + } + return 0; +} + +static inline int maven_resync(struct maven_data* md) { + struct i2c_client* c = md->client; + maven_set_reg(c, 0x95, 0x20); /* start whole thing */ + return 0; +} + +static int maven_set_output_mode(struct maven_data* md, u_int32_t arg) { + switch (arg) { + case MATROXFB_OUTPUT_MODE_PAL: + case MATROXFB_OUTPUT_MODE_NTSC: + case MATROXFB_OUTPUT_MODE_MONITOR: + md->mode = arg; + return 1; + } + return -EINVAL; +} + +static int maven_get_output_mode(struct maven_data* md, u_int32_t *arg) { + *arg = md->mode; + return 0; +} + +/******************************************************/ + +static int maven_out_compute(void* md, struct my_timming* mt, struct matrox_hw_state* mr) { + return maven_compute_timming(md, mt, &mr->maven); +} + +static int maven_out_program(void* md, const struct matrox_hw_state* mr) { + return maven_program_timming(md, &mr->maven); +} + +static int maven_out_start(void* md) { + return maven_resync(md); +} + +static void maven_out_incuse(void* md) { + if (md) + i2c_inc_use_client(((struct maven_data*)md)->client); +} + +static void maven_out_decuse(void* md) { + if (md) + i2c_dec_use_client(((struct maven_data*)md)->client); +} + +static int maven_out_set_mode(void* md, u_int32_t arg) { + return maven_set_output_mode(md, arg); +} + +static int maven_out_get_mode(void* md, u_int32_t* arg) { + return maven_get_output_mode(md, arg); +} + +static struct matrox_altout maven_altout = { + maven_out_compute, + maven_out_program, + maven_out_start, + maven_out_incuse, + maven_out_decuse, + maven_out_set_mode, + maven_out_get_mode +}; + +static int maven_init_client(struct i2c_client* clnt) { + struct i2c_adapter* a = clnt->adapter; + /* data are set to primary head... maybe I should change it */ + struct matroxfb_dh_maven_info* m2info = + (struct matroxfb_dh_maven_info*)(((u_int8_t*)a) - offsetof(struct matroxfb_dh_maven_info, maven.adapter)); + struct maven_data* md = clnt->data; + /* add some checks that m2info is matroxfb_dh_fb_info here... */ + struct matrox_fb_info* minfo = m2info->primary_dev; + + md->mode = MODE_MONITOR; + md->primary_head = MINFO; + md->client = clnt; + down_write(&ACCESS_FBINFO(altout.lock)); + ACCESS_FBINFO(altout.device) = md; + ACCESS_FBINFO(altout.output) = &maven_altout; + up_write(&ACCESS_FBINFO(altout.lock)); + ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY; + return 0; +} + +static int maven_shutdown_client(struct i2c_client* clnt) { + struct maven_data* md = clnt->data; + + if (md->primary_head) { + md->primary_head->output.all &= ~MATROXFB_OUTPUT_CONN_SECONDARY; + md->primary_head->output.ph &= ~MATROXFB_OUTPUT_CONN_SECONDARY; + md->primary_head->output.sh &= ~MATROXFB_OUTPUT_CONN_SECONDARY; + down_write(&md->primary_head->altout.lock); + md->primary_head->altout.device = NULL; + md->primary_head->altout.output = NULL; + up_write(&md->primary_head->altout.lock); + md->primary_head = NULL; + } + return 0; +} + +static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { MAVEN_I2CID, MAVEN_I2CID, I2C_CLIENT_END }; +I2C_CLIENT_INSMOD; + +static void maven_inc_use(struct i2c_client* clnt) { + MOD_INC_USE_COUNT; +} + +static void maven_dec_use(struct i2c_client* clnt) { + MOD_DEC_USE_COUNT; +} + +static struct i2c_driver maven_driver; + +static int maven_detect_client(struct i2c_adapter* adapter, int address, unsigned short flags, + int kind) { + int err = 0; + struct i2c_client* new_client; + struct maven_data* data; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_PROTOCOL_MANGLING)) + goto ERROR0; + if (!(new_client = (struct i2c_client*)kmalloc(sizeof(struct i2c_client) + sizeof(struct maven_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR0; + } + data = (struct maven_data*)(new_client + 1); + new_client->data = data; + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &maven_driver; + new_client->flags = 0; + if (kind < 0) { + ; + } + strcpy(new_client->name, "maven client"); + if ((err = i2c_attach_client(new_client))) + goto ERROR3; + err = maven_init_client(new_client); + if (err) + goto ERROR4; + return 0; +ERROR4:; + i2c_detach_client(new_client); +ERROR3:; + kfree(new_client); +ERROR0:; + return err; +} + +static int maven_attach_adapter(struct i2c_adapter* adapter) { + if (adapter->id == (I2C_ALGO_BIT | I2C_HW_B_G400)) + return i2c_probe(adapter, &addr_data, &maven_detect_client); + return 0; +} + +static int maven_detach_client(struct i2c_client* client) { + int err; + + if ((err = i2c_detach_client(client))) { + printk(KERN_ERR "maven: Cannot deregister client\n"); + return err; + } + maven_shutdown_client(client); + kfree(client); + return 0; +} + +static int maven_command(struct i2c_client* client, unsigned int cmd, void* arg) { + return -ENOIOCTLCMD; /* or -EINVAL, depends on who will call this */ +} + +static int maven_driver_registered = 0; + +static struct i2c_driver maven_driver={ + "maven", + I2C_DRIVERID_MGATVO, + I2C_DF_NOTIFY, + maven_attach_adapter, + maven_detach_client, + maven_command, + maven_inc_use, + maven_dec_use +}; + +/* ************************** */ + +static int matroxfb_maven_init(void) { + int err; + + err = i2c_add_driver(&maven_driver); + if (err) { + printk(KERN_ERR "maven: Maven driver failed to register (%d).\n", err); + return err; + } + maven_driver_registered = 1; + return 0; +} + +static void matroxfb_maven_exit(void) { + if (maven_driver_registered) + i2c_del_driver(&maven_driver); +} + +MODULE_AUTHOR("(c) 1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver"); +module_init(matroxfb_maven_init); +module_exit(matroxfb_maven_exit); +/* we do not have __setup() yet */ diff --git a/drivers/video/matrox/matroxfb_maven.h b/drivers/video/matrox/matroxfb_maven.h new file mode 100644 index 000000000..cbf340e0a --- /dev/null +++ b/drivers/video/matrox/matroxfb_maven.h @@ -0,0 +1,23 @@ +#ifndef __MATROXFB_MAVEN_H__ +#define __MATROXFB_MAVEN_H__ + +#include <linux/ioctl.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#include "matroxfb_base.h" + +struct i2c_bit_adapter { + struct i2c_adapter adapter; + int initialized; + struct i2c_algo_bit_data bac; +}; + +struct matroxfb_dh_maven_info { + struct matrox_fb_info* primary_dev; + + struct i2c_bit_adapter maven; + struct i2c_bit_adapter ddc1; + struct i2c_bit_adapter ddc2; +}; + +#endif /* __MATROXFB_MAVEN_H__ */ diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c new file mode 100644 index 000000000..126ab9b66 --- /dev/null +++ b/drivers/video/matrox/matroxfb_misc.c @@ -0,0 +1,660 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 + * + * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Version: 1.21 2000/01/09 + * + * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> + * + * Contributors: "menion?" <menion@mindless.com> + * Betatesting, fixes, ideas + * + * "Kurt Garloff" <garloff@kg1.ping.de> + * Betatesting, fixes, ideas, videomodes, videomodes timmings + * + * "Tom Rini" <trini@kernel.crashing.org> + * MTRR stuff, PPC cleanups, betatesting, fixes, ideas + * + * "Bibek Sahu" <scorpio@dodds.net> + * Access device through readb|w|l and write b|w|l + * Extensive debugging stuff + * + * "Daniel Haun" <haund@usa.net> + * Testing, hardware cursor fixes + * + * "Scott Wood" <sawst46+@pitt.edu> + * Fixes + * + * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> + * Betatesting + * + * "Kelly French" <targon@hazmat.com> + * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> + * Betatesting, bug reporting + * + * "Pablo Bianucci" <pbian@pccp.com.ar> + * Fixes, ideas, betatesting + * + * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> + * Fixes, enhandcements, ideas, betatesting + * + * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> + * PPC betatesting, PPC support, backward compatibility + * + * "Paul Womar" <Paul@pwomar.demon.co.uk> + * "Owen Waller" <O.Waller@ee.qub.ac.uk> + * PPC betatesting + * + * "Thomas Pornin" <pornin@bolet.ens.fr> + * Alpha betatesting + * + * "Pieter van Leuven" <pvl@iae.nl> + * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> + * G100 testing + * + * "H. Peter Arvin" <hpa@transmeta.com> + * Ideas + * + * "Cort Dougan" <cort@cs.nmt.edu> + * CHRP fixes and PReP cleanup + * + * "Mark Vojkovich" <mvojkovi@ucsd.edu> + * G400 support + * + * (following author is not in any relation with this code, but his code + * is included in this driver) + * + * Based on framebuffer driver for VBE 2.0 compliant graphic boards + * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> + * + * (following author is not in any relation with this code, but his ideas + * were used when writting this driver) + * + * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> + * + */ + +/* make checkconfig does not check includes for this... */ +#include <linux/config.h> + +#include "matroxfb_misc.h" +#include <linux/interrupt.h> +#include <linux/matroxfb.h> + +void matroxfb_createcursorshape(WPMINFO struct display* p, int vmode) { + unsigned int h; + unsigned int cu, cd; + + h = fontheight(p); + + if (vmode & FB_VMODE_DOUBLE) + h *= 2; + cd = h; + if (cd >= 10) + cd--; + switch (ACCESS_FBINFO(cursor.type) = (p->conp->vc_cursor_type & CUR_HWMASK)) { + case CUR_NONE: + cu = cd; + break; + case CUR_UNDERLINE: + cu = cd - 2; + break; + case CUR_LOWER_THIRD: + cu = (h * 2) / 3; + break; + case CUR_LOWER_HALF: + cu = h / 2; + break; + case CUR_TWO_THIRDS: + cu = h / 3; + break; + case CUR_BLOCK: + default: + cu = 0; + cd = h; + break; + } + ACCESS_FBINFO(cursor.w) = fontwidth(p); + ACCESS_FBINFO(cursor.u) = cu; + ACCESS_FBINFO(cursor.d) = cd; +} + +void matroxfb_DAC_out(CPMINFO int reg, int val) { + DBG_REG("outDAC"); + mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); + mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val); +} + +int matroxfb_DAC_in(CPMINFO int reg) { + DBG_REG("inDAC"); + mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); + return mga_inb(M_RAMDAC_BASE+M_X_DATAREG); +} + +void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) { + unsigned int pixclock = var->pixclock; + + DBG("var2my") + + if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ + mt->pixclock = 1000000000 / pixclock; + if (mt->pixclock < 1) mt->pixclock = 1; + mt->dblscan = var->vmode & FB_VMODE_DOUBLE; + mt->interlaced = var->vmode & FB_VMODE_INTERLACED; + mt->HDisplay = var->xres; + mt->HSyncStart = mt->HDisplay + var->right_margin; + mt->HSyncEnd = mt->HSyncStart + var->hsync_len; + mt->HTotal = mt->HSyncEnd + var->left_margin; + mt->VDisplay = var->yres; + mt->VSyncStart = mt->VDisplay + var->lower_margin; + mt->VSyncEnd = mt->VSyncStart + var->vsync_len; + mt->VTotal = mt->VSyncEnd + var->upper_margin; + mt->sync = var->sync; +} + +int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax, + unsigned int* in, unsigned int* feed, unsigned int* post) { + unsigned int bestdiff = ~0; + unsigned int bestvco = 0; + unsigned int fxtal = pll->ref_freq; + unsigned int fwant; + unsigned int p; + + DBG("PLL_calcclock") + + fwant = freq; + +#ifdef DEBUG + printk(KERN_ERR "post_shift_max: %d\n", pll->post_shift_max); + printk(KERN_ERR "ref_freq: %d\n", pll->ref_freq); + printk(KERN_ERR "freq: %d\n", freq); + printk(KERN_ERR "vco_freq_min: %d\n", pll->vco_freq_min); + printk(KERN_ERR "in_div_min: %d\n", pll->in_div_min); + printk(KERN_ERR "in_div_max: %d\n", pll->in_div_max); + printk(KERN_ERR "feed_div_min: %d\n", pll->feed_div_min); + printk(KERN_ERR "feed_div_max: %d\n", pll->feed_div_max); + printk(KERN_ERR "fmax: %d\n", fmax); +#endif + for (p = 1; p <= pll->post_shift_max; p++) { + if (fwant * 2 > fmax) + break; + fwant *= 2; + } + if (fwant < pll->vco_freq_min) fwant = pll->vco_freq_min; + if (fwant > fmax) fwant = fmax; + for (; p-- > 0; fwant >>= 1, bestdiff >>= 1) { + unsigned int m; + + if (fwant < pll->vco_freq_min) break; + for (m = pll->in_div_min; m <= pll->in_div_max; m++) { + unsigned int diff, fvco; + unsigned int n; + + n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1; + if (n > pll->feed_div_max) + break; + if (n < pll->feed_div_min) + n = pll->feed_div_min; + fvco = (fxtal * (n + 1)) / (m + 1); + if (fvco < fwant) + diff = fwant - fvco; + else + diff = fvco - fwant; + if (diff < bestdiff) { + bestdiff = diff; + *post = p; + *in = m; + *feed = n; + bestvco = fvco; + } + } + } + dprintk(KERN_ERR "clk: %02X %02X %02X %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant); + return bestvco; +} + +int matroxfb_vgaHWinit(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) { + unsigned int hd, hs, he, hbe, ht; + unsigned int vd, vs, ve, vt; + unsigned int wd; + unsigned int divider; + int i; + int text = p->type == FB_TYPE_TEXT; + int fwidth; + + if (text) { + fwidth = fontwidth(p); + if (!fwidth) fwidth = 8; + } else + fwidth = 8; + + DBG("vgaHWinit") + + hw->SEQ[0] = 0x00; + if (fwidth == 9) + hw->SEQ[1] = 0x00; + else + hw->SEQ[1] = 0x01; /* or 0x09 */ + hw->SEQ[2] = 0x0F; /* bitplanes */ + hw->SEQ[3] = 0x00; + if (text) + hw->SEQ[4] = 0x02; + else + hw->SEQ[4] = 0x0E; + /* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millennium code... Hope that by MGA1064 too */ + if (m->dblscan) { + m->VTotal <<= 1; + m->VDisplay <<= 1; + m->VSyncStart <<= 1; + m->VSyncEnd <<= 1; + } + if (m->interlaced) { + m->VTotal >>= 1; + m->VDisplay >>= 1; + m->VSyncStart >>= 1; + m->VSyncEnd >>= 1; + } + + /* GCTL is ignored when not using 0xA0000 aperture */ + hw->GCTL[0] = 0x00; + hw->GCTL[1] = 0x00; + hw->GCTL[2] = 0x00; + hw->GCTL[3] = 0x00; + hw->GCTL[4] = 0x00; + if (text) { + hw->GCTL[5] = 0x10; + hw->GCTL[6] = 0x02; + } else { + hw->GCTL[5] = 0x40; + hw->GCTL[6] = 0x05; + } + hw->GCTL[7] = 0x0F; + hw->GCTL[8] = 0xFF; + + /* Whole ATTR is ignored in PowerGraphics mode */ + for (i = 0; i < 16; i++) + hw->ATTR[i] = i; + if (text) { + hw->ATTR[16] = 0x04; + } else { + hw->ATTR[16] = 0x41; + } + hw->ATTR[17] = 0xFF; + hw->ATTR[18] = 0x0F; + if (fwidth == 9) + hw->ATTR[19] = 0x08; + else + hw->ATTR[19] = 0x00; + hw->ATTR[20] = 0x00; + + if (text) { + hd = m->HDisplay / fwidth; + hs = m->HSyncStart / fwidth; + he = m->HSyncEnd / fwidth; + ht = m->HTotal / fwidth; + divider = 8; + } else { + hd = m->HDisplay >> 3; + hs = m->HSyncStart >> 3; + he = m->HSyncEnd >> 3; + ht = m->HTotal >> 3; + /* standard timmings are in 8pixels, but for interleaved we cannot */ + /* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */ + /* using 16 or more pixels per unit can save us */ + divider = ACCESS_FBINFO(curr.final_bppShift); + } + while (divider & 3) { + hd >>= 1; + hs >>= 1; + he >>= 1; + ht >>= 1; + divider <<= 1; + } + divider = divider / 4; + /* divider can be from 1 to 8 */ + while (divider > 8) { + hd <<= 1; + hs <<= 1; + he <<= 1; + ht <<= 1; + divider >>= 1; + } + hd = hd - 1; + hs = hs - 1; + he = he - 1; + ht = ht - 1; + vd = m->VDisplay - 1; + vs = m->VSyncStart - 1; + ve = m->VSyncEnd - 1; + vt = m->VTotal - 2; + /* G200 cannot work with (ht & 7) == 6 */ + if (((ht & 0x07) == 0x06) || ((ht & 0x0F) == 0x04)) + ht++; + if (text) { + hbe = ht - 1; + wd = p->var.xres_virtual / (fwidth * 2); + } else { + hbe = ht; + wd = p->var.xres_virtual * ACCESS_FBINFO(curr.final_bppShift) / 64; + } + + hw->CRTCEXT[0] = 0; + hw->CRTCEXT[5] = 0; + if (m->interlaced) { + hw->CRTCEXT[0] = 0x80; + hw->CRTCEXT[5] = (hs + he - ht) >> 1; + if (!m->dblscan) + wd <<= 1; + vt &= ~1; + } + hw->CRTCEXT[0] |= (wd & 0x300) >> 4; + hw->CRTCEXT[1] = (((ht - 4) & 0x100) >> 8) | + ((hd & 0x100) >> 7) | /* blanking */ + ((hs & 0x100) >> 6) | /* sync start */ + (hbe & 0x040); /* end hor. blanking */ + if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) + hw->CRTCEXT[1] |= 0x88; /* enable horizontal and vertical vidrst */ + hw->CRTCEXT[2] = ((vt & 0xC00) >> 10) | + ((vd & 0x400) >> 8) | /* disp end */ + ((vd & 0xC00) >> 7) | /* vblanking start */ + ((vs & 0xC00) >> 5); + if (text) + hw->CRTCEXT[3] = 0x00; + else + hw->CRTCEXT[3] = (divider - 1) | 0x80; + hw->CRTCEXT[4] = 0; + + hw->CRTC[0] = ht-4; + hw->CRTC[1] = hd; + hw->CRTC[2] = hd; + hw->CRTC[3] = (hbe & 0x1F) | 0x80; + hw->CRTC[4] = hs; + hw->CRTC[5] = ((hbe & 0x20) << 2) | (he & 0x1F); + if (text) + hw->CRTC[5] |= 0x60; /* delay sync for 3 clocks (to same picture position on MGA and VGA) */ + hw->CRTC[6] = vt & 0xFF; + hw->CRTC[7] = ((vt & 0x100) >> 8) | + ((vd & 0x100) >> 7) | + ((vs & 0x100) >> 6) | + ((vd & 0x100) >> 5) | + 0x10 | + ((vt & 0x200) >> 4) | + ((vd & 0x200) >> 3) | + ((vs & 0x200) >> 2); + hw->CRTC[8] = 0x00; + hw->CRTC[9] = ((vd & 0x200) >> 4) | 0x40; + if (text) + hw->CRTC[9] |= fontheight(p) - 1; + if (m->dblscan && !m->interlaced) + hw->CRTC[9] |= 0x80; + for (i = 10; i < 16; i++) + hw->CRTC[i] = 0x00; + hw->CRTC[16] = vs /* & 0xFF */; + hw->CRTC[17] = (ve & 0x0F) | 0x20; + hw->CRTC[18] = vd /* & 0xFF */; + hw->CRTC[19] = wd /* & 0xFF */; + hw->CRTC[20] = 0x00; + hw->CRTC[21] = vd /* & 0xFF */; + hw->CRTC[22] = (vt + 1) /* & 0xFF */; + if (text) { + if (ACCESS_FBINFO(devflags.textmode) == 1) + hw->CRTC[23] = 0xC3; + else + hw->CRTC[23] = 0xA3; + if (ACCESS_FBINFO(devflags.textmode) == 4) + hw->CRTC[20] = 0x5F; + else + hw->CRTC[20] = 0x1F; + } else + hw->CRTC[23] = 0xC3; + hw->CRTC[24] = 0xFF; + return 0; +}; + +void matroxfb_vgaHWrestore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw) { + int i; + CRITFLAGS + + DBG("vgaHWrestore") + + dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg); + dprintk(KERN_INFO "SEQ regs: "); + for (i = 0; i < 5; i++) + dprintk("%02X:", hw->SEQ[i]); + dprintk("\n"); + dprintk(KERN_INFO "GDC regs: "); + for (i = 0; i < 9; i++) + dprintk("%02X:", hw->GCTL[i]); + dprintk("\n"); + dprintk(KERN_INFO "CRTC regs: "); + for (i = 0; i < 25; i++) + dprintk("%02X:", hw->CRTC[i]); + dprintk("\n"); + dprintk(KERN_INFO "ATTR regs: "); + for (i = 0; i < 21; i++) + dprintk("%02X:", hw->ATTR[i]); + dprintk("\n"); + + CRITBEGIN + + mga_inb(M_ATTR_RESET); + mga_outb(M_ATTR_INDEX, 0); + mga_outb(M_MISC_REG, hw->MiscOutReg); + for (i = 1; i < 5; i++) + mga_setr(M_SEQ_INDEX, i, hw->SEQ[i]); + mga_setr(M_CRTC_INDEX, 17, hw->CRTC[17] & 0x7F); + for (i = 0; i < 25; i++) + mga_setr(M_CRTC_INDEX, i, hw->CRTC[i]); + for (i = 0; i < 9; i++) + mga_setr(M_GRAPHICS_INDEX, i, hw->GCTL[i]); + for (i = 0; i < 21; i++) { + mga_inb(M_ATTR_RESET); + mga_outb(M_ATTR_INDEX, i); + mga_outb(M_ATTR_INDEX, hw->ATTR[i]); + } + mga_outb(M_PALETTE_MASK, 0xFF); + mga_outb(M_DAC_REG, 0x00); + for (i = 0; i < 768; i++) + mga_outb(M_DAC_VAL, hw->DACpal[i]); + mga_inb(M_ATTR_RESET); + mga_outb(M_ATTR_INDEX, 0x20); + + CRITEND +} + +void matroxfb_fastfont_init(struct matrox_fb_info* minfo){ + unsigned int size; + + size = ACCESS_FBINFO(fastfont.size); + ACCESS_FBINFO(fastfont.size) = 0; + if (size) { + unsigned int end = ACCESS_FBINFO(video.len_usable); + + if (size < end) { + unsigned int start; + + start = (end - size) & PAGE_MASK; + if (start >= 0x00100000) { + ACCESS_FBINFO(video.len_usable) = start; + ACCESS_FBINFO(fastfont.mgabase) = start * 8; + ACCESS_FBINFO(fastfont.vbase) = ACCESS_FBINFO(video.vbase); + vaddr_add(&ACCESS_FBINFO(fastfont.vbase), start); + ACCESS_FBINFO(fastfont.size) = end - start; + } + } + } +} + +#ifndef FNTCHARCNT +#define FNTCHARCNT(fd) (((int *)(fd))[-3]) +#endif + +int matrox_text_loadfont(WPMINFO struct display* p) { + unsigned int fsize; + unsigned int width; + vaddr_t dst; + unsigned int i; + u_int8_t* font; + CRITFLAGS + + if (!p || !p->fontdata) + return 0; + width = fontwidth(p); + fsize = p->userfont?FNTCHARCNT(p->fontdata):256; + + dst = ACCESS_FBINFO(video.vbase); + i = 2; + font = (u_int8_t*)p->fontdata; + + CRITBEGIN + + mga_setr(M_SEQ_INDEX, 0x02, 0x04); + while (fsize--) { + int l; + + for (l = 0; l < fontheight(p); l++) { + mga_writeb(dst, i, *font++); + if (fontwidth(p) > 8) font++; + i += ACCESS_FBINFO(devflags.vgastep); + } + i += (32 - fontheight(p)) * ACCESS_FBINFO(devflags.vgastep); + } + mga_setr(M_SEQ_INDEX, 0x02, 0x03); + + CRITEND + + return 1; +} + +int matroxfb_fastfont_tryset(WPMINFO struct display* p) { + unsigned int fsize; + unsigned int width; + CRITFLAGS + + if (!p || !p->fontdata) + return 0; + width = fontwidth(p); + if (width > 32) + return 0; + fsize = (p->userfont?FNTCHARCNT(p->fontdata):256) * fontheight(p); + if (((fsize * width + 31) / 32) * 4 > ACCESS_FBINFO(fastfont.size)) + return 0; + + CRITBEGIN + + mga_outl(M_OPMODE, M_OPMODE_8BPP); + if (width <= 8) { + if (width == 8) + mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize); + else { + vaddr_t dst; + unsigned int i; + u_int8_t* font; + u_int32_t mask, valid, reg; + + dst = ACCESS_FBINFO(fastfont.vbase); + font = (u_int8_t*)p->fontdata; + mask = ~0 << (8 - width); + valid = 0; + reg = 0; + i = 0; + while (fsize--) { + reg |= (*font++ & mask) << (8 - valid); + valid += width; + if (valid >= 8) { + mga_writeb(dst, i++, reg >> 8); + reg = reg << 8; + valid -= 8; + } + } + if (valid) + mga_writeb(dst, i, reg >> 8); + } + } else if (width <= 16) { + if (width == 16) + mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize*2); + else { + vaddr_t dst; + u_int16_t* font; + u_int32_t mask, valid, reg; + unsigned int i; + + dst = ACCESS_FBINFO(fastfont.vbase); + font = (u_int16_t*)p->fontdata; + mask = ~0 << (16 - width); + valid = 0; + reg = 0; + i = 0; + while (fsize--) { + reg |= (ntohs(*font++) & mask) << (16 - valid); + valid += width; + if (valid >= 16) { + mga_writew(dst, i, htons(reg >> 16)); + i += 2; + reg = reg << 16; + valid -= 16; + } + } + if (valid) + mga_writew(dst, i, htons(reg >> 16)); + } + } else { + if (width == 32) + mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize*4); + else { + vaddr_t dst; + u_int32_t* font; + u_int32_t mask, valid, reg; + unsigned int i; + + dst = ACCESS_FBINFO(fastfont.vbase); + font = (u_int32_t*)p->fontdata; + mask = ~0 << (32 - width); + valid = 0; + reg = 0; + i = 0; + while (fsize--) { + reg |= (ntohl(*font) & mask) >> valid; + valid += width; + if (valid >= 32) { + mga_writel(dst, i, htonl(reg)); + i += 4; + valid -= 32; + if (valid) + reg = (ntohl(*font) & mask) << (width - valid); + else + reg = 0; + } + font++; + } + if (valid) + mga_writel(dst, i, htonl(reg)); + } + } + mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); + + CRITEND + + return 1; +} + +EXPORT_SYMBOL(matroxfb_DAC_in); +EXPORT_SYMBOL(matroxfb_DAC_out); +EXPORT_SYMBOL(matroxfb_var2my); +EXPORT_SYMBOL(matroxfb_PLL_calcclock); +#ifndef CONFIG_FB_MATROX_MULTIHEAD +struct matrox_fb_info matroxfb_global_mxinfo; +EXPORT_SYMBOL(matroxfb_global_mxinfo); +#endif +EXPORT_SYMBOL(matrox_text_loadfont); /* for matroxfb_accel */ +EXPORT_SYMBOL(matroxfb_createcursorshape); /* accel, DAC1064, Ti3026 */ +EXPORT_SYMBOL(matroxfb_fastfont_tryset); /* accel */ +EXPORT_SYMBOL(matroxfb_fastfont_init); /* DAC1064, Ti3026 */ +EXPORT_SYMBOL(matroxfb_vgaHWinit); /* DAC1064, Ti3026 */ +EXPORT_SYMBOL(matroxfb_vgaHWrestore); /* DAC1064, Ti3026 */ +#ifdef MATROXFB_USE_SPINLOCK +spinlock_t matroxfb_spinlock = SPIN_LOCK_UNLOCKED; +EXPORT_SYMBOL(matroxfb_spinlock); +#endif diff --git a/drivers/video/matrox/matroxfb_misc.h b/drivers/video/matrox/matroxfb_misc.h new file mode 100644 index 000000000..b88ccd8ca --- /dev/null +++ b/drivers/video/matrox/matroxfb_misc.h @@ -0,0 +1,21 @@ +#ifndef __MATROXFB_MISC_H__ +#define __MATROXFB_MISC_H__ + +#include "matroxfb_base.h" + +/* also for modules */ +int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax, + unsigned int* in, unsigned int* feed, unsigned int* post); +static inline int PLL_calcclock(CPMINFO unsigned int freq, unsigned int fmax, + unsigned int* in, unsigned int* feed, unsigned int* post) { + return matroxfb_PLL_calcclock(&ACCESS_FBINFO(features.pll), freq, fmax, in, feed, post); +} + +void matroxfb_createcursorshape(WPMINFO struct display* p, int vmode); +int matroxfb_vgaHWinit(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p); +void matroxfb_vgaHWrestore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw); +void matroxfb_fastfont_init(struct matrox_fb_info* minfo); +int matrox_text_loadfont(WPMINFO struct display* p); +int matroxfb_fastfont_tryset(WPMINFO struct display* p); + +#endif /* __MATROXFB_MISC_H__ */ diff --git a/drivers/video/matroxfb.c b/drivers/video/matroxfb.c deleted file mode 100644 index 8fbff9bc4..000000000 --- a/drivers/video/matroxfb.c +++ /dev/null @@ -1,6107 +0,0 @@ -/* - * - * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 - * - * (c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz> - * - * Version: 1.19 1999/08/05 - * - * MTRR stuff: 1998 Tom Rini <tmrini@ntplx.net> - * - * Contributors: "menion?" <menion@mindless.com> - * Betatesting, fixes, ideas - * - * "Kurt Garloff" <garloff@kg1.ping.de> - * Betatesting, fixes, ideas, videomodes, videomodes timmings - * - * "Tom Rini" <trini@disparity.net> - * MTRR stuff, PPC cleanups, betatesting, fixes, ideas - * - * "Bibek Sahu" <scorpio@dodds.net> - * Access device through readb|w|l and write b|w|l - * Extensive debugging stuff - * - * "Daniel Haun" <haund@usa.net> - * Testing, hardware cursor fixes - * - * "Scott Wood" <sawst46+@pitt.edu> - * Fixes - * - * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> - * Betatesting - * - * "Kelly French" <targon@hazmat.com> - * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> - * Betatesting, bug reporting - * - * "Pablo Bianucci" <pbian@pccp.com.ar> - * Fixes, ideas, betatesting - * - * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> - * Fixes, enhandcements, ideas, betatesting - * - * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> - * PPC betatesting, PPC support, backward compatibility - * - * "Paul Womar" <Paul@pwomar.demon.co.uk> - * "Owen Waller" <O.Waller@ee.qub.ac.uk> - * PPC betatesting - * - * "Thomas Pornin" <pornin@bolet.ens.fr> - * Alpha betatesting - * - * "Pieter van Leuven" <pvl@iae.nl> - * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> - * G100 testing - * - * "H. Peter Arvin" <hpa@transmeta.com> - * Ideas - * - * "Cort Dougan" <cort@cs.nmt.edu> - * CHRP fixes and PReP cleanup - * - * "Mark Vojkovich" <mvojkovi@ucsd.edu> - * G400 support - * - * (following author is not in any relation with this code, but his code - * is included in this driver) - * - * Based on framebuffer driver for VBE 2.0 compliant graphic boards - * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> - * - * (following author is not in any relation with this code, but his ideas - * were used when writting this driver) - * - * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> - * - */ - -/* general, but fairly heavy, debugging */ -#undef MATROXFB_DEBUG - -/* heavy debugging: */ -/* -- logs putc[s], so everytime a char is displayed, it's logged */ -#undef MATROXFB_DEBUG_HEAVY - -/* This one _could_ cause infinite loops */ -/* It _does_ cause lots and lots of messages during idle loops */ -#undef MATROXFB_DEBUG_LOOP - -/* Debug register calls, too? */ -#undef MATROXFB_DEBUG_REG - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/tty.h> -#include <linux/malloc.h> -#include <linux/delay.h> -#include <linux/fb.h> -#include <linux/console.h> -#include <linux/selection.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/pci.h> -#include <linux/spinlock.h> - -#include <asm/io.h> -#include <asm/unaligned.h> -#ifdef CONFIG_MTRR -#include <asm/mtrr.h> -#endif - -#include <video/fbcon.h> -#include <video/fbcon-cfb4.h> -#include <video/fbcon-cfb8.h> -#include <video/fbcon-cfb16.h> -#include <video/fbcon-cfb24.h> -#include <video/fbcon-cfb32.h> - -#if defined(CONFIG_FB_OF) -#if defined(CONFIG_FB_COMPAT_XPMAC) -#include <asm/vc_ioctl.h> -#endif -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#include <video/macmodes.h> -#endif - -/* always compile support for 32MB... It cost almost nothing */ -#define CONFIG_FB_MATROX_32MB - -#define FBCON_HAS_VGATEXT - -#ifdef MATROXFB_DEBUG - -#define DEBUG -#define DBG(x) printk(KERN_DEBUG "matroxfb: %s\n", (x)); - -#ifdef MATROXFB_DEBUG_HEAVY -#define DBG_HEAVY(x) DBG(x) -#else /* MATROXFB_DEBUG_HEAVY */ -#define DBG_HEAVY(x) /* DBG_HEAVY */ -#endif /* MATROXFB_DEBUG_HEAVY */ - -#ifdef MATROXFB_DEBUG_LOOP -#define DBG_LOOP(x) DBG(x) -#else /* MATROXFB_DEBUG_LOOP */ -#define DBG_LOOP(x) /* DBG_LOOP */ -#endif /* MATROXFB_DEBUG_LOOP */ - -#ifdef MATROXFB_DEBUG_REG -#define DBG_REG(x) DBG(x) -#else /* MATROXFB_DEBUG_REG */ -#define DBG_REG(x) /* DBG_REG */ -#endif /* MATROXFB_DEBUG_REG */ - -#else /* MATROXFB_DEBUG */ - -#define DBG(x) /* DBG */ -#define DBG_HEAVY(x) /* DBG_HEAVY */ -#define DBG_REG(x) /* DBG_REG */ -#define DBG_LOOP(x) /* DBG_LOOP */ - -#endif /* MATROXFB_DEBUG */ - -#ifndef __i386__ -#ifndef ioremap_nocache -#define ioremap_nocache(X,Y) ioremap(X,Y) -#endif -#endif - -#if defined(__alpha__) || defined(__m68k__) -#define READx_WORKS -#define MEMCPYTOIO_WORKS -#else -#define READx_FAILS -/* recheck __ppc__, maybe that __ppc__ needs MEMCPYTOIO_WRITEL */ -/* I benchmarked PII/350MHz with G200... MEMCPY, MEMCPYTOIO and WRITEL are on same speed ( <2% diff) */ -/* so that means that G200 speed (or AGP speed?) is our limit... I do not have benchmark to test, how */ -/* much of PCI bandwidth is used during transfers... */ -#if defined(__i386__) -#define MEMCPYTOIO_MEMCPY -#else -#define MEMCPYTOIO_WRITEL -#endif -#endif - -#ifdef __sparc__ -#error "Sorry, I have no idea how to do this on sparc... There is mapioaddr... With bus_type parameter..." -#endif - -#if defined(__m68k__) -#define MAP_BUSTOVIRT -#else -#define MAP_IOREMAP -#endif - -#ifdef DEBUG -#define dprintk(X...) printk(X) -#else -#define dprintk(X...) -#endif - -#ifndef PCI_SS_VENDOR_ID_SIEMENS_NIXDORF -#define PCI_SS_VENDOR_ID_SIEMENS_NIXDORF 0x110A -#endif -#ifndef PCI_SS_VENDOR_ID_MATROX -#define PCI_SS_VENDOR_ID_MATROX PCI_VENDOR_ID_MATROX -#endif -#ifndef PCI_DEVICE_ID_MATROX_G200_PCI -#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520 -#endif -#ifndef PCI_DEVICE_ID_MATROX_G200_AGP -#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521 -#endif -#ifndef PCI_DEVICE_ID_MATROX_G100 -#define PCI_DEVICE_ID_MATROX_G100 0x1000 -#endif -#ifndef PCI_DEVICE_ID_MATROX_G100_AGP -#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001 -#endif -#ifndef PCI_DEVICE_ID_MATROX_G400_AGP -#define PCI_DEVICE_ID_MATROX_G400_AGP 0x0525 -#endif - -#ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP -#define PCI_SS_ID_MATROX_GENERIC 0xFF00 -#define PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP 0xFF01 -#define PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP 0xFF02 -#define PCI_SS_ID_MATROX_MILLENIUM_G200_AGP 0xFF03 -#define PCI_SS_ID_MATROX_MARVEL_G200_AGP 0xFF04 -#define PCI_SS_ID_MATROX_MGA_G100_PCI 0xFF05 -#define PCI_SS_ID_MATROX_MGA_G100_AGP 0x1001 -#define PCI_SS_ID_SIEMENS_MGA_G100_AGP 0x001E /* 30 */ -#define PCI_SS_ID_SIEMENS_MGA_G200_AGP 0x0032 /* 50 */ -#endif - -#define MX_VISUAL_TRUECOLOR FB_VISUAL_DIRECTCOLOR -#define MX_VISUAL_DIRECTCOLOR FB_VISUAL_TRUECOLOR -#define MX_VISUAL_PSEUDOCOLOR FB_VISUAL_PSEUDOCOLOR - -#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) - -/* G100, G200 and Mystique have (almost) same DAC */ -#undef NEED_DAC1064 -#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G100) -#define NEED_DAC1064 1 -#endif - -typedef struct { - u_int8_t* vaddr; -} vaddr_t; - -#ifdef READx_WORKS -static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) { - return readb(va.vaddr + offs); -} - -static inline unsigned int mga_readw(vaddr_t va, unsigned int offs) { - return readw(va.vaddr + offs); -} - -static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) { - return readl(va.vaddr + offs); -} - -static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) { - writeb(value, va.vaddr + offs); -} - -static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) { - writew(value, va.vaddr + offs); -} - -static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) { - writel(value, va.vaddr + offs); -} -#else -static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) { - return *(volatile u_int8_t*)(va.vaddr + offs); -} - -static inline unsigned int mga_readw(vaddr_t va, unsigned int offs) { - return *(volatile u_int16_t*)(va.vaddr + offs); -} - -static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) { - return *(volatile u_int32_t*)(va.vaddr + offs); -} - -static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) { - *(volatile u_int8_t*)(va.vaddr + offs) = value; -} - -static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) { - *(volatile u_int16_t*)(va.vaddr + offs) = value; -} - -static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) { - *(volatile u_int32_t*)(va.vaddr + offs) = value; -} -#endif - -static inline void mga_memcpy_toio(vaddr_t va, unsigned int offs, const void* src, int len) { -#ifdef MEMCPYTOIO_WORKS - memcpy_toio(va.vaddr + offs, src, len); -#elif defined(MEMCPYTOIO_WRITEL) -#define srcd ((const u_int32_t*)src) - if (offs & 3) { - while (len >= 4) { - mga_writel(va, offs, get_unaligned(srcd++)); - offs += 4; - len -= 4; - } - } else { - while (len >= 4) { - mga_writel(va, offs, *srcd++); - offs += 4; - len -= 4; - } - } -#undef srcd - if (len) { - u_int32_t tmp; - - memcpy(&tmp, src, len); - mga_writel(va, offs, tmp); - } -#elif defined(MEMCPYTOIO_MEMCPY) - memcpy(va.vaddr + offs, src, len); -#else -#error "Sorry, do not know how to write block of data to device" -#endif -} - -static inline void vaddr_add(vaddr_t* va, unsigned long offs) { - va->vaddr += offs; -} - -static inline void* vaddr_va(vaddr_t va) { - return va.vaddr; -} - -#define MGA_IOREMAP_NORMAL 0 -#define MGA_IOREMAP_NOCACHE 1 - -#define MGA_IOREMAP_FB MGA_IOREMAP_NOCACHE -#define MGA_IOREMAP_MMIO MGA_IOREMAP_NOCACHE -static inline int mga_ioremap(unsigned long phys, unsigned long size, int flags, vaddr_t* virt) { -#ifdef MAP_IOREMAP - if (flags & MGA_IOREMAP_NOCACHE) - virt->vaddr = ioremap_nocache(phys, size); - else - virt->vaddr = ioremap(phys, size); -#else -#ifdef MAP_BUSTOVIRT - virt->vaddr = bus_to_virt(phys); -#else -#error "Your architecture does not have neither ioremap nor bus_to_virt... Giving up" -#endif -#endif - return (virt->vaddr == 0); /* 0, !0... 0, error_code in future */ -} - -static inline void mga_iounmap(vaddr_t va) { -#ifdef MAP_IOREMAP - iounmap(va.vaddr); -#endif -} - -struct matroxfb_par -{ - unsigned int final_bppShift; - unsigned int cmap_len; - struct { - unsigned int bytes; - unsigned int pixels; - unsigned int chunks; - } ydstorg; - void (*putc)(u_int32_t, u_int32_t, struct display*, int, int, int); - void (*putcs)(u_int32_t, u_int32_t, struct display*, const unsigned short*, int, int, int); -}; - -struct my_timming { - unsigned int pixclock; - unsigned int HDisplay; - unsigned int HSyncStart; - unsigned int HSyncEnd; - unsigned int HTotal; - unsigned int VDisplay; - unsigned int VSyncStart; - unsigned int VSyncEnd; - unsigned int VTotal; - unsigned int sync; - int dblscan; - int interlaced; -}; - -struct matrox_fb_info; - -#define MATROX_2MB_WITH_4MB_ADDON - -struct matrox_pll_features { - unsigned int vco_freq_min; - unsigned int ref_freq; - unsigned int feed_div_min; - unsigned int feed_div_max; - unsigned int in_div_min; - unsigned int in_div_max; - unsigned int post_shift_max; -}; - -struct matrox_DAC1064_features { - u_int8_t xvrefctrl; - unsigned int cursorimage; -}; - -struct matrox_accel_features { - int has_cacheflush; -}; - -/* current hardware status */ -struct matrox_hw_state { - u_int32_t MXoptionReg; - unsigned char DACclk[6]; - unsigned char DACreg[64]; - unsigned char MiscOutReg; - unsigned char DACpal[768]; - unsigned char CRTC[25]; - unsigned char CRTCEXT[9]; - unsigned char SEQ[5]; - /* unused for MGA mode, but who knows... */ - unsigned char GCTL[9]; - /* unused for MGA mode, but who knows... */ - unsigned char ATTR[21]; -}; - -struct matrox_accel_data { -#ifdef CONFIG_FB_MATROX_MILLENIUM - unsigned char ramdac_rev; -#endif - u_int32_t m_dwg_rect; - u_int32_t m_opmode; -}; - -#ifdef CONFIG_FB_MATROX_MULTIHEAD -#define ACCESS_FBINFO2(info, x) (info->x) -#define ACCESS_FBINFO(x) ACCESS_FBINFO2(minfo,x) - -#define MINFO minfo - -#define WPMINFO struct matrox_fb_info* minfo, -#define CPMINFO const struct matrox_fb_info* minfo, -#define PMINFO minfo, - -static inline struct matrox_fb_info* mxinfo(const struct display* p) { - return (struct matrox_fb_info*)p->fb_info; -} - -#define PMXINFO(p) mxinfo(p), -#define MINFO_FROM(x) struct matrox_fb_info* minfo = x -#define MINFO_FROM_DISP(x) MINFO_FROM(mxinfo(x)) - -#else - -struct matrox_fb_info global_mxinfo; -struct display global_disp; - -#define ACCESS_FBINFO(x) (global_mxinfo.x) -#define ACCESS_FBINFO2(info, x) (global_mxinfo.x) - -#define MINFO (&global_mxinfo) - -#define WPMINFO -#define CPMINFO -#define PMINFO - -#if 0 -static inline struct matrox_fb_info* mxinfo(const struct display* p) { - return &global_mxinfo; -} -#endif - -#define PMXINFO(p) -#define MINFO_FROM(x) -#define MINFO_FROM_DISP(x) - -#endif - -struct matrox_switch { - int (*preinit)(WPMINFO struct matrox_hw_state*); - void (*reset)(WPMINFO struct matrox_hw_state*); - int (*init)(CPMINFO struct matrox_hw_state*, struct my_timming*, struct display*); - void (*restore)(WPMINFO struct matrox_hw_state*, struct matrox_hw_state*, struct display*); -}; - -struct matrox_fb_info { - /* fb_info must be first */ - struct fb_info fbcon; - - struct matrox_fb_info* next_fb; - - struct matroxfb_par curr; - struct matrox_hw_state hw1; - struct matrox_hw_state hw2; - struct matrox_hw_state* newhw; - struct matrox_hw_state* currenthw; - - struct matrox_accel_data accel; - - struct pci_dev* pcidev; - - struct { - unsigned long base; /* physical */ - vaddr_t vbase; /* CPU view */ - unsigned int len; - unsigned int len_usable; - } video; - - struct { - unsigned long base; /* physical */ - vaddr_t vbase; /* CPU view */ - unsigned int len; - } mmio; - - unsigned int max_pixel_clock; - - struct matrox_switch* hw_switch; - int currcon; - struct display* currcon_display; - - struct { - struct matrox_pll_features pll; - struct matrox_DAC1064_features DAC1064; - struct matrox_accel_features accel; - } features; - struct { - spinlock_t DAC; - } lock; - - int interleave; - int millenium; - int milleniumII; - struct { - int cfb4; - const int* vxres; - int cross4MB; - int text; - int plnwt; - } capable; - struct { - unsigned int size; - unsigned int mgabase; - vaddr_t vbase; - } fastfont; -#ifdef CONFIG_MTRR - struct { - int vram; - int vram_valid; - } mtrr; -#endif - struct { - int precise_width; - int mga_24bpp_fix; - int novga; - int nobios; - int nopciretry; - int noinit; - int inverse; - int hwcursor; - int blink; - int sgram; -#ifdef CONFIG_FB_MATROX_32MB - int support32MB; -#endif - - int accelerator; - int text_type_aux; - int video64bits; - unsigned int vgastep; - unsigned int textmode; - unsigned int textstep; - unsigned int textvram; /* character cells */ - unsigned int ydstorg; /* offset in bytes from video start to usable memory */ - /* 0 except for 6MB Millenium */ - } devflags; - struct display_switch dispsw; - struct { - int x; - int y; - unsigned int w; - unsigned int u; - unsigned int d; - unsigned int type; - int state; - int redraw; - struct timer_list timer; - } cursor; -#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32) - union { -#ifdef FBCON_HAS_CFB16 - u_int16_t cfb16[16]; -#endif -#ifdef FBCON_HAS_CFB24 - u_int32_t cfb24[16]; -#endif -#ifdef FBCON_HAS_CFB32 - u_int32_t cfb32[16]; -#endif - } cmap; -#endif - struct { unsigned red, green, blue, transp; } palette[256]; -#if defined(CONFIG_FB_OF) && defined(CONFIG_FB_COMPAT_XPMAC) - char matrox_name[32]; -#endif -}; - -#if defined(CONFIG_FB_OF) -unsigned char nvram_read_byte(int); -int matrox_of_init(struct device_node *dp); -static int default_vmode = VMODE_NVRAM; -static int default_cmode = CMODE_NVRAM; -#endif - -#define curr_ydstorg(x) ACCESS_FBINFO2(x, curr.ydstorg.pixels) - -#define PCI_OPTION_REG 0x40 -#define PCI_MGA_INDEX 0x44 -#define PCI_MGA_DATA 0x48 - -#define M_DWGCTL 0x1C00 -#define M_MACCESS 0x1C04 -#define M_CTLWTST 0x1C08 - -#define M_PLNWT 0x1C1C - -#define M_BCOL 0x1C20 -#define M_FCOL 0x1C24 - -#define M_SGN 0x1C58 -#define M_LEN 0x1C5C -#define M_AR0 0x1C60 -#define M_AR1 0x1C64 -#define M_AR2 0x1C68 -#define M_AR3 0x1C6C -#define M_AR4 0x1C70 -#define M_AR5 0x1C74 -#define M_AR6 0x1C78 - -#define M_CXBNDRY 0x1C80 -#define M_FXBNDRY 0x1C84 -#define M_YDSTLEN 0x1C88 -#define M_PITCH 0x1C8C -#define M_YDST 0x1C90 -#define M_YDSTORG 0x1C94 -#define M_YTOP 0x1C98 -#define M_YBOT 0x1C9C - -/* mystique only */ -#define M_CACHEFLUSH 0x1FFF - -#define M_EXEC 0x0100 - -#define M_DWG_TRAP 0x04 -#define M_DWG_BITBLT 0x08 -#define M_DWG_ILOAD 0x09 - -#define M_DWG_LINEAR 0x0080 -#define M_DWG_SOLID 0x0800 -#define M_DWG_ARZERO 0x1000 -#define M_DWG_SGNZERO 0x2000 -#define M_DWG_SHIFTZERO 0x4000 - -#define M_DWG_REPLACE 0x000C0000 -#define M_DWG_REPLACE2 (M_DWG_REPLACE | 0x40) -#define M_DWG_XOR 0x00060010 - -#define M_DWG_BFCOL 0x04000000 -#define M_DWG_BMONOWF 0x08000000 - -#define M_DWG_TRANSC 0x40000000 - -#define M_FIFOSTATUS 0x1E10 -#define M_STATUS 0x1E14 - -#define M_IEN 0x1E1C - -#define M_VCOUNT 0x1E20 - -#define M_RESET 0x1E40 - -#define M_AGP2PLL 0x1E4C - -#define M_OPMODE 0x1E54 -#define M_OPMODE_DMA_GEN_WRITE 0x00 -#define M_OPMODE_DMA_BLIT 0x04 -#define M_OPMODE_DMA_VECTOR_WRITE 0x08 -#define M_OPMODE_DMA_LE 0x0000 /* little endian - no transformation */ -#define M_OPMODE_DMA_BE_8BPP 0x0000 -#define M_OPMODE_DMA_BE_16BPP 0x0100 -#define M_OPMODE_DMA_BE_32BPP 0x0200 -#define M_OPMODE_DIR_LE 0x000000 /* little endian - no transformation */ -#define M_OPMODE_DIR_BE_8BPP 0x000000 -#define M_OPMODE_DIR_BE_16BPP 0x010000 -#define M_OPMODE_DIR_BE_32BPP 0x020000 - -#define M_ATTR_INDEX 0x1FC0 -#define M_ATTR_DATA 0x1FC1 - -#define M_MISC_REG 0x1FC2 -#define M_3C2_RD 0x1FC2 - -#define M_SEQ_INDEX 0x1FC4 -#define M_SEQ_DATA 0x1FC5 - -#define M_MISC_REG_READ 0x1FCC - -#define M_GRAPHICS_INDEX 0x1FCE -#define M_GRAPHICS_DATA 0x1FCF - -#define M_CRTC_INDEX 0x1FD4 - -#define M_ATTR_RESET 0x1FDA -#define M_3DA_WR 0x1FDA - -#define M_EXTVGA_INDEX 0x1FDE -#define M_EXTVGA_DATA 0x1FDF - -/* G200 only */ -#define M_SRCORG 0x2CB4 - -#define M_RAMDAC_BASE 0x3C00 - -/* fortunately, same on TVP3026 and MGA1064 */ -#define M_DAC_REG (M_RAMDAC_BASE+0) -#define M_DAC_VAL (M_RAMDAC_BASE+1) -#define M_PALETTE_MASK (M_RAMDAC_BASE+2) - -#define M_X_INDEX 0x00 -#define M_X_DATAREG 0x0A - -#define DAC_XGENIOCTRL 0x2A -#define DAC_XGENIODATA 0x2B - -#ifdef CONFIG_FB_MATROX_MILLENIUM -#define TVP3026_INDEX 0x00 -#define TVP3026_PALWRADD 0x00 -#define TVP3026_PALDATA 0x01 -#define TVP3026_PIXRDMSK 0x02 -#define TVP3026_PALRDADD 0x03 -#define TVP3026_CURCOLWRADD 0x04 -#define TVP3026_CLOVERSCAN 0x00 -#define TVP3026_CLCOLOR0 0x01 -#define TVP3026_CLCOLOR1 0x02 -#define TVP3026_CLCOLOR2 0x03 -#define TVP3026_CURCOLDATA 0x05 -#define TVP3026_CURCOLRDADD 0x07 -#define TVP3026_CURCTRL 0x09 -#define TVP3026_X_DATAREG 0x0A -#define TVP3026_CURRAMDATA 0x0B -#define TVP3026_CURPOSXL 0x0C -#define TVP3026_CURPOSXH 0x0D -#define TVP3026_CURPOSYL 0x0E -#define TVP3026_CURPOSYH 0x0F - -#define TVP3026_XSILICONREV 0x01 -#define TVP3026_XCURCTRL 0x06 -#define TVP3026_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */ -#define TVP3026_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */ -#define TVP3026_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */ -#define TVP3026_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */ -#define TVP3026_XCURCTRL_BLANK2048 0x00 -#define TVP3026_XCURCTRL_BLANK4096 0x10 -#define TVP3026_XCURCTRL_INTERLACED 0x20 -#define TVP3026_XCURCTRL_ODD 0x00 /* ext.signal ODD/\EVEN */ -#define TVP3026_XCURCTRL_EVEN 0x40 /* ext.signal EVEN/\ODD */ -#define TVP3026_XCURCTRL_INDIRECT 0x00 -#define TVP3026_XCURCTRL_DIRECT 0x80 -#define TVP3026_XLATCHCTRL 0x0F -#define TVP3026_XLATCHCTRL_1_1 0x06 -#define TVP3026_XLATCHCTRL_2_1 0x07 -#define TVP3026_XLATCHCTRL_4_1 0x06 -#define TVP3026_XLATCHCTRL_8_1 0x06 -#define TVP3026_XLATCHCTRL_16_1 0x06 -#define TVP3026A_XLATCHCTRL_4_3 0x06 /* ??? do not understand... but it works... !!! */ -#define TVP3026A_XLATCHCTRL_8_3 0x07 -#define TVP3026B_XLATCHCTRL_4_3 0x08 -#define TVP3026B_XLATCHCTRL_8_3 0x06 /* ??? do not understand... but it works... !!! */ -#define TVP3026_XTRUECOLORCTRL 0x18 -#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_ACCEL 0x00 -#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_TVP 0x20 -#define TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR 0x80 -#define TVP3026_XTRUECOLORCTRL_TRUECOLOR 0x40 /* paletized */ -#define TVP3026_XTRUECOLORCTRL_DIRECTCOLOR 0x00 -#define TVP3026_XTRUECOLORCTRL_24_ALTERNATE 0x08 /* 5:4/5:2 instead of 4:3/8:3 */ -#define TVP3026_XTRUECOLORCTRL_RGB_888 0x16 /* 4:3/8:3 (or 5:4/5:2) */ -#define TVP3026_XTRUECOLORCTRL_BGR_888 0x17 -#define TVP3026_XTRUECOLORCTRL_ORGB_8888 0x06 -#define TVP3026_XTRUECOLORCTRL_BGRO_8888 0x07 -#define TVP3026_XTRUECOLORCTRL_RGB_565 0x05 -#define TVP3026_XTRUECOLORCTRL_ORGB_1555 0x04 -#define TVP3026_XTRUECOLORCTRL_RGB_664 0x03 -#define TVP3026_XTRUECOLORCTRL_RGBO_4444 0x01 -#define TVP3026_XMUXCTRL 0x19 -#define TVP3026_XMUXCTRL_MEMORY_8BIT 0x01 /* - */ -#define TVP3026_XMUXCTRL_MEMORY_16BIT 0x02 /* - */ -#define TVP3026_XMUXCTRL_MEMORY_32BIT 0x03 /* 2MB RAM, 512K * 4 */ -#define TVP3026_XMUXCTRL_MEMORY_64BIT 0x04 /* >2MB RAM, 512K * 8 & more */ -#define TVP3026_XMUXCTRL_PIXEL_4BIT 0x40 /* L0,H0,L1,H1... */ -#define TVP3026_XMUXCTRL_PIXEL_4BIT_SWAPPED 0x60 /* H0,L0,H1,L1... */ -#define TVP3026_XMUXCTRL_PIXEL_8BIT 0x48 -#define TVP3026_XMUXCTRL_PIXEL_16BIT 0x50 -#define TVP3026_XMUXCTRL_PIXEL_32BIT 0x58 -#define TVP3026_XMUXCTRL_VGA 0x98 /* VGA MEMORY, 8BIT PIXEL */ -#define TVP3026_XCLKCTRL 0x1A -#define TVP3026_XCLKCTRL_DIV1 0x00 -#define TVP3026_XCLKCTRL_DIV2 0x10 -#define TVP3026_XCLKCTRL_DIV4 0x20 -#define TVP3026_XCLKCTRL_DIV8 0x30 -#define TVP3026_XCLKCTRL_DIV16 0x40 -#define TVP3026_XCLKCTRL_DIV32 0x50 -#define TVP3026_XCLKCTRL_DIV64 0x60 -#define TVP3026_XCLKCTRL_CLKSTOPPED 0x70 -#define TVP3026_XCLKCTRL_SRC_CLK0 0x00 -#define TVP3026_XCLKCTRL_SRC_CLK1 0x01 -#define TVP3026_XCLKCTRL_SRC_CLK2 0x02 /* CLK2 is TTL source*/ -#define TVP3026_XCLKCTRL_SRC_NCLK2 0x03 /* not CLK2 is TTL source */ -#define TVP3026_XCLKCTRL_SRC_ECLK2 0x04 /* CLK2 and not CLK2 is ECL source */ -#define TVP3026_XCLKCTRL_SRC_PLL 0x05 -#define TVP3026_XCLKCTRL_SRC_DIS 0x06 /* disable & poweroff internal clock */ -#define TVP3026_XCLKCTRL_SRC_CLK0VGA 0x07 -#define TVP3026_XPALETTEPAGE 0x1C -#define TVP3026_XGENCTRL 0x1D -#define TVP3026_XGENCTRL_HSYNC_POS 0x00 -#define TVP3026_XGENCTRL_HSYNC_NEG 0x01 -#define TVP3026_XGENCTRL_VSYNC_POS 0x00 -#define TVP3026_XGENCTRL_VSYNC_NEG 0x02 -#define TVP3026_XGENCTRL_LITTLE_ENDIAN 0x00 -#define TVP3026_XGENCTRL_BIG_ENDIAN 0x08 -#define TVP3026_XGENCTRL_BLACK_0IRE 0x00 -#define TVP3026_XGENCTRL_BLACK_75IRE 0x10 -#define TVP3026_XGENCTRL_NO_SYNC_ON_GREEN 0x00 -#define TVP3026_XGENCTRL_SYNC_ON_GREEN 0x20 -#define TVP3026_XGENCTRL_OVERSCAN_DIS 0x00 -#define TVP3026_XGENCTRL_OVERSCAN_EN 0x40 -#define TVP3026_XMISCCTRL 0x1E -#define TVP3026_XMISCCTRL_DAC_PUP 0x00 -#define TVP3026_XMISCCTRL_DAC_PDOWN 0x01 -#define TVP3026_XMISCCTRL_DAC_EXT 0x00 /* or 8, bit 3 is ignored */ -#define TVP3026_XMISCCTRL_DAC_6BIT 0x04 -#define TVP3026_XMISCCTRL_DAC_8BIT 0x0C -#define TVP3026_XMISCCTRL_PSEL_DIS 0x00 -#define TVP3026_XMISCCTRL_PSEL_EN 0x10 -#define TVP3026_XMISCCTRL_PSEL_LOW 0x00 /* PSEL high selects directcolor */ -#define TVP3026_XMISCCTRL_PSEL_HIGH 0x20 /* PSEL high selects truecolor or pseudocolor */ -#define TVP3026_XGENIOCTRL 0x2A -#define TVP3026_XGENIODATA 0x2B -#define TVP3026_XPLLADDR 0x2C -#define TVP3026_XPLLADDR_X(LOOP,MCLK,PIX) (((LOOP)<<4) | ((MCLK)<<2) | (PIX)) -#define TVP3026_XPLLDATA_N 0x00 -#define TVP3026_XPLLDATA_M 0x01 -#define TVP3026_XPLLDATA_P 0x02 -#define TVP3026_XPLLDATA_STAT 0x03 -#define TVP3026_XPIXPLLDATA 0x2D -#define TVP3026_XMEMPLLDATA 0x2E -#define TVP3026_XLOOPPLLDATA 0x2F -#define TVP3026_XCOLKEYOVRMIN 0x30 -#define TVP3026_XCOLKEYOVRMAX 0x31 -#define TVP3026_XCOLKEYREDMIN 0x32 -#define TVP3026_XCOLKEYREDMAX 0x33 -#define TVP3026_XCOLKEYGREENMIN 0x34 -#define TVP3026_XCOLKEYGREENMAX 0x35 -#define TVP3026_XCOLKEYBLUEMIN 0x36 -#define TVP3026_XCOLKEYBLUEMAX 0x37 -#define TVP3026_XCOLKEYCTRL 0x38 -#define TVP3026_XCOLKEYCTRL_OVR_EN 0x01 -#define TVP3026_XCOLKEYCTRL_RED_EN 0x02 -#define TVP3026_XCOLKEYCTRL_GREEN_EN 0x04 -#define TVP3026_XCOLKEYCTRL_BLUE_EN 0x08 -#define TVP3026_XCOLKEYCTRL_NEGATE 0x10 -#define TVP3026_XCOLKEYCTRL_ZOOM1 0x00 -#define TVP3026_XCOLKEYCTRL_ZOOM2 0x20 -#define TVP3026_XCOLKEYCTRL_ZOOM4 0x40 -#define TVP3026_XCOLKEYCTRL_ZOOM8 0x60 -#define TVP3026_XCOLKEYCTRL_ZOOM16 0x80 -#define TVP3026_XCOLKEYCTRL_ZOOM32 0xA0 -#define TVP3026_XMEMPLLCTRL 0x39 -#define TVP3026_XMEMPLLCTRL_DIV(X) (((X)-1)>>1) /* 2,4,6,8,10,12,14,16, division applied to LOOP PLL after divide by 2^P */ -#define TVP3026_XMEMPLLCTRL_STROBEMKC4 0x08 -#define TVP3026_XMEMPLLCTRL_MCLK_DOTCLOCK 0x00 /* MKC4 */ -#define TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL 0x10 /* MKC4 */ -#define TVP3026_XMEMPLLCTRL_RCLK_PIXPLL 0x00 -#define TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL 0x20 -#define TVP3026_XMEMPLLCTRL_RCLK_DOTDIVN 0x40 /* dot clock divided by loop pclk N prescaler */ -#define TVP3026_XSENSETEST 0x3A -#define TVP3026_XTESTMODEDATA 0x3B -#define TVP3026_XCRCREML 0x3C -#define TVP3026_XCRCREMH 0x3D -#define TVP3026_XCRCBITSEL 0x3E -#define TVP3026_XID 0x3F - -#endif - -#ifdef NEED_DAC1064 - -#define DAC1064_OPT_SCLK_PCI 0x00 -#define DAC1064_OPT_SCLK_PLL 0x01 -#define DAC1064_OPT_SCLK_EXT 0x02 -#define DAC1064_OPT_SCLK_MASK 0x03 -#define DAC1064_OPT_GDIV1 0x04 /* maybe it is GDIV2 on G100 ?! */ -#define DAC1064_OPT_GDIV3 0x00 -#define DAC1064_OPT_MDIV1 0x08 -#define DAC1064_OPT_MDIV2 0x00 -#define DAC1064_OPT_RESERVED 0x10 - -#define M1064_INDEX 0x00 -#define M1064_PALWRADD 0x00 -#define M1064_PALDATA 0x01 -#define M1064_PIXRDMSK 0x02 -#define M1064_PALRDADD 0x03 -#define M1064_X_DATAREG 0x0A -#define M1064_CURPOSXL 0x0C /* can be accessed as DWORD */ -#define M1064_CURPOSXH 0x0D -#define M1064_CURPOSYL 0x0E -#define M1064_CURPOSYH 0x0F - -#define M1064_XCURADDL 0x04 -#define M1064_XCURADDH 0x05 -#define M1064_XCURCTRL 0x06 -#define M1064_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */ -#define M1064_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */ -#define M1064_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */ -#define M1064_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */ -#define M1064_XCURCOL0RED 0x08 -#define M1064_XCURCOL0GREEN 0x09 -#define M1064_XCURCOL0BLUE 0x0A -#define M1064_XCURCOL1RED 0x0C -#define M1064_XCURCOL1GREEN 0x0D -#define M1064_XCURCOL1BLUE 0x0E -#define M1064_XCURCOL2RED 0x10 -#define M1064_XCURCOL2GREEN 0x11 -#define M1064_XCURCOL2BLUE 0x12 -#define DAC1064_XVREFCTRL 0x18 -#define DAC1064_XVREFCTRL_INTERNAL 0x3F -#define DAC1064_XVREFCTRL_EXTERNAL 0x00 -#define DAC1064_XVREFCTRL_G100_DEFAULT 0x03 -#define M1064_XMULCTRL 0x19 -#define M1064_XMULCTRL_DEPTH_8BPP 0x00 /* 8 bpp paletized */ -#define M1064_XMULCTRL_DEPTH_15BPP_1BPP 0x01 /* 15 bpp paletized + 1 bpp overlay */ -#define M1064_XMULCTRL_DEPTH_16BPP 0x02 /* 16 bpp paletized */ -#define M1064_XMULCTRL_DEPTH_24BPP 0x03 /* 24 bpp paletized */ -#define M1064_XMULCTRL_DEPTH_24BPP_8BPP 0x04 /* 24 bpp direct + 8 bpp overlay paletized */ -#define M1064_XMULCTRL_2G8V16 0x05 /* 15 bpp video direct, half xres, 8bpp paletized */ -#define M1064_XMULCTRL_G16V16 0x06 /* 15 bpp video, 15bpp graphics, one of them paletized */ -#define M1064_XMULCTRL_DEPTH_32BPP 0x07 /* 24 bpp paletized + 8 bpp unused */ -#define M1064_XMULCTRL_GRAPHICS_PALETIZED 0x00 -#define M1064_XMULCTRL_VIDEO_PALETIZED 0x08 -#define M1064_XPIXCLKCTRL 0x1A -#define M1064_XPIXCLKCTRL_SRC_PCI 0x00 -#define M1064_XPIXCLKCTRL_SRC_PLL 0x01 -#define M1064_XPIXCLKCTRL_SRC_EXT 0x02 -#define M1064_XPIXCLKCTRL_SRC_MASK 0x03 -#define M1064_XPIXCLKCTRL_EN 0x00 -#define M1064_XPIXCLKCTRL_DIS 0x04 -#define M1064_XPIXCLKCTRL_PLL_DOWN 0x00 -#define M1064_XPIXCLKCTRL_PLL_UP 0x08 -#define M1064_XGENCTRL 0x1D -#define M1064_XGENCTRL_VS_0 0x00 -#define M1064_XGENCTRL_VS_1 0x01 -#define M1064_XGENCTRL_ALPHA_DIS 0x00 -#define M1064_XGENCTRL_ALPHA_EN 0x02 -#define M1064_XGENCTRL_BLACK_0IRE 0x00 -#define M1064_XGENCTRL_BLACK_75IRE 0x10 -#define M1064_XGENCTRL_SYNC_ON_GREEN 0x00 -#define M1064_XGENCTRL_NO_SYNC_ON_GREEN 0x20 -#define M1064_XGENCTRL_SYNC_ON_GREEN_MASK 0x20 -#define M1064_XMISCCTRL 0x1E -#define M1064_XMISCCTRL_DAC_DIS 0x00 -#define M1064_XMISCCTRL_DAC_EN 0x01 -#define M1064_XMISCCTRL_MFC_VGA 0x00 -#define M1064_XMISCCTRL_MFC_MAFC 0x02 -#define M1064_XMISCCTRL_MFC_DIS 0x06 -#define M1064_XMISCCTRL_DAC_6BIT 0x00 -#define M1064_XMISCCTRL_DAC_8BIT 0x08 -#define M1064_XMISCCTRL_LUT_DIS 0x00 -#define M1064_XMISCCTRL_LUT_EN 0x10 -#define M1064_XGENIOCTRL 0x2A -#define M1064_XGENIODATA 0x2B -#define DAC1064_XSYSPLLM 0x2C -#define DAC1064_XSYSPLLN 0x2D -#define DAC1064_XSYSPLLP 0x2E -#define DAC1064_XSYSPLLSTAT 0x2F -#define M1064_XZOOMCTRL 0x38 -#define M1064_XZOOMCTRL_1 0x00 -#define M1064_XZOOMCTRL_2 0x01 -#define M1064_XZOOMCTRL_4 0x03 -#define M1064_XSENSETEST 0x3A -#define M1064_XSENSETEST_BCOMP 0x01 -#define M1064_XSENSETEST_GCOMP 0x02 -#define M1064_XSENSETEST_RCOMP 0x04 -#define M1064_XSENSETEST_PDOWN 0x00 -#define M1064_XSENSETEST_PUP 0x80 -#define M1064_XCRCREML 0x3C -#define M1064_XCRCREMH 0x3D -#define M1064_XCRCBITSEL 0x3E -#define M1064_XCOLKEYMASKL 0x40 -#define M1064_XCOLKEYMASKH 0x41 -#define M1064_XCOLKEYL 0x42 -#define M1064_XCOLKEYH 0x43 -#define M1064_XPIXPLLAM 0x44 -#define M1064_XPIXPLLAN 0x45 -#define M1064_XPIXPLLAP 0x46 -#define M1064_XPIXPLLBM 0x48 -#define M1064_XPIXPLLBN 0x49 -#define M1064_XPIXPLLBP 0x4A -#define M1064_XPIXPLLCM 0x4C -#define M1064_XPIXPLLCN 0x4D -#define M1064_XPIXPLLCP 0x4E -#define M1064_XPIXPLLSTAT 0x4F - -#endif - -#ifdef __LITTLE_ENDIAN -#define MX_OPTION_BSWAP 0x00000000 - -#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) -#define M_OPMODE_8BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) -#define M_OPMODE_16BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) -#define M_OPMODE_24BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) -#define M_OPMODE_32BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) -#else -#ifdef __BIG_ENDIAN -#define MX_OPTION_BSWAP 0x80000000 - -#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) /* TODO */ -#define M_OPMODE_8BPP (M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT) -#define M_OPMODE_16BPP (M_OPMODE_DMA_BE_16BPP | M_OPMODE_DIR_BE_16BPP | M_OPMODE_DMA_BLIT) -#define M_OPMODE_24BPP (M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT) /* TODO, ?32 */ -#define M_OPMODE_32BPP (M_OPMODE_DMA_BE_32BPP | M_OPMODE_DIR_BE_32BPP | M_OPMODE_DMA_BLIT) -#else -#error "Byte ordering have to be defined. Cannot continue." -#endif -#endif - -#define mga_inb(addr) mga_readb(ACCESS_FBINFO(mmio.vbase), (addr)) -#define mga_inl(addr) mga_readl(ACCESS_FBINFO(mmio.vbase), (addr)) -#define mga_outb(addr,val) mga_writeb(ACCESS_FBINFO(mmio.vbase), (addr), (val)) -#define mga_outw(addr,val) mga_writew(ACCESS_FBINFO(mmio.vbase), (addr), (val)) -#define mga_outl(addr,val) mga_writel(ACCESS_FBINFO(mmio.vbase), (addr), (val)) -#define mga_readr(port,idx) (mga_outb((port),(idx)), mga_inb((port)+1)) -#ifdef __LITTLE_ENDIAN -#define mga_setr(addr,port,val) mga_outw(addr, ((val)<<8) | (port)) -#else -#define mga_setr(addr,port,val) do { mga_outb(addr, port); mga_outb((addr)+1, val); } while (0) -#endif - -#ifdef __LITTLE_ENDIAN -#define mga_fifo(n) do {} while (mga_inb(M_FIFOSTATUS) < (n)) -#else -#define mga_fifo(n) do {} while ((mga_inl(M_FIFOSTATUS) & 0xFF) < (n)) -#endif - -#define WaitTillIdle() do {} while (mga_inl(M_STATUS) & 0x10000) - -/* code speedup */ -#ifdef CONFIG_FB_MATROX_MILLENIUM -#define isInterleave(x) (x->interleave) -#define isMillenium(x) (x->millenium) -#define isMilleniumII(x) (x->milleniumII) -#else -#define isInterleave(x) (0) -#define isMillenium(x) (0) -#define isMilleniumII(x) (0) -#endif - -#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l)) - -static void matrox_cfbX_init(WPMINFO struct display* p) { - u_int32_t maccess; - u_int32_t mpitch; - u_int32_t mopmode; - - DBG("matrox_cfbX_init") - - mpitch = p->var.xres_virtual; - - if (p->type == FB_TYPE_TEXT) { - maccess = 0x00000000; - mpitch = (mpitch >> 4) | 0x8000; /* set something */ - mopmode = M_OPMODE_8BPP; - } else { - switch (p->var.bits_per_pixel) { - case 4: maccess = 0x00000000; /* accelerate as 8bpp video */ - mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */ - mopmode = M_OPMODE_4BPP; - break; - case 8: maccess = 0x00000000; - mopmode = M_OPMODE_8BPP; - break; - case 16: if (p->var.green.length == 5) - maccess = 0xC0000001; - else - maccess = 0x40000001; - mopmode = M_OPMODE_16BPP; - break; - case 24: maccess = 0x00000003; - mopmode = M_OPMODE_24BPP; - break; - case 32: maccess = 0x00000002; - mopmode = M_OPMODE_32BPP; - break; - default: maccess = 0x00000000; - mopmode = 0x00000000; - break; /* turn off acceleration!!! */ - } - } - mga_fifo(8); - mga_outl(M_PITCH, mpitch); - mga_outl(M_YDSTORG, curr_ydstorg(MINFO)); - if (ACCESS_FBINFO(capable.plnwt)) - mga_outl(M_PLNWT, -1); - mga_outl(M_OPMODE, mopmode); - mga_outl(M_CXBNDRY, 0xFFFF0000); - mga_outl(M_YTOP, 0); - mga_outl(M_YBOT, 0x01FFFFFF); - mga_outl(M_MACCESS, maccess); - ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO; - if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC; - ACCESS_FBINFO(accel.m_opmode) = mopmode; -} - -static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) { - int pixx = p->var.xres_virtual, start, end; - MINFO_FROM_DISP(p); - - DBG("matrox_cfbX_bmove") - - sx *= fontwidth(p); - dx *= fontwidth(p); - width *= fontwidth(p); - height *= fontheight(p); - sy *= fontheight(p); - dy *= fontheight(p); - if ((dy < sy) || ((dy == sy) && (dx <= sx))) { - mga_fifo(2); - mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | - M_DWG_BFCOL | M_DWG_REPLACE); - mga_outl(M_AR5, pixx); - width--; - start = sy*pixx+sx+curr_ydstorg(MINFO); - end = start+width; - } else { - mga_fifo(3); - mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); - mga_outl(M_SGN, 5); - mga_outl(M_AR5, -pixx); - width--; - end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO); - start = end+width; - dy += height-1; - } - mga_fifo(4); - mga_outl(M_AR0, end); - mga_outl(M_AR3, start); - mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); - mga_ydstlen(dy, height); - WaitTillIdle(); -} - -#ifdef FBCON_HAS_CFB4 -static void matrox_cfb4_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) { - int pixx, start, end; - MINFO_FROM_DISP(p); - /* both (sx or dx or width) and fontwidth() are odd, so their multiply is - also odd, that means that we cannot use acceleration */ - - DBG("matrox_cfb4_bmove") - - if ((sx | dx | width) & fontwidth(p) & 1) { - fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width); - return; - } - sx *= fontwidth(p); - dx *= fontwidth(p); - width *= fontwidth(p); - height *= fontheight(p); - sy *= fontheight(p); - dy *= fontheight(p); - pixx = p->var.xres_virtual >> 1; - sx >>= 1; - dx >>= 1; - width >>= 1; - if ((dy < sy) || ((dy == sy) && (dx <= sx))) { - mga_fifo(2); - mga_outl(M_AR5, pixx); - mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | - M_DWG_BFCOL | M_DWG_REPLACE); - width--; - start = sy*pixx+sx+curr_ydstorg(MINFO); - end = start+width; - } else { - mga_fifo(3); - mga_outl(M_SGN, 5); - mga_outl(M_AR5, -pixx); - mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); - width--; - end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO); - start = end+width; - dy += height-1; - } - mga_fifo(5); - mga_outl(M_AR0, end); - mga_outl(M_AR3, start); - mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); - mga_outl(M_YDST, dy*pixx >> 5); - mga_outl(M_LEN | M_EXEC, height); - WaitTillIdle(); -} -#endif - -static void matroxfb_accel_clear(CPMINFO u_int32_t color, int sy, int sx, int height, - int width) { - - DBG("matroxfb_accel_clear") - - mga_fifo(5); - mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE); - mga_outl(M_FCOL, color); - mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); - mga_ydstlen(sy, height); - WaitTillIdle(); -} - -static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) { - - DBG("matrox_cfbX_clear") - - matroxfb_accel_clear(PMXINFO(p) color, sy * fontheight(p), sx * fontwidth(p), - height * fontheight(p), width * fontwidth(p)); -} - -#ifdef FBCON_HAS_CFB4 -static void matrox_cfb4_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { - u_int32_t bgx; - int whattodo; - MINFO_FROM_DISP(p); - - DBG("matrox_cfb4_clear") - - whattodo = 0; - bgx = attr_bgcol_ec(p, conp); - bgx |= bgx << 4; - bgx |= bgx << 8; - bgx |= bgx << 16; - sy *= fontheight(p); - sx *= fontwidth(p); - height *= fontheight(p); - width *= fontwidth(p); - if (sx & 1) { - sx ++; - if (!width) return; - width --; - whattodo = 1; - } - if (width & 1) { - whattodo |= 2; - } - width >>= 1; - sx >>= 1; - if (width) { - mga_fifo(5); - mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE2); - mga_outl(M_FCOL, bgx); - mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); - mga_outl(M_YDST, sy * p->var.xres_virtual >> 6); - mga_outl(M_LEN | M_EXEC, height); - WaitTillIdle(); - } - if (whattodo) { - u_int32_t step = p->var.xres_virtual >> 1; - vaddr_t vbase = ACCESS_FBINFO(video.vbase); - if (whattodo & 1) { - unsigned int uaddr = sy * step + sx - 1; - u_int32_t loop; - u_int8_t bgx2 = bgx & 0xF0; - for (loop = height; loop > 0; loop --) { - mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0x0F) | bgx2); - uaddr += step; - } - } - if (whattodo & 2) { - unsigned int uaddr = sy * step + sx + width; - u_int32_t loop; - u_int8_t bgx2 = bgx & 0x0F; - for (loop = height; loop > 0; loop --) { - mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0xF0) | bgx2); - uaddr += step; - } - } - } -} -#endif - -#ifdef FBCON_HAS_CFB8 -static void matrox_cfb8_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { - u_int32_t bgx; - - DBG("matrox_cfb8_clear") - - bgx = attr_bgcol_ec(p, conp); - bgx |= bgx << 8; - bgx |= bgx << 16; - matrox_cfbX_clear(bgx, p, sy, sx, height, width); -} -#endif - -#ifdef FBCON_HAS_CFB16 -static void matrox_cfb16_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { - u_int32_t bgx; - - DBG("matrox_cfb16_clear") - - bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)]; - matrox_cfbX_clear((bgx << 16) | bgx, p, sy, sx, height, width); -} -#endif - -#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24) -static void matrox_cfb32_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { - u_int32_t bgx; - - DBG("matrox_cfb32_clear") - - bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)]; - matrox_cfbX_clear(bgx, p, sy, sx, height, width); -} -#endif - -static void matrox_cfbX_fastputc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) { - unsigned int charcell; - unsigned int ar3; - MINFO_FROM_DISP(p); - - charcell = fontwidth(p) * fontheight(p); - yy *= fontheight(p); - xx *= fontwidth(p); - - mga_fifo(8); - mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); - - mga_outl(M_FCOL, fgx); - mga_outl(M_BCOL, bgx); - mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx); - ar3 = ACCESS_FBINFO(fastfont.mgabase) + (c & p->charmask) * charcell; - mga_outl(M_AR3, ar3); - mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF); - mga_ydstlen(yy, fontheight(p)); - WaitTillIdle(); -} - -static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) { - u_int32_t ar0; - u_int32_t step; - MINFO_FROM_DISP(p); - - DBG_HEAVY("matrox_cfbX_putc"); - - yy *= fontheight(p); - xx *= fontwidth(p); - -#ifdef __BIG_ENDIAN - WaitTillIdle(); - mga_outl(M_OPMODE, M_OPMODE_8BPP); -#else - mga_fifo(7); -#endif - ar0 = fontwidth(p) - 1; - mga_outl(M_FXBNDRY, ((xx+ar0)<<16) | xx); - if (fontwidth(p) <= 8) - step = 1; - else if (fontwidth(p) <= 16) - step = 2; - else - step = 4; - if (fontwidth(p) == step << 3) { - size_t charcell = fontheight(p)*step; - /* TODO: Align charcell to 4B for BE */ - mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); - mga_outl(M_FCOL, fgx); - mga_outl(M_BCOL, bgx); - mga_outl(M_AR3, 0); - mga_outl(M_AR0, fontheight(p)*fontwidth(p)-1); - mga_ydstlen(yy, fontheight(p)); - mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, p->fontdata+(c&p->charmask)*charcell, charcell); - } else { - u8* chardata = p->fontdata+(c&p->charmask)*fontheight(p)*step; - int i; - - mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE); - mga_outl(M_FCOL, fgx); - mga_outl(M_BCOL, bgx); - mga_outl(M_AR5, 0); - mga_outl(M_AR3, 0); - mga_outl(M_AR0, ar0); - mga_ydstlen(yy, fontheight(p)); - - switch (step) { - case 1: - for (i = fontheight(p); i > 0; i--) { -#ifdef __LITTLE_ENDIAN - mga_outl(0, *chardata++); -#else - mga_outl(0, (*chardata++) << 24); -#endif - } - break; - case 2: - for (i = fontheight(p); i > 0; i--) { -#ifdef __LITTLE_ENDIAN - mga_outl(0, *(u_int16_t*)chardata); -#else - mga_outl(0, (*(u_int16_t*)chardata) << 16); -#endif - chardata += 2; - } - break; - case 4: - mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, chardata, fontheight(p) * 4); - break; - } - } - WaitTillIdle(); -#ifdef __BIG_ENDIAN - mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); -#endif -} - -#ifdef FBCON_HAS_CFB8 -static void matrox_cfb8_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { - u_int32_t fgx, bgx; - MINFO_FROM_DISP(p); - - DBG_HEAVY("matroxfb_cfb8_putc"); - - fgx = attr_fgcol(p, c); - bgx = attr_bgcol(p, c); - fgx |= (fgx << 8); - fgx |= (fgx << 16); - bgx |= (bgx << 8); - bgx |= (bgx << 16); - ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx); -} -#endif - -#ifdef FBCON_HAS_CFB16 -static void matrox_cfb16_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { - u_int32_t fgx, bgx; - MINFO_FROM_DISP(p); - - DBG_HEAVY("matroxfb_cfb16_putc"); - - fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, c)]; - bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, c)]; - fgx |= (fgx << 16); - bgx |= (bgx << 16); - ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx); -} -#endif - -#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24) -static void matrox_cfb32_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { - u_int32_t fgx, bgx; - MINFO_FROM_DISP(p); - - DBG_HEAVY("matroxfb_cfb32_putc"); - - fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, c)]; - bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, c)]; - ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx); -} -#endif - -static void matrox_cfbX_fastputcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) { - unsigned int charcell; - MINFO_FROM_DISP(p); - - yy *= fontheight(p); - xx *= fontwidth(p); - charcell = fontwidth(p) * fontheight(p); - - mga_fifo(3); - mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); - mga_outl(M_FCOL, fgx); - mga_outl(M_BCOL, bgx); - while (count--) { - u_int32_t ar3 = ACCESS_FBINFO(fastfont.mgabase) + (scr_readw(s++) & p->charmask)*charcell; - - mga_fifo(4); - mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx); - mga_outl(M_AR3, ar3); - mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF); - mga_ydstlen(yy, fontheight(p)); - xx += fontwidth(p); - } - WaitTillIdle(); -} - -static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) { - u_int32_t step; - u_int32_t ydstlen; - u_int32_t xlen; - u_int32_t ar0; - u_int32_t charcell; - u_int32_t fxbndry; - vaddr_t mmio; - int easy; - MINFO_FROM_DISP(p); - - DBG_HEAVY("matroxfb_cfbX_putcs"); - - yy *= fontheight(p); - xx *= fontwidth(p); - if (fontwidth(p) <= 8) - step = 1; - else if (fontwidth(p) <= 16) - step = 2; - else - step = 4; - charcell = fontheight(p)*step; - xlen = (charcell + 3) & ~3; - ydstlen = (yy << 16) | fontheight(p); - if (fontwidth(p) == step << 3) { - ar0 = fontheight(p)*fontwidth(p) - 1; - easy = 1; - } else { - ar0 = fontwidth(p) - 1; - easy = 0; - } - -#ifdef __BIG_ENDIAN - WaitTillIdle(); - mga_outl(M_OPMODE, M_OPMODE_8BPP); -#else - mga_fifo(3); -#endif - if (easy) - mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); - else - mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE); - mga_outl(M_FCOL, fgx); - mga_outl(M_BCOL, bgx); - fxbndry = ((xx + fontwidth(p) - 1) << 16) | xx; - mmio = ACCESS_FBINFO(mmio.vbase); - while (count--) { - u_int8_t* chardata = p->fontdata + (scr_readw(s++) & p->charmask)*charcell; - - mga_fifo(6); - mga_writel(mmio, M_FXBNDRY, fxbndry); - mga_writel(mmio, M_AR0, ar0); - mga_writel(mmio, M_AR3, 0); - if (easy) { - mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen); - mga_memcpy_toio(mmio, 0, chardata, xlen); - } else { - mga_writel(mmio, M_AR5, 0); - mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen); - switch (step) { - case 1: { - u_int8_t* charend = chardata + charcell; - for (; chardata != charend; chardata++) { -#ifdef __LITTLE_ENDIAN - mga_writel(mmio, 0, *chardata); -#else - mga_writel(mmio, 0, (*chardata) << 24); -#endif - } - } - break; - case 2: { - u_int8_t* charend = chardata + charcell; - for (; chardata != charend; chardata += 2) { -#ifdef __LITTLE_ENDIAN - mga_writel(mmio, 0, *(u_int16_t*)chardata); -#else - mga_writel(mmio, 0, (*(u_int16_t*)chardata) << 16); -#endif - } - } - break; - default: - mga_memcpy_toio(mmio, 0, chardata, charcell); - break; - } - } - fxbndry += fontwidth(p) + (fontwidth(p) << 16); - } - WaitTillIdle(); -#ifdef __BIG_ENDIAN - mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); -#endif -} - -#ifdef FBCON_HAS_CFB8 -static void matrox_cfb8_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) { - u_int32_t fgx, bgx; - MINFO_FROM_DISP(p); - - DBG_HEAVY("matroxfb_cfb8_putcs"); - - fgx = attr_fgcol(p, scr_readw(s)); - bgx = attr_bgcol(p, scr_readw(s)); - fgx |= (fgx << 8); - fgx |= (fgx << 16); - bgx |= (bgx << 8); - bgx |= (bgx << 16); - ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx); -} -#endif - -#ifdef FBCON_HAS_CFB16 -static void matrox_cfb16_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) { - u_int32_t fgx, bgx; - MINFO_FROM_DISP(p); - - DBG_HEAVY("matroxfb_cfb16_putcs"); - - fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, scr_readw(s))]; - bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, scr_readw(s))]; - fgx |= (fgx << 16); - bgx |= (bgx << 16); - ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx); -} -#endif - -#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24) -static void matrox_cfb32_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) { - u_int32_t fgx, bgx; - MINFO_FROM_DISP(p); - - DBG_HEAVY("matroxfb_cfb32_putcs"); - - fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, scr_readw(s))]; - bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, scr_readw(s))]; - ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx); -} -#endif - -#ifdef FBCON_HAS_CFB4 -static void matrox_cfb4_revc(struct display* p, int xx, int yy) { - MINFO_FROM_DISP(p); - - DBG_LOOP("matroxfb_cfb4_revc"); - - if (fontwidth(p) & 1) { - fbcon_cfb4_revc(p, xx, yy); - return; - } - yy *= fontheight(p); - xx *= fontwidth(p); - xx |= (xx + fontwidth(p)) << 16; - xx >>= 1; - - mga_fifo(5); - mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR); - mga_outl(M_FCOL, 0xFFFFFFFF); - mga_outl(M_FXBNDRY, xx); - mga_outl(M_YDST, yy * p->var.xres_virtual >> 6); - mga_outl(M_LEN | M_EXEC, fontheight(p)); - WaitTillIdle(); -} -#endif - -#ifdef FBCON_HAS_CFB8 -static void matrox_cfb8_revc(struct display* p, int xx, int yy) { - MINFO_FROM_DISP(p); - - DBG_LOOP("matrox_cfb8_revc") - - yy *= fontheight(p); - xx *= fontwidth(p); - - mga_fifo(4); - mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR); - mga_outl(M_FCOL, 0x0F0F0F0F); - mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx); - mga_ydstlen(yy, fontheight(p)); - WaitTillIdle(); -} -#endif - -static void matrox_cfbX_revc(struct display* p, int xx, int yy) { - MINFO_FROM_DISP(p); - - DBG_LOOP("matrox_cfbX_revc") - - yy *= fontheight(p); - xx *= fontwidth(p); - - mga_fifo(4); - mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR); - mga_outl(M_FCOL, 0xFFFFFFFF); - mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx); - mga_ydstlen(yy, fontheight(p)); - WaitTillIdle(); -} - -static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) { - unsigned int bottom_height, right_width; - unsigned int bottom_start, right_start; - unsigned int cell_h, cell_w; - - DBG("matrox_cfbX_clear_margins") - - cell_w = fontwidth(p); - if (!cell_w) return; /* PARANOID */ - right_width = p->var.xres % cell_w; - right_start = p->var.xres - right_width; - if (!bottom_only && right_width) { - /* clear whole right margin, not only visible portion */ - matroxfb_accel_clear( PMXINFO(p) - /* color */ 0x00000000, - /* y */ 0, - /* x */ p->var.xoffset + right_start, - /* height */ p->var.yres_virtual, - /* width */ right_width); - } - cell_h = fontheight(p); - if (!cell_h) return; /* PARANOID */ - bottom_height = p->var.yres % cell_h; - if (bottom_height) { - bottom_start = p->var.yres - bottom_height; - matroxfb_accel_clear( PMXINFO(p) - /* color */ 0x00000000, - /* y */ p->var.yoffset + bottom_start, - /* x */ p->var.xoffset, - /* height */ bottom_height, - /* width */ right_start); - } -} - -static void outDAC(CPMINFO int reg, int val) { - DBG_REG("outDAC"); - mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); - mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val); -} - -static int inDAC(CPMINFO int reg) { - DBG_REG("inDAC"); - mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); - return mga_inb(M_RAMDAC_BASE+M_X_DATAREG); -} - -#define outTi3026 outDAC -#define inTi3026 inDAC -#define outDAC1064 outDAC -#define inDAC1064 inDAC - -static void matroxfb_createcursorshape(WPMINFO struct display* p, int vmode) { - unsigned int h; - unsigned int cu, cd; - - h = fontheight(p); - - if (vmode & FB_VMODE_DOUBLE) - h *= 2; - cd = h; - if (cd >= 10) - cd--; - switch (ACCESS_FBINFO(cursor.type) = (p->conp->vc_cursor_type & CUR_HWMASK)) { - case CUR_NONE: - cu = cd; - break; - case CUR_UNDERLINE: - cu = cd - 2; - break; - case CUR_LOWER_THIRD: - cu = (h * 2) / 3; - break; - case CUR_LOWER_HALF: - cu = h / 2; - break; - case CUR_TWO_THIRDS: - cu = h / 3; - break; - case CUR_BLOCK: - default: - cu = 0; - cd = h; - break; - } - ACCESS_FBINFO(cursor.w) = fontwidth(p); - ACCESS_FBINFO(cursor.u) = cu; - ACCESS_FBINFO(cursor.d) = cd; -} - -#ifdef CONFIG_FB_MATROX_MILLENIUM -#define POS3026_XCURCTRL 20 - -static void matroxfb_ti3026_flashcursor(unsigned long ptr) { -#define minfo ((struct matrox_fb_info*)ptr) - spin_lock(&ACCESS_FBINFO(lock.DAC)); - outTi3026(PMINFO TVP3026_XCURCTRL, inTi3026(PMINFO TVP3026_XCURCTRL) ^ TVP3026_XCURCTRL_DIS ^ TVP3026_XCURCTRL_XGA); - ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2; - add_timer(&ACCESS_FBINFO(cursor.timer)); - spin_unlock(&ACCESS_FBINFO(lock.DAC)); -#undef minfo -} - -static void matroxfb_ti3026_createcursor(WPMINFO struct display* p) { - unsigned long flags; - u_int32_t xline; - unsigned int i; - unsigned int to; - - if (ACCESS_FBINFO(currcon_display) != p) - return; - - DBG("matroxfb_ti3026_createcursor"); - - matroxfb_createcursorshape(PMINFO p, p->var.vmode); - - xline = (~0) << (32 - ACCESS_FBINFO(cursor.w)); - spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags); - mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, 0); - to = ACCESS_FBINFO(cursor.u); - for (i = 0; i < to; i++) { - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - } - to = ACCESS_FBINFO(cursor.d); - for (; i < to; i++) { - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 24); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 16); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 8); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - } - for (; i < 64; i++) { - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - } - for (i = 0; i < 512; i++) - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0xFF); - spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags); -} - -static void matroxfb_ti3026_cursor(struct display* p, int mode, int x, int y) { - unsigned long flags; - MINFO_FROM_DISP(p); - - DBG("matroxfb_ti3026_cursor") - - if (ACCESS_FBINFO(currcon_display) != p) - return; - - if (mode == CM_ERASE) { - if (ACCESS_FBINFO(cursor.state) != CM_ERASE) { - spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags); - ACCESS_FBINFO(cursor.state) = CM_ERASE; - del_timer(&ACCESS_FBINFO(cursor.timer)); - outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL])); - spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags); - } - return; - } - if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type)) - matroxfb_ti3026_createcursor(PMINFO p); - x *= fontwidth(p); - y *= fontheight(p); - y -= p->var.yoffset; - if (p->var.vmode & FB_VMODE_DOUBLE) - y *= 2; - spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags); - if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y)) || ACCESS_FBINFO(cursor.redraw)) { - ACCESS_FBINFO(cursor.redraw) = 0; - ACCESS_FBINFO(cursor.x) = x; - ACCESS_FBINFO(cursor.y) = y; - x += 64; - y += 64; - outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL])); - mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXL, x); - mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXH, x >> 8); - mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYL, y); - mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYH, y >> 8); - } - ACCESS_FBINFO(cursor.state) = CM_DRAW; - if (ACCESS_FBINFO(devflags.blink)) - mod_timer(&ACCESS_FBINFO(cursor.timer), jiffies + HZ/2); - outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]) | TVP3026_XCURCTRL_XGA); - spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags); -} -#undef POS3026_XCURCTRL - -static int matroxfb_ti3026_setfont(struct display* p, int width, int height) { - - DBG("matrox_ti3026_setfont"); - - if (p && p->conp) - matroxfb_ti3026_createcursor(PMXINFO(p) p); - return 0; -} -#endif - -#ifdef NEED_DAC1064 - -static void matroxfb_DAC1064_flashcursor(unsigned long ptr) { -#define minfo ((struct matrox_fb_info*)ptr) - spin_lock(&ACCESS_FBINFO(lock.DAC)); - outDAC1064(PMINFO M1064_XCURCTRL, inDAC1064(PMINFO M1064_XCURCTRL) ^ M1064_XCURCTRL_DIS ^ M1064_XCURCTRL_XGA); - ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2; - add_timer(&ACCESS_FBINFO(cursor.timer)); - spin_unlock(&ACCESS_FBINFO(lock.DAC)); -#undef minfo -} - -static void matroxfb_DAC1064_createcursor(WPMINFO struct display* p) { - vaddr_t cursorbase; - u_int32_t xline; - unsigned int i; - unsigned int h, to; - - if (ACCESS_FBINFO(currcon_display) != p) - return; - - matroxfb_createcursorshape(PMINFO p, p->var.vmode); - - xline = (~0) << (32 - ACCESS_FBINFO(cursor.w)); - cursorbase = ACCESS_FBINFO(video.vbase); - h = ACCESS_FBINFO(features.DAC1064.cursorimage); - -#ifdef __BIG_ENDIAN - WaitTillIdle(); - mga_outl(M_OPMODE, M_OPMODE_32BPP); -#endif - to = ACCESS_FBINFO(cursor.u); - for (i = 0; i < to; i++) { - mga_writel(cursorbase, h, 0); - mga_writel(cursorbase, h+4, 0); - mga_writel(cursorbase, h+8, ~0); - mga_writel(cursorbase, h+12, ~0); - h += 16; - } - to = ACCESS_FBINFO(cursor.d); - for (; i < to; i++) { - mga_writel(cursorbase, h, 0); - mga_writel(cursorbase, h+4, xline); - mga_writel(cursorbase, h+8, ~0); - mga_writel(cursorbase, h+12, ~0); - h += 16; - } - for (; i < 64; i++) { - mga_writel(cursorbase, h, 0); - mga_writel(cursorbase, h+4, 0); - mga_writel(cursorbase, h+8, ~0); - mga_writel(cursorbase, h+12, ~0); - h += 16; - } -#ifdef __BIG_ENDIAN - mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); -#endif -} - -static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) { - unsigned long flags; - MINFO_FROM_DISP(p); - - if (ACCESS_FBINFO(currcon_display) != p) - return; - - if (mode == CM_ERASE) { - if (ACCESS_FBINFO(cursor.state) != CM_ERASE) { - spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags); - ACCESS_FBINFO(cursor.state) = CM_ERASE; - del_timer(&ACCESS_FBINFO(cursor.timer)); - outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS); - spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags); - } - return; - } - if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type)) - matroxfb_DAC1064_createcursor(PMINFO p); - x *= fontwidth(p); - y *= fontheight(p); - y -= p->var.yoffset; - if (p->var.vmode & FB_VMODE_DOUBLE) - y *= 2; - spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags); - if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y)) || ACCESS_FBINFO(cursor.redraw)) { - ACCESS_FBINFO(cursor.redraw) = 0; - ACCESS_FBINFO(cursor.x) = x; - ACCESS_FBINFO(cursor.y) = y; - x += 64; - y += 64; - outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS); - mga_outb(M_RAMDAC_BASE+M1064_CURPOSXL, x); - mga_outb(M_RAMDAC_BASE+M1064_CURPOSXH, x >> 8); - mga_outb(M_RAMDAC_BASE+M1064_CURPOSYL, y); - mga_outb(M_RAMDAC_BASE+M1064_CURPOSYH, y >> 8); - } - ACCESS_FBINFO(cursor.state) = CM_DRAW; - if (ACCESS_FBINFO(devflags.blink)) - mod_timer(&ACCESS_FBINFO(cursor.timer), jiffies + HZ/2); - outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_XGA); - spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags); -} - -static int matroxfb_DAC1064_setfont(struct display* p, int width, int height) { - if (p && p->conp) - matroxfb_DAC1064_createcursor(PMXINFO(p) p); - return 0; -} -#endif - -#ifndef FNTCHARCNT -#define FNTCHARCNT(fd) (((int *)(fd))[-3]) -#endif - -static int matroxfb_fastfont_tryset(WPMINFO struct display* p) { - unsigned int fsize; - unsigned int width; - - if (!p || !p->fontdata) - return 0; - width = fontwidth(p); - if (width > 32) - return 0; - fsize = (p->userfont?FNTCHARCNT(p->fontdata):256) * fontheight(p); - if (((fsize * width + 31) / 32) * 4 > ACCESS_FBINFO(fastfont.size)) - return 0; - - mga_outl(M_OPMODE, M_OPMODE_8BPP); - if (width <= 8) { - if (width == 8) - mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize); - else { - vaddr_t dst; - unsigned int i; - u_int8_t* font; - u_int32_t mask, valid, reg; - - dst = ACCESS_FBINFO(fastfont.vbase); - font = (u_int8_t*)p->fontdata; - mask = ~0 << (8 - width); - valid = 0; - reg = 0; - i = 0; - while (fsize--) { - reg |= (*font++ & mask) << (8 - valid); - valid += width; - if (valid >= 8) { - mga_writeb(dst, i++, reg >> 8); - reg = reg << 8; - valid -= 8; - } - } - if (valid) - mga_writeb(dst, i, reg >> 8); - } - } else if (width <= 16) { - if (width == 16) - mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize*2); - else { - vaddr_t dst; - u_int16_t* font; - u_int32_t mask, valid, reg; - unsigned int i; - - dst = ACCESS_FBINFO(fastfont.vbase); - font = (u_int16_t*)p->fontdata; - mask = ~0 << (16 - width); - valid = 0; - reg = 0; - i = 0; - while (fsize--) { - reg |= (ntohs(*font++) & mask) << (16 - valid); - valid += width; - if (valid >= 16) { - mga_writew(dst, i, htons(reg >> 16)); - i += 2; - reg = reg << 16; - valid -= 16; - } - } - if (valid) - mga_writew(dst, i, htons(reg >> 16)); - } - } else { - if (width == 32) - mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize*4); - else { - vaddr_t dst; - u_int32_t* font; - u_int32_t mask, valid, reg; - unsigned int i; - - dst = ACCESS_FBINFO(fastfont.vbase); - font = (u_int32_t*)p->fontdata; - mask = ~0 << (32 - width); - valid = 0; - reg = 0; - i = 0; - while (fsize--) { - reg |= (ntohl(*font) & mask) >> valid; - valid += width; - if (valid >= 32) { - mga_writel(dst, i, htonl(reg)); - i += 4; - valid -= 32; - if (valid) - reg = (ntohl(*font) & mask) << (width - valid); - else - reg = 0; - } - font++; - } - if (valid) - mga_writel(dst, i, htonl(reg)); - } - } - mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); - - return 1; -} - -static void matrox_text_setup(struct display* p) { - MINFO_FROM_DISP(p); - - p->next_line = p->line_length ? p->line_length : ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep)); - p->next_plane = 0; -} - -static void matrox_text_bmove(struct display* p, int sy, int sx, int dy, int dx, - int height, int width) { - unsigned int srcoff; - unsigned int dstoff; - unsigned int step; - MINFO_FROM_DISP(p); - - step = ACCESS_FBINFO(devflags.textstep); - srcoff = (sy * p->next_line) + (sx * step); - dstoff = (dy * p->next_line) + (dx * step); - if (dstoff < srcoff) { - while (height > 0) { - int i; - for (i = width; i > 0; dstoff += step, srcoff += step, i--) - mga_writew(ACCESS_FBINFO(video.vbase), dstoff, mga_readw(ACCESS_FBINFO(video.vbase), srcoff)); - height--; - dstoff += p->next_line - width * step; - srcoff += p->next_line - width * step; - } - } else { - unsigned int off; - - off = (height - 1) * p->next_line + (width - 1) * step; - srcoff += off; - dstoff += off; - while (height > 0) { - int i; - for (i = width; i > 0; dstoff -= step, srcoff -= step, i--) - mga_writew(ACCESS_FBINFO(video.vbase), dstoff, mga_readw(ACCESS_FBINFO(video.vbase), srcoff)); - dstoff -= p->next_line - width * step; - srcoff -= p->next_line - width * step; - height--; - } - } -} - -static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, int sx, - int height, int width) { - unsigned int offs; - unsigned int val; - unsigned int step; - MINFO_FROM_DISP(p); - - step = ACCESS_FBINFO(devflags.textstep); - offs = sy * p->next_line + sx * step; - val = ntohs((attr_bgcol(p, conp->vc_video_erase_char) << 4) | attr_fgcol(p, conp->vc_video_erase_char) | (' ' << 8)); - - while (height > 0) { - int i; - for (i = width; i > 0; offs += step, i--) - mga_writew(ACCESS_FBINFO(video.vbase), offs, val); - offs += p->next_line - width * step; - height--; - } -} - -static void matrox_text_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { - unsigned int offs; - unsigned int chr; - unsigned int step; - MINFO_FROM_DISP(p); - - step = ACCESS_FBINFO(devflags.textstep); - offs = yy * p->next_line + xx * step; - chr = attr_fgcol(p,c) | (attr_bgcol(p,c) << 4) | ((c & p->charmask) << 8); - if (chr & 0x10000) chr |= 0x08; - - mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(chr)); -} - -static void matrox_text_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, - int count, int yy, int xx) { - unsigned int offs; - unsigned int attr; - unsigned int step; - MINFO_FROM_DISP(p); - - step = ACCESS_FBINFO(devflags.textstep); - offs = yy * p->next_line + xx * step; - attr = attr_fgcol(p, scr_readw(s)) | (attr_bgcol(p, scr_readw(s)) << 4); - - while (count-- > 0) { - unsigned int chr = ((scr_readw(s++)) & p->charmask) << 8; - if (chr & 0x10000) chr ^= 0x10008; - mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(attr|chr)); - offs += step; - } -} - -static void matrox_text_revc(struct display* p, int xx, int yy) { - unsigned int offs; - unsigned int step; - MINFO_FROM_DISP(p); - - step = ACCESS_FBINFO(devflags.textstep); - offs = yy * p->next_line + xx * step + 1; - - mga_writeb(ACCESS_FBINFO(video.vbase), offs, mga_readb(ACCESS_FBINFO(video.vbase), offs) ^ 0x77); -} - -static int matrox_text_loadfont(WPMINFO struct display* p) { - unsigned int fsize; - unsigned int width; - vaddr_t dst; - unsigned int i; - u_int8_t* font; - - if (!p || !p->fontdata) - return 0; - width = fontwidth(p); - fsize = p->userfont?FNTCHARCNT(p->fontdata):256; - - dst = ACCESS_FBINFO(video.vbase); - i = 2; - font = (u_int8_t*)p->fontdata; - - mga_setr(M_SEQ_INDEX, 0x02, 0x04); - while (fsize--) { - int l; - - for (l = 0; l < fontheight(p); l++) { - mga_writeb(dst, i, *font++); - if (fontwidth(p) > 8) font++; - i += ACCESS_FBINFO(devflags.vgastep); - } - i += (32 - fontheight(p)) * ACCESS_FBINFO(devflags.vgastep); - } - mga_setr(M_SEQ_INDEX, 0x02, 0x03); - - return 1; -} - -static void matrox_text_createcursor(WPMINFO struct display* p) { - - if (ACCESS_FBINFO(currcon_display) != p) - return; - - matroxfb_createcursorshape(PMINFO p, 0); - - mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u)); - mga_setr(M_CRTC_INDEX, 0x0B, ACCESS_FBINFO(cursor.d) - 1); -} - -static void matrox_text_cursor(struct display* p, int mode, int x, int y) { - unsigned int pos; - MINFO_FROM_DISP(p); - - if (ACCESS_FBINFO(currcon_display) != p) - return; - - if (mode == CM_ERASE) { - if (ACCESS_FBINFO(cursor.state) != CM_ERASE) { - - mga_setr(M_CRTC_INDEX, 0x0A, 0x20); - - ACCESS_FBINFO(cursor.state) = CM_ERASE; - } - return; - } - if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type)) - matrox_text_createcursor(PMINFO p); - - /* DO NOT CHECK cursor.x != x because of vgaHWinit moves cursor to 0,0 */ - ACCESS_FBINFO(cursor.x) = x; - ACCESS_FBINFO(cursor.y) = y; - pos = p->next_line / ACCESS_FBINFO(devflags.textstep) * y + x; - - mga_setr(M_CRTC_INDEX, 0x0F, pos); - mga_setr(M_CRTC_INDEX, 0x0E, pos >> 8); - - mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u)); - - ACCESS_FBINFO(cursor.state) = CM_DRAW; -} - -static void matrox_text_round(CPMINFO struct fb_var_screeninfo* var, struct display* p) { - unsigned hf; - unsigned vf; - unsigned vxres; - unsigned ych; - - hf = fontwidth(p); - if (!hf) hf = 8; - /* do not touch xres */ - vxres = (var->xres_virtual + hf - 1) / hf; - if (vxres >= 256) - vxres = 255; - if (vxres < 16) - vxres = 16; - vxres = (vxres + 1) & ~1; /* must be even */ - vf = fontheight(p); - if (!vf) vf = 16; - if (var->yres < var->yres_virtual) { - ych = ACCESS_FBINFO(devflags.textvram) / vxres; - var->yres_virtual = ych * vf; - } else - ych = var->yres_virtual / vf; - if (vxres * ych > ACCESS_FBINFO(devflags.textvram)) { - ych = ACCESS_FBINFO(devflags.textvram) / vxres; - var->yres_virtual = ych * vf; - } - var->xres_virtual = vxres * hf; -} - -static int matrox_text_setfont(struct display* p, int width, int height) { - DBG("matrox_text_setfont"); - - if (p) { - MINFO_FROM_DISP(p); - - matrox_text_round(PMINFO &p->var, p); - p->next_line = p->line_length = ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep)); - - if (p->conp) - matrox_text_createcursor(PMINFO p); - } - return 0; -} - -#define matrox_cfb16_revc matrox_cfbX_revc -#define matrox_cfb24_revc matrox_cfbX_revc -#define matrox_cfb32_revc matrox_cfbX_revc - -#define matrox_cfb24_clear matrox_cfb32_clear -#define matrox_cfb24_putc matrox_cfb32_putc -#define matrox_cfb24_putcs matrox_cfb32_putcs - -#ifdef FBCON_HAS_VGATEXT -static struct display_switch matroxfb_text = { - matrox_text_setup, matrox_text_bmove, matrox_text_clear, - matrox_text_putc, matrox_text_putcs, matrox_text_revc, - matrox_text_cursor, matrox_text_setfont, NULL, - FONTWIDTH(8)|FONTWIDTH(9) -}; -#endif - -#ifdef FBCON_HAS_CFB4 -static struct display_switch matroxfb_cfb4 = { - fbcon_cfb4_setup, matrox_cfb4_bmove, matrox_cfb4_clear, - fbcon_cfb4_putc, fbcon_cfb4_putcs, matrox_cfb4_revc, - NULL, NULL, NULL, - /* cursor... */ /* set_font... */ - FONTWIDTH(8) /* fix, fix, fix it */ -}; -#endif - -#ifdef FBCON_HAS_CFB8 -static struct display_switch matroxfb_cfb8 = { - fbcon_cfb8_setup, matrox_cfbX_bmove, matrox_cfb8_clear, - matrox_cfb8_putc, matrox_cfb8_putcs, matrox_cfb8_revc, - NULL, NULL, matrox_cfbX_clear_margins, - ~1 /* FONTWIDTHS */ -}; -#endif - -#ifdef FBCON_HAS_CFB16 -static struct display_switch matroxfb_cfb16 = { - fbcon_cfb16_setup, matrox_cfbX_bmove, matrox_cfb16_clear, - matrox_cfb16_putc, matrox_cfb16_putcs, matrox_cfb16_revc, - NULL, NULL, matrox_cfbX_clear_margins, - ~1 /* FONTWIDTHS */ -}; -#endif - -#ifdef FBCON_HAS_CFB24 -static struct display_switch matroxfb_cfb24 = { - fbcon_cfb24_setup, matrox_cfbX_bmove, matrox_cfb24_clear, - matrox_cfb24_putc, matrox_cfb24_putcs, matrox_cfb24_revc, - NULL, NULL, matrox_cfbX_clear_margins, - ~1 /* FONTWIDTHS */ /* TODO: and what about non-aligned access on BE? I think that there are no in my code */ -}; -#endif - -#ifdef FBCON_HAS_CFB32 -static struct display_switch matroxfb_cfb32 = { - fbcon_cfb32_setup, matrox_cfbX_bmove, matrox_cfb32_clear, - matrox_cfb32_putc, matrox_cfb32_putcs, matrox_cfb32_revc, - NULL, NULL, matrox_cfbX_clear_margins, - ~1 /* FONTWIDTHS */ -}; -#endif - -static void initMatrox(WPMINFO struct display* p) { - struct display_switch *swtmp; - - DBG("initMatrox") - - if (ACCESS_FBINFO(currcon_display) != p) - return; - if (p->dispsw && p->conp) - fb_con.con_cursor(p->conp, CM_ERASE); - p->dispsw_data = NULL; - if ((p->var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) { - if (p->type == FB_TYPE_TEXT) { - swtmp = &matroxfb_text; - } else { - switch (p->var.bits_per_pixel) { -#ifdef FBCON_HAS_CFB4 - case 4: - swtmp = &fbcon_cfb4; - break; -#endif -#ifdef FBCON_HAS_CFB8 - case 8: - swtmp = &fbcon_cfb8; - break; -#endif -#ifdef FBCON_HAS_CFB16 - case 16: - p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16); - swtmp = &fbcon_cfb16; - break; -#endif -#ifdef FBCON_HAS_CFB24 - case 24: - p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24); - swtmp = &fbcon_cfb24; - break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32: - p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32); - swtmp = &fbcon_cfb32; - break; -#endif - default: - p->dispsw = &fbcon_dummy; - return; - } - } - dprintk(KERN_INFO "matroxfb: acceleration disabled\n"); - } else if (p->type == FB_TYPE_TEXT) { - swtmp = &matroxfb_text; - } else { - switch (p->var.bits_per_pixel) { -#ifdef FBCON_HAS_CFB4 - case 4: - swtmp = &matroxfb_cfb4; - break; -#endif -#ifdef FBCON_HAS_CFB8 - case 8: - swtmp = &matroxfb_cfb8; - break; -#endif -#ifdef FBCON_HAS_CFB16 - case 16: - p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16); - swtmp = &matroxfb_cfb16; - break; -#endif -#ifdef FBCON_HAS_CFB24 - case 24: - p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24); - swtmp = &matroxfb_cfb24; - break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32: - p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32); - swtmp = &matroxfb_cfb32; - break; -#endif - default: - p->dispsw = &fbcon_dummy; - return; - } - } - memcpy(&ACCESS_FBINFO(dispsw), swtmp, sizeof(ACCESS_FBINFO(dispsw))); - p->dispsw = &ACCESS_FBINFO(dispsw); - if ((p->type != FB_TYPE_TEXT) && ACCESS_FBINFO(devflags.hwcursor)) { - if (isMillenium(MINFO)) { -#ifdef CONFIG_FB_MATROX_MILLENIUM - ACCESS_FBINFO(dispsw.cursor) = matroxfb_ti3026_cursor; - ACCESS_FBINFO(dispsw.set_font) = matroxfb_ti3026_setfont; -#endif - } else { -#ifdef NEED_DAC1064 - ACCESS_FBINFO(dispsw.cursor) = matroxfb_DAC1064_cursor; - ACCESS_FBINFO(dispsw.set_font) = matroxfb_DAC1064_setfont; -#endif - } - } -} - -/* --------------------------------------------------------------------- */ - -/* - * card parameters - */ - -/* --------------------------------------------------------------------- */ - -static struct fb_var_screeninfo vesafb_defined __initdata = { - 640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/ - 0,0, /* virtual -> visible no offset */ - 8, /* depth -> load bits_per_pixel */ - 0, /* greyscale ? */ - {0,0,0}, /* R */ - {0,0,0}, /* G */ - {0,0,0}, /* B */ - {0,0,0}, /* transparency */ - 0, /* standard pixel format */ - FB_ACTIVATE_NOW, - -1,-1, - FB_ACCELF_TEXT, /* accel flags */ - 39721L,48L,16L,33L,10L, - 96L,2L,~0, /* No sync info */ - FB_VMODE_NONINTERLACED, - {0,0,0,0,0,0} -}; - - - -/* --------------------------------------------------------------------- */ - -static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) { - unsigned int pos; - unsigned short p0, p1, p2; -#ifdef CONFIG_FB_MATROX_32MB - unsigned int p3; -#endif - struct display *disp; - - DBG("matrox_pan_var") - - disp = ACCESS_FBINFO(currcon_display); - if (disp->type == FB_TYPE_TEXT) { - pos = var->yoffset / fontheight(disp) * disp->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(disp)?fontwidth(disp):8); - } else { - pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32; - pos += ACCESS_FBINFO(curr.ydstorg.chunks); - } - p0 = ACCESS_FBINFO(currenthw)->CRTC[0x0D] = pos & 0xFF; - p1 = ACCESS_FBINFO(currenthw)->CRTC[0x0C] = (pos & 0xFF00) >> 8; - p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); -#ifdef CONFIG_FB_MATROX_32MB - p3 = ACCESS_FBINFO(currenthw)->CRTCEXT[8] = pos >> 21; -#endif - - mga_setr(M_CRTC_INDEX, 0x0D, p0); - mga_setr(M_CRTC_INDEX, 0x0C, p1); -#ifdef CONFIG_FB_MATROX_32MB - if (ACCESS_FBINFO(devflags.support32MB)) - mga_setr(M_EXTVGA_INDEX, 0x08, p3); -#endif - mga_setr(M_EXTVGA_INDEX, 0x00, p2); -} - - /* - * Open/Release the frame buffer device - */ - -static int matroxfb_open(struct fb_info *info, int user) -{ - DBG_LOOP("matroxfb_open") - - /* - * Nothing, only a usage count for the moment - */ - MOD_INC_USE_COUNT; - return(0); -} - -static int matroxfb_release(struct fb_info *info, int user) -{ - DBG_LOOP("matroxfb_release") - - MOD_DEC_USE_COUNT; - return(0); -} - -static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info* info) { -#define minfo ((struct matrox_fb_info*)info) - - DBG("matroxfb_pan_display") - - if (var->vmode & FB_VMODE_YWRAP) { - if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset) - return -EINVAL; - } else { - if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual || - var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual) - return -EINVAL; - } - if (con == ACCESS_FBINFO(currcon)) - matrox_pan_var(PMINFO var); - fb_display[con].var.xoffset = var->xoffset; - fb_display[con].var.yoffset = var->yoffset; - if (var->vmode & FB_VMODE_YWRAP) - fb_display[con].var.vmode |= FB_VMODE_YWRAP; - else - fb_display[con].var.vmode &= ~FB_VMODE_YWRAP; - return 0; -#undef minfo -} - -static int matroxfb_updatevar(int con, struct fb_info *info) -{ -#define minfo ((struct matrox_fb_info*)info) - DBG("matroxfb_updatevar"); - - matrox_pan_var(PMINFO &fb_display[con].var); - return 0; -#undef minfo -} - -static int matroxfb_get_final_bppShift(CPMINFO int bpp) { - int bppshft2; - - DBG("matroxfb_get_final_bppShift") - - bppshft2 = bpp; - if (!bppshft2) { - return 8; - } - if (isInterleave(MINFO)) - bppshft2 >>= 1; - if (ACCESS_FBINFO(devflags.video64bits)) - bppshft2 >>= 1; - return bppshft2; -} - -static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) { - int over; - int rounding; - - DBG("matroxfb_test_and_set_rounding") - - switch (bpp) { - case 0: return xres; - case 4: rounding = 128; - break; - case 8: rounding = 64; /* doc says 64; 32 is OK for G400 */ - break; - case 16: rounding = 32; - break; - case 24: rounding = 64; /* doc says 64; 32 is OK for G400 */ - break; - default: rounding = 16; - /* on G400, 16 really does not work */ - if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) - rounding = 32; - break; - } - if (isInterleave(MINFO)) { - rounding *= 2; - } - over = xres % rounding; - if (over) - xres += rounding-over; - return xres; -} - -static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) { - const int* width; - int xres_new; - - DBG("matroxfb_pitch_adjust") - - if (!bpp) return xres; - - width = ACCESS_FBINFO(capable.vxres); - - if (ACCESS_FBINFO(devflags.precise_width)) { - while (*width) { - if ((*width >= xres) && (matroxfb_test_and_set_rounding(PMINFO *width, bpp) == *width)) { - break; - } - width++; - } - xres_new = *width; - } else { - xres_new = matroxfb_test_and_set_rounding(PMINFO xres, bpp); - } - if (!xres_new) return 0; - if (xres != xres_new) { - printk(KERN_INFO "matroxfb: cannot set xres to %d, rounded up to %d\n", xres, xres_new); - } - return xres_new; -} - -#ifdef CONFIG_FB_MATROX_MILLENIUM -static const unsigned char DACseq[] = -{ TVP3026_XLATCHCTRL, TVP3026_XTRUECOLORCTRL, - TVP3026_XMUXCTRL, TVP3026_XCLKCTRL, - TVP3026_XPALETTEPAGE, - TVP3026_XGENCTRL, - TVP3026_XMISCCTRL, - TVP3026_XGENIOCTRL, - TVP3026_XGENIODATA, - TVP3026_XCOLKEYOVRMIN, TVP3026_XCOLKEYOVRMAX, TVP3026_XCOLKEYREDMIN, TVP3026_XCOLKEYREDMAX, - TVP3026_XCOLKEYGREENMIN, TVP3026_XCOLKEYGREENMAX, TVP3026_XCOLKEYBLUEMIN, TVP3026_XCOLKEYBLUEMAX, - TVP3026_XCOLKEYCTRL, - TVP3026_XMEMPLLCTRL, TVP3026_XSENSETEST, TVP3026_XCURCTRL }; - -#define POS3026_XLATCHCTRL 0 -#define POS3026_XTRUECOLORCTRL 1 -#define POS3026_XMUXCTRL 2 -#define POS3026_XCLKCTRL 3 -#define POS3026_XGENCTRL 5 -#define POS3026_XMISCCTRL 6 -#define POS3026_XMEMPLLCTRL 18 -#define POS3026_XCURCTRL 20 - -static const unsigned char MGADACbpp32[] = -{ TVP3026_XLATCHCTRL_2_1, TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_8888, - 0x00, TVP3026_XCLKCTRL_DIV1 | TVP3026_XCLKCTRL_SRC_PLL, - 0x00, - TVP3026_XGENCTRL_HSYNC_POS | TVP3026_XGENCTRL_VSYNC_POS | TVP3026_XGENCTRL_LITTLE_ENDIAN | TVP3026_XGENCTRL_BLACK_0IRE | TVP3026_XGENCTRL_NO_SYNC_ON_GREEN | TVP3026_XGENCTRL_OVERSCAN_DIS, - TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_HIGH, - 0x00, - 0x1E, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - TVP3026_XCOLKEYCTRL_ZOOM1, - 0x00, 0x00, TVP3026_XCURCTRL_DIS }; -#endif /* CONFIG_FB_MATROX_MILLENIUM */ - -static int PLL_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) { - unsigned int bestdiff = ~0; - unsigned int bestvco = 0; - unsigned int fxtal = ACCESS_FBINFO(features.pll.ref_freq); - unsigned int fwant; - unsigned int p; - - DBG("PLL_calcclock") - - fwant = freq; - -#ifdef DEBUG - printk(KERN_ERR "post_shift_max: %d\n", ACCESS_FBINFO(features.pll.post_shift_max)); - printk(KERN_ERR "ref_freq: %d\n", ACCESS_FBINFO(features.pll.ref_freq)); - printk(KERN_ERR "freq: %d\n", freq); - printk(KERN_ERR "vco_freq_min: %d\n", ACCESS_FBINFO(features.pll.vco_freq_min)); - printk(KERN_ERR "in_div_min: %d\n", ACCESS_FBINFO(features.pll.in_div_min)); - printk(KERN_ERR "in_div_max: %d\n", ACCESS_FBINFO(features.pll.in_div_max)); - printk(KERN_ERR "feed_div_min: %d\n", ACCESS_FBINFO(features.pll.feed_div_min)); - printk(KERN_ERR "feed_div_max: %d\n", ACCESS_FBINFO(features.pll.feed_div_max)); - printk(KERN_ERR "fmax: %d\n", fmax); -#endif - for (p = 1; p <= ACCESS_FBINFO(features.pll.post_shift_max); p++) { - if (fwant * 2 > fmax) - break; - fwant *= 2; - } - if (fwant < ACCESS_FBINFO(features.pll.vco_freq_min)) fwant = ACCESS_FBINFO(features.pll.vco_freq_min); - if (fwant > fmax) fwant = fmax; - for (; p-- > 0; fwant >>= 1, bestdiff >>= 1) { - unsigned int m; - - if (fwant < ACCESS_FBINFO(features.pll.vco_freq_min)) break; - for (m = ACCESS_FBINFO(features.pll.in_div_min); m <= ACCESS_FBINFO(features.pll.in_div_max); m++) { - unsigned int diff, fvco; - unsigned int n; - - n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1; - if (n > ACCESS_FBINFO(features.pll.feed_div_max)) - break; - if (n < ACCESS_FBINFO(features.pll.feed_div_min)) - n = ACCESS_FBINFO(features.pll.feed_div_min); - fvco = (fxtal * (n + 1)) / (m + 1); - if (fvco < fwant) - diff = fwant - fvco; - else - diff = fvco - fwant; - if (diff < bestdiff) { - bestdiff = diff; - *post = p; - *in = m; - *feed = n; - bestvco = fvco; - } - } - } - dprintk(KERN_ERR "clk: %02X %02X %02X %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant); - return bestvco; -} - -#ifdef NEED_DAC1064 -static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) { - unsigned int fvco; - unsigned int p; - - DBG("DAC1064_calcclock") - - fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p); - p = (1 << p) - 1; - if (fvco <= 100000) - ; - else if (fvco <= 140000) - p |= 0x08; - else if (fvco <= 180000) - p |= 0x10; - else - p |= 0x18; - *post = p; -} -#endif - -#ifdef CONFIG_FB_MATROX_MILLENIUM -static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* in, int* feed, int* post) { - unsigned int fvco; - unsigned int lin, lfeed, lpost; - - DBG("Ti3026_calcclock") - - fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost); - fvco >>= (*post = lpost); - *in = 64 - lin; - *feed = 64 - lfeed; - return fvco; -} - -static int Ti3026_setpclk(CPMINFO struct matrox_hw_state* hw, int clk, struct display* p) { - unsigned int f_pll; - unsigned int pixfeed, pixin, pixpost; - - DBG("Ti3026_setpclk") - - f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost); - - hw->DACclk[0] = pixin | 0xC0; - hw->DACclk[1] = pixfeed; - hw->DACclk[2] = pixpost | 0xB0; - - if (p->type == FB_TYPE_TEXT) { - hw->DACreg[POS3026_XMEMPLLCTRL] = TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_PIXPLL; - hw->DACclk[3] = 0xFD; - hw->DACclk[4] = 0x3D; - hw->DACclk[5] = 0x70; - } else { - unsigned int loopfeed, loopin, looppost, loopdiv, z; - unsigned int Bpp; - - Bpp = ACCESS_FBINFO(curr.final_bppShift); - - if (p->var.bits_per_pixel == 24) { - loopfeed = 3; /* set lm to any possible value */ - loopin = 3 * 32 / Bpp; - } else { - loopfeed = 4; - loopin = 4 * 32 / Bpp; - } - z = (110000 * loopin) / (f_pll * loopfeed); - loopdiv = 0; /* div 2 */ - if (z < 2) - looppost = 0; - else if (z < 4) - looppost = 1; - else if (z < 8) - looppost = 2; - else { - looppost = 3; - loopdiv = z/16; - } - if (p->var.bits_per_pixel == 24) { - hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0; - hw->DACclk[4] = (65 - loopfeed) | 0x80; - if (ACCESS_FBINFO(accel.ramdac_rev) > 0x20) { - if (isInterleave(MINFO)) - hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_8_3; - else { - hw->DACclk[4] &= ~0xC0; - hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_4_3; - } - } else { - if (isInterleave(MINFO)) - ; /* default... */ - else { - hw->DACclk[4] ^= 0xC0; /* change from 0x80 to 0x40 */ - hw->DACreg[POS3026_XLATCHCTRL] = TVP3026A_XLATCHCTRL_4_3; - } - } - hw->DACclk[5] = looppost | 0xF8; - if (ACCESS_FBINFO(devflags.mga_24bpp_fix)) - hw->DACclk[5] ^= 0x40; - } else { - hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0; - hw->DACclk[4] = 65 - loopfeed; - hw->DACclk[5] = looppost | 0xF0; - } - hw->DACreg[POS3026_XMEMPLLCTRL] = loopdiv | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL; - } - return 0; -} -#endif - -static void var2my(struct fb_var_screeninfo* var, struct my_timming* mt) { - unsigned int pixclock = var->pixclock; - - DBG("var2my") - - if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ - mt->pixclock = 1000000000 / pixclock; - if (mt->pixclock < 1) mt->pixclock = 1; - mt->dblscan = var->vmode & FB_VMODE_DOUBLE; - mt->interlaced = var->vmode & FB_VMODE_INTERLACED; - mt->HDisplay = var->xres; - mt->HSyncStart = mt->HDisplay + var->right_margin; - mt->HSyncEnd = mt->HSyncStart + var->hsync_len; - mt->HTotal = mt->HSyncEnd + var->left_margin; - mt->VDisplay = var->yres; - mt->VSyncStart = mt->VDisplay + var->lower_margin; - mt->VSyncEnd = mt->VSyncStart + var->vsync_len; - mt->VTotal = mt->VSyncEnd + var->upper_margin; - mt->sync = var->sync; -} - -static int vgaHWinit(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) { - unsigned int hd, hs, he, hbe, ht; - unsigned int vd, vs, ve, vt; - unsigned int wd; - unsigned int divider; - int i; - int text = p->type == FB_TYPE_TEXT; - int fwidth; - - if (text) { - fwidth = fontwidth(p); - if (!fwidth) fwidth = 8; - } else - fwidth = 8; - - DBG("vgaHWinit") - - hw->SEQ[0] = 0x00; - if (fwidth == 9) - hw->SEQ[1] = 0x00; - else - hw->SEQ[1] = 0x01; /* or 0x09 */ - hw->SEQ[2] = 0x0F; /* bitplanes */ - hw->SEQ[3] = 0x00; - if (text) - hw->SEQ[4] = 0x02; - else - hw->SEQ[4] = 0x0E; - /* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millenium code... Hope that by MGA1064 too */ - if (m->dblscan) { - m->VTotal <<= 1; - m->VDisplay <<= 1; - m->VSyncStart <<= 1; - m->VSyncEnd <<= 1; - } - if (m->interlaced) { - m->VTotal >>= 1; - m->VDisplay >>= 1; - m->VSyncStart >>= 1; - m->VSyncEnd >>= 1; - } - - /* GCTL is ignored when not using 0xA0000 aperture */ - hw->GCTL[0] = 0x00; - hw->GCTL[1] = 0x00; - hw->GCTL[2] = 0x00; - hw->GCTL[3] = 0x00; - hw->GCTL[4] = 0x00; - if (text) { - hw->GCTL[5] = 0x10; - hw->GCTL[6] = 0x02; - } else { - hw->GCTL[5] = 0x40; - hw->GCTL[6] = 0x05; - } - hw->GCTL[7] = 0x0F; - hw->GCTL[8] = 0xFF; - - /* Whole ATTR is ignored in PowerGraphics mode */ - for (i = 0; i < 16; i++) - hw->ATTR[i] = i; - if (text) { - hw->ATTR[16] = 0x04; - } else { - hw->ATTR[16] = 0x41; - } - hw->ATTR[17] = 0xFF; - hw->ATTR[18] = 0x0F; - if (fwidth == 9) - hw->ATTR[19] = 0x08; - else - hw->ATTR[19] = 0x00; - hw->ATTR[20] = 0x00; - - if (text) { - hd = m->HDisplay / fwidth; - hs = m->HSyncStart / fwidth; - he = m->HSyncEnd / fwidth; - ht = m->HTotal / fwidth; - divider = 8; - } else { - hd = m->HDisplay >> 3; - hs = m->HSyncStart >> 3; - he = m->HSyncEnd >> 3; - ht = m->HTotal >> 3; - /* standard timmings are in 8pixels, but for interleaved we cannot */ - /* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */ - /* using 16 or more pixels per unit can save us */ - divider = ACCESS_FBINFO(curr.final_bppShift); - } - while (divider & 3) { - hd >>= 1; - hs >>= 1; - he >>= 1; - ht >>= 1; - divider <<= 1; - } - divider = divider / 4; - /* divider can be from 1 to 8 */ - while (divider > 8) { - hd <<= 1; - hs <<= 1; - he <<= 1; - ht <<= 1; - divider >>= 1; - } - hd = hd - 1; - hs = hs - 1; - he = he - 1; - ht = ht - 1; - vd = m->VDisplay - 1; - vs = m->VSyncStart - 1; - ve = m->VSyncEnd - 1; - vt = m->VTotal - 2; - /* G200 cannot work with (ht & 7) == 6 */ - if (((ht & 0x07) == 0x06) || ((ht & 0x0F) == 0x04)) - ht++; - if (text) { - hbe = ht - 1; - wd = p->var.xres_virtual / (fwidth * 2); - } else { - hbe = ht; - wd = p->var.xres_virtual * ACCESS_FBINFO(curr.final_bppShift) / 64; - } - - hw->CRTCEXT[0] = 0; - hw->CRTCEXT[5] = 0; - if (m->interlaced) { - hw->CRTCEXT[0] = 0x80; - hw->CRTCEXT[5] = (hs + he - ht) >> 1; - if (!m->dblscan) - wd <<= 1; - vt &= ~1; - } - hw->CRTCEXT[0] |= (wd & 0x300) >> 4; - hw->CRTCEXT[1] = (((ht - 4) & 0x100) >> 8) | - ((hd & 0x100) >> 7) | /* blanking */ - ((hs & 0x100) >> 6) | /* sync start */ - (hbe & 0x040); /* end hor. blanking */ - hw->CRTCEXT[2] = ((vt & 0xC00) >> 10) | - ((vd & 0x400) >> 8) | /* disp end */ - ((vd & 0xC00) >> 7) | /* vblanking start */ - ((vs & 0xC00) >> 5); - if (text) - hw->CRTCEXT[3] = 0x00; - else - hw->CRTCEXT[3] = (divider - 1) | 0x80; - hw->CRTCEXT[4] = 0; - - hw->CRTC[0] = ht-4; - hw->CRTC[1] = hd; - hw->CRTC[2] = hd; - hw->CRTC[3] = (hbe & 0x1F) | 0x80; - hw->CRTC[4] = hs; - hw->CRTC[5] = ((hbe & 0x20) << 2) | (he & 0x1F); - if (text) - hw->CRTC[5] |= 0x60; /* delay sync for 3 clocks (to same picture position on MGA and VGA) */ - hw->CRTC[6] = vt & 0xFF; - hw->CRTC[7] = ((vt & 0x100) >> 8) | - ((vd & 0x100) >> 7) | - ((vs & 0x100) >> 6) | - ((vd & 0x100) >> 5) | - 0x10 | - ((vt & 0x200) >> 4) | - ((vd & 0x200) >> 3) | - ((vs & 0x200) >> 2); - hw->CRTC[8] = 0x00; - hw->CRTC[9] = ((vd & 0x200) >> 4) | 0x40; - if (text) - hw->CRTC[9] |= fontheight(p) - 1; - if (m->dblscan && !m->interlaced) - hw->CRTC[9] |= 0x80; - for (i = 10; i < 16; i++) - hw->CRTC[i] = 0x00; - hw->CRTC[16] = vs /* & 0xFF */; - hw->CRTC[17] = (ve & 0x0F) | 0x20; - hw->CRTC[18] = vd /* & 0xFF */; - hw->CRTC[19] = wd /* & 0xFF */; - hw->CRTC[20] = 0x00; - hw->CRTC[21] = vd /* & 0xFF */; - hw->CRTC[22] = (vt + 1) /* & 0xFF */; - if (text) { - if (ACCESS_FBINFO(devflags.textmode) == 1) - hw->CRTC[23] = 0xC3; - else - hw->CRTC[23] = 0xA3; - if (ACCESS_FBINFO(devflags.textmode) == 4) - hw->CRTC[20] = 0x5F; - else - hw->CRTC[20] = 0x1F; - } else - hw->CRTC[23] = 0xC3; - hw->CRTC[24] = 0xFF; - return 0; -}; - -#ifdef NEED_DAC1064 - -static const unsigned char MGA1064_DAC_regs[] = { - M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL, - M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE, - M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE, - M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE, - DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL, - M1064_XMISCCTRL, - M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST, - M1064_XCRCBITSEL, - M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH }; - -#define POS1064_XCURADDL 0 -#define POS1064_XCURADDH 1 -#define POS1064_XVREFCTRL 12 -#define POS1064_XMULCTRL 13 -#define POS1064_XGENCTRL 15 -#define POS1064_XMISCCTRL 16 - -static const unsigned char MGA1064_DAC[] = { - 0x00, 0x00, M1064_XCURCTRL_DIS, - 0x00, 0x00, 0x00, /* black */ - 0xFF, 0xFF, 0xFF, /* white */ - 0xFF, 0x00, 0x00, /* red */ - 0x00, 0, - M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL, - M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN, - M1064_XMISCCTRL_DAC_EN | M1064_XMISCCTRL_MFC_DIS | M1064_XMISCCTRL_DAC_8BIT | M1064_XMISCCTRL_LUT_EN, - 0x10, 0x3F, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN, - 0x00, - 0x00, 0x00, 0xFF, 0xFF}; - -static void DAC1064_setpclk(CPMINFO struct matrox_hw_state* hw, unsigned long fout) { - unsigned int m, n, p; - - DBG("DAC1064_setpclk") - - DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); - hw->DACclk[0] = m; - hw->DACclk[1] = n; - hw->DACclk[2] = p; -} - -static void __init DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem){ - u_int32_t mx; - - DBG("DAC1064_setmclk") - - if (ACCESS_FBINFO(devflags.noinit)) { - /* read MCLK and give up... */ - hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM); - hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN); - hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP); - return; - } - mx = hw->MXoptionReg | 0x00000004; - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); - mx &= ~0x000000BB; - if (oscinfo & DAC1064_OPT_GDIV1) - mx |= 0x00000008; - if (oscinfo & DAC1064_OPT_MDIV1) - mx |= 0x00000010; - if (oscinfo & DAC1064_OPT_RESERVED) - mx |= 0x00000080; - if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) { - /* select PCI clock until we have setup oscilator... */ - int clk; - unsigned int m, n, p; - - /* powerup system PLL, select PCI clock */ - mx |= 0x00000020; - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); - mx &= ~0x00000004; - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); - - /* !!! you must not access device if MCLK is not running !!! - Doing so cause immediate PCI lockup :-( Maybe they should - generate ABORT or I/O (parity...) error and Linux should - recover from this... (kill driver/process). But world is not - perfect... */ - /* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not - select PLL... because of PLL can be stopped at this time) */ - DAC1064_calcclock(PMINFO fmem, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); - outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3] = m); - outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4] = n); - outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5] = p); - for (clk = 65536; clk; --clk) { - if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40) - break; - } - if (!clk) - printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n"); - /* select PLL */ - mx |= 0x00000005; - } else { - /* select specified system clock source */ - mx |= oscinfo & DAC1064_OPT_SCLK_MASK; - } - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); - mx &= ~0x00000004; - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); - hw->MXoptionReg = mx; -} - -static int DAC1064_init_1(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display *p) { - - DBG("DAC1064_init_1") - - memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs)); - if (p->type == FB_TYPE_TEXT) { - hw->DACreg[POS1064_XMISCCTRL] = M1064_XMISCCTRL_DAC_EN - | M1064_XMISCCTRL_MFC_DIS - | M1064_XMISCCTRL_DAC_6BIT - | M1064_XMISCCTRL_LUT_EN; - hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP - | M1064_XMULCTRL_GRAPHICS_PALETIZED; - } else { - switch (p->var.bits_per_pixel) { - /* case 4: not supported by MGA1064 DAC */ - case 8: - hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; - break; - case 16: - if (p->var.green.length == 5) - hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; - else - hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; - break; - case 24: - hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; - break; - case 32: - hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; - break; - default: - return 1; /* unsupported depth */ - } - } - hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl); - hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK; - hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN; - hw->DACreg[POS1064_XCURADDL] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 10; - hw->DACreg[POS1064_XCURADDH] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 18; - return 0; -} - -static int DAC1064_init_2(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) { - - DBG("DAC1064_init_2") - - DAC1064_setpclk(PMINFO hw, m->pixclock); - if (p->var.bits_per_pixel > 16) { /* 256 entries */ - int i; - - for (i = 0; i < 256; i++) { - hw->DACpal[i * 3 + 0] = i; - hw->DACpal[i * 3 + 1] = i; - hw->DACpal[i * 3 + 2] = i; - } - } else if (p->var.bits_per_pixel > 8) { - if (p->var.green.length == 5) { /* 0..31, 128..159 */ - int i; - - for (i = 0; i < 32; i++) { - /* with p15 == 0 */ - hw->DACpal[i * 3 + 0] = i << 3; - hw->DACpal[i * 3 + 1] = i << 3; - hw->DACpal[i * 3 + 2] = i << 3; - /* with p15 == 1 */ - hw->DACpal[(i + 128) * 3 + 0] = i << 3; - hw->DACpal[(i + 128) * 3 + 1] = i << 3; - hw->DACpal[(i + 128) * 3 + 2] = i << 3; - } - } else { - int i; - - for (i = 0; i < 64; i++) { /* 0..63 */ - hw->DACpal[i * 3 + 0] = i << 3; - hw->DACpal[i * 3 + 1] = i << 2; - hw->DACpal[i * 3 + 2] = i << 3; - } - } - } else { - memset(hw->DACpal, 0, 768); - } - return 0; -} - -static void DAC1064_restore_1(CPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) { - - DBG("DAC1064_restore_1") - - outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]); - outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]); - outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]); - if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) { - unsigned int i; - - for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) - outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]); - } -} - -static void DAC1064_restore_2(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw, struct display* p) { - unsigned int i; - unsigned int tmout; - - DBG("DAC1064_restore_2") - - for (i = 0; i < 3; i++) - outDAC1064(PMINFO M1064_XPIXPLLCM + i, hw->DACclk[i]); - for (tmout = 500000; tmout; tmout--) { - if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40) - break; - udelay(10); - } - - if (!tmout) - printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n"); - - if (p && p->conp) { - if (p->type == FB_TYPE_TEXT) { - matrox_text_createcursor(PMINFO p); - matrox_text_loadfont(PMINFO p); - i = 0; - } else { - matroxfb_DAC1064_createcursor(PMINFO p); - i = matroxfb_fastfont_tryset(PMINFO p); - } - } else - i = 0; - if (i) { - ACCESS_FBINFO(curr.putc) = matrox_cfbX_fastputc; - ACCESS_FBINFO(curr.putcs) = matrox_cfbX_fastputcs; - } else { - ACCESS_FBINFO(curr.putc) = matrox_cfbX_putc; - ACCESS_FBINFO(curr.putcs) = matrox_cfbX_putcs; - } -#ifdef DEBUG - dprintk(KERN_DEBUG "DAC1064regs "); - for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) { - dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], hw->DACreg[i]); - if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... "); - } - dprintk("\n" KERN_DEBUG "DAC1064clk "); - for (i = 0; i < 6; i++) - dprintk("C%02X=%02X ", i, hw->DACclk[i]); - dprintk("\n"); -#endif -} -#endif /* NEED_DAC1064 */ - -#ifdef CONFIG_FB_MATROX_MYSTIQUE -static int MGA1064_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) { - - DBG("MGA1064_init") - - if (DAC1064_init_1(PMINFO hw, m, p)) return 1; - if (vgaHWinit(PMINFO hw, m, p)) return 1; - - hw->MiscOutReg = 0xCB; - if (m->sync & FB_SYNC_HOR_HIGH_ACT) - hw->MiscOutReg &= ~0x40; - if (m->sync & FB_SYNC_VERT_HIGH_ACT) - hw->MiscOutReg &= ~0x80; - if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */ - hw->CRTCEXT[3] |= 0x40; - - if (DAC1064_init_2(PMINFO hw, m, p)) return 1; - return 0; -} -#endif - -#ifdef CONFIG_FB_MATROX_G100 -static int MGAG100_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) { - - DBG("MGAG100_init") - - if (DAC1064_init_1(PMINFO hw, m, p)) return 1; - hw->MXoptionReg &= ~0x2000; - if (vgaHWinit(PMINFO hw, m, p)) return 1; - - hw->MiscOutReg = 0xEF; - if (m->sync & FB_SYNC_HOR_HIGH_ACT) - hw->MiscOutReg &= ~0x40; - if (m->sync & FB_SYNC_VERT_HIGH_ACT) - hw->MiscOutReg &= ~0x80; - if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */ - hw->CRTCEXT[3] |= 0x40; - - if (DAC1064_init_2(PMINFO hw, m, p)) return 1; - return 0; -} -#endif /* G100 */ - -#ifdef CONFIG_FB_MATROX_MILLENIUM -static int Ti3026_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) { - u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT; - - DBG("Ti3026_init") - - memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg)); - if (p->type == FB_TYPE_TEXT) { - hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1; - hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR; - hw->DACreg[POS3026_XMUXCTRL] = TVP3026_XMUXCTRL_VGA; - hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | - TVP3026_XCLKCTRL_DIV4; - hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_6BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW; - } else { - switch (p->var.bits_per_pixel) { - case 4: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1; /* or _8_1, they are same */ - hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR; - hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT; - hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV8; - hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW; - break; - case 8: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1; /* or _4_1, they are same */ - hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR; - hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_8BIT; - hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4; - hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW; - break; - case 16: - /* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used everytime) */ - hw->DACreg[POS3026_XTRUECOLORCTRL] = (p->var.green.length == 5)? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555 ) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565); - hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT; - hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2; - break; - case 24: - /* XLATCHCTRL is: for (A) use _4_3 (?_8_3 is same? TBD), for (B) it is set in setpclk */ - hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_888; - hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT; - hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4; - break; - case 32: - /* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used everytime) */ - hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT; - break; - default: - return 1; /* TODO: failed */ - } - } - if (vgaHWinit(PMINFO hw, m, p)) return 1; - - /* set SYNC */ - hw->MiscOutReg = 0xCB; - if (m->sync & FB_SYNC_HOR_HIGH_ACT) - hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_HSYNC_NEG; - if (m->sync & FB_SYNC_VERT_HIGH_ACT) - hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_VSYNC_NEG; - if (m->sync & FB_SYNC_ON_GREEN) - hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_SYNC_ON_GREEN; - - /* set DELAY */ - if (ACCESS_FBINFO(video.len) < 0x400000) - hw->CRTCEXT[3] |= 0x08; - else if (ACCESS_FBINFO(video.len) > 0x400000) - hw->CRTCEXT[3] |= 0x10; - - /* set HWCURSOR */ - if (m->interlaced) { - hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_INTERLACED; - } - if (m->HTotal >= 1536) - hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_BLANK4096; - - /* set interleaving */ - hw->MXoptionReg &= ~0x00001000; - if ((p->type != FB_TYPE_TEXT) && isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000; - - /* set DAC */ - Ti3026_setpclk(PMINFO hw, m->pixclock, p); - return 0; -} -#endif /* CONFIG_FB_MATROX_MILLENIUM */ - -static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) { - - DBG("matroxfb_get_cmap_len") - - switch (var->bits_per_pixel) { -#ifdef FBCON_HAS_VGATEXT - case 0: - return 16; /* pseudocolor... 16 entries HW palette */ -#endif -#ifdef FBCON_HAS_CFB4 - case 4: - return 16; /* pseudocolor... 16 entries HW palette */ -#endif -#ifdef FBCON_HAS_CFB8 - case 8: - return 256; /* pseudocolor... 256 entries HW palette */ -#endif -#ifdef FBCON_HAS_CFB16 - case 16: - return 16; /* directcolor... 16 entries SW palette */ - /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ -#endif -#ifdef FBCON_HAS_CFB24 - case 24: - return 16; /* directcolor... 16 entries SW palette */ - /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ -#endif -#ifdef FBCON_HAS_CFB32 - case 32: - return 16; /* directcolor... 16 entries SW palette */ - /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ -#endif - } - return 16; /* return something reasonable... or panic()? */ -} - -static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) { - unsigned int vramlen; - unsigned int memlen; - - DBG("matroxfb_decode_var") - - switch (var->bits_per_pixel) { -#ifdef FBCON_HAS_VGATEXT - case 0: if (!ACCESS_FBINFO(capable.text)) return -EINVAL; - break; -#endif -#ifdef FBCON_HAS_CFB4 - case 4: if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL; - break; -#endif -#ifdef FBCON_HAS_CFB8 - case 8: break; -#endif -#ifdef FBCON_HAS_CFB16 - case 16: break; -#endif -#ifdef FBCON_HAS_CFB24 - case 24: break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32: break; -#endif - default: return -EINVAL; - } - *ydstorg = 0; - vramlen = ACCESS_FBINFO(video.len_usable); - if (var->bits_per_pixel) { - var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, var->bits_per_pixel); - memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8; - if (memlen > vramlen) { - var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel); - memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8; - } - /* There is hardware bug that no line can cross 4MB boundary */ - /* give up for CFB24, it is impossible to easy workaround it */ - /* for other try to do something */ - if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) { - if (var->bits_per_pixel == 24) { - /* sorry */ - } else { - unsigned int linelen; - unsigned int m1 = linelen = var->xres_virtual * var->bits_per_pixel / 8; - unsigned int m2 = PAGE_SIZE; /* or 128 if you do not need PAGE ALIGNED address */ - unsigned int max_yres; - - while (m1) { - int t; - - while (m2 >= m1) m2 -= m1; - t = m1; - m1 = m2; - m2 = t; - } - m2 = linelen * PAGE_SIZE / m2; - *ydstorg = m2 = 0x400000 % m2; - max_yres = (vramlen - m2) / linelen; - if (var->yres_virtual > max_yres) - var->yres_virtual = max_yres; - } - } - } else { - matrox_text_round(PMINFO var, p); -#if 0 -/* we must limit pixclock by mclk... - Millenium I: 66 MHz = 15000 - Millenium II: 61 MHz = 16300 - Millenium G200: 83 MHz = 12000 */ - if (var->pixclock < 15000) - var->pixclock = 15000; /* limit for "normal" gclk & mclk */ -#endif - } - /* YDSTLEN contains only signed 16bit value */ - if (var->yres_virtual > 32767) - var->yres_virtual = 32767; - if (var->yres_virtual < var->yres) - var->yres = var->yres_virtual; - if (var->xres_virtual < var->xres) - var->xres = var->xres_virtual; - if (var->xoffset + var->xres > var->xres_virtual) - var->xoffset = var->xres_virtual - var->xres; - if (var->yoffset + var->yres > var->yres_virtual) - var->yoffset = var->yres_virtual - var->yres; - - if (var->bits_per_pixel == 0) { - var->red.offset = 0; - var->red.length = 6; - var->green.offset = 0; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 6; - var->transp.offset = 0; - var->transp.length = 0; - *visual = MX_VISUAL_PSEUDOCOLOR; - } else if (var->bits_per_pixel == 4) { - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - *visual = MX_VISUAL_PSEUDOCOLOR; - } else if (var->bits_per_pixel <= 8) { - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - *visual = MX_VISUAL_PSEUDOCOLOR; - } else { - if (var->bits_per_pixel <= 16) { - if (var->green.length == 5) { - var->red.offset = 10; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 5; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 15; - var->transp.length = 1; - } else { - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - } - } else if (var->bits_per_pixel <= 24) { - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - } else { - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 8; - } - dprintk("matroxfb: truecolor: " - "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", - var->transp.length, - var->red.length, - var->green.length, - var->blue.length, - var->transp.offset, - var->red.offset, - var->green.offset, - var->blue.offset); - *visual = MX_VISUAL_DIRECTCOLOR; - } - *video_cmap_len = matroxfb_get_cmap_len(var); - dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel, - var->xres_virtual, var->yres_virtual); - return 0; -} - -#ifdef CONFIG_FB_MATROX_MILLENIUM -static void __init ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout){ - unsigned int f_pll; - unsigned int pclk_m, pclk_n, pclk_p; - unsigned int mclk_m, mclk_n, mclk_p; - unsigned int rfhcnt, mclk_ctl; - int tmout; - - DBG("ti3026_setMCLK") - - f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p); - - /* save pclk */ - outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC); - pclk_n = inTi3026(PMINFO TVP3026_XPIXPLLDATA); - outTi3026(PMINFO TVP3026_XPLLADDR, 0xFD); - pclk_m = inTi3026(PMINFO TVP3026_XPIXPLLDATA); - outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE); - pclk_p = inTi3026(PMINFO TVP3026_XPIXPLLDATA); - - /* stop pclk */ - outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE); - outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00); - - /* set pclk to new mclk */ - outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC); - outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_n | 0xC0); - outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_m); - outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_p | 0xB0); - - /* wait for PLL to lock */ - for (tmout = 500000; tmout; tmout--) { - if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40) - break; - udelay(10); - }; - if (!tmout) - printk(KERN_ERR "matroxfb: Temporary pixel PLL not locked after 5 secs\n"); - - /* output pclk on mclk pin */ - mclk_ctl = inTi3026(PMINFO TVP3026_XMEMPLLCTRL); - outTi3026(PMINFO TVP3026_XMEMPLLCTRL, mclk_ctl & 0xE7); - outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_STROBEMKC4); - - /* stop MCLK */ - outTi3026(PMINFO TVP3026_XPLLADDR, 0xFB); - outTi3026(PMINFO TVP3026_XMEMPLLDATA, 0x00); - - /* set mclk to new freq */ - outTi3026(PMINFO TVP3026_XPLLADDR, 0xF3); - outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_n | 0xC0); - outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_m); - outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_p | 0xB0); - - /* wait for PLL to lock */ - for (tmout = 500000; tmout; tmout--) { - if (inTi3026(PMINFO TVP3026_XMEMPLLDATA) & 0x40) - break; - udelay(10); - } - if (!tmout) - printk(KERN_ERR "matroxfb: Memory PLL not locked after 5 secs\n"); - - f_pll = f_pll * 333 / (10000 << mclk_p); - if (isMilleniumII(MINFO)) { - rfhcnt = (f_pll - 128) / 256; - if (rfhcnt > 15) - rfhcnt = 15; - } else { - rfhcnt = (f_pll - 64) / 128; - if (rfhcnt > 15) - rfhcnt = 0; - } - hw->MXoptionReg = (hw->MXoptionReg & ~0x000F0000) | (rfhcnt << 16); - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); - - /* output MCLK to MCLK pin */ - outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL); - outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl ) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_STROBEMKC4); - - /* stop PCLK */ - outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE); - outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00); - - /* restore pclk */ - outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC); - outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_n); - outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_m); - outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_p); - - /* wait for PLL to lock */ - for (tmout = 500000; tmout; tmout--) { - if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40) - break; - udelay(10); - } - if (!tmout) - printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n"); -} - -static void __init ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw){ - - DBG("ti3026_ramdac_init") - - ACCESS_FBINFO(features.pll.vco_freq_min) = 110000; - ACCESS_FBINFO(features.pll.ref_freq) = 114545; - ACCESS_FBINFO(features.pll.feed_div_min) = 2; - ACCESS_FBINFO(features.pll.feed_div_max) = 24; - ACCESS_FBINFO(features.pll.in_div_min) = 2; - ACCESS_FBINFO(features.pll.in_div_max) = 63; - ACCESS_FBINFO(features.pll.post_shift_max) = 3; - if (ACCESS_FBINFO(devflags.noinit)) - return; - ti3026_setMCLK(PMINFO hw, 60000); -} -#endif - -static void matroxfb_fastfont_init(struct matrox_fb_info* minfo){ - unsigned int size; - - size = ACCESS_FBINFO(fastfont.size); - ACCESS_FBINFO(fastfont.size) = 0; - if (size) { - unsigned int end = ACCESS_FBINFO(video.len_usable); - - if (size < end) { - unsigned int start; - - start = (end - size) & PAGE_MASK; - if (start >= 0x00100000) { - ACCESS_FBINFO(video.len_usable) = start; - ACCESS_FBINFO(fastfont.mgabase) = start * 8; - ACCESS_FBINFO(fastfont.vbase) = ACCESS_FBINFO(video.vbase); - vaddr_add(&ACCESS_FBINFO(fastfont.vbase), start); - ACCESS_FBINFO(fastfont.size) = end - start; - } - } - } -} - -#ifdef CONFIG_FB_MATROX_MYSTIQUE -static void __init MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw){ - - DBG("MGA1064_ramdac_init"); - - /* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */ - ACCESS_FBINFO(features.pll.vco_freq_min) = 62000; - ACCESS_FBINFO(features.pll.ref_freq) = 14318; - ACCESS_FBINFO(features.pll.feed_div_min) = 100; - ACCESS_FBINFO(features.pll.feed_div_max) = 127; - ACCESS_FBINFO(features.pll.in_div_min) = 1; - ACCESS_FBINFO(features.pll.in_div_max) = 31; - ACCESS_FBINFO(features.pll.post_shift_max) = 3; - ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_EXTERNAL; - /* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */ - DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333); -} - -static int __init MGA1064_preinit(WPMINFO struct matrox_hw_state* hw){ - static const int vxres_mystique[] = { 512, 640, 768, 800, 832, 960, - 1024, 1152, 1280, 1600, 1664, 1920, - 2048, 0}; - DBG("MGA1064_preinit") - - /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ - ACCESS_FBINFO(capable.text) = 1; - ACCESS_FBINFO(capable.vxres) = vxres_mystique; - ACCESS_FBINFO(features.accel.has_cacheflush) = 1; - ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor; - - if (ACCESS_FBINFO(devflags.noinit)) - return 0; /* do not modify settings */ - hw->MXoptionReg &= 0xC0000100; - hw->MXoptionReg |= 0x00094E20; - if (ACCESS_FBINFO(devflags.novga)) - hw->MXoptionReg &= ~0x00000100; - if (ACCESS_FBINFO(devflags.nobios)) - hw->MXoptionReg &= ~0x40000000; - if (ACCESS_FBINFO(devflags.nopciretry)) - hw->MXoptionReg |= 0x20000000; - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); - mga_setr(M_SEQ_INDEX, 0x01, 0x20); - mga_outl(M_CTLWTST, 0x00000000); - udelay(200); - mga_outl(M_MACCESS, 0x00008000); - udelay(100); - mga_outl(M_MACCESS, 0x0000C000); - return 0; -} - -static void __init MGA1064_reset(WPMINFO struct matrox_hw_state* hw){ - - DBG("MGA1064_reset"); - - ACCESS_FBINFO(features.DAC1064.cursorimage) = ACCESS_FBINFO(video.len_usable) - 1024; - if (ACCESS_FBINFO(devflags.hwcursor)) - ACCESS_FBINFO(video.len_usable) -= 1024; - matroxfb_fastfont_init(MINFO); - MGA1064_ramdac_init(PMINFO hw); -} -#endif - -#ifdef CONFIG_FB_MATROX_G100 -/* BIOS environ */ -static int x7AF4 = 0x10; /* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */ - /* G100 wants 0x10, G200 SGRAM does not care... */ -#if 0 -static int def50 = 0; /* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */ -#endif - -static void __init MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p){ - int reg; - int selClk; - int clk; - - DBG("MGAG100_progPixClock") - - outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS | - M1064_XPIXCLKCTRL_PLL_UP); - switch (flags & 3) { - case 0: reg = M1064_XPIXPLLAM; break; - case 1: reg = M1064_XPIXPLLBM; break; - default: reg = M1064_XPIXPLLCM; break; - } - outDAC1064(PMINFO reg++, m); - outDAC1064(PMINFO reg++, n); - outDAC1064(PMINFO reg, p); - selClk = mga_inb(M_MISC_REG_READ) & ~0xC; - /* there should be flags & 0x03 & case 0/1/else */ - /* and we should first select source and after that we should wait for PLL */ - /* and we are waiting for PLL with oscilator disabled... Is it right? */ - switch (flags & 0x03) { - case 0x00: break; - case 0x01: selClk |= 4; break; - default: selClk |= 0x0C; break; - } - mga_outb(M_MISC_REG, selClk); - for (clk = 500000; clk; clk--) { - if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40) - break; - udelay(10); - }; - if (!clk) - printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A'); - selClk = inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK; - switch (flags & 0x0C) { - case 0x00: selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break; - case 0x04: selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break; - default: selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break; - } - outDAC1064(PMINFO M1064_XPIXCLKCTRL, selClk); - outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS); -} - -static void __init MGAG100_setPixClock(CPMINFO int flags, int freq){ - unsigned int m, n, p; - - DBG("MGAG100_setPixClock") - - DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); - MGAG100_progPixClock(PMINFO flags, m, n, p); -} - -static int __init MGAG100_preinit(WPMINFO struct matrox_hw_state* hw){ - static const int vxres_g100[] = { 512, 640, 768, 800, 832, 960, - 1024, 1152, 1280, 1600, 1664, 1920, - 2048, 0}; - u_int32_t reg50; -#if 0 - u_int32_t q; -#endif - - DBG("MGAG100_preinit") - - /* there are some instabilities if in_div > 19 && vco < 61000 */ - ACCESS_FBINFO(features.pll.vco_freq_min) = 62000; - ACCESS_FBINFO(features.pll.ref_freq) = 27000; - ACCESS_FBINFO(features.pll.feed_div_min) = 7; - ACCESS_FBINFO(features.pll.feed_div_max) = 127; - ACCESS_FBINFO(features.pll.in_div_min) = 1; - ACCESS_FBINFO(features.pll.in_div_max) = 31; - ACCESS_FBINFO(features.pll.post_shift_max) = 3; - ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_G100_DEFAULT; - /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ - ACCESS_FBINFO(capable.text) = 1; - ACCESS_FBINFO(capable.vxres) = vxres_g100; - ACCESS_FBINFO(features.accel.has_cacheflush) = 1; - ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor; - ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) != FB_ACCEL_MATROX_MGAG100; - - if (ACCESS_FBINFO(devflags.noinit)) - return 0; - hw->MXoptionReg &= 0xC0000100; - hw->MXoptionReg |= 0x00078020; - if (ACCESS_FBINFO(devflags.novga)) - hw->MXoptionReg &= ~0x00000100; - if (ACCESS_FBINFO(devflags.nobios)) - hw->MXoptionReg &= ~0x40000000; - if (ACCESS_FBINFO(devflags.nopciretry)) - hw->MXoptionReg |= 0x20000000; - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); - pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, ®50); - reg50 &= ~0x3000; - pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50); - - DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333); - - if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100) { - hw->MXoptionReg |= 0x1080; - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); - mga_outl(M_CTLWTST, 0x00000300); - /* mga_outl(M_CTLWTST, 0x03258A31); */ - udelay(100); - mga_outb(0x1C05, 0x00); - mga_outb(0x1C05, 0x80); - udelay(100); - mga_outb(0x1C05, 0x40); - mga_outb(0x1C05, 0xC0); - udelay(100); - reg50 &= ~0xFF; - reg50 |= 0x07; - pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50); - /* it should help with G100 */ - mga_outb(M_GRAPHICS_INDEX, 6); - mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4); - mga_setr(M_EXTVGA_INDEX, 0x03, 0x81); - mga_setr(M_EXTVGA_INDEX, 0x04, 0x00); - mga_writeb(ACCESS_FBINFO(video.vbase), 0x0000, 0xAA); - mga_writeb(ACCESS_FBINFO(video.vbase), 0x0800, 0x55); - mga_writeb(ACCESS_FBINFO(video.vbase), 0x4000, 0x55); -#if 0 - if (mga_readb(ACCESS_FBINFO(video.vbase), 0x0000) != 0xAA) { - hw->MXoptionReg &= ~0x1000; - } -#endif - } else { - hw->MXoptionReg |= 0x00000C00; - if (ACCESS_FBINFO(devflags.sgram)) - hw->MXoptionReg |= 0x4000; - mga_outl(M_CTLWTST, 0x042450A1); - mga_outb(0x1E47, 0x00); - mga_outb(0x1E46, 0x00); - udelay(10); - mga_outb(0x1C05, 0x00); - mga_outb(0x1C05, 0x80); - udelay(100); - mga_outw(0x1E44, 0x0108); - } - hw->MXoptionReg = (hw->MXoptionReg & ~0x1F8000) | 0x78000; - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); - return 0; -} - -static void __init MGAG100_reset(WPMINFO struct matrox_hw_state* hw){ - u_int8_t b; - - DBG("MGAG100_reset") - - ACCESS_FBINFO(features.DAC1064.cursorimage) = ACCESS_FBINFO(video.len_usable) - 1024; - if (ACCESS_FBINFO(devflags.hwcursor)) - ACCESS_FBINFO(video.len_usable) -= 1024; - matroxfb_fastfont_init(MINFO); - - { -#ifdef G100_BROKEN_IBM_82351 - u_int32_t d; - - find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */ - pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b); - if (b == ACCESS_FBINFO(pcidev)->bus->number) { - pci_write_config_byte(ibm, PCI_COMMAND+1, 0); /* disable back-to-back & SERR */ - pci_write_config_byte(ibm, 0x41, 0xF4); /* ??? */ - pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0); /* ??? */ - pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00); /* ??? */ - } -#endif - if (!ACCESS_FBINFO(devflags.noinit)) { - if (x7AF4 & 8) { - hw->MXoptionReg |= 0x40; - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); - } - mga_setr(M_EXTVGA_INDEX, 0x06, 0x50); - } - } - DAC1064_setmclk(PMINFO hw, DAC1064_OPT_RESERVED | DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV1 | DAC1064_OPT_SCLK_PLL, 133333); - if (ACCESS_FBINFO(devflags.noinit)) - return; - MGAG100_setPixClock(PMINFO 4, 25175); - MGAG100_setPixClock(PMINFO 5, 28322); - if (x7AF4 & 0x10) { - b = inDAC1064(PMINFO M1064_XGENIODATA) & ~1; - outDAC1064(PMINFO M1064_XGENIODATA, b); - b = inDAC1064(PMINFO M1064_XGENIOCTRL) | 1; - outDAC1064(PMINFO M1064_XGENIOCTRL, b); - } -} -#endif - -static void vgaHWrestore(CPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw) { - int i; - - DBG("vgaHWrestore") - - dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg); - dprintk(KERN_INFO "SEQ regs: "); - for (i = 0; i < 5; i++) - dprintk("%02X:", hw->SEQ[i]); - dprintk("\n"); - dprintk(KERN_INFO "GDC regs: "); - for (i = 0; i < 9; i++) - dprintk("%02X:", hw->GCTL[i]); - dprintk("\n"); - dprintk(KERN_INFO "CRTC regs: "); - for (i = 0; i < 25; i++) - dprintk("%02X:", hw->CRTC[i]); - dprintk("\n"); - dprintk(KERN_INFO "ATTR regs: "); - for (i = 0; i < 21; i++) - dprintk("%02X:", hw->ATTR[i]); - dprintk("\n"); - - mga_inb(M_ATTR_RESET); - mga_outb(M_ATTR_INDEX, 0); - mga_outb(M_MISC_REG, hw->MiscOutReg); - for (i = 1; i < 5; i++) - mga_setr(M_SEQ_INDEX, i, hw->SEQ[i]); - mga_setr(M_CRTC_INDEX, 17, hw->CRTC[17] & 0x7F); - for (i = 0; i < 25; i++) - mga_setr(M_CRTC_INDEX, i, hw->CRTC[i]); - for (i = 0; i < 9; i++) - mga_setr(M_GRAPHICS_INDEX, i, hw->GCTL[i]); - for (i = 0; i < 21; i++) { - mga_inb(M_ATTR_RESET); - mga_outb(M_ATTR_INDEX, i); - mga_outb(M_ATTR_INDEX, hw->ATTR[i]); - } - mga_outb(M_PALETTE_MASK, 0xFF); - mga_outb(M_DAC_REG, 0x00); - for (i = 0; i < 768; i++) - mga_outb(M_DAC_VAL, hw->DACpal[i]); - mga_inb(M_ATTR_RESET); - mga_outb(M_ATTR_INDEX, 0x20); -} - -static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *fb_info) -{ - struct display* p; -#ifdef CONFIG_FB_MATROX_MULTIHEAD - struct matrox_fb_info* minfo = (struct matrox_fb_info*)fb_info; -#endif - - DBG("matrox_setcolreg") - - /* - * Set a single color register. The values supplied are - * already rounded down to the hardware's capabilities - * (according to the entries in the `var' structure). Return - * != 0 for invalid regno. - */ - - if (regno >= ACCESS_FBINFO(curr.cmap_len)) - return 1; - - ACCESS_FBINFO(palette[regno].red) = red; - ACCESS_FBINFO(palette[regno].green) = green; - ACCESS_FBINFO(palette[regno].blue) = blue; - ACCESS_FBINFO(palette[regno].transp) = transp; - - p = ACCESS_FBINFO(currcon_display); - if (p->var.grayscale) { - /* gray = 0.30*R + 0.59*G + 0.11*B */ - red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; - } - - red = CNVT_TOHW(red, p->var.red.length); - green = CNVT_TOHW(green, p->var.green.length); - blue = CNVT_TOHW(blue, p->var.blue.length); - transp = CNVT_TOHW(transp, p->var.transp.length); - - switch (p->var.bits_per_pixel) { -#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_VGATEXT) -#ifdef FBCON_HAS_VGATEXT - case 0: -#endif -#ifdef FBCON_HAS_CFB4 - case 4: -#endif -#ifdef FBCON_HAS_CFB8 - case 8: -#endif - mga_outb(M_DAC_REG, regno); - mga_outb(M_DAC_VAL, red); - mga_outb(M_DAC_VAL, green); - mga_outb(M_DAC_VAL, blue); - break; -#endif -#ifdef FBCON_HAS_CFB16 - case 16: - ACCESS_FBINFO(cmap.cfb16[regno]) = - (red << p->var.red.offset) | - (green << p->var.green.offset) | - (blue << p->var.blue.offset) | - (transp << p->var.transp.offset); /* for 1:5:5:5 */ - break; -#endif -#ifdef FBCON_HAS_CFB24 - case 24: - ACCESS_FBINFO(cmap.cfb24[regno]) = - (red << p->var.red.offset) | - (green << p->var.green.offset) | - (blue << p->var.blue.offset); - break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32: - ACCESS_FBINFO(cmap.cfb32[regno]) = - (red << p->var.red.offset) | - (green << p->var.green.offset) | - (blue << p->var.blue.offset) | - (transp << p->var.transp.offset); /* 8:8:8:8 */ - break; -#endif - } - return 0; -} - -static void do_install_cmap(WPMINFO struct display* dsp) -{ - DBG("do_install_cmap") - - if (dsp->cmap.len) - fb_set_cmap(&dsp->cmap, 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon)); - else - fb_set_cmap(fb_default_cmap(ACCESS_FBINFO(curr.cmap_len)), - 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon)); -} - -#ifdef CONFIG_FB_MATROX_MYSTIQUE -static void MGA1064_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) { - int i; - - DBG("MGA1064_restore") - - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); - mga_outb(M_IEN, 0x00); - mga_outb(M_CACHEFLUSH, 0x00); - - DAC1064_restore_1(PMINFO hw, oldhw); - vgaHWrestore(PMINFO hw, oldhw); - for (i = 0; i < 6; i++) - mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); - DAC1064_restore_2(PMINFO hw, oldhw, p); -} -#endif - -#ifdef CONFIG_FB_MATROX_G100 -static void MGAG100_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) { - int i; - - DBG("MGAG100_restore") - - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); - - DAC1064_restore_1(PMINFO hw, oldhw); - vgaHWrestore(PMINFO hw, oldhw); -#ifdef CONFIG_FB_MATROX_32MB - if (ACCESS_FBINFO(devflags.support32MB)) - mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]); -#endif - for (i = 0; i < 6; i++) - mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); - DAC1064_restore_2(PMINFO hw, oldhw, p); -} -#endif - -#ifdef CONFIG_FB_MATROX_MILLENIUM -static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) { - int i; - - DBG("Ti3026_restore") - - dprintk(KERN_INFO "EXTVGA regs: "); - for (i = 0; i < 6; i++) - dprintk("%02X:", hw->CRTCEXT[i]); - dprintk("\n"); - - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); - - vgaHWrestore(PMINFO hw, oldhw); - - for (i = 0; i < 6; i++) - mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); - - for (i = 0; i < 21; i++) { - outTi3026(PMINFO DACseq[i], hw->DACreg[i]); - } - if (oldhw) { - outTi3026(PMINFO TVP3026_XPLLADDR, 0x00); - oldhw->DACclk[0] = inTi3026(PMINFO TVP3026_XPIXPLLDATA); - oldhw->DACclk[3] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA); - outTi3026(PMINFO TVP3026_XPLLADDR, 0x15); - oldhw->DACclk[1] = inTi3026(PMINFO TVP3026_XPIXPLLDATA); - oldhw->DACclk[4] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA); - outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A); - oldhw->DACclk[2] = inTi3026(PMINFO TVP3026_XPIXPLLDATA); - oldhw->DACclk[5] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA); - } - if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) { - /* agrhh... setting up PLL is very slow on Millenium... */ - /* Mystique PLL is locked in few ms, but Millenium PLL lock takes about 0.15 s... */ - /* Maybe even we should call schedule() ? */ - - outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]); - outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A); - outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0); - outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0); - - outTi3026(PMINFO TVP3026_XPLLADDR, 0x00); - for (i = 0; i < 3; i++) - outTi3026(PMINFO TVP3026_XPIXPLLDATA, hw->DACclk[i]); - /* wait for PLL only if PLL clock requested (always for PowerMode, never for VGA) */ - if (hw->MiscOutReg & 0x08) { - int tmout; - outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F); - for (tmout = 500000; tmout; --tmout) { - if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40) - break; - udelay(10); - } - - if (!tmout) - printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n"); - else - dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout); - } - outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]); - outTi3026(PMINFO TVP3026_XPLLADDR, 0x00); - for (i = 3; i < 6; i++) - outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]); - if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) { - int tmout; - - outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F); - for (tmout = 500000; tmout; --tmout) { - if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40) - break; - udelay(10); - } - if (!tmout) - printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n"); - else - dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout); - } - } - if (p && p->conp) { - if (p->type == FB_TYPE_TEXT) { - matrox_text_createcursor(PMINFO p); - matrox_text_loadfont(PMINFO p); - i = 0; - } else { - matroxfb_ti3026_createcursor(PMINFO p); - i = matroxfb_fastfont_tryset(PMINFO p); - } - } else - i = 0; - if (i) { - ACCESS_FBINFO(curr.putc) = matrox_cfbX_fastputc; - ACCESS_FBINFO(curr.putcs) = matrox_cfbX_fastputcs; - } else { - ACCESS_FBINFO(curr.putc) = matrox_cfbX_putc; - ACCESS_FBINFO(curr.putcs) = matrox_cfbX_putcs; - } - - dprintk(KERN_DEBUG "3026DACregs "); - for (i = 0; i < 21; i++) { - dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]); - if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... "); - } - dprintk("\n" KERN_DEBUG "DACclk "); - for (i = 0; i < 6; i++) - dprintk("C%02X=%02X ", i, hw->DACclk[i]); - dprintk("\n"); -} -#endif - -static int matroxfb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info) -{ - struct display* p; - DBG("matroxfb_get_fix") - -#define minfo ((struct matrox_fb_info*)info) - - if (con >= 0) - p = fb_display + con; - else - p = ACCESS_FBINFO(fbcon.disp); - - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strcpy(fix->id,"MATROX"); - - fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); - fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes); - fix->type = p->type; - fix->type_aux = p->type_aux; - fix->visual = p->visual; - fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */ - fix->ypanstep = 1; - fix->ywrapstep = 0; - fix->line_length = p->line_length; - fix->mmio_start = ACCESS_FBINFO(mmio.base); - fix->mmio_len = ACCESS_FBINFO(mmio.len); - fix->accel = ACCESS_FBINFO(devflags.accelerator); - return 0; -#undef minfo -} - -static int matroxfb_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) -{ -#define minfo ((struct matrox_fb_info*)info) - DBG("matroxfb_get_var") - - if(con < 0) - *var=ACCESS_FBINFO(fbcon.disp)->var; - else - *var=fb_display[con].var; - return 0; -#undef minfo -} - -static int matroxfb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) -{ -#define minfo ((struct matrox_fb_info*)info) - int err; - int visual; - int cmap_len; - unsigned int ydstorg; - struct display* display; - int chgvar; - - DBG("matroxfb_set_var") - - if (con >= 0) - display = fb_display + con; - else - display = ACCESS_FBINFO(fbcon.disp); - if ((err = matroxfb_decode_var(PMINFO display, var, &visual, &cmap_len, &ydstorg)) != 0) - return err; - switch (var->activate & FB_ACTIVATE_MASK) { - case FB_ACTIVATE_TEST: return 0; - case FB_ACTIVATE_NXTOPEN: /* ?? */ - case FB_ACTIVATE_NOW: break; /* continue */ - default: return -EINVAL; /* unknown */ - } - if (con >= 0) { - chgvar = ((display->var.xres != var->xres) || - (display->var.yres != var->yres) || - (display->var.xres_virtual != var->xres_virtual) || - (display->var.yres_virtual != var->yres_virtual) || - (display->var.bits_per_pixel != var->bits_per_pixel) || - memcmp(&display->var.red, &var->red, sizeof(var->red)) || - memcmp(&display->var.green, &var->green, sizeof(var->green)) || - memcmp(&display->var.blue, &var->blue, sizeof(var->blue))); - } else { - chgvar = 0; - } - display->var = *var; - /* cmap */ - display->screen_base = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg; - display->visual = visual; - display->ypanstep = 1; - display->ywrapstep = 0; - if (var->bits_per_pixel) { - display->type = FB_TYPE_PACKED_PIXELS; - display->type_aux = 0; - display->next_line = display->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; - } else { - display->type = FB_TYPE_TEXT; - display->type_aux = ACCESS_FBINFO(devflags.text_type_aux); - display->next_line = display->line_length = (var->xres_virtual / (fontwidth(display)?fontwidth(display):8)) * ACCESS_FBINFO(devflags.textstep); - } - display->can_soft_blank = 1; - display->inverse = ACCESS_FBINFO(devflags.inverse); - /* conp, fb_info, vrows, cursor_x, cursor_y, fgcol, bgcol */ - /* next_plane, fontdata, _font*, userfont */ - initMatrox(PMINFO display); /* dispsw */ - /* dispsw, scrollmode, yscroll */ - /* fgshift, bgshift, charmask */ - if (chgvar && info && info->changevar) - info->changevar(con); - if (con == ACCESS_FBINFO(currcon)) { - unsigned int pos; - - ACCESS_FBINFO(curr.cmap_len) = cmap_len; - if (display->type == FB_TYPE_TEXT) { - /* textmode must be in first megabyte, so no ydstorg allowed */ - ACCESS_FBINFO(curr.ydstorg.bytes) = 0; - ACCESS_FBINFO(curr.ydstorg.chunks) = 0; - ACCESS_FBINFO(curr.ydstorg.pixels) = 0; - } else { - ydstorg += ACCESS_FBINFO(devflags.ydstorg); - ACCESS_FBINFO(curr.ydstorg.bytes) = ydstorg; - ACCESS_FBINFO(curr.ydstorg.chunks) = ydstorg >> (isInterleave(MINFO)?3:2); - if (var->bits_per_pixel == 4) - ACCESS_FBINFO(curr.ydstorg.pixels) = ydstorg; - else - ACCESS_FBINFO(curr.ydstorg.pixels) = (ydstorg * 8) / var->bits_per_pixel; - } - ACCESS_FBINFO(curr.final_bppShift) = matroxfb_get_final_bppShift(PMINFO var->bits_per_pixel); - if (visual == MX_VISUAL_PSEUDOCOLOR) { - int i; - - for (i = 0; i < 16; i++) { - int j; - - j = color_table[i]; - ACCESS_FBINFO(palette[i].red) = default_red[j]; - ACCESS_FBINFO(palette[i].green) = default_grn[j]; - ACCESS_FBINFO(palette[i].blue) = default_blu[j]; - } - } - - { struct my_timming mt; - struct matrox_hw_state* hw; - struct matrox_hw_state* ohw; - - var2my(var, &mt); - hw = ACCESS_FBINFO(newhw); - ohw = ACCESS_FBINFO(currenthw); - - /* MXoptionReg is not set from scratch */ - hw->MXoptionReg = ohw->MXoptionReg; - /* DACclk[3]..[5] are not initialized with DAC1064 */ - memcpy(hw->DACclk, ohw->DACclk, sizeof(hw->DACclk)); - /* others are initialized by init() */ - - del_timer(&ACCESS_FBINFO(cursor.timer)); - ACCESS_FBINFO(cursor.state) = CM_ERASE; - - ACCESS_FBINFO(hw_switch->init(PMINFO hw, &mt, display)); - if (display->type == FB_TYPE_TEXT) { - if (fontheight(display)) - pos = var->yoffset / fontheight(display) * display->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(display)?fontwidth(display):8); - else - pos = 0; - } else { - pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32; - pos += ACCESS_FBINFO(curr.ydstorg.chunks); - } - - hw->CRTC[0x0D] = pos & 0xFF; - hw->CRTC[0x0C] = (pos & 0xFF00) >> 8; - hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); - hw->CRTCEXT[8] = pos >> 21; - ACCESS_FBINFO(hw_switch->restore(PMINFO hw, ohw, display)); - ACCESS_FBINFO(cursor.redraw) = 1; - ACCESS_FBINFO(currenthw) = hw; - ACCESS_FBINFO(newhw) = ohw; - matrox_cfbX_init(PMINFO display); - do_install_cmap(PMINFO display); -#if defined(CONFIG_FB_OF) && defined(CONFIG_FB_COMPAT_XPMAC) - if (console_fb_info == &ACCESS_FBINFO(fbcon)) { - int vmode, cmode; - - display_info.width = var->xres; - display_info.height = var->yres; - display_info.depth = var->bits_per_pixel; - display_info.pitch = (var->xres_virtual)*(var->bits_per_pixel)/8; - if (mac_var_to_vmode(var, &vmode, &cmode)) - display_info.mode = 0; - else - display_info.mode = vmode; - strcpy(display_info.name, ACCESS_FBINFO(matrox_name)); - display_info.fb_address = ACCESS_FBINFO(video.base); - display_info.cmap_adr_address = 0; - display_info.cmap_data_address = 0; - display_info.disp_reg_address = ACCESS_FBINFO(mmio.base); - } -#endif /* CONFIG_FB_OF && CONFIG_FB_COMPAT_XPMAC */ - } - } - return 0; -#undef minfo -} - -static int matrox_getcolreg(unsigned regno, unsigned *red, unsigned *green, - unsigned *blue, unsigned *transp, - struct fb_info *info) -{ - - DBG("matrox_getcolreg") - -#define minfo ((struct matrox_fb_info*)info) - /* - * Read a single color register and split it into colors/transparent. - * Return != 0 for invalid regno. - */ - - if (regno >= ACCESS_FBINFO(curr.cmap_len)) - return 1; - - *red = ACCESS_FBINFO(palette[regno].red); - *green = ACCESS_FBINFO(palette[regno].green); - *blue = ACCESS_FBINFO(palette[regno].blue); - *transp = ACCESS_FBINFO(palette[regno].transp); - return 0; -#undef minfo -} - -static int matroxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ -#define minfo ((struct matrox_fb_info*)info) - struct display* dsp = (con < 0) ? ACCESS_FBINFO(fbcon.disp) - : fb_display + con; - - DBG("matroxfb_get_cmap") - - if (con == ACCESS_FBINFO(currcon)) /* current console? */ - return fb_get_cmap(cmap, kspc, matrox_getcolreg, info); - else if (dsp->cmap.len) /* non default colormap? */ - fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2); - else - fb_copy_cmap(fb_default_cmap(matroxfb_get_cmap_len(&dsp->var)), - cmap, kspc ? 0 : 2); - return 0; -#undef minfo -} - -static int matroxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ - unsigned int cmap_len; - struct display* dsp = (con < 0) ? info->disp : (fb_display + con); -#define minfo ((struct matrox_fb_info*)info) - - DBG("matroxfb_set_cmap") - - cmap_len = matroxfb_get_cmap_len(&dsp->var); - if (dsp->cmap.len != cmap_len) { - int err; - - err = fb_alloc_cmap(&dsp->cmap, cmap_len, 0); - if (err) - return err; - } - if (con == ACCESS_FBINFO(currcon)) { /* current console? */ - return fb_set_cmap(cmap, kspc, matrox_setcolreg, info); - } else - fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1); - return 0; -#undef minfo -} - -static int matroxfb_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, int con, - struct fb_info *info) -{ - - DBG("matroxfb_ioctl") - - return -EINVAL; -} - -static struct fb_ops matroxfb_ops = { - matroxfb_open, - matroxfb_release, - matroxfb_get_fix, - matroxfb_get_var, - matroxfb_set_var, - matroxfb_get_cmap, - matroxfb_set_cmap, - matroxfb_pan_display, - matroxfb_ioctl, - NULL /* mmap */ -}; - -static int matroxfb_switch(int con, struct fb_info *info) -{ -#define minfo ((struct matrox_fb_info*)info) - struct fb_cmap* cmap; - - DBG("matroxfb_switch"); - - if (ACCESS_FBINFO(currcon) >= 0) { - /* Do we have to save the colormap? */ - cmap = &(ACCESS_FBINFO(currcon_display)->cmap); - dprintk(KERN_DEBUG "switch1: con = %d, cmap.len = %d\n", ACCESS_FBINFO(currcon), cmap->len); - - if (cmap->len) { - dprintk(KERN_DEBUG "switch1a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp); - fb_get_cmap(cmap, 1, matrox_getcolreg, info); -#ifdef DEBUG - if (cmap->red) { - dprintk(KERN_DEBUG "switch1r: %X\n", cmap->red[0]); - } -#endif - } - } - ACCESS_FBINFO(currcon) = con; - ACCESS_FBINFO(currcon_display) = fb_display + con; - fb_display[con].var.activate = FB_ACTIVATE_NOW; -#ifdef DEBUG - cmap = &fb_display[con].cmap; - dprintk(KERN_DEBUG "switch2: con = %d, cmap.len = %d\n", con, cmap->len); - dprintk(KERN_DEBUG "switch2a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp); - if (fb_display[con].cmap.red) { - dprintk(KERN_DEBUG "switch2r: %X\n", cmap->red[0]); - } -#endif - matroxfb_set_var(&fb_display[con].var, con, info); -#ifdef DEBUG - dprintk(KERN_DEBUG "switch3: con = %d, cmap.len = %d\n", con, cmap->len); - dprintk(KERN_DEBUG "switch3a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp); - if (fb_display[con].cmap.red) { - dprintk(KERN_DEBUG "switch3r: %X\n", cmap->red[0]); - } -#endif - return 0; -#undef minfo -} - -/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ - -static void matroxfb_blank(int blank, struct fb_info *info) -{ -#define minfo ((struct matrox_fb_info*)info) - int seq; - int crtc; - - DBG("matroxfb_blank") - - switch (blank) { - case 1: seq = 0x20; crtc = 0x00; break; /* works ??? */ - case 2: seq = 0x20; crtc = 0x10; break; - case 3: seq = 0x20; crtc = 0x20; break; - case 4: seq = 0x20; crtc = 0x30; break; - default: seq = 0x00; crtc = 0x00; break; - } - - mga_outb(M_SEQ_INDEX, 1); - mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq); - mga_outb(M_EXTVGA_INDEX, 1); - mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc); - -#undef minfo -} - -#define RSResolution(X) ((X) & 0x0F) -#define RS640x400 1 -#define RS640x480 2 -#define RS800x600 3 -#define RS1024x768 4 -#define RS1280x1024 5 -#define RS1600x1200 6 -#define RS768x576 7 -#define RS960x720 8 -#define RS1152x864 9 -#define RS1408x1056 10 -#define RS640x350 11 -#define RS1056x344 12 /* 132 x 43 text */ -#define RS1056x400 13 /* 132 x 50 text */ -#define RS1056x480 14 /* 132 x 60 text */ -#define RSNoxNo 15 -/* 10-FF */ -static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = { - { 640, 400, 48, 16, 39, 8, 96, 2, 70 }, - { 640, 480, 48, 16, 33, 10, 96, 2, 60 }, - { 800, 600, 144, 24, 28, 8, 112, 6, 60 }, - { 1024, 768, 160, 32, 30, 4, 128, 4, 60 }, - { 1280, 1024, 224, 32, 32, 4, 136, 4, 60 }, - { 1600, 1200, 272, 48, 32, 5, 152, 5, 60 }, - { 768, 576, 144, 16, 28, 6, 112, 4, 60 }, - { 960, 720, 144, 24, 28, 8, 112, 4, 60 }, - { 1152, 864, 192, 32, 30, 4, 128, 4, 60 }, - { 1408, 1056, 256, 40, 32, 5, 144, 5, 60 }, - { 640, 350, 48, 16, 39, 8, 96, 2, 70 }, - { 1056, 344, 96, 24, 59, 44, 160, 2, 70 }, - { 1056, 400, 96, 24, 39, 8, 160, 2, 70 }, - { 1056, 480, 96, 24, 36, 12, 160, 3, 60 }, - { 0, 0, ~0, ~0, ~0, ~0, 0, 0, 0 } -}; - -#define RSDepth(X) (((X) >> 8) & 0x0F) -#define RS8bpp 0x1 -#define RS15bpp 0x2 -#define RS16bpp 0x3 -#define RS32bpp 0x4 -#define RS4bpp 0x5 -#define RS24bpp 0x6 -#define RSText 0x7 -#define RSText8 0x8 -/* 9-F */ -static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] __initdata = { - { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 8 }, - { { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 }, - { { 11, 5, 0}, { 6, 5, 0}, { 0, 5, 0}, { 0, 0, 0}, 16 }, - { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 }, - { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 4 }, - { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 24 }, - { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode with (default) VGA8x16 */ - { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode hardwired to VGA8x8 */ -}; - -#define RSCreate(X,Y) ((X) | ((Y) << 8)) -static struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = { -/* default must be first */ -#ifdef FBCON_HAS_CFB8 - { ~0, RSCreate(RSNoxNo, RS8bpp ) }, - { 0x101, RSCreate(RS640x480, RS8bpp ) }, - { 0x100, RSCreate(RS640x400, RS8bpp ) }, - { 0x180, RSCreate(RS768x576, RS8bpp ) }, - { 0x103, RSCreate(RS800x600, RS8bpp ) }, - { 0x188, RSCreate(RS960x720, RS8bpp ) }, - { 0x105, RSCreate(RS1024x768, RS8bpp ) }, - { 0x190, RSCreate(RS1152x864, RS8bpp ) }, - { 0x107, RSCreate(RS1280x1024, RS8bpp ) }, - { 0x198, RSCreate(RS1408x1056, RS8bpp ) }, - { 0x11C, RSCreate(RS1600x1200, RS8bpp ) }, -#endif -#ifdef FBCON_HAS_CFB16 - { ~0, RSCreate(RSNoxNo, RS15bpp) }, - { 0x110, RSCreate(RS640x480, RS15bpp) }, - { 0x181, RSCreate(RS768x576, RS15bpp) }, - { 0x113, RSCreate(RS800x600, RS15bpp) }, - { 0x189, RSCreate(RS960x720, RS15bpp) }, - { 0x116, RSCreate(RS1024x768, RS15bpp) }, - { 0x191, RSCreate(RS1152x864, RS15bpp) }, - { 0x119, RSCreate(RS1280x1024, RS15bpp) }, - { 0x199, RSCreate(RS1408x1056, RS15bpp) }, - { 0x11D, RSCreate(RS1600x1200, RS15bpp) }, - { 0x111, RSCreate(RS640x480, RS16bpp) }, - { 0x182, RSCreate(RS768x576, RS16bpp) }, - { 0x114, RSCreate(RS800x600, RS16bpp) }, - { 0x18A, RSCreate(RS960x720, RS16bpp) }, - { 0x117, RSCreate(RS1024x768, RS16bpp) }, - { 0x192, RSCreate(RS1152x864, RS16bpp) }, - { 0x11A, RSCreate(RS1280x1024, RS16bpp) }, - { 0x19A, RSCreate(RS1408x1056, RS16bpp) }, - { 0x11E, RSCreate(RS1600x1200, RS16bpp) }, -#endif -#ifdef FBCON_HAS_CFB24 - { ~0, RSCreate(RSNoxNo, RS24bpp) }, - { 0x1B2, RSCreate(RS640x480, RS24bpp) }, - { 0x184, RSCreate(RS768x576, RS24bpp) }, - { 0x1B5, RSCreate(RS800x600, RS24bpp) }, - { 0x18C, RSCreate(RS960x720, RS24bpp) }, - { 0x1B8, RSCreate(RS1024x768, RS24bpp) }, - { 0x194, RSCreate(RS1152x864, RS24bpp) }, - { 0x1BB, RSCreate(RS1280x1024, RS24bpp) }, - { 0x19C, RSCreate(RS1408x1056, RS24bpp) }, - { 0x1BF, RSCreate(RS1600x1200, RS24bpp) }, -#endif -#ifdef FBCON_HAS_CFB32 - { ~0, RSCreate(RSNoxNo, RS32bpp) }, - { 0x112, RSCreate(RS640x480, RS32bpp) }, - { 0x183, RSCreate(RS768x576, RS32bpp) }, - { 0x115, RSCreate(RS800x600, RS32bpp) }, - { 0x18B, RSCreate(RS960x720, RS32bpp) }, - { 0x118, RSCreate(RS1024x768, RS32bpp) }, - { 0x193, RSCreate(RS1152x864, RS32bpp) }, - { 0x11B, RSCreate(RS1280x1024, RS32bpp) }, - { 0x19B, RSCreate(RS1408x1056, RS32bpp) }, - { 0x11F, RSCreate(RS1600x1200, RS32bpp) }, -#endif -#ifdef FBCON_HAS_VGATEXT - { ~0, RSCreate(RSNoxNo, RSText) }, - { 0x002, RSCreate(RS640x400, RSText) }, /* 80x25 */ - { 0x003, RSCreate(RS640x400, RSText) }, /* 80x25 */ - { 0x007, RSCreate(RS640x400, RSText) }, /* 80x25 */ - { 0x1C0, RSCreate(RS640x400, RSText8) }, /* 80x50 */ - { 0x108, RSCreate(RS640x480, RSText8) }, /* 80x60 */ - { 0x109, RSCreate(RS1056x400, RSText) }, /* 132x25 */ - { 0x10A, RSCreate(RS1056x344, RSText8) }, /* 132x43 */ - { 0x10B, RSCreate(RS1056x400, RSText8) }, /* 132x50 */ - { 0x10C, RSCreate(RS1056x480, RSText8) }, /* 132x60 */ -#endif -#ifdef FBCON_HAS_CFB4 - { ~0, RSCreate(RSNoxNo, RS4bpp ) }, - { 0x010, RSCreate(RS640x350, RS4bpp ) }, - { 0x012, RSCreate(RS640x480, RS4bpp ) }, - { 0x102, RSCreate(RS800x600, RS4bpp ) }, - { 0x104, RSCreate(RS1024x768, RS4bpp ) }, - { 0x106, RSCreate(RS1280x1024, RS4bpp ) }, -#endif - { 0, 0 }}; - -/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */ -static unsigned int mem = 0; /* "matrox:mem:xxxxxM" */ -static int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */ -static int inv24 = 0; /* "matrox:inv24" */ -static int cross4MB = -1; /* "matrox:cross4MB" */ -static int disabled = 0; /* "matrox:disabled" */ -static int noaccel = 0; /* "matrox:noaccel" */ -static int nopan = 0; /* "matrox:nopan" */ -static int no_pci_retry = 0; /* "matrox:nopciretry" */ -static int novga = 0; /* "matrox:novga" */ -static int nobios = 0; /* "matrox:nobios" */ -static int noinit = 1; /* "matrox:init" */ -static int inverse = 0; /* "matrox:inverse" */ -static int hwcursor = 1; /* "matrox:nohwcursor" */ -static int blink = 1; /* "matrox:noblink" */ -static int sgram = 0; /* "matrox:sgram" */ -#ifdef CONFIG_MTRR -static int mtrr = 1; /* "matrox:nomtrr" */ -#endif -static int grayscale = 0; /* "matrox:grayscale" */ -static unsigned int fastfont = 0; /* "matrox:fastfont:xxxxx" */ -static int dev = -1; /* "matrox:dev:xxxxx" */ -static unsigned int vesa = ~0; /* "matrox:vesa:xxxxx" */ -static int depth = -1; /* "matrox:depth:xxxxx" */ -static unsigned int xres = 0; /* "matrox:xres:xxxxx" */ -static unsigned int yres = 0; /* "matrox:yres:xxxxx" */ -static unsigned int upper = ~0; /* "matrox:upper:xxxxx" */ -static unsigned int lower = ~0; /* "matrox:lower:xxxxx" */ -static unsigned int vslen = 0; /* "matrox:vslen:xxxxx" */ -static unsigned int left = ~0; /* "matrox:left:xxxxx" */ -static unsigned int right = ~0; /* "matrox:right:xxxxx" */ -static unsigned int hslen = 0; /* "matrox:hslen:xxxxx" */ -static unsigned int pixclock = 0; /* "matrox:pixclock:xxxxx" */ -static int sync = -1; /* "matrox:sync:xxxxx" */ -static unsigned int fv = 0; /* "matrox:fv:xxxxx" */ -static unsigned int fh = 0; /* "matrox:fh:xxxxxk" */ -static unsigned int maxclk = 0; /* "matrox:maxclk:xxxxM" */ -static char fontname[64]; /* "matrox:font:xxxxx" */ - -#ifndef MODULE -static char videomode[64]; /* "matrox:mode:xxxxx" or "matrox:xxxxx" */ -#endif - -#ifndef MODULE -int __init matroxfb_setup(char *options) { - char *this_opt; - - DBG("matroxfb_setup") - - fontname[0] = '\0'; - - if (!options || !*options) - return 0; - - for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) { - if (!*this_opt) continue; - - dprintk("matroxfb_setup: option %s\n", this_opt); - - if (!strncmp(this_opt, "dev:", 4)) - dev = simple_strtoul(this_opt+4, NULL, 0); - else if (!strncmp(this_opt, "depth:", 6)) { - switch (simple_strtoul(this_opt+6, NULL, 0)) { - case 0: depth = RSText; break; - case 4: depth = RS4bpp; break; - case 8: depth = RS8bpp; break; - case 15:depth = RS15bpp; break; - case 16:depth = RS16bpp; break; - case 24:depth = RS24bpp; break; - case 32:depth = RS32bpp; break; - default: - printk(KERN_ERR "matroxfb: unsupported color depth\n"); - } - } else if (!strncmp(this_opt, "xres:", 5)) - xres = simple_strtoul(this_opt+5, NULL, 0); - else if (!strncmp(this_opt, "yres:", 5)) - yres = simple_strtoul(this_opt+5, NULL, 0); - else if (!strncmp(this_opt, "vslen:", 6)) - vslen = simple_strtoul(this_opt+6, NULL, 0); - else if (!strncmp(this_opt, "hslen:", 6)) - hslen = simple_strtoul(this_opt+6, NULL, 0); - else if (!strncmp(this_opt, "left:", 5)) - left = simple_strtoul(this_opt+5, NULL, 0); - else if (!strncmp(this_opt, "right:", 6)) - right = simple_strtoul(this_opt+6, NULL, 0); - else if (!strncmp(this_opt, "upper:", 6)) - upper = simple_strtoul(this_opt+6, NULL, 0); - else if (!strncmp(this_opt, "lower:", 6)) - lower = simple_strtoul(this_opt+6, NULL, 0); - else if (!strncmp(this_opt, "pixclock:", 9)) - pixclock = simple_strtoul(this_opt+9, NULL, 0); - else if (!strncmp(this_opt, "sync:", 5)) - sync = simple_strtoul(this_opt+5, NULL, 0); - else if (!strncmp(this_opt, "vesa:", 5)) - vesa = simple_strtoul(this_opt+5, NULL, 0); - else if (!strncmp(this_opt, "font:", 5)) - strncpy(fontname, this_opt+5, sizeof(fontname)-1); - else if (!strncmp(this_opt, "maxclk:", 7)) - maxclk = simple_strtoul(this_opt+7, NULL, 0); - else if (!strncmp(this_opt, "fh:", 3)) - fh = simple_strtoul(this_opt+3, NULL, 0); - else if (!strncmp(this_opt, "fv:", 3)) - fv = simple_strtoul(this_opt+3, NULL, 0); - else if (!strncmp(this_opt, "mem:", 4)) - mem = simple_strtoul(this_opt+4, NULL, 0); - else if (!strncmp(this_opt, "mode:", 5)) - strncpy(videomode, this_opt+5, sizeof(videomode)-1); -#ifdef CONFIG_FB_OF - else if (!strncmp(this_opt, "vmode:", 6)) { - unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); - if (vmode > 0 && vmode <= VMODE_MAX) - default_vmode = vmode; - } else if (!strncmp(this_opt, "cmode:", 6)) { - unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0); - switch (cmode) { - case 0: - case 8: - default_cmode = CMODE_8; - break; - case 15: - case 16: - default_cmode = CMODE_16; - break; - case 24: - case 32: - default_cmode = CMODE_32; - break; - } - } -#endif - else if (!strncmp(this_opt, "fastfont:", 9)) - fastfont = simple_strtoul(this_opt+9, NULL, 0); - else if (!strcmp(this_opt, "nofastfont")) /* fastfont:N and nofastfont (nofastfont = fastfont:0) */ - fastfont = 0; - else if (!strcmp(this_opt, "disabled")) /* nodisabled does not exist */ - disabled = 1; - else if (!strcmp(this_opt, "enabled")) /* noenabled does not exist */ - disabled = 0; - else if (!strcmp(this_opt, "sgram")) /* nosgram == sdram */ - sgram = 1; - else if (!strcmp(this_opt, "sdram")) - sgram = 0; - else { - int value = 1; - - if (!strncmp(this_opt, "no", 2)) { - value = 0; - this_opt += 2; - } - if (! strcmp(this_opt, "inverse")) - inverse = value; - else if (!strcmp(this_opt, "accel")) - noaccel = !value; - else if (!strcmp(this_opt, "pan")) - nopan = !value; - else if (!strcmp(this_opt, "pciretry")) - no_pci_retry = !value; - else if (!strcmp(this_opt, "vga")) - novga = !value; - else if (!strcmp(this_opt, "bios")) - nobios = !value; - else if (!strcmp(this_opt, "init")) - noinit = !value; -#ifdef CONFIG_MTRR - else if (!strcmp(this_opt, "mtrr")) - mtrr = value; -#endif - else if (!strcmp(this_opt, "inv24")) - inv24 = value; - else if (!strcmp(this_opt, "cross4MB")) - cross4MB = value; - else if (!strcmp(this_opt, "hwcursor")) - hwcursor = value; - else if (!strcmp(this_opt, "blink")) - blink = value; - else if (!strcmp(this_opt, "grayscale")) - grayscale = value; - else { - strncpy(videomode, this_opt, sizeof(videomode)-1); - } - } - } - return 0; -} -#endif /* !MODULE */ - -static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int* realOffset, unsigned int *realSize){ - vaddr_t vm; - unsigned int offs; - unsigned int offs2; - unsigned char store; - unsigned char bytes[32]; - unsigned char* tmp; - unsigned long cbase; - unsigned long mbase; - unsigned int clen; - unsigned int mlen; - - DBG("matroxfb_getmemory") - - vm = ACCESS_FBINFO(video.vbase); - maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */ - /* at least 2MB */ - if (maxSize < 0x0200000) return 0; - if (maxSize > 0x2000000) maxSize = 0x2000000; - - mga_outb(M_EXTVGA_INDEX, 0x03); - mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80); - - store = mga_readb(vm, 0x1234); - tmp = bytes; - for (offs = 0x100000; offs < maxSize; offs += 0x200000) - *tmp++ = mga_readb(vm, offs); - for (offs = 0x100000; offs < maxSize; offs += 0x200000) - mga_writeb(vm, offs, 0x02); - if (ACCESS_FBINFO(features.accel.has_cacheflush)) - mga_outb(M_CACHEFLUSH, 0x00); - else - mga_writeb(vm, 0x1234, 0x99); - cbase = mbase = 0; - clen = mlen = 0; - for (offs = 0x100000; offs < maxSize; offs += 0x200000) { - if (mga_readb(vm, offs) != 0x02) - continue; - mga_writeb(vm, offs, mga_readb(vm, offs) - 0x02); - if (mga_readb(vm, offs)) - continue; - if (offs - 0x100000 == cbase + clen) { - clen += 0x200000; - } else { - cbase = offs - 0x100000; - clen = 0x200000; - } - if ((clen > mlen) -#ifndef MATROX_2MB_WITH_4MB_ADDON - && (cbase == 0) -#endif - ) { - mbase = cbase; - mlen = clen; - } - } - tmp = bytes; - for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000) - mga_writeb(vm, offs2, *tmp++); - mga_writeb(vm, 0x1234, store); - - mga_outb(M_EXTVGA_INDEX, 0x03); - mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) & ~0x80); - - *realOffset = mbase; - *realSize = mlen; -#ifdef CONFIG_FB_MATROX_MILLENIUM - ACCESS_FBINFO(interleave) = !(!isMillenium(MINFO) || (mbase & 0x3FFFFF) || (mlen & 0x3FFFFF)); -#endif - return 1; -} - -#ifdef CONFIG_FB_MATROX_MILLENIUM -static int __init Ti3026_preinit(WPMINFO struct matrox_hw_state* hw){ - static const int vxres_mill2[] = { 512, 640, 768, 800, 832, 960, - 1024, 1152, 1280, 1600, 1664, 1920, - 2048, 0}; - static const int vxres_mill1[] = { 640, 768, 800, 960, - 1024, 1152, 1280, 1600, 1920, - 2048, 0}; - - DBG("Ti3026_preinit") - - ACCESS_FBINFO(millenium) = 1; - ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL); - ACCESS_FBINFO(capable.cfb4) = 1; - ACCESS_FBINFO(capable.text) = 1; /* isMilleniumII(MINFO); */ - ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1; - ACCESS_FBINFO(cursor.timer.function) = matroxfb_ti3026_flashcursor; - - if (ACCESS_FBINFO(devflags.noinit)) - return 0; - /* preserve VGA I/O, BIOS and PPC */ - hw->MXoptionReg &= 0xC0000100; - hw->MXoptionReg |= 0x002C0000; - if (ACCESS_FBINFO(devflags.novga)) - hw->MXoptionReg &= ~0x00000100; - if (ACCESS_FBINFO(devflags.nobios)) - hw->MXoptionReg &= ~0x40000000; - if (ACCESS_FBINFO(devflags.nopciretry)) - hw->MXoptionReg |= 0x20000000; - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); - - ACCESS_FBINFO(accel.ramdac_rev) = inTi3026(PMINFO TVP3026_XSILICONREV); - - outTi3026(PMINFO TVP3026_XCLKCTRL, TVP3026_XCLKCTRL_SRC_CLK0VGA | TVP3026_XCLKCTRL_CLKSTOPPED); - outTi3026(PMINFO TVP3026_XTRUECOLORCTRL, TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR); - outTi3026(PMINFO TVP3026_XMUXCTRL, TVP3026_XMUXCTRL_VGA); - - outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A); - outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0x00); - outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00); - - mga_outb(M_MISC_REG, 0x67); - - outTi3026(PMINFO TVP3026_XMEMPLLCTRL, TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL); - - mga_outl(M_RESET, 1); - udelay(250); - mga_outl(M_RESET, 0); - udelay(250); - mga_outl(M_MACCESS, 0x00008000); - udelay(10); - return 0; -} - -static void __init Ti3026_reset(WPMINFO struct matrox_hw_state* hw){ - - DBG("Ti3026_reset") - - matroxfb_fastfont_init(MINFO); - - ti3026_ramdac_init(PMINFO hw); -} -#endif - -#ifdef CONFIG_FB_MATROX_MILLENIUM -static struct matrox_switch matrox_millenium = { - Ti3026_preinit, Ti3026_reset, Ti3026_init, Ti3026_restore -}; -#endif - -#ifdef CONFIG_FB_MATROX_MYSTIQUE -static struct matrox_switch matrox_mystique = { - MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore -}; -#endif - -#ifdef CONFIG_FB_MATROX_G100 -static struct matrox_switch matrox_G100 = { - MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore -}; -#endif - -struct video_board { - int maxvram; - int maxdisplayable; - int accelID; - struct matrox_switch* lowlevel; - }; -#ifdef CONFIG_FB_MATROX_MILLENIUM -static struct video_board vbMillenium __initdata = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA2064W, &matrox_millenium}; -static struct video_board vbMillenium2 __initdata = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W, &matrox_millenium}; -static struct video_board vbMillenium2A __initdata = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W_AGP, &matrox_millenium}; -#endif /* CONFIG_FB_MATROX_MILLENIUM */ -#ifdef CONFIG_FB_MATROX_MYSTIQUE -static struct video_board vbMystique __initdata = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA1064SG, &matrox_mystique}; -#endif /* CONFIG_FB_MATROX_MYSTIQUE */ -#ifdef CONFIG_FB_MATROX_G100 -static struct video_board vbG100 __initdata = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGAG100, &matrox_G100}; -static struct video_board vbG200 __initdata = {0x1000000, 0x1000000, FB_ACCEL_MATROX_MGAG200, &matrox_G100}; -#ifdef CONFIG_FB_MATROX_32MB -/* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for - whole 32MB */ -static struct video_board vbG400 __initdata = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100}; -#else -static struct video_board vbG400 __initdata = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100}; -#endif -#endif - -#define DEVF_VIDEO64BIT 0x01 -#define DEVF_SWAPS 0x02 -#define DEVF_MILLENIUM 0x04 -#define DEVF_MILLENIUM2 0x08 -#define DEVF_CROSS4MB 0x10 -#define DEVF_TEXT4B 0x20 -#define DEVF_DDC_8_2 0x40 -#define DEVF_DMA 0x80 -#define DEVF_SUPPORT32MB 0x100 -#define DEVF_ANY_VXRES 0x200 -#define DEVF_TEXT16B 0x400 - -#define DEVF_G100 (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2) /* no doc, no vxres... */ -#define DEVF_G200 (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2 | DEVF_ANY_VXRES) -#define DEVF_G400 (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2 | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B) - -static struct board { - unsigned short vendor, device, rev, svid, sid; - unsigned int flags; - unsigned int maxclk; - struct video_board* base; - const char* name; - } dev_list[] __initdata = { -#ifdef CONFIG_FB_MATROX_MILLENIUM - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, 0xFF, - 0, 0, - DEVF_MILLENIUM | DEVF_TEXT4B, - 230000, - &vbMillenium, - "Millennium (PCI)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, 0xFF, - 0, 0, - DEVF_MILLENIUM | DEVF_MILLENIUM2 | DEVF_SWAPS, - 220000, - &vbMillenium2, - "Millennium II (PCI)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, 0xFF, - 0, 0, - DEVF_MILLENIUM | DEVF_MILLENIUM2 | DEVF_SWAPS, - 250000, - &vbMillenium2A, - "Millennium II (AGP)"}, -#endif -#ifdef CONFIG_FB_MATROX_MYSTIQUE - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0x02, - 0, 0, - DEVF_VIDEO64BIT, - 180000, - &vbMystique, - "Mystique (PCI)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0xFF, - 0, 0, - DEVF_VIDEO64BIT | DEVF_SWAPS, - 220000, - &vbMystique, - "Mystique 220 (PCI)"}, -#endif -#ifdef CONFIG_FB_MATROX_G100 - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF, - PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_PCI, - DEVF_G100, - 230000, - &vbG100, - "MGA-G100 (PCI)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF, - 0, 0, - DEVF_G100, - 230000, - &vbG100, - "unknown G100 (PCI)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, - PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC, - DEVF_G100, - 230000, - &vbG100, - "MGA-G100 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, - PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_AGP, - DEVF_G100, - 230000, - &vbG100, - "MGA-G100 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, - PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G100_AGP, - DEVF_G100, - 230000, - &vbG100, - "MGA-G100 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, - PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP, - DEVF_G100, - 230000, - &vbG100, - "Productiva G100 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, - 0, 0, - DEVF_G100, - 230000, - &vbG100, - "unknown G100 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 0xFF, - 0, 0, - DEVF_G200, - 250000, - &vbG200, - "unknown G200 (PCI)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, - PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC, - DEVF_G200, - 220000, - &vbG200, - "MGA-G200 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, - PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP, - DEVF_G200, - 230000, - &vbG200, - "Mystique G200 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, - PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENIUM_G200_AGP, - DEVF_G200, - 250000, - &vbG200, - "Millennium G200 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, - PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MARVEL_G200_AGP, - DEVF_G200, - 230000, - &vbG200, - "Marvel G200 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, - PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G200_AGP, - DEVF_G200, - 230000, - &vbG200, - "MGA-G200 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, - 0, 0, - DEVF_G200, - 230000, - &vbG200, - "unknown G200 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0xFF, - 0, 0, - DEVF_G400, - 360000, - &vbG400, - "unknown G400 (AGP)"}, -#endif - {0, 0, 0xFF, - 0, 0, - 0, - 0, - NULL, - NULL}}; - -#ifndef MODULE - /* it cannot be static const struct due to __initdata - marker */ - static struct fb_videomode defaultmode __initdata = { - /* 640x480 @ 60Hz, 31.5 kHz */ - NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, - 0, FB_VMODE_NONINTERLACED - }; -#endif /* !MODULE */ - -static int __init initMatrox2(WPMINFO struct display* d, struct board* b){ - unsigned long ctrlptr_phys = 0; - unsigned long video_base_phys = 0; - unsigned int memsize; - struct matrox_hw_state* hw = ACCESS_FBINFO(currenthw); - - DBG("initMatrox2") - - /* set default values... */ - vesafb_defined.accel_flags = FB_ACCELF_TEXT; - - ACCESS_FBINFO(hw_switch) = b->base->lowlevel; - ACCESS_FBINFO(devflags.accelerator) = b->base->accelID; - ACCESS_FBINFO(max_pixel_clock) = b->maxclk; - - printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name); - ACCESS_FBINFO(capable.plnwt) = 1; - ACCESS_FBINFO(devflags.video64bits) = b->flags & DEVF_VIDEO64BIT; - if (b->flags & DEVF_TEXT4B) { - ACCESS_FBINFO(devflags.vgastep) = 4; - ACCESS_FBINFO(devflags.textmode) = 4; - ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16; - } else if (b->flags & DEVF_TEXT16B) { - ACCESS_FBINFO(devflags.vgastep) = 16; - ACCESS_FBINFO(devflags.textmode) = 1; - ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16; - } else { - ACCESS_FBINFO(devflags.vgastep) = 8; - ACCESS_FBINFO(devflags.textmode) = 1; - ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8; - } -#ifdef CONFIG_FB_MATROX_32MB - ACCESS_FBINFO(devflags.support32MB) = b->flags & DEVF_SUPPORT32MB; -#endif - ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES); - ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode); - ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode); - - if (ACCESS_FBINFO(capable.cross4MB) < 0) - ACCESS_FBINFO(capable.cross4MB) = b->flags & DEVF_CROSS4MB; - if (b->flags & DEVF_SWAPS) { - ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[1].start; - video_base_phys = ACCESS_FBINFO(pcidev)->resource[0].start; - } else { - ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[0].start; - video_base_phys = ACCESS_FBINFO(pcidev)->resource[1].start; - } - if (!ctrlptr_phys) { - printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n"); - return -EINVAL; - } - if (!video_base_phys) { - printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n"); - return -EINVAL; - } - if (mga_ioremap(ctrlptr_phys, 16384, MGA_IOREMAP_MMIO, &ACCESS_FBINFO(mmio.vbase))) { - printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys); - return -ENOMEM; - } - ACCESS_FBINFO(mmio.base) = ctrlptr_phys; - ACCESS_FBINFO(mmio.len) = 16384; - memsize = b->base->maxvram; -/* convert mem (autodetect k, M) */ - if (mem < 1024) mem *= 1024; - if (mem < 0x00100000) mem *= 1024; - - if (mem && (mem < memsize)) - memsize = mem; - ACCESS_FBINFO(video.base) = video_base_phys; - if (mga_ioremap(video_base_phys, memsize, MGA_IOREMAP_FB, &ACCESS_FBINFO(video.vbase))) { - printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n", - video_base_phys, memsize); - mga_iounmap(ACCESS_FBINFO(mmio.vbase)); - return -ENOMEM; - } - { - u_int32_t cmd; - u_int32_t mga_option; - - /* Matrox MilleniumII is deactivated on bootup, but address - regions are assigned to board. So we have to enable it */ - pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &mga_option); - pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd); - mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */ - if ((cmd & PCI_COMMAND_MEMORY) != - PCI_COMMAND_MEMORY) { - /* But if we have to enable it, we have probably to - disable VGA I/O and BIOS... Sure? */ - dprintk(KERN_WARNING "matroxfb: PCI BIOS did not enable device!\n"); - cmd = (cmd | PCI_COMMAND_MEMORY) & ~PCI_COMMAND_VGA_PALETTE; - mga_option &= 0xBFFFFEFF; - /* we must not enable VGA, BIOS if PCI BIOS did not enable device itself */ - ACCESS_FBINFO(devflags.novga) = 1; - ACCESS_FBINFO(devflags.nobios) = 1; - /* we must initialize device if PCI BIOS did not enable it. - It probably means that it is second head ... */ - ACCESS_FBINFO(devflags.noinit) = 0; - } - mga_option |= MX_OPTION_BSWAP; - if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, NULL)) { - if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) { - printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n"); - } - mga_option |= 0x20000000; - ACCESS_FBINFO(devflags.nopciretry) = 1; - } - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, cmd); - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mga_option); - hw->MXoptionReg = mga_option; - - /* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */ - /* maybe preinit() candidate, but it is same... for all devices... at this time... */ - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MGA_INDEX, 0x00003C00); - } - - if (ACCESS_FBINFO(hw_switch)->preinit(PMINFO hw)) { - mga_iounmap(ACCESS_FBINFO(video.vbase)); - mga_iounmap(ACCESS_FBINFO(mmio.vbase)); - return -ENXIO; - } - - { - unsigned int offs; - - if (!matroxfb_getmemory(PMINFO memsize, &offs, &ACCESS_FBINFO(video.len)) || !ACCESS_FBINFO(video.len)) { - printk(KERN_ERR "matroxfb: cannot determine memory size\n"); - mga_iounmap(ACCESS_FBINFO(video.vbase)); - mga_iounmap(ACCESS_FBINFO(mmio.vbase)); - return -ENOMEM; - } -#ifdef MATROX_2MB_WITH_4MB_ADDON -#ifdef FBCON_HAS_CFB24 - { - unsigned int end = offs + ACCESS_FBINFO(video.len); - - if (offs) - offs = ((offs - 1) / (4096 * 3) + 1) * 4096 * 3; - ACCESS_FBINFO(video.len) = end - offs; - } -#endif - ACCESS_FBINFO(devflags.ydstorg) = offs; - video_base_phys += offs; - if (offs) - ACCESS_FBINFO(capable.text) = 0; -#else - ACCESS_FBINFO(devflags.ydstorg) = 0; -#endif - } - ACCESS_FBINFO(currcon) = -1; - ACCESS_FBINFO(currcon_display) = d; - mga_iounmap(ACCESS_FBINFO(video.vbase)); - ACCESS_FBINFO(video.base) = video_base_phys; - if (mga_ioremap(video_base_phys, ACCESS_FBINFO(video.len), MGA_IOREMAP_FB, &ACCESS_FBINFO(video.vbase))) { - printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n", - video_base_phys, ACCESS_FBINFO(video.len)); - mga_iounmap(ACCESS_FBINFO(mmio.vbase)); - return -ENOMEM; - } - ACCESS_FBINFO(video.len_usable) = ACCESS_FBINFO(video.len); - if (ACCESS_FBINFO(video.len_usable) > b->base->maxdisplayable) - ACCESS_FBINFO(video.len_usable) = b->base->maxdisplayable; -#ifdef CONFIG_MTRR - if (mtrr) { - ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video.len), MTRR_TYPE_WRCOMB, 1); - ACCESS_FBINFO(mtrr.vram_valid) = 1; - printk(KERN_INFO "matroxfb: MTRR's turned on\n"); - } -#endif /* CONFIG_MTRR */ - - if (!ACCESS_FBINFO(devflags.novga)) - request_region(0x3C0, 32, "matrox"); - ACCESS_FBINFO(hw_switch->reset(PMINFO hw)); - -/* validate params, autodetect k, M */ - if (fh < 1000) fh *= 1000; /* 1kHz minimum */ - if (maxclk < 1000) maxclk *= 1000; /* kHz -> Hz, MHz -> kHz */ - if (maxclk < 1000000) maxclk *= 1000; /* kHz -> Hz, 1MHz minimum */ - if (vesa != ~0) - vesa &= 0x1DFF; /* mask out clearscreen, acceleration and so on */ - - ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0; - ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh; - ACCESS_FBINFO(fbcon.monspecs.vfmin) = 0; - ACCESS_FBINFO(fbcon.monspecs.vfmax) = fv; - ACCESS_FBINFO(fbcon.monspecs.dpms) = 0; /* TBD */ - -/* static settings */ - for (RSptr = vesamap; RSptr->vesa; RSptr++) { - if (RSptr->vesa == vesa) break; - } - if (!RSptr->vesa) { - printk(KERN_ERR "Invalid vesa mode 0x%04X\n", vesa); - RSptr = vesamap; - } - { - int res = RSResolution(RSptr->info)-1; - if (left == ~0) - left = timmings[res].left; - if (!xres) - xres = timmings[res].xres; - if (right == ~0) - right = timmings[res].right; - if (!hslen) - hslen = timmings[res].hslen; - if (upper == ~0) - upper = timmings[res].upper; - if (!yres) - yres = timmings[res].yres; - if (lower == ~0) - lower = timmings[res].lower; - if (!vslen) - vslen = timmings[res].vslen; - if (!(fv||fh||maxclk||pixclock)) - fv = timmings[res].vfreq; - if (depth == -1) - depth = RSDepth(RSptr->info); - } - if ((depth == RSText8) && (!*ACCESS_FBINFO(fbcon.fontname))) { - strcpy(ACCESS_FBINFO(fbcon.fontname), "VGA8x8"); - } - vesafb_defined.red = colors[depth-1].red; - vesafb_defined.green = colors[depth-1].green; - vesafb_defined.blue = colors[depth-1].blue; - vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel; - vesafb_defined.grayscale = grayscale; - vesafb_defined.vmode = 0; - if (noaccel) - vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT; - - strcpy(ACCESS_FBINFO(fbcon.modename), "MATROX VGA"); - ACCESS_FBINFO(fbcon.changevar) = NULL; - ACCESS_FBINFO(fbcon.node) = -1; - ACCESS_FBINFO(fbcon.fbops) = &matroxfb_ops; - ACCESS_FBINFO(fbcon.disp) = d; - ACCESS_FBINFO(fbcon.switch_con) = &matroxfb_switch; - ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar; - ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank; - ACCESS_FBINFO(fbcon.flags) = FBINFO_FLAG_DEFAULT; - ACCESS_FBINFO(video.len_usable) &= PAGE_MASK; - -#ifndef MODULE - /* mode database is marked __init ... */ - { - fb_find_mode(&vesafb_defined, &ACCESS_FBINFO(fbcon), videomode[0]?videomode:NULL, - NULL, 0, &defaultmode, vesafb_defined.bits_per_pixel); - } -#endif /* !MODULE */ - - /* mode modifiers */ - if (hslen) - vesafb_defined.hsync_len = hslen; - if (vslen) - vesafb_defined.vsync_len = vslen; - if (left != ~0) - vesafb_defined.left_margin = left; - if (right != ~0) - vesafb_defined.right_margin = right; - if (upper != ~0) - vesafb_defined.upper_margin = upper; - if (lower != ~0) - vesafb_defined.lower_margin = lower; - if (xres) - vesafb_defined.xres = xres; - if (yres) - vesafb_defined.yres = yres; - if (sync != -1) - vesafb_defined.sync = sync; - else if (vesafb_defined.sync == ~0) { - vesafb_defined.sync = 0; - if (yres < 400) - vesafb_defined.sync |= FB_SYNC_HOR_HIGH_ACT; - else if (yres < 480) - vesafb_defined.sync |= FB_SYNC_VERT_HIGH_ACT; - } - - /* fv, fh, maxclk limits was specified */ - { - unsigned int tmp; - - if (fv) { - tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres - + vesafb_defined.lower_margin + vesafb_defined.vsync_len); - if ((tmp < fh) || (fh == 0)) fh = tmp; - } - if (fh) { - tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres - + vesafb_defined.right_margin + vesafb_defined.hsync_len); - if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp; - } - maxclk = (maxclk + 499) / 500; - if (maxclk) { - tmp = (2000000000 + maxclk) / maxclk; - if (tmp > pixclock) pixclock = tmp; - } - } - if (pixclock) { - if (pixclock < 2000) /* > 500MHz */ - pixclock = 4000; /* 250MHz */ - if (pixclock > 1000000) - pixclock = 1000000; /* 1MHz */ - vesafb_defined.pixclock = pixclock; - } - - /* FIXME: Where to move this?! */ -#if defined(CONFIG_FB_OF) -#if defined(CONFIG_FB_COMPAT_XPMAC) - strcpy(ACCESS_FBINFO(matrox_name), "MTRX,"); /* OpenFirmware naming convension */ - strncat(ACCESS_FBINFO(matrox_name), b->name, 26); - if (!console_fb_info) - console_fb_info = &ACCESS_FBINFO(fbcon); -#endif - if ((xres <= 640) && (yres <= 480)) { - struct fb_var_screeninfo var; - if (default_vmode == VMODE_NVRAM) { - default_vmode = nvram_read_byte(NV_VMODE); - if (default_vmode <= 0 || default_vmode > VMODE_MAX) - default_vmode = VMODE_CHOOSE; - } - if (default_vmode <= 0 || default_vmode > VMODE_MAX) - default_vmode = VMODE_640_480_60; - if (default_cmode == CMODE_NVRAM) - default_cmode = nvram_read_byte(NV_CMODE); - if (default_cmode < CMODE_8 || default_cmode > CMODE_32) - default_cmode = CMODE_8; - if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) { - var.accel_flags = vesafb_defined.accel_flags; - var.xoffset = var.yoffset = 0; - vesafb_defined = var; /* Note: mac_vmode_to_var() doesnot set all parameters */ - } - } -#endif - vesafb_defined.xres_virtual = vesafb_defined.xres; - if (nopan) { - vesafb_defined.yres_virtual = vesafb_defined.yres; - } else { - vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough - to yres_virtual * xres_virtual < 2^32 */ - } - if (matroxfb_set_var(&vesafb_defined, -2, &ACCESS_FBINFO(fbcon))) { - printk(KERN_ERR "matroxfb: cannot set required parameters\n"); - return -EINVAL; - } - - printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n", - vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, - vesafb_defined.xres_virtual, vesafb_defined.yres_virtual); - printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n", - ACCESS_FBINFO(video.base), vaddr_va(ACCESS_FBINFO(video.vbase)), ACCESS_FBINFO(video.len)); - -/* We do not have to set currcon to 0... register_framebuffer do it for us on first console - * and we do not want currcon == 0 for subsequent framebuffers */ - - if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0) { - return -EINVAL; - } - printk("fb%d: %s frame buffer device\n", - GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), ACCESS_FBINFO(fbcon.modename)); - if (ACCESS_FBINFO(currcon) < 0) { - /* there is no console on this fb... but we have to initialize hardware - * until someone tells me what is proper thing to do */ - printk(KERN_INFO "fb%d: initializing hardware\n", - GET_FB_IDX(ACCESS_FBINFO(fbcon.node))); - matroxfb_set_var(&vesafb_defined, -1, &ACCESS_FBINFO(fbcon)); - } - return 0; -} - -static struct matrox_fb_info* fb_list = NULL; - -static int __init matrox_init(void){ - struct pci_dev* pdev = NULL; - - DBG("matrox_init") - - if (disabled) - return -ENXIO; - while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) { - struct board* b; - u_int8_t rev; - u_int16_t svid; - u_int16_t sid; - - pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); - svid = pdev->subsystem_vendor; - sid = pdev->subsystem_device; - for (b = dev_list; b->vendor; b++) { - if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue; - if (b->svid) - if ((b->svid != svid) || (b->sid != sid)) continue; - if (dev <= 0) { - struct matrox_fb_info* minfo; - struct display* d; - int err; - -#ifdef CONFIG_FB_MATROX_MULTIHEAD - minfo = (struct matrox_fb_info*)kmalloc(sizeof(*minfo), GFP_KERNEL); - if (minfo) { - d = (struct display*)kmalloc(sizeof(*d), GFP_KERNEL); - if (d) { -#else - minfo = &global_mxinfo; - d = &global_disp; -#endif - memset(MINFO, 0, sizeof(*MINFO)); - memset(d, 0, sizeof(*d)); - - ACCESS_FBINFO(currenthw) = &ACCESS_FBINFO(hw1); - ACCESS_FBINFO(newhw) = &ACCESS_FBINFO(hw2); - ACCESS_FBINFO(pcidev) = pdev; - /* CMDLINE */ - memcpy(ACCESS_FBINFO(fbcon.fontname), fontname, sizeof(ACCESS_FBINFO(fbcon.fontname))); - /* DEVFLAGS */ - ACCESS_FBINFO(devflags.inverse) = inverse; - ACCESS_FBINFO(devflags.novga) = novga; - ACCESS_FBINFO(devflags.nobios) = nobios; - ACCESS_FBINFO(devflags.noinit) = noinit; - ACCESS_FBINFO(devflags.nopciretry) = no_pci_retry; - ACCESS_FBINFO(devflags.mga_24bpp_fix) = inv24; - ACCESS_FBINFO(devflags.precise_width) = option_precise_width; - ACCESS_FBINFO(devflags.hwcursor) = hwcursor; - ACCESS_FBINFO(devflags.blink) = blink; - ACCESS_FBINFO(devflags.sgram) = sgram; - ACCESS_FBINFO(capable.cross4MB) = cross4MB; - - ACCESS_FBINFO(fastfont.size) = fastfont; - - ACCESS_FBINFO(cursor.state) = CM_ERASE; - ACCESS_FBINFO(cursor.timer.prev) = ACCESS_FBINFO(cursor.timer.next) = NULL; - ACCESS_FBINFO(cursor.timer.data) = (unsigned long)MINFO; - spin_lock_init(&ACCESS_FBINFO(lock.DAC)); - - err = initMatrox2(PMINFO d, b); - if (!err) { - ACCESS_FBINFO(next_fb) = fb_list; - fb_list = MINFO; -#ifdef CONFIG_FB_MATROX_MULTIHEAD - goto leave; -#else - return 0; -#endif - } -#ifdef CONFIG_FB_MATROX_MULTIHEAD - kfree(d); - } - kfree(minfo); - } -#endif - } -#ifdef CONFIG_FB_MATROX_MULTIHEAD -leave:; -#endif - if (dev == 0) return 0; - if (dev > 0) dev--; - break; - } - } - return 0; -} - -#ifndef MODULE -static int __init initialized = 0; - -int __init matroxfb_init(void) -{ - DBG("matroxfb_init") - - if (!initialized) { - initialized = 1; - matrox_init(); - } - if (!fb_list) return -ENXIO; - return 0; -} - -#if defined(CONFIG_FB_OF) -int __init matrox_of_init(struct device_node *dp){ - DBG("matrox_of_init"); - - if (!initialized) { - initialized = 1; - matrox_init(); - } - if (!fb_list) return -ENXIO; - return 0; -} -#endif /* CONFIG_FB_OF */ - -#else - -MODULE_AUTHOR("(c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>"); -MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400"); -MODULE_PARM(mem, "i"); -MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)"); -MODULE_PARM(disabled, "i"); -MODULE_PARM_DESC(disabled, "Disabled (0 or 1=disabled), meaningless for module (default=0)"); -MODULE_PARM(noaccel, "i"); -MODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)"); -MODULE_PARM(nopan, "i"); -MODULE_PARM_DESC(nopan, "Disable pan on startup (0 or 1=disabled) (default=0)"); -MODULE_PARM(no_pci_retry, "i"); -MODULE_PARM_DESC(no_pci_retry, "PCI retries enabled (0 or 1=disabled) (default=0)"); -MODULE_PARM(novga, "i"); -MODULE_PARM_DESC(novga, "VGA I/O (0x3C0-0x3DF) disabled (0 or 1=disabled) (default=0)"); -MODULE_PARM(nobios, "i"); -MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)"); -MODULE_PARM(noinit, "i"); -MODULE_PARM_DESC(noinit, "Disables W/SG/SD-RAM and bus interface initialization (0 or 1=do not initialize) (default=0)"); -MODULE_PARM(mtrr, "i"); -MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)"); -MODULE_PARM(sgram, "i"); -MODULE_PARM_DESC(sgram, "Indicates that G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)"); -MODULE_PARM(inv24, "i"); -MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)"); -MODULE_PARM(inverse, "i"); -MODULE_PARM_DESC(inverse, "Inverse (0 or 1) (default=0)"); -#ifdef CONFIG_FB_MATROX_MULTIHEAD -MODULE_PARM(dev, "i"); -MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=all working)"); -#else -MODULE_PARM(dev, "i"); -MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=first working)"); -#endif -MODULE_PARM(vesa, "i"); -MODULE_PARM_DESC(vesa, "Startup videomode (0x000-0x1FF) (default=0x101)"); -MODULE_PARM(xres, "i"); -MODULE_PARM_DESC(xres, "Horizontal resolutioni (px), overrides xres from vesa (default=vesa)"); -MODULE_PARM(yres, "i"); -MODULE_PARM_DESC(yres, "Vertical resolution (scans), overrides yres from vesa (default=vesa)"); -MODULE_PARM(upper, "i"); -MODULE_PARM_DESC(upper, "Upper blank space (scans), overrides upper from vesa (default=vesa)"); -MODULE_PARM(lower, "i"); -MODULE_PARM_DESC(lower, "Lower blank space (scans), overrides lower from vesa (default=vesa)"); -MODULE_PARM(vslen, "i"); -MODULE_PARM_DESC(vslen, "Vertical sync length (scans), overrides lower from vesa (default=vesa)"); -MODULE_PARM(left, "i"); -MODULE_PARM_DESC(left, "Left blank space (px), overrides left from vesa (default=vesa)"); -MODULE_PARM(right, "i"); -MODULE_PARM_DESC(right, "Right blank space (px), overrides right from vesa (default=vesa)"); -MODULE_PARM(hslen, "i"); -MODULE_PARM_DESC(hslen, "Horizontal sync length (px), overrides hslen from vesa (default=vesa)"); -MODULE_PARM(pixclock, "i"); -MODULE_PARM_DESC(pixclock, "Pixelclock (ns), overrides pixclock from vesa (default=vesa)"); -MODULE_PARM(sync, "i"); -MODULE_PARM_DESC(sync, "Sync polarity, overrides sync from vesa (default=vesa)"); -MODULE_PARM(depth, "i"); -MODULE_PARM_DESC(depth, "Color depth (0=text,8,15,16,24,32) (default=vesa)"); -MODULE_PARM(maxclk, "i"); -MODULE_PARM_DESC(maxclk, "Startup maximal clock, 0-999MHz, 1000-999999kHz, 1000000-INF Hz"); -MODULE_PARM(fh, "i"); -MODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz"); -MODULE_PARM(fv, "i"); -MODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n" -"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\"\n"); -MODULE_PARM(hwcursor, "i"); -MODULE_PARM_DESC(hwcursor, "Enables hardware cursor (0 or 1) (default=0)"); -MODULE_PARM(blink, "i"); -MODULE_PARM_DESC(blink, "Enables hardware cursor blinking (0 or 1) (default=1)"); -MODULE_PARM(fastfont, "i"); -MODULE_PARM_DESC(fastfont, "Specifies, how much memory should be used for font data (0, 1024-65536 are reasonable) (default=0)"); -MODULE_PARM(grayscale, "i"); -MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)"); -MODULE_PARM(cross4MB, "i"); -MODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)"); -#ifdef CONFIG_FB_OF -MODULE_PARM(vmode, "i"); -MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)"); -MODULE_PARM(cmode, "i"); -MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)"); -#endif - -int __init init_module(void){ - - DBG("init_module") - -#ifdef DEBUG - if( disabled ) - return -ENXIO; -#endif /* DEBUG */ - - if (depth == 0) - depth = RSText; - else if (depth == 4) - depth = RS4bpp; - else if (depth == 8) - depth = RS8bpp; - else if (depth == 15) - depth = RS15bpp; - else if (depth == 16) - depth = RS16bpp; - else if (depth == 24) - depth = RS24bpp; - else if (depth == 32) - depth = RS32bpp; - else if (depth != -1) { - printk(KERN_ERR "matroxfb: depth %d is not supported, using default\n", depth); - depth = -1; - } - matrox_init(); - if (!fb_list) return -ENXIO; - return 0; -} - -void cleanup_module(void) { - - DBG("cleanup_module") - -#ifdef DEBUG - if( disabled ) - return; -#endif /* DEBUG */ - - while (fb_list) { - struct matrox_fb_info* minfo; - - minfo = fb_list; - fb_list = fb_list->next_fb; - unregister_framebuffer(&ACCESS_FBINFO(fbcon)); - del_timer(&ACCESS_FBINFO(cursor.timer)); -#ifdef CONFIG_MTRR - if (ACCESS_FBINFO(mtrr.vram_valid)) - mtrr_del(ACCESS_FBINFO(mtrr.vram), ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len)); -#endif - mga_iounmap(ACCESS_FBINFO(mmio.vbase)); - mga_iounmap(ACCESS_FBINFO(video.vbase)); -#ifdef CONFIG_FB_MATROX_MULTIHEAD - kfree_s(ACCESS_FBINFO(fbcon.disp), sizeof(struct display)); - kfree_s(minfo, sizeof(struct matrox_fb_info)); -#endif - } -} -#endif /* MODULE */ -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/video/vgacon.c b/drivers/video/vgacon.c index 696845f8a..1180d3ee0 100644 --- a/drivers/video/vgacon.c +++ b/drivers/video/vgacon.c @@ -106,7 +106,14 @@ static int vga_can_do_color = 0; /* Do we support colors? */ static unsigned int vga_default_font_height; /* Height of default screen font */ static unsigned char vga_video_type; /* Card type */ static unsigned char vga_hardscroll_enabled; +#ifdef CONFIG_IA64_SOFTSDV_HACKS +/* + * SoftSDV doesn't have hardware assist VGA scrolling + */ +static unsigned char vga_hardscroll_user_enable = 0; +#else static unsigned char vga_hardscroll_user_enable = 1; +#endif static unsigned char vga_font_is_default = 1; static int vga_vesa_blanked; static int vga_palette_blanked; diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c index 823893aad..11b485b05 100644 --- a/drivers/zorro/proc.c +++ b/drivers/zorro/proc.c @@ -77,10 +77,6 @@ static struct file_operations proc_bus_zorro_operations = { read: proc_bus_zorro_read, }; -static struct inode_operations proc_bus_zorro_inode_operations = { - &proc_bus_zorro_operations, /* default base directory file-ops */ -}; - static int get_zorro_dev_info(char *buf, char **start, off_t pos, int count) { @@ -118,7 +114,7 @@ static int __init zorro_proc_attach_device(u_int slot) entry = create_proc_entry(name, 0, proc_bus_zorro_dir); if (!entry) return -ENOMEM; - entry->ops = &proc_bus_zorro_inode_operations; + entry->proc_fops = &proc_bus_zorro_operations; entry->data = &zorro_autocon[slot]; entry->size = sizeof(struct zorro_dev); return 0; |