Commit 159f5e24 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.3.35pre4

parent 587f241d
SiS 900/7016 Fast Ethernet Device Driver SiS 900/7016 Fast Ethernet Device Driver
by Ollie Lho (ollie@sis.com.tw) by Ollie Lho (ollie@sis.com.tw)
November 4, 1999. Document Revision: 0.1 November 4, 1999. Document Revision: 0.2
This document gives some information on installation and usage of SiS This document gives some information on installation and usage of SiS
900/7016 device driver under Linux. 900/7016 device driver under Linux.
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
4. Tested Environment 4. Tested Environment
5. Files in This Rackage 5. Files in This Package
6. Installation 6. Installation
...@@ -111,9 +111,11 @@ ...@@ -111,9 +111,11 @@
9. Names of variables were changed to be more consistent. 9. Names of variables were changed to be more consistent.
10. Clean up of auo-negotiation and timer code. 10.
Clean up of auo-negotiation and timer code.
11. Automatic detection and change of PHY on the fly. 11.
Automatic detection and change of PHY on the fly.
4. Tested Environment 4. Tested Environment
...@@ -137,7 +139,7 @@ ...@@ -137,7 +139,7 @@
o Samba version 2.0.3 o Samba version 2.0.3
5. Files in This Rackage 5. Files in This Package
In the package you can find these files: In the package you can find these files:
...@@ -157,10 +159,16 @@ ...@@ -157,10 +159,16 @@
6. Installation 6. Installation
Before trying to install the driver, be sure to get the latest Silicon Integrated System Corp. is cooperating closely with core Linux
revision from SiS' Home Page. If you have no prior experience in Kernel developers. The revisions of SiS 900 driver are distributed by
networking under Linux, please read Ethernet HOWTO and Networking the usuall channels for kernel tar files and patches. Those kernel tar
HOWTO available from Linux Documentation Project (LDP). files for official kernel and patches for kernel pre-release can be
download at official kernel ftp site
<http://ftp.kernel.org/pub/linux/kernel/> and its mirrors. The 1.06
revision can be found in kernel version later than 2.3.15 and
pre-2.2.14. If you have no prior experience in networking under
Linux, please read Ethernet HOWTO and Networking HOWTO available from
Linux Documentation Project (LDP).
The installation procedure are different according to your kernel The installation procedure are different according to your kernel
versions. versions.
...@@ -244,6 +252,7 @@ ...@@ -244,6 +252,7 @@
sis900.c: v1.06 11/04/99 sis900.c: v1.06 11/04/99
eth0: SiS 900 PCI Fast Ethernet at 0xd000, IRQ 10, 00:00:e8:83:7f:a4. eth0: SiS 900 PCI Fast Ethernet at 0xd000, IRQ 10, 00:00:e8:83:7f:a4.
eth0: SiS 900 Internal MII PHY transceiver found at address 1. eth0: SiS 900 Internal MII PHY transceiver found at address 1.
eth0: Using SiS 900 Internal MII PHY as default
...@@ -269,7 +278,6 @@ ...@@ -269,7 +278,6 @@
eth0: Using SiS 900 Internal MII PHY as default
eth0: Media Link On 100mbps full-duplex eth0: Media Link On 100mbps full-duplex
......
...@@ -119,6 +119,7 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC ...@@ -119,6 +119,7 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
source drivers/parport/Config.in source drivers/parport/Config.in
bool 'ACPI support' CONFIG_ACPI
bool 'Advanced Power Management BIOS support' CONFIG_APM bool 'Advanced Power Management BIOS support' CONFIG_APM
if [ "$CONFIG_APM" != "n" ]; then if [ "$CONFIG_APM" != "n" ]; then
bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND
......
...@@ -71,6 +71,7 @@ CONFIG_BINFMT_AOUT=y ...@@ -71,6 +71,7 @@ CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y CONFIG_BINFMT_MISC=y
# CONFIG_PARPORT is not set # CONFIG_PARPORT is not set
CONFIG_ACPI=y
# CONFIG_APM is not set # CONFIG_APM is not set
# #
...@@ -405,7 +406,6 @@ CONFIG_DRM_TDFX=y ...@@ -405,7 +406,6 @@ CONFIG_DRM_TDFX=y
# #
# Misc devices # Misc devices
# #
CONFIG_ACPI=y
# #
# Filesystems # Filesystems
......
...@@ -39,6 +39,10 @@ else ...@@ -39,6 +39,10 @@ else
endif endif
endif endif
ifeq ($(CONFIG_ACPI),y)
OX_OBJS += acpi.o
endif
ifeq ($(CONFIG_APM),y) ifeq ($(CONFIG_APM),y)
OX_OBJS += apm.o OX_OBJS += apm.o
else else
......
...@@ -110,6 +110,8 @@ static spinlock_t acpi_devs_lock = SPIN_LOCK_UNLOCKED; ...@@ -110,6 +110,8 @@ static spinlock_t acpi_devs_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(acpi_devs); static LIST_HEAD(acpi_devs);
/* Make it impossible to enter C2/C3 until after we've initialized */ /* Make it impossible to enter C2/C3 until after we've initialized */
static unsigned long acpi_enter_lvl2_lat = ACPI_INFINITE_LAT;
static unsigned long acpi_enter_lvl3_lat = ACPI_INFINITE_LAT;
static unsigned long acpi_p_lvl2_lat = ACPI_INFINITE_LAT; static unsigned long acpi_p_lvl2_lat = ACPI_INFINITE_LAT;
static unsigned long acpi_p_lvl3_lat = ACPI_INFINITE_LAT; static unsigned long acpi_p_lvl3_lat = ACPI_INFINITE_LAT;
...@@ -636,87 +638,143 @@ static int acpi_disable(struct acpi_facp *facp) ...@@ -636,87 +638,143 @@ static int acpi_disable(struct acpi_facp *facp)
return 0; return 0;
} }
static inline int bm_activity(void)
{
return 0 && acpi_read_pm1_status(acpi_facp) & ACPI_BM;
}
static inline void clear_bm_activity(void)
{
acpi_write_pm1_status(acpi_facp, ACPI_BM);
}
static void sleep_on_busmaster(void)
{
u32 pm1_cntr = acpi_read_pm1_control(acpi_facp);
if (pm1_cntr & ACPI_BM_RLD) {
pm1_cntr &= ~ACPI_BM_RLD;
acpi_write_pm1_control(acpi_facp, pm1_cntr);
}
}
static void wake_on_busmaster(void)
{
u32 pm1_cntr = acpi_read_pm1_control(acpi_facp);
if (!(pm1_cntr & ACPI_BM_RLD)) {
pm1_cntr |= ACPI_BM_RLD;
acpi_write_pm1_control(acpi_facp, pm1_cntr);
}
clear_bm_activity();
}
/* /*
* Idle loop (uniprocessor only) * Idle loop (uniprocessor only)
*/ */
static void acpi_idle_handler(void) static void acpi_idle_handler(void)
{ {
static int sleep_level = 1; static int sleep_level = 1;
u32 pm1_cnt, timer, pm2_cnt, bm_active;
unsigned long time;
// return to C0 on bus master request (necessary for C3 only)
pm1_cnt = acpi_read_pm1_control(acpi_facp);
if (sleep_level == 3) {
if (!(pm1_cnt & ACPI_BM_RLD)) {
pm1_cnt |= ACPI_BM_RLD;
acpi_write_pm1_control(acpi_facp, pm1_cnt);
}
}
else {
if (pm1_cnt & ACPI_BM_RLD) {
pm1_cnt &= ~ACPI_BM_RLD;
acpi_write_pm1_control(acpi_facp, pm1_cnt);
}
}
// clear bus master activity flag if (!acpi_facp->pm_tmr || !acpi_p_blk)
acpi_write_pm1_status(acpi_facp, ACPI_BM); goto not_initialized;
// get current time /*
timer = acpi_facp->pm_tmr; * start from the previous sleep level..
time = inl(timer); */
if (sleep_level == 1)
goto sleep1;
if (sleep_level == 2 || bm_activity())
goto sleep2;
sleep3:
sleep_level = 3;
if (!acpi_p_lvl3_tested) {
printk("ACPI C3 works\n");
acpi_p_lvl3_tested = 1;
}
wake_on_busmaster();
if (acpi_facp->pm2_cnt)
goto sleep3_with_arbiter;
// sleep for (;;) {
switch (sleep_level) { unsigned long time;
case 1: __cli();
__asm__ __volatile__("sti ; hlt": : :"memory"); if (current->need_resched)
break; goto out;
case 2: time = inl(acpi_facp->pm_tmr);
inb(acpi_p_blk + ACPI_P_LVL2);
break;
case 3:
pm2_cnt = acpi_facp->pm2_cnt;
if (pm2_cnt) {
/* Disable PCI arbitration while sleeping,
to avoid DMA corruption? */
cli();
outb(inb(pm2_cnt) | ACPI_ARB_DIS, pm2_cnt);
inb(acpi_p_blk + ACPI_P_LVL3); inb(acpi_p_blk + ACPI_P_LVL3);
outb(inb(pm2_cnt) & ~ACPI_ARB_DIS, pm2_cnt); time = inl(acpi_facp->pm_tmr) - time;
sti(); __sti();
if (time > acpi_p_lvl3_lat || bm_activity())
goto sleep2;
} }
else {
sleep3_with_arbiter:
for (;;) {
unsigned long time;
unsigned int pm2_cntr = acpi_facp->pm2_cnt;
__cli();
if (current->need_resched)
goto out;
time = inl(acpi_facp->pm_tmr);
outb(inb(pm2_cntr) | ACPI_ARB_DIS, pm2_cntr);
inb(acpi_p_blk + ACPI_P_LVL3); inb(acpi_p_blk + ACPI_P_LVL3);
outb(inb(pm2_cntr) & ~ACPI_ARB_DIS, pm2_cntr);
time = inl(acpi_facp->pm_tmr) - time;
__sti();
if (time > acpi_p_lvl3_lat || bm_activity())
goto sleep2;
} }
break;
}
// calculate time spent sleeping
time = (inl(timer) - time) & ACPI_TMR_MASK;
// check for bus master activity sleep2:
bm_active = (acpi_read_pm1_status(acpi_facp) & ACPI_BM); sleep_level = 2;
if (!acpi_p_lvl2_tested) {
// record working C2/C3 printk("ACPI C2 works\n");
if (sleep_level == 2 && !acpi_p_lvl2_tested) {
acpi_p_lvl2_tested = 1; acpi_p_lvl2_tested = 1;
printk(KERN_INFO "ACPI: C2 works\n");
} }
else if (sleep_level == 3 && !acpi_p_lvl3_tested) { wake_on_busmaster(); /* Required to track BM activity.. */
acpi_p_lvl3_tested = 1; for (;;) {
printk(KERN_INFO "ACPI: C3 works\n"); unsigned long time;
__cli();
if (current->need_resched)
goto out;
time = inl(acpi_facp->pm_tmr);
inb(acpi_p_blk + ACPI_P_LVL2);
time = inl(acpi_facp->pm_tmr) - time;
__sti();
if (time > acpi_p_lvl2_lat)
goto sleep1;
if (bm_activity()) {
clear_bm_activity();
continue;
}
if (time < acpi_enter_lvl3_lat)
goto sleep3;
} }
// pick next C-state based on time spent sleeping, sleep1:
// C-state latencies, and bus master activity
sleep_level = 1; sleep_level = 1;
if (acpi_p_blk) { sleep_on_busmaster();
if (time > acpi_p_lvl3_lat && !bm_active) for (;;) {
sleep_level = 3; unsigned long time;
else if (time > acpi_p_lvl2_lat) __cli();
sleep_level = 2; if (current->need_resched)
goto out;
time = inl(acpi_facp->pm_tmr);
__asm__ __volatile__("sti ; hlt": : :"memory");
time = inl(acpi_facp->pm_tmr) - time;
if (time < acpi_enter_lvl2_lat)
goto sleep2;
} }
not_initialized:
for (;;) {
__cli();
if (current->need_resched)
goto out;
__asm__ __volatile__("sti ; hlt": : :"memory");
}
out:
__sti();
} }
/* /*
...@@ -1119,10 +1177,12 @@ static int __init acpi_init(void) ...@@ -1119,10 +1177,12 @@ static int __init acpi_init(void)
if (acpi_facp->p_lvl2_lat if (acpi_facp->p_lvl2_lat
&& acpi_facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) { && acpi_facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) {
acpi_p_lvl2_lat = acpi_facp->p_lvl2_lat; acpi_p_lvl2_lat = acpi_facp->p_lvl2_lat;
acpi_enter_lvl2_lat = ACPI_TMR_HZ / 1000;
} }
if (acpi_facp->p_lvl3_lat if (acpi_facp->p_lvl3_lat
&& acpi_facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) { && acpi_facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) {
acpi_p_lvl3_lat = acpi_facp->p_lvl3_lat; acpi_p_lvl3_lat = acpi_facp->p_lvl3_lat;
acpi_enter_lvl3_lat = acpi_facp->p_lvl3_lat * 5;
} }
if (acpi_facp->sci_int if (acpi_facp->sci_int
......
...@@ -772,6 +772,41 @@ unsigned long probe_irq_on(void) ...@@ -772,6 +772,41 @@ unsigned long probe_irq_on(void)
return 0x12345678; return 0x12345678;
} }
/*
* Return a mask of triggered interrupts (this
* can handle only legacy ISA interrupts).
*/
unsigned int probe_irq_mask(unsigned long unused)
{
int i;
unsigned int mask;
if (unused != 0x12345678)
printk("Bad IRQ probe from %lx\n", (&unused)[-1]);
mask = 0;
spin_lock_irq(&irq_controller_lock);
for (i = 0; i < 16; i++) {
unsigned int status = irq_desc[i].status;
if (!(status & IRQ_AUTODETECT))
continue;
if (!(status & IRQ_WAITING))
mask |= 1 << i;
irq_desc[i].status = status & ~IRQ_AUTODETECT;
irq_desc[i].handler->shutdown(i);
}
spin_unlock_irq(&irq_controller_lock);
return mask;
}
/*
* Return the one interrupt that triggered (this can
* handle any interrupt source)
*/
int probe_irq_off(unsigned long unused) int probe_irq_off(unsigned long unused)
{ {
int i, irq_found, nr_irqs; int i, irq_found, nr_irqs;
......
...@@ -709,7 +709,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -709,7 +709,7 @@ void __init setup_arch(char **cmdline_p)
#endif #endif
#ifdef CONFIG_BLK_DEV_INITRD #ifdef CONFIG_BLK_DEV_INITRD
if (LOADER_TYPE) { if (LOADER_TYPE && INITRD_START) {
if (INITRD_START + INITRD_SIZE < (max_low_pfn << PAGE_SHIFT)) { if (INITRD_START + INITRD_SIZE < (max_low_pfn << PAGE_SHIFT)) {
reserve_bootmem(INITRD_START, INITRD_SIZE); reserve_bootmem(INITRD_START, INITRD_SIZE);
initrd_start = initrd_start =
......
...@@ -185,6 +185,8 @@ static void rd_request(request_queue_t * q) ...@@ -185,6 +185,8 @@ static void rd_request(request_queue_t * q)
{ {
unsigned int minor; unsigned int minor;
unsigned long offset, len; unsigned long offset, len;
struct buffer_head *rbh;
struct buffer_head *sbh;
repeat: repeat:
INIT_REQUEST; INIT_REQUEST;
...@@ -211,16 +213,66 @@ static void rd_request(request_queue_t * q) ...@@ -211,16 +213,66 @@ static void rd_request(request_queue_t * q)
} }
/* /*
* If we're reading, fill the buffer with 0's. This is okay since * This has become somewhat more complicated with the addition of
* we're using protected buffers which should never get freed... * the page cache. The problem is that in some cases the furnished
* buffer is "real", i.e., part of the existing ramdisk, while in
* others it is "unreal", e.g., part of a page. In the first case
* not much needs to be done, while in the second, some kind of
* transfer is needed.
* *
* If we're writing, we protect the buffer. * The two cases are distinguished here by checking whether the
* real buffer is already in the buffer cache, and whether it is
* the same as the one supplied.
*
* There are three cases with read/write to consider:
*
* 1. Supplied buffer matched one in the buffer cache:
* Read - Clear the buffer, as it wasn't already valid.
* Write - Mark the buffer as "Protected".
*
* 2. Supplied buffer mismatched one in the buffer cache:
* Read - Copy the data from the buffer cache entry.
* Write - Copy the data to the buffer cache entry.
*
* 3 No buffer cache entry existed:
* Read - Clear the supplied buffer, but do not create a real
* one.
* Write - Create a real buffer, copy the data to it, and mark
* it as "Protected".
*
* NOTE: There seems to be some schizophrenia here - the logic
* using "len" seems to assume arbitrary request lengths, while
* the "protect" logic assumes a single buffer cache entry.
* This seems to be left over from the ancient contiguous ramdisk
* logic.
*/ */
sbh = CURRENT->bh;
rbh = get_hash_table(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
if (sbh == rbh) {
if (CURRENT->cmd == READ)
memset(CURRENT->buffer, 1, len);
} else if (rbh) {
if (CURRENT->cmd == READ) if (CURRENT->cmd == READ)
memset(CURRENT->buffer, 0, len); memcpy(CURRENT->buffer, rbh->b_data, rbh->b_size);
else else
set_bit(BH_Protected, &CURRENT->bh->b_state); memcpy(rbh->b_data, CURRENT->buffer, rbh->b_size);
} else { /* !rbh */
if (CURRENT->cmd == READ)
memset(sbh->b_data, 2, len);
else {
rbh = getblk(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
if (rbh)
memcpy(rbh->b_data, CURRENT->buffer,
rbh->b_size);
else
BUG(); /* No buffer, what to do here? */
}
}
if (rbh) {
set_bit(BH_Protected, &rbh->b_state);
brelse(rbh);
}
end_request(1); end_request(1);
goto repeat; goto repeat;
......
...@@ -4,6 +4,4 @@ ...@@ -4,6 +4,4 @@
mainmenu_option next_comment mainmenu_option next_comment
comment 'Misc devices' comment 'Misc devices'
bool 'ACPI support' CONFIG_ACPI
endmenu endmenu
...@@ -18,10 +18,6 @@ M_OBJS := ...@@ -18,10 +18,6 @@ M_OBJS :=
O_OBJS := O_OBJS :=
OX_OBJS := OX_OBJS :=
ifeq ($(CONFIG_ACPI),y)
OX_OBJS += acpi.o
endif
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
fastdep: fastdep:
/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux. /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
Silicon Integrated System Corporation Copyright 1999 Silicon Integrated System Corporation
Revision: 1.05 Aug 7 1999 Revision: 1.06.03 Dec 23 1999
Modified from the driver which is originally written by Donald Becker. Modified from the driver which is originally written by Donald Becker.
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
preliminary Rev. 1.0 Jan. 18, 1998 preliminary Rev. 1.0 Jan. 18, 1998
http://www.sis.com.tw/support/databook.htm http://www.sis.com.tw/support/databook.htm
Rev 1.06.03 Dec. 23 1999 Ollie Lho Third release
Rev 1.06.02 Nov. 23 1999 Ollie Lho bug in mac probing fixed
Rev 1.06.01 Nov. 16 1999 Ollie Lho CRC calculation provide by Joseph Zbiciak (im14u2c@primenet.com)
Rev 1.06 Nov. 4 1999 Ollie Lho (ollie@sis.com.tw) Second release Rev 1.06 Nov. 4 1999 Ollie Lho (ollie@sis.com.tw) Second release
Rev 1.05.05 Oct. 29 1999 Ollie Lho (ollie@sis.com.tw) Single buffer Tx/Rx Rev 1.05.05 Oct. 29 1999 Ollie Lho (ollie@sis.com.tw) Single buffer Tx/Rx
Chin-Shan Li (lcs@sis.com.tw) Added AMD Am79c901 HomePNA PHY support Chin-Shan Li (lcs@sis.com.tw) Added AMD Am79c901 HomePNA PHY support
...@@ -47,7 +50,7 @@ ...@@ -47,7 +50,7 @@
#include "sis900.h" #include "sis900.h"
static const char *version = static const char *version =
"sis900.c: v1.06 11/04/99\n"; "sis900.c: v1.06.03 12/23/99\n";
static int max_interrupt_work = 20; static int max_interrupt_work = 20;
#define sis900_debug debug #define sis900_debug debug
...@@ -221,6 +224,8 @@ static struct net_device * sis900_mac_probe (struct mac_chip_info * mac, struct ...@@ -221,6 +224,8 @@ static struct net_device * sis900_mac_probe (struct mac_chip_info * mac, struct
if (did_version++ == 0) if (did_version++ == 0)
printk(KERN_INFO "%s", version); printk(KERN_INFO "%s", version);
if ((net_dev = init_etherdev(net_dev, 0)) == NULL)
return NULL;
/* check to see if we have sane EEPROM */ /* check to see if we have sane EEPROM */
signature = (u16) read_eeprom(ioaddr, EEPROMSignature); signature = (u16) read_eeprom(ioaddr, EEPROMSignature);
if (signature == 0xffff || signature == 0x0000) { if (signature == 0xffff || signature == 0x0000) {
...@@ -229,9 +234,6 @@ static struct net_device * sis900_mac_probe (struct mac_chip_info * mac, struct ...@@ -229,9 +234,6 @@ static struct net_device * sis900_mac_probe (struct mac_chip_info * mac, struct
return NULL; return NULL;
} }
if ((net_dev = init_etherdev(net_dev, 0)) == NULL)
return NULL;
printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, mac->name, printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, mac->name,
ioaddr, irq); ioaddr, irq);
...@@ -509,7 +511,7 @@ sis900_open(struct net_device *net_dev) ...@@ -509,7 +511,7 @@ sis900_open(struct net_device *net_dev)
net_dev->start = 1; net_dev->start = 1;
/* Enable all known interrupts by setting the interrupt mask. */ /* Enable all known interrupts by setting the interrupt mask. */
outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr); outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
outl(RxENA, ioaddr + cr); outl(RxENA, ioaddr + cr);
outl(IE, ioaddr + ier); outl(IE, ioaddr + ier);
...@@ -787,6 +789,7 @@ static void sis900_tx_timeout(struct net_device *net_dev) ...@@ -787,6 +789,7 @@ static void sis900_tx_timeout(struct net_device *net_dev)
{ {
struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
long ioaddr = net_dev->base_addr; long ioaddr = net_dev->base_addr;
int i;
printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n", printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n",
net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr)); net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr));
...@@ -794,14 +797,26 @@ static void sis900_tx_timeout(struct net_device *net_dev) ...@@ -794,14 +797,26 @@ static void sis900_tx_timeout(struct net_device *net_dev)
/* Disable interrupts by clearing the interrupt mask. */ /* Disable interrupts by clearing the interrupt mask. */
outl(0x0000, ioaddr + imr); outl(0x0000, ioaddr + imr);
sis_priv->cur_rx = 0; /* discard unsent packets, should this code section be protected by
cli(), sti() ?? */
sis_priv->dirty_tx = sis_priv->cur_tx = 0;
for (i = 0; i < NUM_TX_DESC; i++) {
if (sis_priv->tx_skbuff[i] != NULL) {
dev_kfree_skb(sis_priv->tx_skbuff[i]);
sis_priv->tx_skbuff[i] = 0;
sis_priv->tx_ring[i].cmdsts = 0;
sis_priv->tx_ring[i].bufptr = 0;
sis_priv->stats.tx_dropped++;
}
}
net_dev->trans_start = jiffies; net_dev->trans_start = jiffies;
sis_priv->stats.tx_errors++; net_dev->tbusy = sis_priv->tx_full = 0;
/* FIXME: Should we restart the transmission thread here ?? */ /* FIXME: Should we restart the transmission thread here ?? */
/* Enable all known interrupts by setting the interrupt mask. */ /* Enable all known interrupts by setting the interrupt mask. */
outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr); outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
return; return;
} }
...@@ -876,13 +891,7 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs) ...@@ -876,13 +891,7 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
do { do {
status = inl(ioaddr + isr); status = inl(ioaddr + isr);
if (sis900_debug > 3) if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0)
printk(KERN_INFO "%s: entering interrupt, "
"original status = %#8.8x, "
"new status = %#8.8x.\n",
net_dev->name, status, inl(ioaddr + isr));
if ((status & (HIBERR|TxURN|TxERR|TxOK|RxORN|RxERR|RxOK)) == 0)
/* nothing intresting happened */ /* nothing intresting happened */
break; break;
...@@ -891,7 +900,7 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs) ...@@ -891,7 +900,7 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
/* Rx interrupt */ /* Rx interrupt */
sis900_rx(net_dev); sis900_rx(net_dev);
if (status & (TxURN | TxERR | TxOK)) if (status & (TxURN | TxERR | TxIDLE))
/* Tx interrupt */ /* Tx interrupt */
sis900_finish_xmit(net_dev); sis900_finish_xmit(net_dev);
...@@ -961,6 +970,9 @@ static int sis900_rx(struct net_device *net_dev) ...@@ -961,6 +970,9 @@ static int sis900_rx(struct net_device *net_dev)
} else { } else {
struct sk_buff * skb; struct sk_buff * skb;
/* This situation should never happen, but due to
some unknow bugs, it is possible that
we are working on NULL sk_buff :-( */
if (sis_priv->rx_skbuff[entry] == NULL) { if (sis_priv->rx_skbuff[entry] == NULL) {
printk(KERN_INFO "%s: NULL pointer " printk(KERN_INFO "%s: NULL pointer "
"encountered in Rx ring, skipping\n", "encountered in Rx ring, skipping\n",
...@@ -1033,7 +1045,9 @@ static void sis900_finish_xmit (struct net_device *net_dev) ...@@ -1033,7 +1045,9 @@ static void sis900_finish_xmit (struct net_device *net_dev)
tx_status = sis_priv->tx_ring[entry].cmdsts; tx_status = sis_priv->tx_ring[entry].cmdsts;
if (tx_status & OWN) { if (tx_status & OWN) {
/* The packet is not transmited yet (owned by hardware) ! */ /* The packet is not transmited yet (owned by hardware) !
Note: the interrupt is generated only when Tx Machine
is idle, so this is an almost impossible case */
break; break;
} }
...@@ -1054,8 +1068,6 @@ static void sis900_finish_xmit (struct net_device *net_dev) ...@@ -1054,8 +1068,6 @@ static void sis900_finish_xmit (struct net_device *net_dev)
sis_priv->stats.tx_window_errors++; sis_priv->stats.tx_window_errors++;
} else { } else {
/* packet successfully transmited */ /* packet successfully transmited */
if (sis900_debug > 3)
printk(KERN_INFO "Tx Transmit OK\n");
sis_priv->stats.collisions += (tx_status & COLCNT) >> 16; sis_priv->stats.collisions += (tx_status & COLCNT) >> 16;
sis_priv->stats.tx_bytes += tx_status & DSIZE; sis_priv->stats.tx_bytes += tx_status & DSIZE;
sis_priv->stats.tx_packets++; sis_priv->stats.tx_packets++;
...@@ -1069,8 +1081,8 @@ static void sis900_finish_xmit (struct net_device *net_dev) ...@@ -1069,8 +1081,8 @@ static void sis900_finish_xmit (struct net_device *net_dev)
if (sis_priv->tx_full && net_dev->tbusy && if (sis_priv->tx_full && net_dev->tbusy &&
sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) { sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) {
/* The ring is no longer full, clear tbusy, tx_full and schedule /* The ring is no longer full, clear tbusy, tx_full and
more transmission by marking NET_BH */ schedule more transmission by marking NET_BH */
sis_priv->tx_full = 0; sis_priv->tx_full = 0;
clear_bit(0, (void *)&net_dev->tbusy); clear_bit(0, (void *)&net_dev->tbusy);
mark_bh(NET_BH); mark_bh(NET_BH);
...@@ -1153,11 +1165,13 @@ static u16 sis900_compute_hashtable_index(u8 *addr) ...@@ -1153,11 +1165,13 @@ static u16 sis900_compute_hashtable_index(u8 *addr)
{ {
/* what is the correct value of the POLYNOMIAL ?? /* what is the correct value of the POLYNOMIAL ??
Donald Becker use 0x04C11DB7U */ Donald Becker use 0x04C11DB7U
#define POLYNOMIAL 0x04C11DB6L Joseph Zbiciak im14u2c@primenet.com gives me the
correct answer, thank you Joe !! */
#define POLYNOMIAL 0x04C11DB7L
u32 crc = 0xffffffff, msb; u32 crc = 0xffffffff, msb;
int i, j; int i, j;
u8 byte; u32 byte;
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
byte = *addr++; byte = *addr++;
...@@ -1166,7 +1180,6 @@ static u16 sis900_compute_hashtable_index(u8 *addr) ...@@ -1166,7 +1180,6 @@ static u16 sis900_compute_hashtable_index(u8 *addr)
crc <<= 1; crc <<= 1;
if (msb ^ (byte & 1)) { if (msb ^ (byte & 1)) {
crc ^= POLYNOMIAL; crc ^= POLYNOMIAL;
crc |= 1;
} }
byte >>= 1; byte >>= 1;
} }
...@@ -1208,7 +1221,7 @@ static void set_rx_mode(struct net_device *net_dev) ...@@ -1208,7 +1221,7 @@ static void set_rx_mode(struct net_device *net_dev)
/* update Multicast Hash Table in Receive Filter */ /* update Multicast Hash Table in Receive Filter */
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
/* why plus 0x04 ??, I don't know, UNDOCUMENT FEATURE ?? */ + /* why plus 0x04 ??, That makes the correct value for hash table. */
outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr); outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
outl(mc_filter[i], ioaddr + rfdr); outl(mc_filter[i], ioaddr + rfdr);
} }
......
...@@ -92,8 +92,8 @@ enum sis900_transmit_config_register_bits { ...@@ -92,8 +92,8 @@ enum sis900_transmit_config_register_bits {
/* recevie FIFO thresholds */ /* recevie FIFO thresholds */
#define RxDRNT_shift 1 #define RxDRNT_shift 1
#define RxDRNT_100 24 /* 3/4 FIFO size */ #define RxDRNT_100 16 /* 1/2 FIFO size */
#define RxDRNT_10 16 /* 1/2 FIFO size */ #define RxDRNT_10 24 /* 3/4 FIFO size */
enum sis900_reveive_config_register_bits { enum sis900_reveive_config_register_bits {
RxAEP = 0x80000000, RxARP = 0x40000000, RxATX = 0x10000000, RxAEP = 0x80000000, RxARP = 0x40000000, RxATX = 0x10000000,
......
...@@ -413,44 +413,186 @@ void __init pci_read_bridge_bases(struct pci_bus *child) ...@@ -413,44 +413,186 @@ void __init pci_read_bridge_bases(struct pci_bus *child)
} }
} }
static unsigned int __init pci_do_scan_bus(struct pci_bus *bus) static __init struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
{ {
unsigned int devfn, l, max, class;
unsigned char irq, hdr_type, is_multi = 0;
struct pci_dev *dev, **bus_last;
struct pci_bus *child; struct pci_bus *child;
struct pci_dev *dev_cache = NULL;
DBG("pci_do_scan_bus for bus %d\n", bus->number); /*
bus_last = &bus->devices; * Allocate a new bus, and inherit stuff from the parent..
max = bus->secondary; */
for (devfn = 0; devfn < 0xff; ++devfn) { child = kmalloc(sizeof(*child), GFP_KERNEL);
if (PCI_FUNC(devfn) && !is_multi) { memset(child, 0, sizeof(*child));
/* not a multi-function device */
continue; child->next = parent->children;
parent->children = child;
child->self = dev;
dev->subordinate = child;
child->parent = parent;
child->ops = parent->ops;
child->sysdata = parent->sysdata;
/*
* Set up the primary, secondary and subordinate
* bus numbers. Read resource ranges behind the bridge.
*/
child->number = child->secondary = busnr;
child->primary = parent->secondary;
child->subordinate = 0xff;
return child;
}
/*
* A CardBus bridge is basically the same as a regular PCI bridge,
* except we don't scan behind it because it will be changing.
*/
static __init int pci_scan_cardbus(struct pci_bus *bus, struct pci_dev *dev, int busnr)
{
unsigned short cr;
unsigned int buses;
struct pci_bus *child;
/*
* Insert it into the tree of buses.
*/
child = pci_add_new_bus(bus, dev, ++busnr);
child->subordinate = busnr;
sprintf(child->name, "PCI CardBus #%02x", child->number);
/*
* Clear all status bits and turn off memory,
* I/O and master enables.
*/
pci_read_config_word(dev, PCI_COMMAND, &cr);
pci_write_config_word(dev, PCI_COMMAND, 0x0000);
pci_write_config_word(dev, PCI_STATUS, 0xffff);
/*
* Read the existing primary/secondary/subordinate bus
* number configuration to determine if the bridge
* has already been configured by the system. If so,
* do not modify the configuration, merely note it.
*/
pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
if ((buses & 0xFFFFFF) != 0 && ! pcibios_assign_all_busses()) {
child->primary = buses & 0xFF;
child->secondary = (buses >> 8) & 0xFF;
child->subordinate = (buses >> 16) & 0xFF;
child->number = child->secondary;
if (child->subordinate > busnr)
busnr = child->subordinate;
} else {
/*
* Configure the bus numbers for this bridge:
*/
buses &= 0xff000000;
buses |=
(((unsigned int)(child->primary) << 0) |
((unsigned int)(child->secondary) << 8) |
((unsigned int)(child->subordinate) << 16));
pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
} }
if (!dev_cache) { pci_write_config_word(dev, PCI_COMMAND, cr);
dev_cache = kmalloc(sizeof(*dev), GFP_KERNEL); return busnr;
if (!dev_cache) }
continue;
static unsigned int __init pci_do_scan_bus(struct pci_bus *bus);
/*
* If it's a bridge, scan the bus behind it.
*/
static __init int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max)
{
unsigned int buses;
unsigned short cr;
struct pci_bus *child;
/*
* Insert it into the tree of buses.
*/
child = pci_add_new_bus(bus, dev, ++max);
sprintf(child->name, "PCI Bus #%02x", child->number);
/*
* Clear all status bits and turn off memory,
* I/O and master enables.
*/
pci_read_config_word(dev, PCI_COMMAND, &cr);
pci_write_config_word(dev, PCI_COMMAND, 0x0000);
pci_write_config_word(dev, PCI_STATUS, 0xffff);
/*
* Read the existing primary/secondary/subordinate bus
* number configuration to determine if the PCI bridge
* has already been configured by the system. If so,
* do not modify the configuration, merely note it.
*/
pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
if ((buses & 0xFFFFFF) != 0 && ! pcibios_assign_all_busses()) {
unsigned int cmax;
child->primary = buses & 0xFF;
child->secondary = (buses >> 8) & 0xFF;
child->subordinate = (buses >> 16) & 0xFF;
child->number = child->secondary;
cmax = pci_do_scan_bus(child);
if (cmax > max) max = cmax;
} else {
/*
* Configure the bus numbers for this bridge:
*/
buses &= 0xff000000;
buses |=
(((unsigned int)(child->primary) << 0) |
((unsigned int)(child->secondary) << 8) |
((unsigned int)(child->subordinate) << 16));
pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
/*
* Now we can scan all subordinate buses:
*/
max = pci_do_scan_bus(child);
/*
* Set the subordinate bus number to its real
* value:
*/
child->subordinate = max;
buses = (buses & 0xff00ffff)
| ((unsigned int)(child->subordinate) << 16);
pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
} }
dev = dev_cache; pci_write_config_word(dev, PCI_COMMAND, cr);
memset(dev, 0, sizeof(*dev)); return max;
dev->bus = bus; }
dev->sysdata = bus->sysdata;
dev->devfn = devfn;
if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type)) /*
continue; * Read interrupt line and base address registers.
if (!PCI_FUNC(devfn)) * The architecture-dependent code can tweak these, of course.
is_multi = hdr_type & 0x80; */
static __init void pci_read_irq(struct pci_dev *dev)
{
unsigned char irq;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
if (irq)
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
dev->irq = irq;
}
/*
* Read the config data for a PCI device
* and sanity-check it and fill in the dev
* structure...
*/
static __init int pci_scan_device(struct pci_bus *bus, struct pci_dev *dev, unsigned int devfn)
{
unsigned int l, class;
if (pci_read_config_dword(dev, PCI_VENDOR_ID, &l))
return -1;
if (pci_read_config_dword(dev, PCI_VENDOR_ID, &l) ||
/* some broken boards return 0 if a slot is empty: */ /* some broken boards return 0 if a slot is empty: */
l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
continue; return -1;
dev_cache = NULL;
dev->vendor = l & 0xffff; dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff; dev->device = (l >> 16) & 0xffff;
sprintf(dev->slot_name, "%02x:%02x.%d", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); sprintf(dev->slot_name, "%02x:%02x.%d", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
...@@ -460,46 +602,86 @@ static unsigned int __init pci_do_scan_bus(struct pci_bus *bus) ...@@ -460,46 +602,86 @@ static unsigned int __init pci_do_scan_bus(struct pci_bus *bus)
class >>= 8; /* upper 3 bytes */ class >>= 8; /* upper 3 bytes */
dev->class = class; dev->class = class;
class >>= 8; class >>= 8;
dev->hdr_type = hdr_type & 0x7f;
switch (dev->hdr_type) { /* header type */ switch (dev->hdr_type) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */ case PCI_HEADER_TYPE_NORMAL: /* standard header */
if (class == PCI_CLASS_BRIDGE_PCI) if (class == PCI_CLASS_BRIDGE_PCI)
goto bad; goto bad;
/* pci_read_irq(dev);
* Read interrupt line and base address registers.
* The architecture-dependent code can tweak these, of course.
*/
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
if (irq)
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
dev->irq = irq;
pci_read_bases(dev, 6, PCI_ROM_ADDRESS); pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor); pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device); pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
break; break;
case PCI_HEADER_TYPE_BRIDGE: /* bridge header */ case PCI_HEADER_TYPE_BRIDGE: /* bridge header */
if (class != PCI_CLASS_BRIDGE_PCI) if (class != PCI_CLASS_BRIDGE_PCI)
goto bad; goto bad;
pci_read_bases(dev, 2, PCI_ROM_ADDRESS1); pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
break; break;
case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */ case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */
if (class != PCI_CLASS_BRIDGE_CARDBUS) if (class != PCI_CLASS_BRIDGE_CARDBUS)
goto bad; goto bad;
pci_read_irq(dev);
pci_read_bases(dev, 1, 0); pci_read_bases(dev, 1, 0);
pci_read_config_word(dev, PCI_CB_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor); pci_read_config_word(dev, PCI_CB_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
pci_read_config_word(dev, PCI_CB_SUBSYSTEM_ID, &dev->subsystem_device); pci_read_config_word(dev, PCI_CB_SUBSYSTEM_ID, &dev->subsystem_device);
break; break;
default: /* unknown header */ default: /* unknown header */
printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n", printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n",
dev->slot_name, hdr_type); dev->slot_name, dev->hdr_type);
continue; return -1;
bad: bad:
printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring class.\n", printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring class.\n",
dev->slot_name, class, hdr_type); dev->slot_name, class, dev->hdr_type);
dev->class = PCI_CLASS_NOT_DEFINED; dev->class = PCI_CLASS_NOT_DEFINED;
} }
/* We found a fine healthy device, go go go... */
return 0;
}
static unsigned int __init pci_do_scan_bus(struct pci_bus *bus)
{
unsigned int devfn, max;
struct pci_dev *dev, **bus_last;
int is_multi = 0;
DBG("pci_do_scan_bus for bus %d\n", bus->number);
bus_last = &bus->devices;
max = bus->secondary;
/* Allocate the device ahead of time.. */
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return max;
/* Go find them, Rover! */
for (devfn = 0; devfn < 0xff; ++devfn) {
unsigned char hdr_type;
/* not a multi-function device */
if (PCI_FUNC(devfn) && !is_multi)
continue;
memset(dev, 0, sizeof(*dev));
dev->bus = bus;
dev->sysdata = bus->sysdata;
dev->devfn = devfn;
if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type))
continue;
if (!PCI_FUNC(devfn))
is_multi = hdr_type & 0x80;
dev->hdr_type = hdr_type & 0x7f;
if (pci_scan_device(bus, dev, devfn))
continue;
DBG("PCI: %02x:%02x [%04x/%04x] %06x %02x\n", bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type); DBG("PCI: %02x:%02x [%04x/%04x] %06x %02x\n", bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type);
/* /*
...@@ -533,94 +715,25 @@ static unsigned int __init pci_do_scan_bus(struct pci_bus *bus) ...@@ -533,94 +715,25 @@ static unsigned int __init pci_do_scan_bus(struct pci_bus *bus)
if (tmp < 32) if (tmp < 32)
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32); pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32);
#endif #endif
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
} }
if (dev_cache) kfree(dev);
kfree(dev_cache);
/* /*
* After performing arch-dependent fixup of the bus, look behind * After performing arch-dependent fixup of the bus, look behind
* all PCI-to-PCI bridges on this bus. * all PCI-to-PCI bridges on this bus.
*/ */
pcibios_fixup_bus(bus); pcibios_fixup_bus(bus);
for(dev=bus->devices; dev; dev=dev->sibling) for (dev = bus->devices; dev; dev = dev->sibling) {
/* switch (dev->class >> 8) {
* If it's a bridge, scan the bus behind it. case PCI_CLASS_BRIDGE_PCI:
*/ max = pci_scan_bridge(bus, dev, max);
if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { break;
unsigned int buses; case PCI_CLASS_BRIDGE_CARDBUS:
unsigned short cr; max = pci_scan_cardbus(bus, dev, max);
break;
/*
* Insert it into the tree of buses.
*/
child = kmalloc(sizeof(*child), GFP_KERNEL);
memset(child, 0, sizeof(*child));
child->next = bus->children;
bus->children = child;
child->self = dev;
child->parent = bus;
child->ops = bus->ops;
child->sysdata = bus->sysdata;
/*
* Set up the primary, secondary and subordinate
* bus numbers. Read resource ranges behind the bridge.
*/
child->number = child->secondary = ++max;
child->primary = bus->secondary;
child->subordinate = 0xff;
sprintf(child->name, "PCI Bus #%02x", child->number);
/*
* Clear all status bits and turn off memory,
* I/O and master enables.
*/
pci_read_config_word(dev, PCI_COMMAND, &cr);
pci_write_config_word(dev, PCI_COMMAND, 0x0000);
pci_write_config_word(dev, PCI_STATUS, 0xffff);
/*
* Read the existing primary/secondary/subordinate bus
* number configuration to determine if the PCI bridge
* has already been configured by the system. If so,
* do not modify the configuration, merely note it.
*/
pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
if ((buses & 0xFFFFFF) != 0
&& ! pcibios_assign_all_busses())
{
unsigned int cmax;
child->primary = buses & 0xFF;
child->secondary = (buses >> 8) & 0xFF;
child->subordinate = (buses >> 16) & 0xFF;
child->number = child->secondary;
cmax = pci_do_scan_bus(child);
if (cmax > max) max = cmax;
}
else
{
/*
* Configure the bus numbers for this bridge:
*/
buses &= 0xff000000;
buses |=
(((unsigned int)(child->primary) << 0) |
((unsigned int)(child->secondary) << 8) |
((unsigned int)(child->subordinate) << 16));
pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
/*
* Now we can scan all subordinate buses:
*/
max = pci_do_scan_bus(child);
/*
* Set the subordinate bus number to its real
* value:
*/
child->subordinate = max;
buses = (buses & 0xff00ffff)
| ((unsigned int)(child->subordinate) << 16);
pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
} }
pci_write_config_word(dev, PCI_COMMAND, cr);
} }
/* /*
......
...@@ -8,11 +8,12 @@ struct pci_socket_ops; ...@@ -8,11 +8,12 @@ struct pci_socket_ops;
typedef struct pci_socket { typedef struct pci_socket {
struct pci_dev *dev; struct pci_dev *dev;
int irq; int cb_irq, io_irq;
void *base; void *base;
void (*handler)(void *, unsigned int); void (*handler)(void *, unsigned int);
void *info; void *info;
struct pci_socket_ops *op; struct pci_socket_ops *op;
socket_cap_t cap;
} pci_socket_t; } pci_socket_t;
struct pci_socket_ops { struct pci_socket_ops {
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h>
#include <pcmcia/ss.h> #include <pcmcia/ss.h>
...@@ -19,19 +20,9 @@ ...@@ -19,19 +20,9 @@
#define to_cycles(ns) ((ns)/120) #define to_cycles(ns) ((ns)/120)
#define to_ns(cycles) ((cycles)*120) #define to_ns(cycles) ((cycles)*120)
/* Fixme! */
static int yenta_inquire(pci_socket_t *socket, socket_cap_t *cap) static int yenta_inquire(pci_socket_t *socket, socket_cap_t *cap)
{ {
cap->features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS; *cap = socket->cap;
cap->irq_mask = 0xdeb8; /* irq 15,14,12,11,10,9,7,5,4,3 */
cap->map_size = 0x1000;
cap->pci_irq = socket->irq;
cap->cardbus = 0;
cap->cb_bus = NULL;
cap->bus = NULL;
printk("yenta_inquire()\n");
return 0; return 0;
} }
...@@ -92,7 +83,7 @@ static int yenta_get_socket(pci_socket_t *socket, socket_state_t *state) ...@@ -92,7 +83,7 @@ static int yenta_get_socket(pci_socket_t *socket, socket_state_t *state)
state->Vcc = yenta_Vcc_power(control); state->Vcc = yenta_Vcc_power(control);
state->Vpp = yenta_Vpp_power(control); state->Vpp = yenta_Vpp_power(control);
state->io_irq = socket->irq; state->io_irq = socket->io_irq;
reg = exca_readb(socket, I365_POWER); reg = exca_readb(socket, I365_POWER);
state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0; state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0;
...@@ -130,13 +121,36 @@ printk("yenta_set_socket(%p, %d, %d, %x)\n", socket, state->Vcc, state->Vpp, sta ...@@ -130,13 +121,36 @@ printk("yenta_set_socket(%p, %d, %d, %x)\n", socket, state->Vcc, state->Vpp, sta
bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0; bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0;
config_writew(socket, CB_BRIDGE_CONTROL, bridge); config_writew(socket, CB_BRIDGE_CONTROL, bridge);
reg = socket->irq; /* Set the IO interrupt and socket state */
reg = state->io_irq;
reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET; reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0; reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
exca_writeb(socket, I365_INTCTL, reg); exca_writeb(socket, I365_INTCTL, reg);
/* Set host interrupt and CSC mask state */
reg = socket->cb_irq << 4;
reg |= (state->csc_mask & SS_DETECT) ? I365_CSC_DETECT : 0;
if (state->flags & SS_IOCARD) {
reg |= (state->csc_mask & SS_STSCHG) ? I365_CSC_STSCHG : 0;
} else {
reg |= (state->csc_mask & SS_BATDEAD) ? I365_CSC_BVD1 : 0;
reg |= (state->csc_mask & SS_BATWARN) ? I365_CSC_BVD2 : 0;
reg |= (state->csc_mask & SS_READY) ? I365_CSC_READY : 0;
}
exca_writeb(socket, I365_CSCINT, reg);
exca_readb(socket, I365_CSC);
/*
* Set power state..
*
* I wonder if we could do the Vcc/Vpp part through the
* CB interface only..
*/
reg = I365_PWR_NORESET; reg = I365_PWR_NORESET;
control = 0; /* CB_STOPCLK ? Better power management */ reg |= (state->flags & SS_PWR_AUTO) ? I365_PWR_AUTO : 0;
reg |= (state->flags & SS_OUTPUT_ENA) ? I365_PWR_OUT : 0;
control = CB_STOPCLK;
switch (state->Vcc) { switch (state->Vcc) {
case 33: case 33:
control |= CB_PWR3V << CB_VCCCTRL; control |= CB_PWR3V << CB_VCCCTRL;
...@@ -161,24 +175,8 @@ printk("yenta_set_socket(%p, %d, %d, %x)\n", socket, state->Vcc, state->Vpp, sta ...@@ -161,24 +175,8 @@ printk("yenta_set_socket(%p, %d, %d, %x)\n", socket, state->Vcc, state->Vpp, sta
reg |= I365_VPP1_12V; reg |= I365_VPP1_12V;
break; break;
} }
cb_writel(socket, CB_SOCKET_CONTROL, control);
reg |= (state->flags & SS_PWR_AUTO) ? I365_PWR_AUTO : 0;
reg |= (state->flags & SS_OUTPUT_ENA) ? I365_PWR_OUT : 0;
if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO;
exca_writeb(socket, I365_POWER, reg); exca_writeb(socket, I365_POWER, reg);
cb_writel(socket, CB_SOCKET_CONTROL, control);
reg = socket->irq;
reg |= (state->csc_mask & SS_DETECT) ? I365_CSC_DETECT : 0;
if (state->flags & SS_IOCARD) {
reg |= (state->csc_mask & SS_STSCHG) ? I365_CSC_STSCHG : 0;
} else {
reg |= (state->csc_mask & SS_BATDEAD) ? I365_CSC_BVD1 : 0;
reg |= (state->csc_mask & SS_BATWARN) ? I365_CSC_BVD2 : 0;
reg |= (state->csc_mask & SS_READY) ? I365_CSC_READY : 0;
}
exca_writeb(socket, I365_CSCINT, reg);
exca_readb(socket, I365_CSC);
return 0; return 0;
} }
...@@ -329,6 +327,8 @@ printk("yenta_set_map(%d, %x, %x, %x)\n", map, start, stop, card_start); ...@@ -329,6 +327,8 @@ printk("yenta_set_map(%d, %x, %x, %x)\n", map, start, stop, card_start);
word |= I365_MEM_REG; word |= I365_MEM_REG;
exca_writew(socket, I365_MEM(map) + I365_W_OFF, word); exca_writew(socket, I365_MEM(map) + I365_W_OFF, word);
exca_writeb(socket, CB_MEM_PAGE(map), start >> 24);
if (mem->flags & MAP_ACTIVE) if (mem->flags & MAP_ACTIVE)
exca_writeb(socket, I365_ADDRWIN, addr | enable); exca_writeb(socket, I365_ADDRWIN, addr | enable);
return 0; return 0;
...@@ -336,14 +336,65 @@ printk("yenta_set_map(%d, %x, %x, %x)\n", map, start, stop, card_start); ...@@ -336,14 +336,65 @@ printk("yenta_set_map(%d, %x, %x, %x)\n", map, start, stop, card_start);
static int yenta_get_bridge(pci_socket_t *socket, struct cb_bridge_map *m) static int yenta_get_bridge(pci_socket_t *socket, struct cb_bridge_map *m)
{ {
printk("yenta_get_bridge() called\n"); unsigned map;
map = m->map;
if (map > 1)
return -EINVAL; return -EINVAL;
m->flags &= MAP_IOSPACE;
map += (m->flags & MAP_IOSPACE) ? 2 : 0;
m->start = config_readl(socket, CB_BRIDGE_BASE(map));
m->stop = config_readl(socket, CB_BRIDGE_LIMIT(map));
if (m->start || m->stop) {
m->flags |= MAP_ACTIVE;
m->stop |= (map > 1) ? 3 : 0x0fff;
}
/* Get prefetch state for memory mappings */
if (map < 2) {
u16 ctrl, prefetch_mask = CB_BRIDGE_PREFETCH0 << map;
ctrl = config_readw(socket, CB_BRIDGE_CONTROL);
m->flags |= (ctrl & prefetch_mask) ? MAP_PREFETCH : 0;
}
return 0;
} }
static int yenta_set_bridge(pci_socket_t *socket, struct cb_bridge_map *m) static int yenta_set_bridge(pci_socket_t *socket, struct cb_bridge_map *m)
{ {
printk("yenta_set_bridge() called\n"); unsigned map;
u32 start, end;
map = m->map;
if (map > 1 || m->stop < m->start)
return -EINVAL;
if (m->flags & MAP_IOSPACE) {
if ((m->stop > 0xffff) || (m->start & 3) ||
((m->stop & 3) != 3))
return -EINVAL;
map += 2;
} else {
u16 ctrl, prefetch_mask = CB_BRIDGE_PREFETCH0 << map;
if ((m->start & 0x0fff) || ((m->stop & 0x0fff) != 0x0fff))
return -EINVAL; return -EINVAL;
ctrl = config_readw(socket, CB_BRIDGE_CONTROL);
ctrl &= ~prefetch_mask;
ctrl |= (m->flags & MAP_PREFETCH) ? prefetch_mask : 0;
config_writew(socket, CB_BRIDGE_CONTROL, ctrl);
}
start = 0;
end = 0;
if (m->flags & MAP_ACTIVE) {
start = m->start;
end = m->stop;
}
config_writel(socket, CB_BRIDGE_BASE(map), start);
config_writel(socket, CB_BRIDGE_LIMIT(map), end);
return 0;
} }
static void yenta_proc_setup(pci_socket_t *socket, struct proc_dir_entry *base) static void yenta_proc_setup(pci_socket_t *socket, struct proc_dir_entry *base)
...@@ -380,6 +431,39 @@ static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -380,6 +431,39 @@ static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
socket->handler(socket->info, events); socket->handler(socket->info, events);
} }
static unsigned int yenta_probe_irq(pci_socket_t *socket)
{
int i;
unsigned long val;
cb_writel(socket, CB_SOCKET_EVENT, -1);
cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK);
val = probe_irq_on();
for (i = 1; i < 16; i++) {
exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG | (i << 4));
cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS);
udelay(100);
cb_writel(socket, CB_SOCKET_EVENT, -1);
}
cb_writel(socket, CB_SOCKET_MASK, 0);
return probe_irq_mask(val);
}
static void yenta_get_socket_capabilities(pci_socket_t *socket)
{
socket->cap.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS;
socket->cap.irq_mask = yenta_probe_irq(socket);
if (socket->cb_irq && socket->cb_irq < 16)
socket->cap.irq_mask |= 1 << socket->cb_irq;
socket->cap.map_size = 0x1000;
socket->cap.pci_irq = socket->cb_irq;
socket->cap.cardbus = config_readb(socket, PCI_CB_CARD_BUS);
socket->cap.cb_bus = socket->dev->subordinate;
socket->cap.bus = NULL;
printk("Yenta IRQ list %04x\n", socket->cap.irq_mask);
}
/* /*
* Initialize a cardbus controller. Make sure we have a usable * Initialize a cardbus controller. Make sure we have a usable
* interrupt, and that we can map the cardbus area. Fill in the * interrupt, and that we can map the cardbus area. Fill in the
...@@ -396,10 +480,6 @@ static int yenta_open(pci_socket_t *socket) ...@@ -396,10 +480,6 @@ static int yenta_open(pci_socket_t *socket)
printk("Unable to enable device\n"); printk("Unable to enable device\n");
return -1; return -1;
} }
if (!dev->irq) {
printk("No cardbus irq!\n");
return -1;
}
if (!dev->resource[0].start) { if (!dev->resource[0].start) {
printk("No cardbus resource!\n"); printk("No cardbus resource!\n");
return -1; return -1;
...@@ -412,9 +492,12 @@ static int yenta_open(pci_socket_t *socket) ...@@ -412,9 +492,12 @@ static int yenta_open(pci_socket_t *socket)
socket->base = ioremap(dev->resource[0].start, 0x1000); socket->base = ioremap(dev->resource[0].start, 0x1000);
if (!socket->base) if (!socket->base)
return -1; return -1;
if (request_irq(dev->irq, yenta_interrupt, SA_SHIRQ, dev->name, socket))
return -1; if (dev->irq && !request_irq(dev->irq, yenta_interrupt, SA_SHIRQ, dev->name, socket))
socket->irq = dev->irq; socket->cb_irq = dev->irq;
/* Figure out what the dang thing can do.. */
yenta_get_socket_capabilities(socket);
/* Enable all events */ /* Enable all events */
writel(0x0f, socket->base + 4); writel(0x0f, socket->base + 4);
...@@ -428,8 +511,8 @@ static int yenta_open(pci_socket_t *socket) ...@@ -428,8 +511,8 @@ static int yenta_open(pci_socket_t *socket)
*/ */
static void yenta_close(pci_socket_t *sock) static void yenta_close(pci_socket_t *sock)
{ {
if (sock->irq) if (sock->cb_irq)
free_irq(sock->irq, sock); free_irq(sock->cb_irq, sock);
if (sock->base) if (sock->base)
iounmap(sock->base); iounmap(sock->base);
} }
......
...@@ -102,6 +102,8 @@ ...@@ -102,6 +102,8 @@
/* /*
* Cardbus configuration space * Cardbus configuration space
*/ */
#define CB_BRIDGE_BASE(m) (0x1c + 8*(m))
#define CB_BRIDGE_LIMIT(m) (0x20 + 8*(m))
#define CB_BRIDGE_CONTROL 0x3e #define CB_BRIDGE_CONTROL 0x3e
#define CB_BRIDGE_CPERREN 0x00000001 #define CB_BRIDGE_CPERREN 0x00000001
#define CB_BRIDGE_CSERREN 0x00000002 #define CB_BRIDGE_CSERREN 0x00000002
......
...@@ -821,12 +821,14 @@ void scsi_request_fn(request_queue_t * q) ...@@ -821,12 +821,14 @@ void scsi_request_fn(request_queue_t * q)
* get those allocated here. * get those allocated here.
*/ */
if (!SDpnt->scsi_init_io_fn(SCpnt)) { if (!SDpnt->scsi_init_io_fn(SCpnt)) {
spin_lock_irq(&io_request_lock);
continue; continue;
} }
/* /*
* Initialize the actual SCSI command for this request. * Initialize the actual SCSI command for this request.
*/ */
if (!STpnt->init_command(SCpnt)) { if (!STpnt->init_command(SCpnt)) {
spin_lock_irq(&io_request_lock);
continue; continue;
} }
} }
......
/* /*
* USB Abstract Control Model based on Brad Keryan's USB busmouse driver * USB Abstract Control Model based on Brad Keryan's USB busmouse driver
* *
* (C) Copyright 1999 Armin Fuerst <armin.please@put.your.email.here.!!!!> * (C) Copyright 1999 Armin Fuerst <fuerst@in.tum.de>
* (C) Copyright 1999 Pavel Machek <pavel@suse.cz> * (C) Copyright 1999 Pavel Machek <pavel@suse.cz>
* (C) Copyright 1999 Johannes Erdfelt <jerdfelt@valinux.com> * (C) Copyright 1999 Johannes Erdfelt <jerdfelt@valinux.com>
* *
* version 0.9: Johanness Erdfelt converted this to urb interface.
*
* version 0.8: Fixed endianity bug, some cleanups. I really hate to have * version 0.8: Fixed endianity bug, some cleanups. I really hate to have
* half of driver in form if (...) { info("x"); return y; } * half of driver in form if (...) { info("x"); return y; }
* Pavel Machek <pavel@suse.cz> * Pavel Machek <pavel@suse.cz>
...@@ -92,13 +94,12 @@ struct acm_state { ...@@ -92,13 +94,12 @@ struct acm_state {
char active; //someone has this acm's device open char active; //someone has this acm's device open
unsigned int ctrlstate; //Status of the serial control lines (handshake,...) unsigned int ctrlstate; //Status of the serial control lines (handshake,...)
unsigned int linecoding; //Status of the line coding (Bits, Stop, Parity) unsigned int linecoding; //Status of the line coding (Bits, Stop, Parity)
int writesize, readsize; //size of the usb buffers int writesize, readsize, ctrlsize; //size of the usb buffers
char *writebuffer, *readbuffer; //the usb buffers char *writebuffer, *readbuffer, *ctrlbuffer; //the usb buffers
void *readtransfer, *writetransfer;
void *ctrltransfer; //ptr to HC internal transfer struct
char writing, reading; //flag if transfer is running char writing, reading; //flag if transfer is running
unsigned int readendp,writeendp,ctrlendp; //endpoints and unsigned int readendp,writeendp,ctrlendp; //endpoints and
unsigned int readpipe,writepipe,ctrlpipe; //pipes (are one of these obsolete?) unsigned int readpipe,writepipe,ctrlpipe; //pipes (are one of these obsolete?)
urb_t *readurb, *writeurb, *ctrlurb;
unsigned ctrlinterval; //interval to poll from device unsigned ctrlinterval; //interval to poll from device
}; };
...@@ -135,26 +136,25 @@ void Set_Line_Coding(unsigned int coding, struct acm_state *acm) ...@@ -135,26 +136,25 @@ void Set_Line_Coding(unsigned int coding, struct acm_state *acm)
} }
//Interrupt handler for various usb events //Interrupt handler for various usb events
static int acm_irq(int state, void *__buffer, int count, void *dev_id) static void acm_irq(urb_t *urb)
{ {
unsigned char *data; struct acm_state *acm = (struct acm_state *)urb->context;
struct acm_state *acm = (struct acm_state *)dev_id; unsigned char *data = urb->transfer_buffer;
devrequest *dr; devrequest *dr;
info("ACM_USB_IRQ\n"); info("ACM_USB_IRQ\n");
if (state) { if (urb->status < 0) {
printk(KERN_DEBUG "acm_irq: strange state received: %x\n", state); printk(KERN_DEBUG "acm_irq: strange status received: %d\n", urb->status);
return 0; return;
} }
if (!acm->present) if (!acm->present)
return 0; return;
if (!acm->active) if (!acm->active)
return 1; return;
dr = __buffer; dr = (devrequest *)data;
data = __buffer;
data += sizeof(dr); data += sizeof(dr);
#if 0 #if 0
...@@ -179,55 +179,56 @@ static int acm_irq(int state, void *__buffer, int count, void *dev_id) ...@@ -179,55 +179,56 @@ static int acm_irq(int state, void *__buffer, int count, void *dev_id)
case 0x20: /* Set serial line state */ case 0x20: /* Set serial line state */
printk(KERN_DEBUG "acm.c: Set serial control line state\n"); printk(KERN_DEBUG "acm.c: Set serial control line state\n");
if ((dr->index==1) && (dr->length==2)) { if ((dr->index==1) && (dr->length==2)) {
acm->ctrlstate= data[0] || (data[1] << 16); acm->ctrlstate = data[0] || (data[1] << 16);
printk(KERN_DEBUG "Serstate: %02X\n",acm->ctrlstate); printk(KERN_DEBUG "Serstate: %02X\n", acm->ctrlstate);
} }
break; break;
} }
return 1; /* Continue transfer */ return;
} }
static int acm_read_irq(int state, void *__buffer, int count, void *dev_id) static void acm_read_irq(urb_t *urb)
{ {
struct acm_state *acm = (struct acm_state *) dev_id; struct acm_state *acm = (struct acm_state *)urb->context;
struct tty_struct *tty = acm->tty; struct tty_struct *tty = acm->tty;
unsigned char* data=__buffer; unsigned char *data = acm->readbuffer;
int i; int i;
info("ACM_READ_IRQ: state %d, %d bytes\n", state, count); info("ACM_READ_IRQ: state %d, %d bytes\n", urb->status, urb->actual_length);
if (state) { if (urb->status) {
printk( "acm_read_irq: strange state received: %x\n", state ); printk("acm_read_irq: strange state received: %d\n", urb->status);
return 1; return;
} }
if (!ACM_READY) if (!ACM_READY)
return 0; /* stop transfer */ return;
for (i=0;i<count;i++) for (i=0;i<urb->actual_length;i++)
tty_insert_flip_char(tty,data[i],0); tty_insert_flip_char(tty,data[i],0);
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
return 1; usb_submit_urb(urb);
return;
} }
static int acm_write_irq(int state, void *__buffer, int count, void *dev_id) static void acm_write_irq(urb_t *urb)
{ {
struct acm_state *acm = (struct acm_state *) dev_id; struct acm_state *acm = (struct acm_state *)urb->context;
struct tty_struct *tty = acm->tty; struct tty_struct *tty = acm->tty;
info("ACM_WRITE_IRQ\n"); info("ACM_WRITE_IRQ\n");
if (!ACM_READY) if (!ACM_READY)
return 0; /* stop transfer */ return;
usb_terminate_bulk(acm->dev, acm->writetransfer);
acm->writing = 0; acm->writing = 0;
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty); (tty->ldisc.write_wakeup)(tty);
wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->write_wait);
return 0; /* stop tranfer */ return;
} }
/*TTY STUFF*/ /*TTY STUFF*/
...@@ -251,13 +252,21 @@ static int rs_open(struct tty_struct *tty, struct file *filp) ...@@ -251,13 +252,21 @@ static int rs_open(struct tty_struct *tty, struct file *filp)
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
/* Start reading from the device */ /* Start reading from the device */
ret = usb_request_irq(acm->dev, acm->ctrlpipe, acm_irq, FILL_INT_URB(acm->ctrlurb, acm->dev, acm->ctrlpipe,
acm->ctrlinterval, acm, &acm->ctrltransfer); acm->ctrlbuffer, acm->ctrlsize,
acm_irq, acm, acm->ctrlinterval);
ret = usb_submit_urb(acm->ctrlurb);
if (ret)
printk(KERN_ERR "acm: usb_submit_urb(INT) failed (%d)\n", ret);
acm->reading = 1;
FILL_BULK_URB(acm->readurb, acm->dev, acm->readpipe, acm->readbuffer,
acm->readsize, acm_read_irq, acm);
ret = usb_submit_urb(acm->readurb);
if (ret) if (ret)
printk(KERN_ERR "usb-acm: usb_request_irq failed (0x%x)\n", ret); printk(KERN_ERR "acm: usb_submit_urb(READ) failed (%d)\n", ret);
acm->reading = 1; acm->reading = 1;
acm->readtransfer = usb_request_bulk(acm->dev, acm->readpipe,
acm_read_irq, acm->readbuffer, acm->readsize, acm);
Set_Control_Line_Status(CTRL_STAT_DTR | CTRL_STAT_RTS, acm); Set_Control_Line_Status(CTRL_STAT_DTR | CTRL_STAT_RTS, acm);
...@@ -266,7 +275,7 @@ static int rs_open(struct tty_struct *tty, struct file *filp) ...@@ -266,7 +275,7 @@ static int rs_open(struct tty_struct *tty, struct file *filp)
static void rs_close(struct tty_struct *tty, struct file *filp) static void rs_close(struct tty_struct *tty, struct file *filp)
{ {
struct acm_state *acm = (struct acm_state *) tty->driver_data; struct acm_state *acm = (struct acm_state *)tty->driver_data;
info("rs_close\n"); info("rs_close\n");
...@@ -274,20 +283,22 @@ static void rs_close(struct tty_struct *tty, struct file *filp) ...@@ -274,20 +283,22 @@ static void rs_close(struct tty_struct *tty, struct file *filp)
return; return;
if (--acm->active) if (--acm->active)
return; goto early;
Set_Control_Line_Status(0, acm); Set_Control_Line_Status(0, acm);
if (acm->writing) { if (acm->writing) {
usb_terminate_bulk(acm->dev, acm->writetransfer); if (acm->writeurb)
usb_unlink_urb(acm->writeurb);
acm->writing = 0; acm->writing = 0;
} }
if (acm->reading) { if (acm->reading) {
usb_terminate_bulk(acm->dev, acm->readtransfer); if (acm->readurb)
usb_unlink_urb(acm->readurb);
acm->reading = 0; acm->reading = 0;
} }
// usb_release_irq(acm->dev, acm->ctrltransfer, acm->ctrlpipe);
early:
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
} }
...@@ -295,7 +306,7 @@ static int rs_write(struct tty_struct *tty, int from_user, ...@@ -295,7 +306,7 @@ static int rs_write(struct tty_struct *tty, int from_user,
const unsigned char *buf, int count) const unsigned char *buf, int count)
{ {
struct acm_state *acm = (struct acm_state *)tty->driver_data; struct acm_state *acm = (struct acm_state *)tty->driver_data;
int written; int written, ret;
info("rs_write\n"); info("rs_write\n");
...@@ -316,8 +327,12 @@ static int rs_write(struct tty_struct *tty, int from_user, ...@@ -316,8 +327,12 @@ static int rs_write(struct tty_struct *tty, int from_user,
//start the transfer //start the transfer
acm->writing = 1; acm->writing = 1;
acm->writetransfer = usb_request_bulk(acm->dev, acm->writepipe,
acm_write_irq, acm->writebuffer, written, acm); FILL_BULK_URB(acm->writeurb, acm->dev, acm->writepipe, acm->writebuffer,
written, acm_write_irq, acm);
ret = usb_submit_urb(acm->writeurb);
if (ret)
printk("acm: usb_submit_urb(WRITE) failed: %d\n", ret);
return written; return written;
} }
...@@ -330,7 +345,7 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch) ...@@ -330,7 +345,7 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch)
static int rs_write_room(struct tty_struct *tty) static int rs_write_room(struct tty_struct *tty)
{ {
struct acm_state *acm = (struct acm_state *) tty->driver_data; struct acm_state *acm = (struct acm_state *)tty->driver_data;
info("rs_write_room\n"); info("rs_write_room\n");
...@@ -342,7 +357,7 @@ static int rs_write_room(struct tty_struct *tty) ...@@ -342,7 +357,7 @@ static int rs_write_room(struct tty_struct *tty)
static int rs_chars_in_buffer(struct tty_struct *tty) static int rs_chars_in_buffer(struct tty_struct *tty)
{ {
struct acm_state *acm = (struct acm_state *) tty->driver_data; struct acm_state *acm = (struct acm_state *)tty->driver_data;
// info("rs_chars_in_buffer\n"); // info("rs_chars_in_buffer\n");
...@@ -354,7 +369,7 @@ static int rs_chars_in_buffer(struct tty_struct *tty) ...@@ -354,7 +369,7 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
static void rs_throttle(struct tty_struct *tty) static void rs_throttle(struct tty_struct *tty)
{ {
struct acm_state *acm = (struct acm_state *) tty->driver_data; struct acm_state *acm = (struct acm_state *)tty->driver_data;
info("rs_throttle\n"); info("rs_throttle\n");
...@@ -423,6 +438,8 @@ static void * acm_probe(struct usb_device *dev, unsigned int ifnum) ...@@ -423,6 +438,8 @@ static void * acm_probe(struct usb_device *dev, unsigned int ifnum)
* selecting or should the usbcore? [different configurations * selecting or should the usbcore? [different configurations
* can have different bandwidth requirements] -greg */ * can have different bandwidth requirements] -greg */
printk("Acm: found device with right class...\n" );
/* Now scan all configs for a ACM configuration */ /* Now scan all configs for a ACM configuration */
for (cfgnum=0;cfgnum<dev->descriptor.bNumConfigurations;cfgnum++) { for (cfgnum=0;cfgnum<dev->descriptor.bNumConfigurations;cfgnum++) {
/* The first one should be Communications interface? */ /* The first one should be Communications interface? */
...@@ -465,7 +482,7 @@ static void * acm_probe(struct usb_device *dev, unsigned int ifnum) ...@@ -465,7 +482,7 @@ static void * acm_probe(struct usb_device *dev, unsigned int ifnum)
(endpoint->bmAttributes & 3) != 2) (endpoint->bmAttributes & 3) != 2)
continue; continue;
printk("USB ACM %d found\n",acmno); printk("USB ACM %d found on config %d\n", acmno, cfgnum);
usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue); usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue);
acm->dev=dev; acm->dev=dev;
...@@ -478,6 +495,11 @@ static void * acm_probe(struct usb_device *dev, unsigned int ifnum) ...@@ -478,6 +495,11 @@ static void * acm_probe(struct usb_device *dev, unsigned int ifnum)
printk("ACM: Couldn't allocate readbuffer\n"); printk("ACM: Couldn't allocate readbuffer\n");
return NULL; return NULL;
} }
acm->readurb = usb_alloc_urb(0);
if (!acm->readurb) {
printk("acm: couldn't allocate read urb\n");
return NULL;
}
acm->writeendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[1^swapped].bEndpointAddress; acm->writeendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[1^swapped].bEndpointAddress;
acm->writepipe=usb_sndbulkpipe(dev,acm->writeendp); acm->writepipe=usb_sndbulkpipe(dev,acm->writeendp);
...@@ -488,10 +510,25 @@ static void * acm_probe(struct usb_device *dev, unsigned int ifnum) ...@@ -488,10 +510,25 @@ static void * acm_probe(struct usb_device *dev, unsigned int ifnum)
kfree(acm->readbuffer); kfree(acm->readbuffer);
return NULL; return NULL;
} }
acm->writeurb = usb_alloc_urb(0);
if (!acm->writeurb) {
printk("acm: couldn't allocate write urb\n");
return NULL;
}
acm->ctrlbuffer=kmalloc(acm->ctrlsize=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].wMaxPacketSize, GFP_KERNEL);
acm->ctrlendp=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bEndpointAddress; acm->ctrlendp=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bEndpointAddress;
acm->ctrlpipe=usb_rcvctrlpipe(acm->dev,acm->ctrlendp); acm->ctrlpipe=usb_rcvintpipe(acm->dev,acm->ctrlendp);
acm->ctrlinterval=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bInterval; acm->ctrlinterval=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bInterval;
if (!acm->ctrlbuffer) {
printk("acm: couldn't allocate ctrlbuffer\n");
return NULL;
}
acm->ctrlurb = usb_alloc_urb(0);
if (!acm->ctrlurb) {
printk("acm: couldn't allocate write urb\n");
return NULL;
}
acm->cfgnum = cfgnum; acm->cfgnum = cfgnum;
acm->present=1; acm->present=1;
...@@ -517,18 +554,30 @@ static void acm_disconnect(struct usb_device *dev, void *ptr) ...@@ -517,18 +554,30 @@ static void acm_disconnect(struct usb_device *dev, void *ptr)
acm->active=0; acm->active=0;
acm->present=0; acm->present=0;
if (acm->writing){ if (acm->writing)
usb_terminate_bulk(acm->dev, acm->writetransfer);
acm->writing=0; acm->writing=0;
} if (acm->reading)
if (acm->reading){
usb_terminate_bulk(acm->dev, acm->readtransfer);
acm->reading=0; acm->reading=0;
if (acm->ctrlurb) {
usb_unlink_urb(acm->ctrlurb);
usb_free_urb(acm->ctrlurb);
acm->ctrlurb = NULL;
}
if (acm->readurb) {
usb_unlink_urb(acm->readurb);
usb_free_urb(acm->readurb);
acm->readurb = NULL;
}
if (acm->writeurb) {
usb_unlink_urb(acm->writeurb);
usb_free_urb(acm->writeurb);
acm->writeurb = NULL;
} }
usb_release_irq(acm->dev,acm->ctrltransfer, acm->ctrlpipe);
//BUG: What to do if a device is open?? Notify process or not allow cleanup? //BUG: What to do if a device is open?? Notify process or not allow cleanup?
kfree(acm->writebuffer); kfree(acm->writebuffer);
kfree(acm->readbuffer); kfree(acm->readbuffer);
kfree(acm->ctrlbuffer);
/* release the interfaces so that other drivers can have at them */ /* release the interfaces so that other drivers can have at them */
usb_driver_release_interface(&acm_driver, usb_driver_release_interface(&acm_driver,
......
...@@ -513,7 +513,7 @@ static struct pid_entry base_stuff[] = { ...@@ -513,7 +513,7 @@ static struct pid_entry base_stuff[] = {
E(PROC_PID_CMDLINE, "cmdline", S_IFREG|S_IRUGO), E(PROC_PID_CMDLINE, "cmdline", S_IFREG|S_IRUGO),
E(PROC_PID_STAT, "stat", S_IFREG|S_IRUGO), E(PROC_PID_STAT, "stat", S_IFREG|S_IRUGO),
E(PROC_PID_STATM, "statm", S_IFREG|S_IRUGO), E(PROC_PID_STATM, "statm", S_IFREG|S_IRUGO),
#ifdef SMP #ifdef __SMP__
E(PROC_PID_CPU, "cpu", S_IFREG|S_IRUGO), E(PROC_PID_CPU, "cpu", S_IFREG|S_IRUGO),
#endif #endif
#if CONFIG_AP1000 #if CONFIG_AP1000
...@@ -865,7 +865,7 @@ static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry) ...@@ -865,7 +865,7 @@ static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
case PROC_PID_MAPS: case PROC_PID_MAPS:
inode->i_op = &proc_maps_inode_operations; inode->i_op = &proc_maps_inode_operations;
break; break;
#ifdef SMP #ifdef __SMP__
case PROC_PID_CPU: case PROC_PID_CPU:
inode->i_op = &proc_info_inode_operations; inode->i_op = &proc_info_inode_operations;
inode->u.proc_i.op.proc_read = proc_pid_cpu; inode->u.proc_i.op.proc_read = proc_pid_cpu;
......
...@@ -42,6 +42,7 @@ struct i2c_device; ...@@ -42,6 +42,7 @@ struct i2c_device;
#define I2C_BUSID_PARPORT 2 /* Bit banging on a parallel port */ #define I2C_BUSID_PARPORT 2 /* Bit banging on a parallel port */
#define I2C_BUSID_BUZ 3 #define I2C_BUSID_BUZ 3
#define I2C_BUSID_ZORAN 4 #define I2C_BUSID_ZORAN 4
#define I2C_BUSID_CYBER2000 5
/* /*
* struct for a driver for a i2c chip (tuner, soundprocessor, * struct for a driver for a i2c chip (tuner, soundprocessor,
......
...@@ -80,5 +80,6 @@ enum { ...@@ -80,5 +80,6 @@ enum {
*/ */
extern unsigned long probe_irq_on(void); /* returns 0 on failure */ extern unsigned long probe_irq_on(void); /* returns 0 on failure */
extern int probe_irq_off(unsigned long); /* returns 0 or negative on failure */ extern int probe_irq_off(unsigned long); /* returns 0 or negative on failure */
extern unsigned int probe_irq_mask(unsigned long); /* returns mask of ISA interrupts */
#endif #endif
...@@ -299,6 +299,7 @@ struct pci_dev { ...@@ -299,6 +299,7 @@ struct pci_dev {
int ro; /* Read/Only */ int ro; /* Read/Only */
struct pci_bus *bus; /* bus this device is on */ struct pci_bus *bus; /* bus this device is on */
struct pci_bus *subordinate; /* bus this device bridges to */
struct pci_dev *sibling; /* next device on this bus */ struct pci_dev *sibling; /* next device on this bus */
struct pci_dev *next; /* chain of all devices */ struct pci_dev *next; /* chain of all devices */
......
...@@ -484,6 +484,7 @@ asmlinkage void __init start_kernel(void) ...@@ -484,6 +484,7 @@ asmlinkage void __init start_kernel(void)
kmem_cache_init(); kmem_cache_init();
sti(); sti();
calibrate_delay(); calibrate_delay();
#if 0000
#ifdef CONFIG_BLK_DEV_INITRD #ifdef CONFIG_BLK_DEV_INITRD
// FIXME, use the bootmem.h interface. // FIXME, use the bootmem.h interface.
if (initrd_start && !initrd_below_start_ok && initrd_start < memory_start) { if (initrd_start && !initrd_below_start_ok && initrd_start < memory_start) {
...@@ -492,6 +493,7 @@ asmlinkage void __init start_kernel(void) ...@@ -492,6 +493,7 @@ asmlinkage void __init start_kernel(void)
initrd_start = 0; initrd_start = 0;
} }
#endif #endif
#endif /* 0000 */
mem_init(); mem_init();
kmem_cache_sizes_init(); kmem_cache_sizes_init();
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment