backlight at all, or it might print a lot of errors to the console,
especially if you are using gpm.
-Ignore multiple suspend/standby events
-CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
- This option is necessary on the IBM Thinkpad 560, but should work on
- all other laptops. When the APM BIOS returns multiple suspend or
- standby events while one is already being processed they will be
- ignored. Without this the Thinkpad 560 has troubles with the user
- level daemon apmd, and with the PCMCIA package pcmcia-cs.
-
Ignore multiple suspend/resume cycles
CONFIG_APM_IGNORE_SUSPEND_BOUNCE
This option is necessary on the Dell Inspiron 3200 and others, but
VERSION = 2
PATCHLEVEL = 2
SUBLEVEL = 16
-EXTRAVERSION = pre4
+EXTRAVERSION = pre5
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
#
# For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
#
mainmenu_name "Kernel configuration of Linux for Alpha machines"
#
# For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
#
mainmenu_name "Linux Kernel Configuration"
#
# For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
#
mainmenu_name "Linux Kernel Configuration"
bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE
bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK
- bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE
bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT
bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS
* Register the /proc/apm entry even on SMP so that
* scripts that check for it before doing power off
* work (Jim Avera <jima@hal.com>).
+ * 1.13: Fix the Thinkpad (again) :-( (CONFIG_APM_IGNORE_MULTIPLE_SUSPENDS
+ * is now the way life works).
+ * Fix thinko in suspend() (wrong return).
*
* APM 1.1 Reference:
*
#endif
static int suspends_pending = 0;
static int standbys_pending = 0;
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
static int waiting_for_resume = 0;
-#endif
#ifdef CONFIG_APM_RTC_IS_GMT
# define clock_cmos_diff 0
static struct timer_list apm_timer;
-static char driver_version[] = "1.12"; /* no spaces */
+static char driver_version[] = "1.13"; /* no spaces */
static char * apm_event_name[] = {
"system standby",
static int suspend(void)
{
int err;
- int ret;
struct apm_user *as;
get_time_diff();
err = apm_set_power_state(APM_STATE_SUSPEND);
reinit_timer();
set_time();
- ret = (err == APM_SUCCESS) || (err == APM_NO_ERROR);
- if (!ret)
+ if (err == APM_NO_ERROR)
+ err = APM_SUCCESS;
+ if (err != APM_SUCCESS)
apm_error("suspend", err);
for (as = user_list; as != NULL; as = as->next) {
as->suspend_wait = 0;
- as->suspend_result = (ret ? 0 : -EIO);
+ as->suspend_result = ((err == APM_SUCCESS) ? 0 : -EIO);
}
wake_up_interruptible(&apm_suspend_waitqueue);
return err;
switch (event) {
case APM_SYS_STANDBY:
case APM_USER_STANDBY:
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
- if (waiting_for_resume)
- break;
-#endif
if (send_event(event, APM_STANDBY_RESUME, NULL)) {
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
- waiting_for_resume = 1;
-#endif
if (standbys_pending <= 0)
standby();
}
if (ignore_bounce)
break;
#endif
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+ /*
+ * If we are already processing a SUSPEND,
+ * then further SUSPEND events from the BIOS
+ * will be ignored. We also return here to
+ * cope with the fact that the Thinkpads keep
+ * sending a SUSPEND event until something else
+ * happens!
+ */
if (waiting_for_resume)
- break;
-#endif
+ return;
if (send_event(event, APM_NORMAL_RESUME, NULL)) {
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
waiting_for_resume = 1;
-#endif
if (suspends_pending <= 0)
(void) suspend();
}
case APM_NORMAL_RESUME:
case APM_CRITICAL_RESUME:
case APM_STANDBY_RESUME:
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
waiting_for_resume = 0;
-#endif
#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
last_resume = jiffies;
ignore_bounce = 1;
int err;
if ((standbys_pending > 0) || (suspends_pending > 0)) {
- if ((apm_bios_info.version > 0x100) && (pending_count-- < 0)) {
+ if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) {
pending_count = 4;
+ if (debug)
+ printk(KERN_DEBUG "apm: setting state busy\n");
err = apm_set_power_state(APM_STATE_BUSY);
if (err)
apm_error("busy", err);
static int check_apm_user(struct apm_user *as, const char *func)
{
if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
- printk(KERN_ERR "apm: %s passed bad filp", func);
+ printk(KERN_ERR "apm: %s passed bad filp\n", func);
return 1;
}
return 0;
} else if (!send_event(APM_USER_SUSPEND, APM_NORMAL_RESUME, as))
return -EAGAIN;
if (suspends_pending <= 0) {
- if (!suspend())
+ if (suspend() != APM_SUCCESS)
return -EIO;
} else {
as->suspend_wait = 1;
as1 = as1->next)
;
if (as1 == NULL)
- printk(KERN_ERR "apm: filp not in user list");
+ printk(KERN_ERR "apm: filp not in user list\n");
else
as1->next = as->next;
}
as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
if (as == NULL) {
- printk(KERN_ERR "apm: cannot allocate struct of size %d bytes",
+ printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
sizeof(*as));
return -ENOMEM;
}
#
# For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
#
mainmenu_name "Linux/68k Kernel Configuration"
#
# For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
#
mainmenu_name "Linux Kernel Configuration"
# $Id: config.in,v 1.92.2.4 1999/09/10 01:23:40 paulus Exp $
# For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
#
mainmenu_name "Linux/PowerPC Kernel Configuration"
-
+#
# For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
#
mainmenu_name "Linux Kernel Configuration"
define_bool CONFIG_ARCH_S390 y
}
ret = -ESRCH;
// printk("child=%lX child->flags=%lX",child,child->flags);
+ /* I added child!=current line so we can get the */
+ /* ieee_instruction_pointer from the user structure DJB */
+ if(child!=current)
+ {
if (!(child->flags & PF_PTRACED))
goto out;
if (child->state != TASK_STOPPED)
}
if (child->p_pptr != current)
goto out;
-
+ }
switch (request)
{
/* If I and D space are separate, these will need to be fixed. */
else
{
ioinfo[irq]->schib.pmcw.ena = 1;
+
+ if ( irq == cons_dev )
+ {
+ ioinfo[irq]->schib.pmcw.isc = 7;
+ }
+ else
+ {
ioinfo[irq]->schib.pmcw.isc = 3;
+ } /* endif */
+
do
{
ccode = msch( irq, &(ioinfo[irq]->schib) );
ioinfo[irq]->orb.fmt = 1;
ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH);
- ioinfo[irq]->orb.spnd = (flag & DOIO_ALLOW_SUSPEND);
+ ioinfo[irq]->orb.spnd = (flag & DOIO_ALLOW_SUSPEND ? TRUE : FALSE);
ioinfo[irq]->orb.ssic = ( (flag & DOIO_ALLOW_SUSPEND )
&& (flag & DOIO_SUPPRESS_INTER) );
ccode = tsch( irq, &(ioinfo[irq]->devstat.ii.irb) );
//
- // We must only accumulate the status if initiated by do_IO() or halt_IO()
+ // We must only accumulate the status if the device is busy already
//
if ( ioinfo[irq]->ui.flags.busy )
{
* Save residual count and CCW information in case primary and
* secondary status are presented with different interrupts.
*/
- if ( ioinfo[irq]->devstat.ii.irb.scsw.stctl & SCSW_STCTL_PRIM_STATUS )
+ if ( ioinfo[irq]->devstat.ii.irb.scsw.stctl
+ & ( SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_INTER_STATUS ) )
{
ioinfo[irq]->devstat.rescnt = ioinfo[irq]->devstat.ii.irb.scsw.count;
+ ioinfo[irq]->devstat.cpa = ioinfo[irq]->devstat.ii.irb.scsw.cpa;
#ifdef CONFIG_DEBUG_IO
if ( irq != cons_dev )
"residual count from irb after tsch() %d\n",
irq, ioinfo[irq]->devstat.rescnt );
#endif
- } /* endif */
-
- if ( ioinfo[irq]->devstat.ii.irb.scsw.cpa != 0 )
- {
- ioinfo[irq]->devstat.cpa = ioinfo[irq]->devstat.ii.irb.scsw.cpa;
} /* endif */
sizeof( devstat_t) );
s_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
- s_ccw->cda = (char *)virt_to_phys( ioinfo[irq]->devstat.ii.sense.data);
+ s_ccw->cda = (char *)virt_to_phys( ioinfo[irq]->sense_data);
s_ccw->count = SENSE_MAX_COUNT;
s_ccw->flags = CCW_FLAG_SLI;
* we allow for the device action handler if .
* - we received ending status
* - the action handler requested to see all interrupts
- * - we received a PCI
+ * - we received an intermediate status
* - fast notification was requested (primary status)
* - unsollicited interrupts
*
{
allow4handler = ending_status
|| ( ioinfo[irq]->ui.flags.repall )
- || ( ioinfo[irq]->devstat.ii.irb.scsw.cstat & SCHN_STAT_PCI )
+ || ( stctl & SCSW_STCTL_INTER_STATUS )
|| ( (ioinfo[irq]->ui.flags.fast ) && (stctl & SCSW_STCTL_PRIM_STATUS) )
|| ( ioinfo[irq]->ui.flags.oper == 0 );
if ( sense_count >= 0 )
{
memcpy( ((devstat_t *)(action->dev_id))->ii.sense.data,
- &(ioinfo[irq]->devstat.ii.sense.data),
+ &(ioinfo[irq]->sense_data),
sense_count);
}
else
{
ioinfo[irq]->ui.flags.w4final = 1;
+ /*
+ * Eventually reset subchannel PCI status and
+ * set the PCI or SUSPENDED flag in the user
+ * device status block if appropriate.
+ */
+ if ( ioinfo[irq]->devstat.cstat & SCHN_STAT_PCI )
+ {
+ ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_PCI;
+ ioinfo[irq]->devstat.cstat &= ~SCHN_STAT_PCI;
+ }
+ else if ( actl & SCSW_ACTL_SUSPENDED )
+ {
+ ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_SUSPENDED;
+
+ } /* endif */
+
if ( ioinfo[irq]->ui.flags.newreq )
{
action->handler( irq, ioinfo[irq]->u_intparm );
}
else
{
- ((io_handler_func1_t)action->handler)( irq, action->dev_id, ®s );
+ ((io_handler_func1_t)action->handler)( irq,
+ action->dev_id,
+ ®s );
} /* endif */
ioinfo[irq]->schib.pmcw.dev,
irq);
#endif
- io_retry = 0;
+ io_retry = 1;
}
#ifdef CONFIG_DEBUG_IO
else
#endif
}
else if ( ( pdevstat->flag & DEVSTAT_NOT_OPER )
- || ( irq_ret != -ENODEV ) )
+ || ( irq_ret == -ENODEV ) )
{
#ifdef CONFIG_DEBUG_IO
printk( "SenseID : path %02X for "
#endif
memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/
memory_end = MEMORY_SIZE;
+ /*
+ * We need some free virtual space to be able to do vmalloc.
+ * On a machine with 2GB memory we make sure that we have at
+ * least 128 MB free space for vmalloc.
+ */
+ if (memory_end > 1920*1024*1024)
+ memory_end = 1920*1024*1024;
init_task.mm->start_code = PAGE_OFFSET;
init_task.mm->end_code = (unsigned long) &_etext;
init_task.mm->end_data = (unsigned long) &_edata;
int do_sig = 0;
lock_kernel();
- if (regs->psw.mask & 0x00010000L) {
location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+ if(MACHINE_HAS_IEEE)
+ {
+ __asm__ volatile ("stfpc %0\n\t"
+ : "=m" (current->tss.fp_regs.fpc));
+
+ }
+ /* Same code should work when we implement fpu emulation */
+ /* provided we call data exception from the fpu emulator */
+ if(current->tss.fp_regs.fpc&FPC_DXC_MASK)
+ {
+ current->tss.ieee_instruction_pointer=
+ (addr_t)ADDR_BITS_REMOVE((addr_t)location);
+ force_sig(SIGFPE, current);
+ }
+ else if ((regs->psw.mask & 0x00010000L))
+ {
get_user(*((__u16 *) opcode), location);
switch (opcode[0]) {
case 0x28: /* LDR Rx,Ry */
do_sig = 1;
break;
}
- } else
+ }
+ else
do_sig = 1;
if (do_sig) {
if (check_for_fixup(regs) == 0) {
# $Id: config.in,v 1.68.2.1 1999/09/22 11:37:34 jj Exp $
# For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
#
mainmenu_name "Linux/SPARC Kernel Configuration"
# $Id: config.in,v 1.67.2.5 1999/10/19 16:49:37 davem Exp $
# For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
#
mainmenu_name "Linux/UltraSPARC Kernel Configuration"
#include <linux/videodev.h>
#include <linux/netdevice.h>
#include <linux/smb_fs.h>
+#include <linux/blkdev.h>
#include <scsi/scsi.h>
/* Ugly hack. */
} else
hd_status = IDE_ALTSTATUS_REG; /* use non-intrusive polling */
+ /* set features register for atapi identify command */
+ if((cmd == WIN_PIDENTIFY))
+ OUT_BYTE(0,IDE_FEATURE_REG); /* disable dma & overlap mode */
+
#if CONFIG_BLK_DEV_PDC4030
if (IS_PDC4030_DRIVE) {
extern int pdc4030_cmd(ide_drive_t *, byte);
case BLKELVSET:
return blkelvset_ioctl(elevator, __arg);
}
+ return -EINVAL;
}
static inline int seek_to_not_starving_chunk(struct request ** req, int * lat)
nr = space;
if (nr > sizeof(buf))
nr = sizeof(buf);
- nr -= copy_from_user(buf, inbuf, nr);
- if (!nr)
- return 0;
+
+ if (copy_from_user(buf, inbuf, nr))
+ return -EFAULT;
for (i = 0, cp = buf; i < nr; i++, cp++) {
switch (*cp) {
{ { 0, 1 }, } },
{ PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, 1,
{ { 2, -1 }, } },
+ { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_4008A, 1,
+ { { 0, 1 }, } },
{ 0, }
};
}
outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
outw(DownUnstall, ioaddr + EL3_CMD);
- } else
+ } else {
vp->stats.tx_dropped++;
+ clear_bit(0, (void *)&dev->tbusy);
+ }
/* Issue Tx Enable */
outw(TxEnable, ioaddr + EL3_CMD);
This is a compatibility hardware problem.
Versions:
+ 0.12a fixed bug that would make impossible have ee10 boards and
+ other previous supported boards. (aris, 05/19/2000)
0.12 added support to 82595FX etherexpress 10 based cards
(aris <aris@conectiva.com.br>), 04/26/2000)
0.11e some tweaks about multiple cards support (PdP, jul/aug 1999)
*/
static const char *version =
- "eepro.c: v0.12 04/26/2000 aris@conectiva.com.br\n";
+ "eepro.c: v0.12a 04/26/2000 aris@conectiva.com.br\n";
#include <linux/module.h>
#include <linux/skbuff.h>
-/* need to remove these asap */
-/* 2.1.xx compatibility macros... */
-/* */
-
-
#include <linux/version.h>
/* For linux 2.1.xx */
/* First, a few definitions that the brave might change. */
/* A zero-terminated list of I/O addresses to be probed. */
static unsigned int eepro_portlist[] compat_init_data =
-#ifdef PnPWakeup
- { 0x210, 0x300,
-#else
- { 0x300, 0x210,
-#endif
- 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0};
+ { 0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0};
/* note: 0x300 is default, the 595FX supports ALL IO Ports
from 0x000 to 0x3F0, some of which are reserved in PCs */
-/* To try the (not-really PnP Wakeup: */
-/*
-#define PnPWakeup
-*/
-
/* use 0 for production, 1 for verification, >2 for debug */
#ifndef NET_DEBUG
#define NET_DEBUG 0
#define LAN595 0
#define LAN595TX 1
#define LAN595FX 2
-
-/* global to recall the read_eepro */
-static unsigned char etherexpress10 = 0;
+#define LAN595FX_10ISA 3
/* Information that need to be kept for each board. */
struct eepro_local {
int version; /* a flag to indicate if this is a TX or FX
version of the 82595 chip. */
int stepping;
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
spinlock_t lock; /* Serializing lock */
-#endif
};
/* The station (ethernet) address prefix, used for IDing the board. */
static struct enet_statistics *eepro_get_stats(struct device *dev);
static void set_multicast_list(struct device *dev);
-static int read_eeprom(int ioaddr, int location);
+static int read_eeprom(int ioaddr, int location, struct device *dev);
static void hardware_send_packet(struct device *dev, void *buf, short length);
static int eepro_grab_irq(struct device *dev);
#define EEDI 0x04
#define EEDO 0x08
+/* do a full reset */
+#define eepro_reset(ioaddr) outb(RESET_CMD, ioaddr)
+
+/* do a nice reset */
+#define eepro_sel_reset(ioaddr) { \
+ outb(SEL_RESET_CMD, ioaddr); \
+ SLOW_DOWN; \
+ SLOW_DOWN; \
+ }
+
+/* disable all interrupts */
+#define eepro_dis_int(ioaddr) outb(ALL_MASK, ioaddr + INT_MASK_REG)
+
+/* clear all interrupts */
+#define eepro_clear_int(ioaddr) outb(ALL_MASK, ioaddr + STATUS_REG)
+
+/* enable tx/rx */
+#define eepro_en_int(ioaddr) outb(ALL_MASK & ~(RX_MASK | TX_MASK), \
+ ioaddr + INT_MASK_REG)
+
+/* enable exec event interrupt */
+#define eepro_en_intexec(ioaddr) outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG)
+
+/* enable rx */
+#define eepro_en_rx(ioaddr) outb(RCV_ENABLE_CMD, ioaddr)
+
+/* disable rx */
+#define eepro_dis_rx(ioaddr) outb(RCV_DISABLE_CMD, ioaddr)
+
+/* switch bank */
+#define eepro_sw2bank0(ioaddr) outb(BANK0_SELECT, ioaddr)
+#define eepro_sw2bank1(ioaddr) outb(BANK1_SELECT, ioaddr)
+#define eepro_sw2bank2(ioaddr) outb(BANK2_SELECT, ioaddr)
+
+/* enable interrupt line */
+#define eepro_en_intline(ioaddr) outb(inb(ioaddr + REG1) | INT_ENABLE,\
+ ioaddr + REG1)
+
+/* disable interrupt line */
+#define eepro_dis_intline(ioaddr) outb(inb(ioaddr + REG1) & 0x7f, \
+ ioaddr + REG1);
+
+/* set diagnose flag */
+#define eepro_diag(ioaddr) outb(DIAGNOSE_CMD, ioaddr)
+
+/* ack for rx/tx int */
+#define eepro_ack_rxtx(ioaddr) outb (RX_INT | TX_INT, ioaddr + STATUS_REG)
+
+/* ack for rx int */
+#define eepro_ack_rx(ioaddr) outb (RX_INT, ioaddr + STATUS_REG)
+
+/* ack for tx int */
+#define eepro_ack_tx(ioaddr) outb (TX_INT, ioaddr + STATUS_REG)
/* Check for a network adaptor of this type, and return '0' if one exists.
If dev->base_addr == 0, probe all likely locations.
{
int i;
int base_addr = dev ? dev->base_addr : 0;
-
-
-#ifdef PnPWakeup
- /* XXXX for multiple cards should this only be run once? */
-
- /* Wakeup: */
- #define WakeupPort 0x279
- #define WakeupSeq {0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,\
- 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,\
- 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,\
- 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43}
-
- {
- unsigned short int WS[32]=WakeupSeq;
-
- if (check_region(WakeupPort, 2)==0) {
-
- if (net_debug>5)
- printk(KERN_DEBUG "Waking UP\n");
-
- outb_p(0,WakeupPort);
- outb_p(0,WakeupPort);
- for (i=0; i<32; i++) {
- outb_p(WS[i],WakeupPort);
- if (net_debug>5) printk(KERN_DEBUG ": %#x ",WS[i]);
- }
- } else printk(KERN_WARNING "Checkregion Failed!\n");
- }
-#endif
-
-
if (base_addr > 0x1ff) /* Check a single specified location. */
return eepro_probe1(dev, base_addr);
else if (base_addr != 0) /* Don't probe at all. */
return ENXIO;
-
for (i = 0; eepro_portlist[i]; i++) {
int ioaddr = eepro_portlist[i];
if (eepro_probe1(dev, ioaddr) == 0)
return 0;
}
-
+
return ENODEV;
}
#endif
-static void printEEPROMInfo(short ioaddr)
+static void printEEPROMInfo(short ioaddr, struct device *dev)
{
unsigned short Word;
int i,j;
for (i=0, j=ee_Checksum; i<ee_SIZE; i++)
- j+=read_eeprom(ioaddr,i);
+ j+=read_eeprom(ioaddr,i,dev);
printk("Checksum: %#x\n",j&0xffff);
- Word=read_eeprom(ioaddr, 0);
+ Word=read_eeprom(ioaddr, 0, dev);
printk(KERN_DEBUG "Word0:\n");
printk(KERN_DEBUG " Plug 'n Pray: %d\n",GetBit(Word,ee_PnP));
printk(KERN_DEBUG " Buswidth: %d\n",(GetBit(Word,ee_BusWidth)+1)*8 );
printk(KERN_DEBUG " IO Address: %#x\n", (Word>>ee_IO0)<<4);
if (net_debug>4) {
- Word=read_eeprom(ioaddr, 1);
+ Word=read_eeprom(ioaddr, 1, dev);
printk(KERN_DEBUG "Word1:\n");
printk(KERN_DEBUG " INT: %d\n", Word & ee_IntMask);
printk(KERN_DEBUG " LI: %d\n", GetBit(Word,ee_LI));
printk(KERN_DEBUG " Duplex: %d\n", GetBit(Word,ee_Duplex));
}
- Word=read_eeprom(ioaddr, 5);
+ Word=read_eeprom(ioaddr, 5, dev);
printk(KERN_DEBUG "Word5:\n");
printk(KERN_DEBUG " BNC: %d\n",GetBit(Word,ee_BNC_TPE));
printk(KERN_DEBUG " NumConnectors: %d\n",GetBit(Word,ee_NumConn));
if (GetBit(Word,ee_PortAUI)) printk("AUI ");
printk("port(s) \n");
- Word=read_eeprom(ioaddr, 6);
+ Word=read_eeprom(ioaddr, 6, dev);
printk(KERN_DEBUG "Word6:\n");
printk(KERN_DEBUG " Stepping: %d\n",Word & ee_StepMask);
printk(KERN_DEBUG " BoardID: %d\n",Word>>ee_BoardID);
- Word=read_eeprom(ioaddr, 7);
+ Word=read_eeprom(ioaddr, 7, dev);
printk(KERN_DEBUG "Word7:\n");
printk(KERN_DEBUG " INT to IRQ:\n");
{
unsigned short station_addr[6], id, counter;
int i,j, irqMask;
- int eepro;
+ int eepro = 0;
+ struct eepro_local *lp;
const char *ifmap[] = {"AUI", "10Base2", "10BaseT"};
enum iftype { AUI=0, BNC=1, TPE=2 };
/* We seem to have the 82595 signature, let's
play with its counter (last 2 bits of
register 2 of bank 0) to be sure. */
-
counter = (id & R_ROBIN_BITS);
if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS) ==
(counter + 0x40)) {
printk(KERN_DEBUG " id: %#x ",id);
printk(" io: %#x ",ioaddr);
+ /* Initialize the device structure */
+ dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset(dev->priv, 0, sizeof(struct eepro_local));
+
+ lp = (struct eepro_local *)dev->priv;
+
/* Now, get the ethernet hardware address from
the EEPROM */
- station_addr[0] = read_eeprom(ioaddr, 2);
+ station_addr[0] = read_eeprom(ioaddr, 2, dev);
/* FIXME - find another way to know that we've found
* a Etherexpress 10
*/
if (station_addr[0] == 0x0000 ||
station_addr[0] == 0xffff) {
- etherexpress10 = 1;
+ eepro = 3;
+ lp->eepro = LAN595FX_10ISA;
eeprom_reg = EEPROM_REG_10;
rcv_start = RCV_START_10;
xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10;
xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10;
- station_addr[0] = read_eeprom(ioaddr, 2);
+ station_addr[0] = read_eeprom(ioaddr, 2, dev);
}
- station_addr[1] = read_eeprom(ioaddr, 3);
- station_addr[2] = read_eeprom(ioaddr, 4);
+ station_addr[1] = read_eeprom(ioaddr, 3, dev);
+ station_addr[2] = read_eeprom(ioaddr, 4, dev);
- /* Check the station address for the manufacturer's code */
- if (net_debug>3)
- printEEPROMInfo(ioaddr);
- if (etherexpress10) {
- eepro = 2;
+ if (eepro) {
printk("%s: Intel EtherExpress 10 ISA\n at %#x,",
dev->name, ioaddr);
- } else if (read_eeprom(ioaddr,7)== ee_FX_INT2IRQ) {
+ } else if (read_eeprom(ioaddr,7,dev)== ee_FX_INT2IRQ) {
/* int to IRQ Mask */
eepro = 2;
printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,",
dev->name, ioaddr);
- } else
- if (station_addr[2] == 0x00aa) {
+ } else if (station_addr[2] == SA_ADDR1) {
eepro = 1;
printk("%s: Intel EtherExpress Pro/10 ISA at %#x,",
dev->name, ioaddr);
dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
}
-
+
dev->mem_start = (RCV_LOWER_LIMIT << 8);
if ((dev->mem_end & 0x3f) < 3 || /* RX buffer must be more than 3K */
/* ............... */
- if (GetBit( read_eeprom(ioaddr, 5),ee_BNC_TPE))
+ if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE))
dev->if_port = BNC;
else dev->if_port = TPE;
if ((dev->irq < 2) && (eepro!=0)) {
- i = read_eeprom(ioaddr, 1);
- irqMask = read_eeprom(ioaddr, 7);
+ i = read_eeprom(ioaddr, 1, dev);
+ irqMask = read_eeprom(ioaddr, 7, dev);
i &= 0x07; /* Mask off INT number */
for (j=0; ((j<16) && (i>=0)); j++) {
i--; /* count bits set in irqMask */
}
}
- if (dev -> irq<2) {
+ if (dev->irq < 2) {
printk(" Duh! illegal interrupt vector stored in EEPROM.\n");
return ENODEV;
} else
else printk(", %s.\n", ifmap[dev->if_port]);
if (net_debug > 3) {
- i = read_eeprom(ioaddr, 5);
+ i = read_eeprom(ioaddr, 5, dev);
if (i & 0x2000) /* bit 13 of EEPROM word 5 */
printk(KERN_DEBUG "%s: Concurrent Processing is enabled but not used!\n",
dev->name);
/* Grab the region so we can find another board if autoIRQ fails. */
request_region(ioaddr, EEPRO_IO_EXTENT, dev->name);
- /* Initialize the device structure */
- dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL);
- if (dev->priv == NULL)
- return -ENOMEM;
- memset(dev->priv, 0, sizeof(struct eepro_local));
-
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
spin_lock_init(&(((struct eepro_local *)dev->priv)->lock));
-#endif
dev->open = eepro_open;
dev->stop = eepro_close;
dev->hard_start_xmit = eepro_send_packet;
ether_setup(dev);
- outb(RESET_CMD, ioaddr); /* RESET the 82595 */
+ /* Check the station address for the manufacturer's code */
+ if (net_debug>3)
+ printEEPROMInfo(ioaddr, dev);
+
+ /* reset 82595 */
+ eepro_reset(ioaddr);
return 0;
}
int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12 };
int *irqp = irqlist, temp_reg, ioaddr = dev->base_addr;
- outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */
+ eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
/* Enable the interrupt line. */
- temp_reg = inb(ioaddr + REG1);
- outb(temp_reg | INT_ENABLE, ioaddr + REG1);
+ eepro_en_intline(ioaddr);
- outb(BANK0_SELECT, ioaddr); /* be CAREFUL, BANK 0 now */
+ eepro_sw2bank0(ioaddr); /* be CAREFUL, BANK 0 now */
/* clear all interrupts */
- outb(ALL_MASK, ioaddr + STATUS_REG);
+ eepro_clear_int(ioaddr);
/* Let EXEC event to interrupt */
- outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG);
+ eepro_en_intexec(ioaddr);
do {
- outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */
-
+ eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
temp_reg = inb(ioaddr + INT_NO_REG);
outb((temp_reg & 0xf8) | irqrmap[*irqp], ioaddr + INT_NO_REG);
- outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+ eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
if (request_irq (*irqp, NULL, 0, "bogus", dev) != EBUSY) {
/* Twinkle the interrupt, and check if it's seen */
autoirq_setup(0);
- outb(DIAGNOSE_CMD, ioaddr); /* RESET the 82595 */
+ eepro_diag(ioaddr); /* RESET the 82595 */
if (*irqp == autoirq_report(2)) /* It's a good IRQ line */
break;
/* clear all interrupts */
- outb(ALL_MASK, ioaddr + STATUS_REG);
+ eepro_clear_int(ioaddr);
}
} while (*++irqp);
- outb(BANK1_SELECT, ioaddr); /* Switch back to Bank 1 */
+ eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
/* Disable the physical interrupt line. */
- temp_reg = inb(ioaddr + REG1);
- outb(temp_reg & 0x7f, ioaddr + REG1);
+ eepro_dis_intline(ioaddr);
- outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+ eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
/* Mask all the interrupts. */
- outb(ALL_MASK, ioaddr + INT_MASK_REG);
+ eepro_dis_int(ioaddr);
/* clear all interrupts */
- outb(ALL_MASK, ioaddr + STATUS_REG);
+ eepro_clear_int(ioaddr);
return dev->irq;
}
if (net_debug > 3)
printk(KERN_DEBUG "%s: entering eepro_open routine.\n", dev->name);
- if ((irqMask=read_eeprom(ioaddr,7))== ee_FX_INT2IRQ) /* INT to IRQ Mask */
+ irqMask = read_eeprom(ioaddr,7,dev);
+
+ if (lp->eepro == LAN595FX_10ISA) {
+ if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 3;\n");
+ }
+ else if (irqMask == ee_FX_INT2IRQ) /* INT to IRQ Mask */
{
lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */
if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n");
/* Initialize the 82595. */
- outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
+ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
temp_reg = inb(ioaddr + eeprom_reg);
lp->stepping = temp_reg >> 5; /* Get the stepping number of the 595 */
-
+ /* Get the stepping number of the 595 */
+
if (net_debug > 3)
printk(KERN_DEBUG "The stepping of the 82595 is %d\n", lp->stepping);
if (temp_reg & 0x10) /* Check the TurnOff Enable bit */
outb(temp_reg & 0xef, ioaddr + eeprom_reg);
- for (i=0; i < 6; i++)
- outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i);
+ for (i=0; i < 6; i++) /* Fill the mac address */
+ outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i);
temp_reg = inb(ioaddr + REG1); /* Setup Transmit Chaining */
outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */
outb(temp_reg & 0x3f, ioaddr + REG3); /* clear test mode */
/* Set the receiving mode */
- outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */
+ eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
/* Set the interrupt vector */
temp_reg = inb(ioaddr + INT_NO_REG);
- if (lp->eepro == 2)
+ if (lp->eepro == 2 || lp->eepro == LAN595FX_10ISA)
outb((temp_reg & 0xf8) | irqrmap2[dev->irq], ioaddr + INT_NO_REG);
else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
-
temp_reg = inb(ioaddr + INT_NO_REG);
- if (lp->eepro == 2)
+ if (lp->eepro == 2 || lp->eepro == LAN595FX_10ISA)
outb((temp_reg & 0xf0) | irqrmap2[dev->irq] | 0x08,ioaddr+INT_NO_REG);
else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
outb(XMT_UPPER_LIMIT, ioaddr + xmt_upper_limit_reg);
/* Enable the interrupt line. */
- temp_reg = inb(ioaddr + REG1);
- outb(temp_reg | INT_ENABLE, ioaddr + REG1);
+ eepro_en_intline(ioaddr);
- outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+ eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
/* Let RX and TX events to interrupt */
- outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+ eepro_en_int(ioaddr);
/* clear all interrupts */
- outb(ALL_MASK, ioaddr + STATUS_REG);
+ eepro_clear_int(ioaddr);
/* Initialize RCV */
outw((RCV_LOWER_LIMIT << 8), ioaddr + RCV_BAR);
lp->version = LAN595TX;
outb(old8, ioaddr + 8);
old9 = inb(ioaddr + 9);
- /*outb(~old9, ioaddr + 9);
- if (((temp_reg = inb(ioaddr + 9)) == ( (~old9)&0xff) )) {*/
if (irqMask==ee_FX_INT2IRQ) {
enum iftype { AUI=0, BNC=1, TPE=2 };
if (dev->if_port != TPE) { /* Hopefully, this will fix the
problem of using Pentiums and
pro/10 w/ BNC. */
- outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
+ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
temp_reg = inb(ioaddr + REG13);
/* disable the full duplex mode since it is not
applicable with the 10Base2 cable. */
outb(temp_reg & ~(FDX | A_N_ENABLE), REG13);
- outb(BANK0_SELECT, ioaddr); /* be CAREFUL, BANK 0 now */
+ eepro_sw2bank0(ioaddr); /* be CAREFUL, BANK 0 now */
}
}
else if (net_debug > 3) {
}
}
- outb(SEL_RESET_CMD, ioaddr);
-
- /* We are supposed to wait for 2 us after a SEL_RESET */
- SLOW_DOWN;
- SLOW_DOWN;
+ eepro_sel_reset(ioaddr);
lp->tx_start = lp->tx_end = (XMT_LOWER_LIMIT << 8);
lp->tx_last = 0;
if (net_debug > 3)
printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name);
- outb(RCV_ENABLE_CMD, ioaddr);
+ /* enabling rx */
+ eepro_en_rx(ioaddr);
MOD_INC_USE_COUNT;
return 0;
struct eepro_local *lp = (struct eepro_local *)dev->priv;
int ioaddr = dev->base_addr;
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
unsigned long flags;
-#endif
-
+
if (net_debug > 5)
printk(KERN_DEBUG "%s: entering eepro_send_packet routine.\n", dev->name);
-
+
if (dev->tbusy) {
/* If we get here, some higher level has decided we are broken.
There should really be a "kick me" function call instead. */
int tickssofar = jiffies - dev->trans_start;
+
if (tickssofar < 40)
return 1;
-
+
/* let's disable interrupts so we can avoid confusion on SMP
*/
- outb(ALL_MASK, ioaddr + INT_MASK_REG);
+ eepro_dis_int(ioaddr);
/* if (net_debug > 1) */
printk(KERN_ERR "%s: transmit timed out, %s?\n", dev->name,
lp->stats.tx_errors++;
/* Try to restart the adaptor. */
- outb(SEL_RESET_CMD, ioaddr);
/* We are supposed to wait for 2 us after a SEL_RESET */
- SLOW_DOWN;
- SLOW_DOWN;
+ eepro_sel_reset(ioaddr);
/* Do I also need to flush the transmit buffers here? YES? */
lp->tx_start = lp->tx_end = (XMT_LOWER_LIMIT << 8);
/* re-enabling all interrupts */
- outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
-
- outb(RCV_ENABLE_CMD, ioaddr);
- }
+ eepro_en_int(ioaddr);
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
+ /* enable rx */
+ eepro_en_rx(ioaddr);
+ }
spin_lock_irqsave(&lp->lock, flags);
-#endif
/* Block a timer-based transmit from overlapping. */
if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
spin_unlock_irqrestore(&lp->lock, flags);
-#endif
} else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = skb->data;
int discard = lp->stats.tx_dropped;
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
lp->stats.tx_bytes+=skb->len;
-#endif
-
hardware_send_packet(dev, buf, length);
if (lp->stats.tx_dropped != discard)
if (net_debug > 5)
printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name);
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
spin_unlock_irqrestore(&lp->lock, flags);
-#endif
return 0;
}
return;
}
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
spin_lock(&lp->lock);
-#endif
if (dev->interrupt) {
printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
spin_unlock(&lp->lock);
/* FIXME : with the lock, could this ever happen ? */
-#endif
return;
}
+
dev->interrupt = 1;
if (net_debug > 5)
{
switch (status & (RX_INT | TX_INT)) {
case (RX_INT | TX_INT):
- outb (RX_INT | TX_INT, ioaddr + STATUS_REG);
+ eepro_ack_rxtx(ioaddr);
break;
case RX_INT:
- outb (RX_INT, ioaddr + STATUS_REG);
+ eepro_ack_rx(ioaddr);
break;
case TX_INT:
- outb (TX_INT, ioaddr + STATUS_REG);
+ eepro_ack_tx(ioaddr);
break;
}
if (status & RX_INT) {
}
if (status & TX_INT) {
if (net_debug > 4)
- printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name);
+ printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name);
/* Process the status of transmitted packets */
eepro_transmit_interrupt(dev);
if (net_debug > 5)
printk(KERN_DEBUG "%s: exiting eepro_interrupt routine.\n", dev->name);
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
spin_unlock(&lp->lock);
-#endif
+
return;
}
dev->tbusy = 1;
dev->start = 0;
- outb(BANK1_SELECT, ioaddr); /* Switch back to Bank 1 */
+ eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
/* Disable the physical interrupt line. */
temp_reg = inb(ioaddr + REG1);
outb(temp_reg & 0x7f, ioaddr + REG1);
- outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+ eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
/* Flush the Tx and disable Rx. */
outb(STOP_RCV_CMD, ioaddr);
lp->tx_last = 0;
/* Mask all the interrupts. */
- outb(ALL_MASK, ioaddr + INT_MASK_REG);
+ eepro_dis_int(ioaddr);
/* clear all interrupts */
- outb(ALL_MASK, ioaddr + STATUS_REG);
+ eepro_clear_int(ioaddr);
/* Reset the 82595 */
- outb(RESET_CMD, ioaddr);
+ eepro_reset(ioaddr);
/* release the interrupt */
free_irq(dev->irq, dev);
/* Update the statistics here. What statistics? */
- /* We are supposed to wait for 200 us after a RESET */
- SLOW_DOWN;
- SLOW_DOWN; /* May not be enough? */
-
MOD_DEC_USE_COUNT;
return 0;
}
*/
dev->flags|=IFF_PROMISC;
- outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
+ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
mode = inb(ioaddr + REG2);
outb(mode | PRMSC_Mode, ioaddr + REG2);
mode = inb(ioaddr + REG3);
outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
- outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */
+ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
printk("%s: promiscuous mode enabled.\n", dev->name);
}
else if (dev->mc_count==0 )
{
- outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
+ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
mode = inb(ioaddr + REG2);
outb(mode & 0xd6, ioaddr + REG2); /* Turn off Multi-IA and PRMSC_Mode bits */
mode = inb(ioaddr + REG3);
outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
- outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */
+ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
}
else
/* Disable RX and TX interrupts. Necessary to avoid
corruption of the HOST_ADDRESS_REG by interrupt
service routines. */
- outb(ALL_MASK, ioaddr + INT_MASK_REG);
+ eepro_dis_int(ioaddr);
- outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
+ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
mode = inb(ioaddr + REG2);
outb(mode | Multi_IA, ioaddr + REG2);
mode = inb(ioaddr + REG3);
outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
- outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */
+ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
outw(lp->tx_end, ioaddr + HOST_ADDRESS_REG);
outw(MC_SETUP, ioaddr + IO_PORT);
outw(0, ioaddr + IO_PORT);
} while (++boguscount < 100);
/* Re-enable RX and TX interrupts */
- outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+ eepro_en_int(ioaddr);
}
- outb(RCV_ENABLE_CMD, ioaddr);
+ /* enabling rx */
+ eepro_en_rx(ioaddr);
}
/* The horrible routine to read a word from the serial EEPROM. */
#define EE_READ_CMD (6 << 6)
int
-read_eeprom(int ioaddr, int location)
+read_eeprom(int ioaddr, int location, struct device *dev)
{
int i;
unsigned short retval = 0;
short ee_addr = ioaddr + eeprom_reg;
+ struct eepro_local *lp = (struct eepro_local *)dev->priv;
int read_cmd = location | EE_READ_CMD;
short ctrl_val = EECS ;
* boards other than eepro10. I think that it won't let other
* boards to fail. (aris)
*/
- if (etherexpress10) {
- outb(BANK1_SELECT, ioaddr);
+ if (lp->eepro == LAN595FX_10ISA) {
+ eepro_sw2bank1(ioaddr);
outb(0x00, ioaddr + STATUS_REG);
}
- outb(BANK2_SELECT, ioaddr);
+ eepro_sw2bank2(ioaddr);
outb(ctrl_val, ee_addr);
/* Shift the read command bits out. */
eeprom_delay();
outb(ctrl_val, ee_addr);
eeprom_delay();
- outb(BANK0_SELECT, ioaddr);
+ eepro_sw2bank0(ioaddr);
return retval;
}
{
struct eepro_local *lp = (struct eepro_local *)dev->priv;
short ioaddr = dev->base_addr;
+
unsigned status, tx_available, last, end, boguscount = 100;
if (net_debug > 5)
printk(KERN_DEBUG "%s: entering hardware_send_packet routine.\n", dev->name);
- while (boguscount-- > 0) {
+ while (boguscount-- > 0) {
/* Disable RX and TX interrupts. Necessary to avoid
corruption of the HOST_ADDRESS_REG by interrupt
service routines. */
- outb(ALL_MASK, ioaddr + INT_MASK_REG);
+ eepro_dis_int(ioaddr);
if (dev->interrupt == 1) {
/* Enable RX and TX interrupts */
- outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+ eepro_en_int(ioaddr);
continue;
}
eepro_transmit_interrupt(dev); /* Clean up the transmiting queue */
/* Enable RX and TX interrupts */
- outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+ eepro_en_int(ioaddr);
continue;
}
else {
/* update the next address and the chain bit in the
last packet */
-
if (lp->tx_end != last) {
outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
outw(last, ioaddr + IO_PORT);
outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
status = inw(ioaddr + IO_PORT);
outw(status | CHAIN_BIT, ioaddr + IO_PORT);
-
/* Continue the transmit command */
outb(RESUME_XMT_CMD, ioaddr);
}
/* now we are serializing tx. tbusy won't come back until
* the tx interrupt
*/
- if (etherexpress10)
+ if (lp->eepro == LAN595FX_10ISA)
dev->tbusy = 1;
/* Enable RX and TX interrupts */
- outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+ eepro_en_int(ioaddr);
if (net_debug > 5)
printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name);
return;
}
- outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+ eepro_en_int(ioaddr);
dev->tbusy = 1;
if (net_debug > 5)
{
struct eepro_local *lp = (struct eepro_local *)dev->priv;
short ioaddr = dev->base_addr;
+
short boguscount = 20;
unsigned rcv_car = lp->rx_start;
unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size;
if (net_debug > 5)
printk(KERN_DEBUG "%s: entering eepro_rx routine.\n", dev->name);
-
- /* disabling all interrupts */
- outb(ALL_MASK, ioaddr + STATUS_REG);
+
+ /* clear all interrupts */
+ eepro_clear_int(ioaddr);
/* Set the read pointer to the start of the RCV */
outw(rcv_car, ioaddr + HOST_ADDRESS_REG);
/* Malloc up new buffer. */
struct sk_buff *skb;
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
lp->stats.rx_bytes+=rcv_size;
-#endif
rcv_size &= 0x3fff;
skb = dev_alloc_skb(rcv_size+5);
if (skb == NULL) {
if (net_debug > 5)
printk(KERN_DEBUG "%s: exiting eepro_rx routine.\n", dev->name);
- outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+ /* enable tx/rx interrupts */
+ eepro_en_int(ioaddr);
}
static void
short ioaddr = dev->base_addr;
short boguscount = 20;
unsigned xmt_status;
-
+
/*
if (dev->tbusy == 0) {
printk("%s: transmit_interrupt called with tbusy = 0 ??\n",
continue;
}
+
xmt_status = inw(ioaddr+IO_PORT);
lp->tx_start = inw(ioaddr+IO_PORT);
- if (etherexpress10) {
+ if (lp->eepro == LAN595FX_10ISA) {
lp->tx_start = (XMT_LOWER_LIMIT << 8);
lp->tx_end = lp->tx_start;
/* yeah, black magic :( */
- outb(BANK0_SELECT, ioaddr);
- outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
-
- outb(RCV_DISABLE_CMD, ioaddr);
- outb(RCV_ENABLE_CMD, ioaddr);
+ eepro_sw2bank0(ioaddr);
+ eepro_en_int(ioaddr);
+
+ /* disabling rx */
+ eepro_dis_rx(ioaddr);
+
+ /* enabling rx */
+ eepro_en_rx(ioaddr);
}
/* here the tbusy comes to 0 for normal and ee10 cards
printk(KERN_DEBUG "%s: XMT status = %#x\n",
dev->name, xmt_status);
}
-
- if (etherexpress10) {
+
+ if (lp->eepro == LAN595FX_10ISA) {
/* Try to restart the adaptor. */
- outb(SEL_RESET_CMD, ioaddr);
-
/* We are supposed to wait for 2 us after a SEL_RESET */
- SLOW_DOWN;
- SLOW_DOWN;
+ eepro_sel_reset(ioaddr);
/* first enable interrupts */
- outb(BANK0_SELECT, ioaddr);
+ eepro_sw2bank0(ioaddr);
outb(ALL_MASK & ~(RX_INT | TX_INT), ioaddr + STATUS_REG);
- outb(RCV_ENABLE_CMD, ioaddr);
+ /* enabling rx */
+ eepro_en_rx(ioaddr);
}
}
static int autodetect;
static int n_eepro = 0;
-/* For linux 2.1.xx */
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
MODULE_AUTHOR("Pascal Dupuis <dupuis@lei.ucl.ac.be> for the 2.1 stuff (locking,...)");
MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver");
MODULE_PARM(io, "1-" __MODULE_STRING(MAX_EEPRO) "i");
MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EEPRO) "i");
MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_EEPRO) "i");
MODULE_PARM(autodetect, "1-" __MODULE_STRING(1) "i");
-#endif
int
init_module(void)
for (i = 0; i < MAX_EEPRO; i++) {
struct device *d = &dev_eepro[n_eepro];
d->name = devicename[n_eepro]; /* inserted by drivers/net/net_init.c */
- d->mem_end = mem[n_eepro];
+ d->mem_end = mem[n_eepro];
d->base_addr = io[0];
d->irq = irq[n_eepro];
d->init = eepro_probe;
if (register_netdev(d) == 0)
n_eepro++;
+ else
+ break;
}
return n_eepro ? 0 : -ENODEV;
DEVICE( NVIDIA_SGS, NVIDIA_SGS_RIVA128, "Riva 128"),
DEVICE( CBOARDS, CBOARDS_DAS1602_16,"DAS1602/16"),
DEVICE( MOTOROLA_OOPS, MOTOROLA_FALCON,"Falcon"),
+ DEVICE( TIMEDIA, TIMEDIA_4008A, "Noname 4008A"),
DEVICE( SYMPHONY, SYMPHONY_101, "82C101"),
DEVICE( TEKRAM, TEKRAM_DC290, "DC-290"),
DEVICE( 3DLABS, 3DLABS_300SX, "GLINT 300SX"),
case PCI_VENDOR_ID_PICTUREL: return "Picture Elements";
case PCI_VENDOR_ID_NVIDIA_SGS: return "NVidia/SGS Thomson";
case PCI_VENDOR_ID_CBOARDS: return "ComputerBoards";
+ case PCI_VENDOR_ID_TIMEDIA: return "Timedia Technology";
case PCI_VENDOR_ID_SYMPHONY: return "Symphony";
case PCI_VENDOR_ID_COMPUTONE: return "Computone Corporation";
case PCI_VENDOR_ID_TEKRAM: return "Tekram";
{
struct tty_struct *tty = hwc_tty_data.tty;
-#if 0
-
if (tty != NULL) {
if (count == 2 && (
tty_flip_buffer_push (tty);
hwc_tty_wake_up ();
}
-#endif
+#if 0
if (tty != NULL) {
tty_flip_buffer_push(tty);
hwc_tty_wake_up ();
}
+#endif
}
void
* IFCONFIG dev DOWN and IFCONFIG dev UP
* - Possibility to switch the automatic selection off
* - Minor bug fixes
+ * 0.52 Bug fixes
+ * - Subchannel check message enhanced
+ * - Read / Write retry routine check for CTC_STOP added
*/
#include <linux/version.h>
#include <linux/init.h>
#define KERN_WARNING KERN_EMERG
#define KERN_DEBUG KERN_EMERG
#endif
-//#undef DEBUG
+
#define CCW_CMD_WRITE 0x01
#define CCW_CMD_READ 0x02
devstat_t *devstat = ((devstat_t *)initparm);
- /* Bypass all 'unsolited interrupts' */
+ /* Bypass all 'unsolicited interrupts' */
if (devstat->intparm == 0) {
#ifdef DEBUG
- printk(KERN_DEBUG "ctc: unsolited interrupt for device: %04x received c-%02x d-%02x f-%02x\n",
+ printk(KERN_DEBUG "ctc: unsolicited interrupt for device: %04x received c-%02x d-%02x f-%02x\n",
devstat->devno, devstat->cstat, devstat->dstat, devstat->flag);
#endif
/* FIXME - find the related intparm!!! No IO outstanding!!!! */
/* Check for good subchannel return code, otherwise error message */
if (devstat->cstat) {
- printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x\n",
- dev->name, ctc->devno, devstat->cstat);
+ printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x %02x %02x\n",
+ dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag);
return;
}
#ifdef DEBUG
printk(KERN_DEBUG "%s: read retry - state-%02x\n" ,dev->name, ctc->state);
#endif
+ if (ctc->state == CTC_STOP)
+ return;
s390irq_spin_lock_irqsave(ctc->irq, saveflags);
ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block);
parm = (__u32) ctc;
#ifdef DEBUG
printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state);
#endif
+ if (ctc->state == CTC_STOP)
+ return;
s390irq_spin_lock_irqsave(ctc->irq, saveflags);
ctc->ccw[1].count = 0;
ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block);
static int ctc_release(net_device *dev)
{
int rc;
+ int x;
int i;
int j;
__u8 flags = 0x00;
ctc_unprotect_busy_irqrestore(dev,flags);
for (i = 0; i < 2; i++) {
s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
+ del_timer(&privptr->channel[READ].timer);
privptr->channel[i].state = CTC_STOP;
parm = (__u32) &privptr->channel[i];
rc = halt_IO (privptr->channel[i].irq, parm, flags );
* Original driver (sg.c):
* Copyright (C) 1992 Lawrence Foard
* 2.x extensions to driver:
- * Copyright (C) 1998, 1999 Douglas Gilbert
+ * Copyright (C) 1998 - 2000 Douglas Gilbert
*
* 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
*
* Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book.
*/
- static char * sg_version_str = "Version: 2.1.36 (991218)";
- static int sg_version_num = 20136; /* 2 digits for each component */
+ static char * sg_version_str = "Version: 2.1.37 (20000504)";
+ static int sg_version_num = 20137; /* 2 digits for each component */
/*
* D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
* - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
static void sg_detach(Scsi_Device *);
-struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", NULL, 0xff,
+struct Scsi_Device_Template sg_template = {NULL, "generic", "sg", NULL, 0xff,
SCSI_GENERIC_MAJOR, 0, 0, 0, 0,
sg_detect, sg_init,
sg_finish, sg_attach, sg_detach};
return -EBUSY;
result = get_user(val, (int *)arg);
if (result) return result;
- /* Don't do anything till scsi mod level visibility */
- return 0;
+ if (SG_SCSI_RESET_NOTHING == val)
+ return 0;
+#ifdef SCSI_TRY_RESET_DEVICE
+ switch (val)
+ {
+ case SG_SCSI_RESET_DEVICE:
+ val = SCSI_TRY_RESET_DEVICE;
+ break;
+ case SG_SCSI_RESET_BUS:
+ val = SCSI_TRY_RESET_BUS;
+ break;
+ case SG_SCSI_RESET_HOST:
+ val = SCSI_TRY_RESET_HOST;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if(! capable(CAP_SYS_ADMIN)) return -EACCES;
+ return (scsi_reset_provider(sdp->device, val) == SUCCESS) ? 0 : -EIO;
+#else
+ SCSI_LOG_TIMEOUT(1, printk("sg_ioctl: SG_RESET_SCSI not supported\n"));
+ result = -EINVAL;
+#endif
case SCSI_IOCTL_SEND_COMMAND:
/* Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the
user already has read/write access to the generic device and so
SCSI_LOG_TIMEOUT(4, printk("sg_start_req: max_buff_size=%d\n",
max_buff_size));
+ if (max_buff_size <= 0)
+ return 0;
if ((! sg_res_in_use(sfp)) && (max_buff_size <= rsv_schp->bufflen)) {
sg_link_reserve(sfp, srp, max_buff_size);
sg_write_xfer(req_schp, inp, num_write_xfer);
Sg_scatter_hold * rsv_schp = &sfp->reserve;
SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size));
+ /* round request up to next highest SG_SECTOR_SZ byte boundary */
+ size = (size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK);
if (rsv_schp->use_sg > 0) {
int k, num;
int rem = size;
static Sg_request * sg_add_request(Sg_fd * sfp)
{
int k;
- Sg_request * resp = NULL;
- Sg_request * rp;
+ Sg_request * resp = sfp->headrp;
+ Sg_request * rp = sfp->req_arr;
- resp = sfp->headrp;
- rp = sfp->req_arr;
if (! resp) {
+ memset(rp, 0, sizeof(Sg_request));
+ rp->parentfp = sfp;
resp = rp;
sfp->headrp = resp;
}
if (0 == sfp->cmd_q)
resp = NULL; /* command queuing disallowed */
else {
- for (k = 0, rp; k < SG_MAX_QUEUE; ++k, ++rp) {
+ for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
if (! rp->parentfp)
break;
}
if (k < SG_MAX_QUEUE) {
- while (resp->nextrp) resp = resp->nextrp;
+ memset(rp, 0, sizeof(Sg_request));
+ rp->parentfp = sfp;
+ while (resp->nextrp)
+ resp = resp->nextrp;
resp->nextrp = rp;
resp = rp;
}
}
}
if (resp) {
- resp->parentfp = sfp;
resp->nextrp = NULL;
- resp->res_used = 0;
- memset(&resp->data, 0, sizeof(Sg_scatter_hold));
- memset(&resp->header, 0, sizeof(struct sg_header));
resp->my_cmdp = NULL;
}
return resp;
return 0;
prev_rp = sfp->headrp;
if (srp == prev_rp) {
- prev_rp->parentfp = NULL;
sfp->headrp = prev_rp->nextrp;
+ prev_rp->parentfp = NULL;
return 1;
}
while ((rp = prev_rp->nextrp)) {
if (srp == rp) {
- rp->parentfp = NULL;
prev_rp->nextrp = rp->nextrp;
+ rp->parentfp = NULL;
return 1;
}
prev_rp = rp;
obj-$(CONFIG_SOUND_CS4232) += uart401.o
obj-$(CONFIG_SOUND_GUS) += gus.o ad1848.o
obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb.o uart401.o
-obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx.o sb.o uart401.o
+obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx.o sb.o uart401.o
obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o
obj-$(CONFIG_SOUND_MPU401) += mpu401.o
obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o
# Declare multi-part drivers.
list-multi := sound.o gus.o pas2.o sb.o softoss2.o vidc_mod.o \
- soundcore.o wavefront.o nm256.o
+ soundcore.o wavefront.o nm256.o via82cxxx.o \
sound-objs := \
dev_table.o soundcard.o sound_syms.o \
vidc_mod-objs := vidc.o vidc_audio.o vidc_fill.o vidc_mixer.o vidc_synth.o
wavefront-objs := wavfront.o wf_midi.o yss225.o
nm256-objs := nm256_audio.o ac97.o
+via82cxxx-objs := via82cxxx_audio.o ac97.o
# Extract lists of the multi-part drivers.
nm256.o: $(nm256-objs)
$(LD) -r -o $@ $(nm256-objs)
+via82cxxx.o: $(via82cxxx-objs)
+ $(LD) -r -o $@ $(via82cxxx-objs)
+
# Firmware files that need translation
#
# The translated files are protected by a file that keeps track
/* --------------------------------------------------------------------- */
-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
+#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
#define DMABUF_MINORDER 1
static void dealloc_dmabuf(struct dmabuf *db)
+++ /dev/null
-/*
- * Support for VIA 82Cxxx Audio Codecs
- * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
- *
- * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2.
- * See the "COPYING" file distributed with this software for more info.
- *
- ********************************************************************
- *
- * TODO:
- *
- * - Integrate AC'97 support, when AC'97 interface released
- *
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "sound_config.h"
-#include "soundmodule.h"
-#include "sb.h"
-
-#ifndef SOUND_LOCK
-#define SOUND_LOCK do {} while (0)
-#define SOUND_LOCK_END do {} while (0)
-#endif
-
-#define MAX_CARDS 2
-
-#define PFX "via82cxxx: "
-
-#define VIA_VERSION "1.0.0"
-#define VIA_CARD_NAME "VIA 82Cxxx Audio driver " VIA_VERSION
-
-#define VIA_FUNC_ENABLE 0x42
-#define VIA_PNP_CONTROL 0x43
-
-#define VIA_CR42_SB_ENABLE 0x01
-#define VIA_CR42_MIDI_ENABLE 0x02
-#define VIA_CR42_FM_ENABLE 0x04
-
-#define via_probe_midi probe_uart401
-#define via_attach_midi attach_uart401
-#define via_unload_midi unload_uart401
-
-static struct address_info sb_data[MAX_CARDS];
-static struct address_info opl3_data[MAX_CARDS];
-static unsigned cards = 0;
-
-
-static void __init via_attach_sb(struct address_info *hw_config)
-{
- if(!sb_dsp_init(hw_config))
- hw_config->slots[0] = -1;
-}
-
-
-static int __init via_probe_sb(struct address_info *hw_config)
-{
- if (check_region(hw_config->io_base, 16))
- {
- printk(KERN_DEBUG PFX "SBPro port 0x%x is already in use\n",
- hw_config->io_base);
- return 0;
- }
- return sb_dsp_detect(hw_config, 0, 0);
-}
-
-
-static void via_unload_sb(struct address_info *hw_config, int unload_mpu)
-{
- if(hw_config->slots[0]!=-1)
- sb_dsp_unload(hw_config, unload_mpu);
-}
-
-
-static int __init via82cxxx_install (struct pci_dev *pcidev)
-{
- int sb_io_base = 0;
- int sb_irq = 0;
- int sb_dma = 0;
- int midi_base = 0;
- u8 tmp8;
-
- memset (&sb_data[cards], 0, sizeof (struct address_info));
- memset (&opl3_data[cards], 0, sizeof (struct address_info));
-
- sb_data[cards].name = opl3_data[cards].name = VIA_CARD_NAME;
- opl3_data[cards].irq = -1;
-
- /* turn on features, if not already */
- pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8);
- tmp8 |= VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE |
- VIA_CR42_FM_ENABLE;
- pci_write_config_byte (pcidev, VIA_FUNC_ENABLE, tmp8);
-
- /* read legacy PNP info byte */
- pci_read_config_byte (pcidev, VIA_PNP_CONTROL, &tmp8);
- pci_write_config_byte (pcidev, VIA_PNP_CONTROL, tmp8);
-
- switch ((tmp8 >> 6) & 0x03) {
- case 0: sb_irq = 5; break;
- case 1: sb_irq = 7; break;
- case 2: sb_irq = 9; break;
- case 3: sb_irq = 10; break;
- default: /* do nothing */ break;
- }
- switch ((tmp8 >> 4) & 0x03) {
- case 0: sb_dma = 0; break;
- case 1: sb_dma = 1; break;
- case 2: sb_dma = 2; break;
- case 3: sb_dma = 3; break;
- default: /* do nothing */ break;
- }
- switch ((tmp8 >> 2) & 0x03) {
- case 0: midi_base = 0x300; break;
- case 1: midi_base = 0x310; break;
- case 2: midi_base = 0x320; break;
- case 3: midi_base = 0x330; break;
- default: /* do nothing */ break;
- }
- switch (tmp8 & 0x03) {
- case 0: sb_io_base = 0x220; break;
- case 1: sb_io_base = 0x240; break;
- case 2: sb_io_base = 0x260; break;
- case 3: sb_io_base = 0x280; break;
- default: /* do nothing */ break;
- }
-
- udelay(100);
-
- printk(KERN_INFO PFX "legacy "
- "MIDI: 0x%X, SB: 0x%X / %d IRQ / %d DMA\n",
- midi_base, sb_io_base, sb_irq, sb_dma);
-
- sb_data[cards].card_subtype = MDL_SBPRO;
- sb_data[cards].io_base = sb_io_base;
- sb_data[cards].irq = sb_irq;
- sb_data[cards].dma = sb_dma;
-
- opl3_data[cards].io_base = midi_base;
-
- /* register legacy SoundBlaster Pro */
- if (!via_probe_sb (&sb_data[cards])) {
- printk (KERN_ERR PFX
- "SB probe @ 0x%X failed, aborting\n",
- sb_io_base);
- return -1;
- }
- via_attach_sb (&sb_data[cards]);
-
- /* register legacy MIDI */
- if (!via_probe_midi (&opl3_data[cards])) {
- printk (KERN_ERR PFX
- "MIDI probe @ 0x%X failed, aborting\n",
- midi_base);
- via_unload_sb (&sb_data[cards], 0);
- return -1;
- }
- via_attach_midi (&opl3_data[cards]);
-
- cards++;
- return 0;
-}
-
-
-/*
- * This loop walks the PCI configuration database and finds where
- * the sound cards are.
- */
-
-static int __init probe_via82cxxx (void)
-{
- struct pci_dev *pcidev = NULL;
-
- while ((pcidev = pci_find_device (PCI_VENDOR_ID_VIA,
- PCI_DEVICE_ID_VIA_82C686_5,
- pcidev)) != NULL) {
-
- if (via82cxxx_install (pcidev) != 0) {
- printk (KERN_ERR PFX "audio init failed\n");
- return -1;
- }
-
- if (cards == MAX_CARDS) {
- printk (KERN_DEBUG PFX "maximum number of cards reached\n");
- break;
- }
- }
-
- return 0;
-}
-
-
-/*
- * This function is called when the user or kernel loads the
- * module into memory.
- */
-
-
-static int __init init_via82cxxx_module(void)
-{
- if (!pci_present ()) {
- printk (KERN_DEBUG PFX "PCI not present, exiting\n");
- return -ENODEV;
- }
-
- if (probe_via82cxxx() != 0) {
- printk(KERN_ERR PFX "probe failed, aborting\n");
- /* XXX unload cards registered so far, if any */
- return -ENODEV;
- }
-
- if (cards == 0) {
- printk(KERN_DEBUG PFX "No chips found, aborting\n");
- return -ENODEV;
- }
-
- printk (KERN_INFO PFX VIA_CARD_NAME " loaded\n");
-
- /*
- * Binds us to the sound subsystem
- */
- SOUND_LOCK;
- return 0;
-}
-
-/*
- * This is called when it is removed. It will only be removed
- * when its use count is 0. For sound the SOUND_LOCK/SOUND_UNLOCK
- * macros hide the entire work for this.
- */
-
-static void cleanup_via82cxxx_module(void)
-{
- int i;
-
- for (i = 0; i < cards; i++)
- via_unload_sb (&sb_data[i], 1);
-
- /*
- * Final clean up with the sound layer
- */
- SOUND_LOCK_END;
-}
-
-#ifdef MODULE
-
-int init_module(void)
-{
- return init_via82cxxx_module();
-}
-
-void cleanup_module(void)
-{
- cleanup_via82cxxx_module();
-}
-
-#endif
--- /dev/null
+/*
+ * Support for VIA 82Cxxx Audio Codecs
+ * Copyright 1999,2000 Jeff Garzik <jgarzik@mandrakesoft.com>
+ *
+ * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2.
+ * See the "COPYING" file distributed with this software for more info.
+ *
+ * Documentation for this driver available as
+ * linux/Documentation/sound/via82cxxx.txt.
+ *
+ * Since the mixer is called from the OSS glue the kernel lock is always held
+ * on our AC97 mixing
+ */
+
+
+#define VIA_VERSION "1.1.2.1"
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#include <asm/io.h>
+
+#include "sound_config.h"
+#include "soundmodule.h"
+#include "sb.h"
+#include "ac97.h"
+
+#ifndef SOUND_LOCK
+#define SOUND_LOCK do {} while (0)
+#define SOUND_LOCK_END do {} while (0)
+#endif
+
+#define VIA_DEBUG 0 /* define to 1 to enable debugging output and checks */
+#if VIA_DEBUG
+/* note: prints function name for you */
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define VIA_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */
+#if VIA_NDEBUG
+#define assert(expr)
+#else
+#define assert(expr) \
+ if(!(expr)) { \
+ printk( "Assertion failed! %s,%s,%s,line=%d\n", \
+ #expr,__FILE__,__FUNCTION__,__LINE__); \
+ }
+#endif
+
+#define arraysize(x) (sizeof(x)/sizeof(*(x)))
+
+#define MAX_CARDS 2
+
+#define LINE_SIZE 10
+
+#define VIA_CARD_NAME "VIA 82Cxxx Audio driver " VIA_VERSION
+#define VIA_MODULE_NAME "via_audio"
+#define PFX VIA_MODULE_NAME ": "
+
+#define VIA_COUNTER_LIMIT 100000
+
+/* 82C686 function 5 (audio codec) PCI configuration registers */
+#define VIA_FUNC_ENABLE 0x42
+#define VIA_PNP_CONTROL 0x43
+#define VIA_AC97_CTRL 0x80
+
+/* PCI configuration register bits and masks */
+#define VIA_CR40_AC97_READY 0x01
+#define VIA_CR40_AC97_LOW_POWER 0x02
+#define VIA_CR40_SECONDARY_READY 0x04
+
+#define VIA_CR41_ACLINK_ENABLE 0x80
+
+#define VIA_CR42_SB_ENABLE 0x01
+#define VIA_CR42_MIDI_ENABLE 0x02
+#define VIA_CR42_FM_ENABLE 0x04
+#define VIA_CR42_GAME_ENABLE 0x08
+
+#define VIA_CR44_SECOND_CODEC_SUPPORT (1 << 6)
+#define VIA_CR44_AC_LINK_ACCESS (1 << 7)
+
+#define VIA_CR80_FIRST_CODEC 0
+#define VIA_CR80_SECOND_CODEC (1 << 30)
+#define VIA_CR80_FIRST_CODEC_VALID (1 << 25)
+#define VIA_CR80_SECOND_CODEC_VALID (1 << 27)
+#define VIA_CR80_BUSY (1 << 24)
+#define VIA_CR80_READ_MODE (1 << 23)
+#define VIA_CR80_WRITE_MODE 0
+#define VIA_CR80_REG_IDX(idx) (((idx) & 0x7E) << 16)
+
+struct via_info {
+ struct address_info sb_data;
+ struct address_info opl3_data;
+ struct pci_dev *pdev;
+ struct ac97_hwint ac97;
+ int mixer_oss_dev;
+ int have_ac97;
+};
+static struct via_info cards [MAX_CARDS];
+static unsigned num_cards = 0;
+
+
+static const struct {
+ int revision;
+ const char *rev_name;
+} via_chip_revs[] __initdata = {
+ { 0x10, "A" },
+ { 0x11, "B" },
+ { 0x12, "C" },
+ { 0x13, "D" },
+ { 0x14, "E" },
+ { 0x20, "H" },
+};
+
+static inline void via_ac97_write32 (struct pci_dev *pdev, int port, u32 data)
+{
+
+ int iobase = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+
+ outw ((u16)data,iobase+port);
+ outw ((u16)(data>>16),iobase+port+2);
+}
+
+static inline u32 via_ac97_read32 (struct pci_dev *pdev, int port)
+{
+ int iobase = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+
+ return
+ ((u32)inw (iobase+port)) |
+ (((u32)inw (iobase+port+2)) << 16);
+}
+
+/****************************************************************
+ *
+ * Intel Audio Codec '97 interface
+ *
+ *
+ */
+
+static inline void via_ac97_wait_idle (struct pci_dev *pdev)
+{
+ u32 tmp;
+ int counter = VIA_COUNTER_LIMIT;
+
+ DPRINTK ("ENTER\n");
+
+ assert (pdev != NULL);
+
+ do {
+ tmp = via_ac97_read32 (pdev,VIA_AC97_CTRL);
+ } while ((tmp & VIA_CR80_BUSY) && (counter-- > 0));
+
+ DPRINTK ("EXIT%s\n", counter > 0 ? "" : ", counter limit reached");
+}
+
+
+static int via_ac97_read_reg (struct ac97_hwint *dev, u8 reg)
+{
+ u32 data;
+ struct via_info *card;
+ struct pci_dev *pdev;
+
+ DPRINTK ("ENTER\n");
+
+ assert (dev != NULL);
+ assert (dev->driver_private != NULL);
+
+ card = (struct via_info *) dev->driver_private;
+ pdev = card->pdev;
+ assert (pdev != NULL);
+
+ via_ac97_wait_idle (pdev);
+ data = VIA_CR80_FIRST_CODEC | VIA_CR80_FIRST_CODEC_VALID |
+ VIA_CR80_READ_MODE | VIA_CR80_REG_IDX(reg);
+ via_ac97_write32 (pdev,VIA_AC97_CTRL,data);
+ via_ac97_wait_idle (pdev);
+ data = via_ac97_read32 (pdev,VIA_AC97_CTRL);
+
+#if 0
+ if (! (data & VIA_CR80_FIRST_CODEC_VALID)) {
+ DPRINTK ("EXIT, first codec not valid, returning -1\n");
+ return -1;
+ }
+#endif
+
+ DPRINTK ("EXIT, returning %d\n", data & 0xFFFF);
+ return data & 0xFFFF;
+}
+
+
+static int via_ac97_write_reg (struct ac97_hwint *dev, u8 reg, u16 value)
+{
+ u32 data;
+ struct via_info *card;
+ struct pci_dev *pdev;
+
+ DPRINTK ("ENTER\n");
+
+ assert (dev != NULL);
+ assert (dev->driver_private != NULL);
+
+ card = (struct via_info *) dev->driver_private;
+ pdev = card->pdev;
+ assert (pdev != NULL);
+
+ via_ac97_wait_idle (pdev);
+ data = VIA_CR80_FIRST_CODEC | VIA_CR80_FIRST_CODEC_VALID |
+ VIA_CR80_WRITE_MODE | VIA_CR80_REG_IDX(reg) | value;
+ via_ac97_write32 (pdev,VIA_AC97_CTRL,data);
+
+#if 0
+ if (! (data & VIA_CR80_FIRST_CODEC_VALID)) {
+ DPRINTK ("EXIT, first codec invalid, returning -1\n");
+ return -1;
+ }
+#endif
+
+ DPRINTK ("EXIT, returning 0\n");
+ return 0;
+}
+
+
+static int via_ac97_reset (struct ac97_hwint *dev)
+{
+ struct via_info *card;
+ struct pci_dev *pdev;
+
+ DPRINTK ("ENTER\n");
+
+ assert (dev != NULL);
+ assert (dev->driver_private != NULL);
+
+ card = (struct via_info *) dev->driver_private;
+ pdev = card->pdev;
+ assert (pdev != NULL);
+
+ pci_write_config_word (pdev, PCI_COMMAND, PCI_COMMAND_IO);
+
+ DPRINTK ("EXIT, returning 0\n");
+ return 0;
+}
+
+
+static struct via_info *via_ac97_find_card_for_mixer (int dev)
+{
+ int x;
+
+ DPRINTK ("ENTER\n");
+
+ for (x = 0; x < num_cards; x++)
+ if (cards[x].mixer_oss_dev == dev) {
+ DPRINTK ("EXIT, returning %p\n", cards + x);
+ return cards + x;
+ }
+
+ DPRINTK ("EXIT, returning 0\n");
+ return NULL;
+}
+
+
+static int
+via_ac97_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
+{
+ int rc;
+ struct via_info *card = via_ac97_find_card_for_mixer (dev);
+
+ DPRINTK ("ENTER\n");
+
+ if (card != NULL) {
+ rc = ac97_mixer_ioctl (&card->ac97, cmd, arg);
+ DPRINTK ("EXIT, returning %d\n", rc);
+ return rc;
+ }
+
+ DPRINTK ("EXIT, returning -ENODEV\n");
+ return -ENODEV;
+
+}
+
+static struct mixer_operations via_ac97_mixer_operations =
+{
+ "VIA82Cxxx",
+ "via82cxxxAC97Mixer",
+ via_ac97_default_mixer_ioctl
+};
+
+static int __init via_attach_ac97 (struct via_info *card)
+{
+ int mixer;
+ struct ac97_hwint *mdev;
+
+ DPRINTK ("ENTER\n");
+
+ assert (card != NULL);
+
+ mdev = &card->ac97;
+
+ memset (mdev, 0, sizeof (*mdev));
+ mdev->reset_device = via_ac97_reset;
+ mdev->read_reg = via_ac97_read_reg;
+ mdev->write_reg = via_ac97_write_reg;
+ mdev->driver_private = (void *) card;
+
+ if (ac97_init (mdev)) {
+ printk (KERN_ERR PFX "Unable to init AC97\n");
+ DPRINTK ("EXIT, returning -1\n");
+ return -1;
+ }
+ mixer = sound_alloc_mixerdev ();
+ if (mixer < 0 || num_mixers >= MAX_MIXER_DEV) {
+ printk (KERN_ERR PFX "Unable to alloc mixerdev\n");
+ DPRINTK ("EXIT, returning -1\n");
+ return -1;
+ }
+ mixer_devs[mixer] = &via_ac97_mixer_operations;
+ card->mixer_oss_dev = mixer;
+
+ /* Some reasonable default values. */
+ ac97_set_mixer (mdev, SOUND_MIXER_VOLUME, (85 << 8) | 85);
+ ac97_set_mixer (mdev, SOUND_MIXER_SPEAKER, 100);
+ ac97_set_mixer (mdev, SOUND_MIXER_PCM, (65 << 8) | 65);
+ ac97_set_mixer (mdev, SOUND_MIXER_CD, (65 << 8) | 65);
+
+ printk (KERN_INFO PFX "Initialized AC97 mixer\n");
+
+ card->have_ac97 = mixer;
+
+ DPRINTK ("EXIT, returning 0\n");
+ return 0;
+}
+
+
+static void via_unload_ac97 (struct via_info *card)
+{
+ DPRINTK ("ENTER\n");
+
+ assert (card != NULL);
+
+ if (card->have_ac97 >= 0)
+ sound_unload_mixerdev (card->have_ac97);
+
+ DPRINTK ("EXIT\n");
+}
+
+#if 0
+#ifdef CONFIG_PROC_FS
+
+/****************************************************************
+ *
+ * /proc/driver/via82cxxx/info
+ *
+ *
+ */
+static int via_info_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+#define YN(val,bit) (((val) & (bit)) ? "yes" : "no")
+
+ int len = 0, i;
+ u8 r40, r41, r42, r44;
+
+ DPRINTK ("ENTER\n");
+
+ len += sprintf (page+len, VIA_CARD_NAME "\n\n");
+
+ for (i = 0; i < num_cards; i++) {
+ pci_read_config_byte (cards[i].pdev, 0x40, &r40);
+ pci_read_config_byte (cards[i].pdev, 0x42, &r41);
+ pci_read_config_byte (cards[i].pdev, 0x42, &r42);
+ pci_read_config_byte (cards[i].pdev, 0x44, &r44);
+
+ len += sprintf (page+len,
+ "40 AC97 Codec Ready: %s\n"
+ " AC97 Codec Low-power: %s\n"
+ " Secondary Codec Ready: %s\n"
+
+ "41 AC-Link Interface Enable: %s\n"
+
+ "42 Game port enabled: %s\n"
+ " SoundBlaster enabled: %s\n"
+ " FM enabled: %s\n"
+ " MIDI enabled: %s\n"
+
+ "44 AC-Link Interface Access: %s\n"
+ " Secondary Codec Support: %s\n"
+
+ "\n",
+
+ YN (r40, VIA_CR40_AC97_READY),
+ YN (r40, VIA_CR40_AC97_LOW_POWER),
+ YN (r40, VIA_CR40_SECONDARY_READY),
+
+ YN (r41, VIA_CR41_ACLINK_ENABLE),
+
+ YN (r42, VIA_CR42_GAME_ENABLE),
+ YN (r42, VIA_CR42_SB_ENABLE),
+ YN (r42, VIA_CR42_FM_ENABLE),
+ YN (r42, VIA_CR42_MIDI_ENABLE),
+
+ YN (r44, VIA_CR44_AC_LINK_ACCESS),
+ YN (r44, VIA_CR44_SECOND_CODEC_SUPPORT)
+
+ );
+ }
+
+ DPRINTK("EXIT, returning %d\n", len);
+ return len;
+
+#undef YN
+}
+
+
+/****************************************************************
+ *
+ * /proc/driver/via82cxxx
+ *
+ *
+ */
+
+static int __init via_init_proc (void)
+{
+ DPRINTK ("ENTER\n");
+
+
+ proc_mkdir ("driver/via_audio", 0);
+ create_proc_read_entry ("driver/via_audio/info", 0, 0, via_info_read_proc, NULL);
+
+ DPRINTK("EXIT\n");
+ return 0;
+}
+
+
+
+static void __exit via_cleanup_proc (void)
+{
+ DPRINTK ("ENTER\n");
+ remove_proc_entry ("driver/via_audio/info", NULL);
+ remove_proc_entry ("driver/via_audio", NULL);
+ DPRINTK("EXIT\n");
+}
+
+
+#else
+#endif /* CONFIG_PROC_FS */
+
+#endif /* if 0 */
+
+static inline int via_init_proc (void) { return 0; }
+static inline void via_cleanup_proc (void) {}
+
+
+
+/****************************************************************
+ *
+ * Legacy SoundBlaster Pro, FM support via OSS
+ *
+ *
+ */
+
+static void via_attach_sb(struct address_info *hw_config)
+{
+ DPRINTK ("ENTER\n");
+
+ if(!sb_dsp_init(hw_config))
+ hw_config->slots[0] = -1;
+
+ DPRINTK("EXIT\n");
+}
+
+
+static int via_probe_sb(struct address_info *hw_config)
+{
+ DPRINTK ("ENTER\n");
+
+ if (check_region(hw_config->io_base, 16))
+ {
+ printk(KERN_DEBUG PFX "SBPro port 0x%x is already in use\n",
+ hw_config->io_base);
+ return 0;
+ }
+ DPRINTK("EXIT after sb_dsp_detect\n");
+ return sb_dsp_detect(hw_config, 0, 0);
+}
+
+
+static void via_unload_sb(struct address_info *hw_config)
+{
+ DPRINTK ("ENTER\n");
+
+ if(hw_config->slots[0] != -1)
+ sb_dsp_unload(hw_config, 1);
+
+ DPRINTK("EXIT\n");
+}
+
+
+static const struct {
+ int sb_irq,
+ sb_dma,
+ midi_base,
+ sb_io_base;
+} via_pnp_data[] __initdata = {
+ { 5, 0, 0x300, 0x220 },
+ { 7, 1, 0x310, 0x240 },
+ { 9, 2, 0x320, 0x260 },
+ { 10,3, 0x330, 0x280 },
+};
+
+
+/****************************************************************
+ *
+ * Chip setup and kernel registration
+ *
+ *
+ */
+
+static int __init via82cxxx_install (struct pci_dev *pcidev)
+{
+ int sb_io_base;
+ int sb_irq;
+ int sb_dma;
+ int midi_base, rc;
+ u8 tmp8;
+ struct via_info *card = &cards[num_cards];
+
+ DPRINTK ("ENTER\n");
+
+ card->pdev = pcidev;
+ card->have_ac97 = -1;
+
+ /* turn off legacy features, if not already */
+ pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8);
+ tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE |
+ VIA_CR42_FM_ENABLE);
+ pci_write_config_byte (pcidev, VIA_FUNC_ENABLE, tmp8);
+
+ /*
+ * try to init AC97 mixer device
+ */
+ rc = via_attach_ac97 (card);
+ if (rc) {
+ printk (KERN_WARNING PFX
+ "AC97 init failed, SB legacy mode only\n");
+ }
+
+ /* turn on legacy features */
+ pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8);
+ tmp8 |= VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE |
+ VIA_CR42_FM_ENABLE;
+ pci_write_config_byte (pcidev, VIA_FUNC_ENABLE, tmp8);
+
+ /* read legacy PNP info byte */
+ pci_read_config_byte (pcidev, VIA_PNP_CONTROL, &tmp8);
+ pci_write_config_byte (pcidev, VIA_PNP_CONTROL, tmp8);
+
+ sb_irq = via_pnp_data[((tmp8 >> 6) & 0x03)].sb_irq;
+ sb_dma = via_pnp_data[((tmp8 >> 4) & 0x03)].sb_dma;
+ midi_base = via_pnp_data[((tmp8 >> 2) & 0x03)].midi_base;
+ sb_io_base = via_pnp_data[(tmp8 & 0x03)].sb_io_base;
+
+ udelay(100);
+
+ printk(KERN_INFO PFX "legacy "
+ "MIDI: 0x%X, SB: 0x%X / %d IRQ / %d DMA\n",
+ midi_base, sb_io_base, sb_irq, sb_dma);
+
+ card->sb_data.name = VIA_CARD_NAME;
+ card->sb_data.card_subtype = MDL_SBPRO;
+ card->sb_data.io_base = sb_io_base;
+ card->sb_data.irq = sb_irq;
+ card->sb_data.dma = sb_dma;
+
+ /* register legacy SoundBlaster Pro */
+ if (!via_probe_sb (&card->sb_data)) {
+ printk (KERN_ERR PFX
+ "SB probe @ 0x%X failed, aborting\n",
+ sb_io_base);
+ DPRINTK ("EXIT, returning -1\n");
+ return -1;
+ }
+ via_attach_sb (&card->sb_data);
+
+ card->opl3_data.name = card->sb_data.name;
+ card->opl3_data.io_base = midi_base;
+ card->opl3_data.irq = -1;
+
+ /* register legacy MIDI */
+ if (!probe_uart401 (&card->opl3_data)) {
+ printk (KERN_WARNING PFX
+ "MIDI probe @ 0x%X failed, continuing\n",
+ midi_base);
+ card->opl3_data.io_base = 0;
+ } else {
+ attach_uart401 (&card->opl3_data);
+ }
+
+ num_cards++;
+ DPRINTK ("EXIT, returning 0\n");
+ return 0;
+}
+
+
+/*
+ * This loop walks the PCI configuration database and finds where
+ * the sound cards are.
+ *
+ * Note - only a single PCI scan occurs, eliminating possibility
+ * of multiple audio chips
+ *
+ */
+
+static int __init probe_via82cxxx (void)
+{
+ struct pci_dev *pcidev = NULL;
+
+ DPRINTK ("ENTER\n");
+
+ pcidev = pci_find_device (PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_82C686_5, NULL);
+
+ if (!pcidev || via82cxxx_install (pcidev) != 0) {
+ printk (KERN_ERR PFX "audio init failed\n");
+ DPRINTK ("EXIT, returning -1\n");
+ return -1;
+ }
+
+ DPRINTK ("EXIT, returning 0\n");
+ return 0;
+}
+
+
+/*
+ * This function is called when the user or kernel loads the
+ * module into memory.
+ */
+
+
+static int init_via82cxxx_module(void)
+{
+ u8 tmp;
+ int i;
+ const char *rev = "unknown!";
+
+ memset (cards, 0, sizeof (cards));
+
+ DPRINTK ("ENTER\n");
+
+ if (!pci_present ()) {
+ printk (KERN_DEBUG PFX "PCI not present, exiting\n");
+ DPRINTK ("EXIT, returning -ENODEV\n");
+ return -ENODEV;
+ }
+
+ if (probe_via82cxxx() != 0) {
+ printk(KERN_ERR PFX "probe failed, aborting\n");
+ /* XXX unload cards registered so far, if any */
+ DPRINTK ("EXIT, returning -ENODEV\n");
+ return -ENODEV;
+ }
+
+ pci_read_config_byte (cards[0].pdev, PCI_REVISION_ID, &tmp);
+ for (i = 0; i < arraysize(via_chip_revs); i++)
+ if (via_chip_revs[i].revision == tmp) {
+ rev = via_chip_revs[i].rev_name;
+ break;
+ }
+ printk (KERN_INFO PFX VIA_CARD_NAME " loaded\n");
+ printk (KERN_INFO PFX "Chip rev %s. Features: SBPro compat%s%s\n",
+ rev,
+ cards[0].opl3_data.io_base == 0 ? "" : ", MPU-401 MIDI",
+ cards[0].have_ac97 == -1 ? "" : ", AC97 mixer");
+
+ if (via_init_proc () != 0) {
+ printk (KERN_WARNING PFX
+ "Unable to init experimental /proc, ignoring\n");
+ }
+
+ /*
+ * Binds us to the sound subsystem
+ */
+ SOUND_LOCK;
+ DPRINTK ("EXIT, returning 0\n");
+ return 0;
+}
+
+int init_module(void) {
+ return init_via82cxxx_module();
+}
+
+/*
+ * This is called when it is removed. It will only be removed
+ * when its use count is 0. For sound the SOUND_LOCK/SOUND_UNLOCK
+ * macros hide the entire work for this.
+ */
+
+static void cleanup_via82cxxx_module(void)
+{
+ DPRINTK("ENTER\n");
+
+ if (cards[0].opl3_data.io_base)
+ unload_uart401 (&cards[0].opl3_data);
+
+ via_unload_sb (&cards[0].sb_data);
+
+ via_unload_ac97 (&cards[0]);
+
+ via_cleanup_proc ();
+
+ /*
+ * Final clean up with the sound layer
+ */
+ SOUND_LOCK_END;
+
+ DPRINTK("EXIT\n");
+}
+
+void cleanup_module(void) {
+ cleanup_via82cxxx_module();
+}
+
/* This is the point of no return */
release_old_signals(oldsig);
+ current->sas_ss_sp = current->sas_ss_size = 0;
+
if (current->euid == current->uid && current->egid == current->gid)
current->dumpable = 1;
name = bprm->filename;
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
+#include <linux/init.h>
#include <asm/byteorder.h>
static struct nls_table *tables = (struct nls_table *) NULL;
EXPORT_SYMBOL(utf8_wctomb);
EXPORT_SYMBOL(utf8_wcstombs);
-int init_nls(void)
+int __init init_nls(void)
{
#ifdef CONFIG_NLS_ISO8859_1
init_nls_iso8859_1();
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp437(void)
+int __init init_nls_cp437(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp737(void)
+int __init init_nls_cp737(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp775(void)
+int __init init_nls_cp775(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp850(void)
+int __init init_nls_cp850(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp852(void)
+int __init init_nls_cp852(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp855(void)
+int __init init_nls_cp855(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp857(void)
+int __init init_nls_cp857(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp860(void)
+int __init init_nls_cp860(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp861(void)
+int __init init_nls_cp861(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp862(void)
+int __init init_nls_cp862(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp863(void)
+int __init init_nls_cp863(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp864(void)
+int __init init_nls_cp864(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp865(void)
+int __init init_nls_cp865(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp866(void)
+int __init init_nls_cp866(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp869(void)
+int __init init_nls_cp869(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_cp874(void)
+int __init init_nls_cp874(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode c2u_81[256] = {
{0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, /* 0x00-0x03 */
NULL
};
-int init_nls_cp932(void)
+int __init init_nls_cp932(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode c2u_81[256] = {
{0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, /* 0x00-0x03 */
NULL
};
-int init_nls_cp936(void)
+int __init init_nls_cp936(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode c2u_81[256] = {
{0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, /* 0x00-0x03 */
NULL
};
-int init_nls_cp949(void)
+int __init init_nls_cp949(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode c2u_A1[256] = {
{0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, /* 0x00-0x03 */
NULL
};
-int init_nls_cp950(void)
+int __init init_nls_cp950(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_iso8859_1(void)
+int __init init_nls_iso8859_1(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};
+static void uni2char(unsigned char ch, unsigned char cl, unsigned char *out, int boundlen, int *outlen)
+{
+ unsigned char *uni2charset;
+
+ if (boundlen <= 0)
+ return;
+
+ uni2charset = page_uni2charset[ch];
+ if (uni2charset && uni2charset[cl])
+ out[0] = uni2charset[cl];
+ else
+ out[0] = '?';
+ *outlen = 1;
+ return;
+}
+
+static void char2uni(unsigned char *rawstring, int *offset, unsigned char *uni1, unsigned char *uni2)
+{
+ *uni1 = charset2uni[*rawstring].uni1;
+ *uni2 = charset2uni[*rawstring].uni2;
+ *offset = 1;
+ return;
+}
+
static void inc_use_count(void)
{
MOD_INC_USE_COUNT;
static struct nls_table table = {
"iso8859-14",
- page_uni2charset,
- charset2uni,
+ uni2char,
+ char2uni,
inc_use_count,
dec_use_count,
NULL
};
-int init_nls_iso8859_14(void)
+int __init init_nls_iso8859_14(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_iso8859_15(void)
+int __init init_nls_iso8859_15(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_iso8859_2(void)
+int __init init_nls_iso8859_2(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_iso8859_3(void)
+int __init init_nls_iso8859_3(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_iso8859_4(void)
+int __init init_nls_iso8859_4(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_iso8859_5(void)
+int __init init_nls_iso8859_5(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_iso8859_6(void)
+int __init init_nls_iso8859_6(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_iso8859_7(void)
+int __init init_nls_iso8859_7(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_iso8859_8(void)
+int __init init_nls_iso8859_8(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_iso8859_9(void)
+int __init init_nls_iso8859_9(void)
{
return register_nls(&table);
}
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/nls.h>
+#include <linux/init.h>
static struct nls_unicode charset2uni[256] = {
/* 0x00*/
NULL
};
-int init_nls_koi8_r(void)
+int __init init_nls_koi8_r(void)
{
return register_nls(&table);
}
fp = rw->ins[6] + bias;
} while (++count < 16);
}
+#elif defined (__s390__)
+ {
+ unsigned long ksp, backchain, ip;
+ unsigned long stack_page;
+ int count = 0;
+
+ stack_page = (unsigned long)p;
+ ksp = p->tss.ksp;
+ if (!stack_page || ksp < stack_page || ksp >= 8188+stack_page)
+ return 0;
+ backchain = (*(unsigned long *) ksp) & 0x7fffffff;
+ do {
+ if (backchain < stack_page || backchain >= 8188+stack_page)
+ return 0;
+ ip = (*(unsigned long *) (backchain+56)) & 0x7fffffff;
+ if (ip < first_sched || ip >= last_sched)
+ return ip;
+ backchain = (*(unsigned long *) backchain) & 0x7fffffff;
+ } while (count++ < 16);
+ }
#endif
return 0;
#define DEVSTAT_DEVICE_GONE 0x00000040
#define DEVSTAT_DEVICE_OWNED 0x00000080
#define DEVSTAT_CLEAR_FUNCTION 0x00000100
+#define DEVSTAT_PCI 0x00000200
+#define DEVSTAT_SUSPENDED 0x00000400
#define DEVSTAT_FINAL_STATUS 0x80000000
#define INTPARM_STATUS_PENDING 0xFFFFFFFF
extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
{
address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
- if (pmd_none(*pmd)) {
- pte_t * page = (pte_t *) get_pte_fast();
-
- if (!page)
- return get_pte_kernel_slow(pmd, address);
- pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(page);
- pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(page+1024);
- pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(page+2048);
- pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(page+3072);
- return page + address;
- }
- if (pmd_bad(*pmd)) {
- __bad_pte_kernel(pmd);
- return NULL;
- }
+
+ if (pmd_none(*pmd))
+ goto getnew;
+ if (pmd_bad(*pmd))
+ goto fix;
return (pte_t *) pmd_page(*pmd) + address;
+getnew:
+{
+ unsigned long page = (unsigned long) get_pte_fast();
+
+ if (!page)
+ return get_pte_kernel_slow(pmd, address);
+ pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(page);
+ pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(page+1024);
+ pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(page+2048);
+ pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(page+3072);
+ return (pte_t *) page + address;
+}
+fix:
+ __bad_pte_kernel(pmd);
+ return NULL;
}
extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
+
/*
* include/asm-s390/ptrace.h
*
* this is the way intel does it
*/
per_struct per_info;
+ addr_t ieee_instruction_pointer;
+ /* Used to give failing instruction back to user for ieee exceptions */
};
typedef struct user_regs_struct user_regs_struct;
PT_CR_9=pt_off(per_info.control_regs.words.cr[0]),
PT_CR_10=pt_off(per_info.control_regs.words.cr[1]),
PT_CR_11=pt_off(per_info.control_regs.words.cr[2]),
- PT_LASTOFF=PT_CR_11,
- PT_ENDREGS=offsetof(user_regs_struct,per_info.lowcore.words.perc_atmid)
+ PT_IEEE_IP=pt_off(ieee_instruction_pointer),
+ PT_LASTOFF=PT_IEEE_IP,
+ PT_ENDREGS=sizeof(user_regs_struct)-1
};
#define PTRACE_AREA \
freg_t fprs[NUM_FPRS];
} s390_fp_regs;
+#define FPC_DXC_MASK 0x0000FF00
+#define FPC_EXCEPTION_MASK 0xF8000000
+#define FPC_FLAGS_MASK 0x00F80000
+#define FPC_RM_MASK 0x00000003
+
+
/*
gdb structures & the kernel have this much always in common
*/
devstat_t devstat; /* device status */
ccw1_t *qcpa; /* queued channel program */
ccw1_t senseccw; /* ccw for sense command */
+ __u8 sense_data[32];/* buffer for basic sense */
unsigned int stctl; /* accumulated status control from irb */
unsigned long qintparm; /* queued interruption parameter */
unsigned long qflag; /* queued flags */
#define _LINUX_CAPABILITY_H
#include <linux/types.h>
-#include <linux/fs.h>
/* User-level do most of the mapping between kernel and user
capabilities based on the version tag given by the kernel. The
extern int init_nls_iso8859_7(void);
extern int init_nls_iso8859_8(void);
extern int init_nls_iso8859_9(void);
+extern int init_nls_iso8859_14(void);
extern int init_nls_iso8859_15(void);
extern int init_nls_cp437(void);
extern int init_nls_cp737(void);
#define PCI_VENDOR_ID_AFAVLAB 0x14db
#define PCI_DEVICE_ID_AFAVLAB_TK9902 0x2120
+#define PCI_VENDOR_ID_TIMEDIA 0x1409
+#define PCI_DEVICE_ID_TIMEDIA_4008A 0x7268
+
#define PCI_VENDOR_ID_SYMPHONY 0x1c1c
#define PCI_DEVICE_ID_SYMPHONY_101 0x0001
* Pick up the architecture specific timex specifications
*/
#include <asm/timex.h>
+/*
+ * Pick up the definition of timeval
+ */
+#include <linux/time.h>
/* LATCH is used in the interval timer and ftape setup. */
#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
Original driver (sg.h):
* Copyright (C) 1992 Lawrence Foard
2.x extensions to driver:
-* Copyright (C) 1998, 1999 Douglas Gilbert
+* Copyright (C) 1998 - 2000 Douglas Gilbert
-
- Version: 2.1.36 (991008)
+ Version: 2.1.37 (20000504)
This version for 2.2.x series kernels
D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
+ Changes since 2.1.36 (991008)
+ - fix 0 length scatter gather requests + alignment
+ - activate SG_SCSI_RESET ioctl() [to work needs mid level changes]
Changes since 2.1.34 (990603)
- skipped 2.1.35 (never fully released)
- add queuing info into struct sg_scsi_id
- clean up logging of pointers to use %p (for 64 bit architectures)
- rework usage of get_user/copy_to_user family of kernel calls
- "disown" scsi_command blocks before releasing them
- Changes since 2.1.30 (990320)
- - memory tweaks: change flags on kmalloc (GFP_KERNEL to GFP_ATOMIC)
- - increase max allowable mid-level pool usage
+Map of SG verions to the Linux kernels in which they appear:
+ ---------- ----------------------------------
+ original all kernels < 2.2.6
+ 2.1.31 2.2.6 and 2.2.7
+ 2.1.32 2.2.8 and 2.2.9
+ 2.1.34 2.2.10 to 2.2.13
+ 2.1.36 2.2.14 and 2.2.15
+ 2.1.37 2.2.16
+ 3.0.13 optional version 3 sg driver for 2.2 series
+ 3.1.13 2.3.99-pre5, version 3 sg driver for 2.3 series
New features and changes:
- - per file descriptor (fd) write-read sequencing and command queues.
- - command queuing supported (SG_MAX_QUEUE is maximum per fd).
+ - per file descriptor (fd) write-read sequencing
+ - command queuing supported
- scatter-gather supported (allowing potentially megabyte transfers).
- - the SCSI target, host and driver status are returned
- in unused fields of sg_header (maintaining its original size).
- - asynchronous notification support added (SIGPOLL, SIGIO) for
- read()s (write()s should never block).
+ - more SCSI status information returned
+ - asynchronous notification support added (SIGPOLL, SIGIO)
- pack_id logic added so read() can wait for a specific pack_id.
- uses memory > ISA_DMA_THRESHOLD if adapter allows it (e.g. a
pci scsi adapter).
calling the ioctl of the same name is a more flexible and
safer approach.
- adds several ioctl calls, see ioctl section below.
-
- Good documentation on the original "sg" device interface and usage can be
- found in the Linux HOWTO document: "SCSI Programming HOWTO" (version 0.5)
- by Heiko Eissfeldt; last updated 7 May 1996. Here is a quick summary of
- sg basics:
- An SG device is accessed by writing SCSI commands plus any associated
- outgoing data to it; the resulting status codes and any incoming data
- are then obtained by a read call. The device can be opened O_NONBLOCK
- (non-blocking) and poll() used to monitor its progress. The device may be
- opened O_EXCL which excludes other "sg" users from this device (but not
- "sd", "st" or "sr" users). The buffer given to the write() call is made
- up as follows:
- - struct sg_header image (see below)
- - scsi command (6, 10 or 12 bytes long)
- - data to be written to the device (if any)
-
- The buffer received from the corresponding read() call contains:
- - struct sg_header image (check results + sense_buffer)
- - data read back from device (if any)
-
- The given SCSI command has its LUN field overwritten internally by the
- value associated with the device that has been opened.
-
- This device currently uses "indirect IO" in the sense that data is
- DMAed into kernel buffers from the hardware and afterwards is
- transferred into the user space (or vice versa if you are writing).
- Transfer speeds or up to 20 to 30MBytes/sec have been measured using
- indirect IO. For faster throughputs "direct IO" which cuts out the
- double handling of data is required. This will also need a new interface.
-
- Grabbing memory for those kernel buffers used in this driver for DMA may
- cause the dreaded ENOMEM error. This error seems to be more prevalent
- under early 2.2.x kernels than under the 2.0.x kernel series. For a given
- (large) transfer the memory obtained by this driver must be contiguous or
- scatter-gather must be used (if supported by the adapter). [Furthermore,
- ISA SCSI adapters can only use memory below the 16MB level on a i386.]
-
- When a "sg" device is open()ed O_RDWR then this driver will attempt to
- reserve a buffer of SG_DEF_RESERVED_SIZE that will be used by subsequent
- write()s on this file descriptor as long as:
- - it is not already in use (eg when command queuing is in use)
- - the write() does not call for a buffer size larger than the
- reserved size.
- In these cases the write() will attempt to find the memory it needs for
- DMA buffers dynamically and in the worst case will fail with ENOMEM.
- The amount of memory actually reserved depends on various dynamic factors
- and can be checked with the SG_GET_RESERVED_SIZE ioctl(). [In a very
- tight memory situation it may yield 0!] The size of the reserved buffer
- can be changed with the SG_SET_RESERVED_SIZE ioctl(). It should be
- followed with a call to the SG_GET_RESERVED_SIZE ioctl() to find out how
- much was actually reserved.
-
- More documentation plus test and utility programs can be found at
- http://www.torque.net/sg
+
+ Documentation
+ =============
+ A web site for SG device drivers can be found at:
+ http://www.torque.net/sg [alternatively check the MAINTAINERS file]
+ The main documents are still based on 2.x versions:
+ http://www.torque.net/sg/p/scsi-generic.txt
+ http://www.torque.net/sg/p/scsi-generic_long.txt
+ The first document can also be found in the kernel source tree, probably at:
+ /usr/src/linux/Documentation/scsi-generic.txt .
+ Documentation on the changes and additions in 3.x version of the sg driver
+ can be found at: http://www.torque.net/sg/p/scsi-generic_v3.txt
+ Utility and test programs are also available at that web site.
*/
+
#define SG_MAX_SENSE 16 /* too little, unlikely to change in 2.2.x */
#define SG_NEXT_CMD_LEN 0x2283 /* override SCSI command length with given
number on the next write() on this file descriptor */
-/* Returns -EBUSY if occupied else takes as input: 0 -> do nothing,
- 1 -> device reset or 2 -> bus reset (not operational yet) */
+/* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */
#define SG_SCSI_RESET 0x2284
+/* Associated values that can be given to SG_SCSI_RESET follow */
+#define SG_SCSI_RESET_NOTHING 0
+#define SG_SCSI_RESET_DEVICE 1
+#define SG_SCSI_RESET_BUS 2
+#define SG_SCSI_RESET_HOST 3
#define SG_SCATTER_SZ (8 * 4096) /* PAGE_SIZE not available to user */
EXPORT_SYMBOL(add_mouse_randomness);
EXPORT_SYMBOL(fasync_helper);
-#ifdef CONFIG_BLK_DEV_MD
-EXPORT_SYMBOL(disk_name); /* for md.c */
-#endif
+EXPORT_SYMBOL(disk_name); /* for md.c and others */
/* binfmt_aout */
EXPORT_SYMBOL(get_write_access);
--- /dev/null
+--- linux/include/scsi/sg.h Thu Jan 13 20:40:36 2000
++++ linux/include/scsi/sg.h2137 Thu May 4 01:25:19 2000
+@@ -9,13 +9,15 @@
+ Original driver (sg.h):
+ * Copyright (C) 1992 Lawrence Foard
+ 2.x extensions to driver:
+-* Copyright (C) 1998, 1999 Douglas Gilbert
+-
++* Copyright (C) 1998 - 2000 Douglas Gilbert
+
+- Version: 2.1.36 (991008)
++ Version: 2.1.37 (20000504)
+ This version for 2.2.x series kernels
+ D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
+
++ Changes since 2.1.36 (991008)
++ - fix 0 length scatter gather requests + alignment
++ - activate SG_SCSI_RESET ioctl() [to work needs mid level changes]
+ Changes since 2.1.34 (990603)
+ - skipped 2.1.35 (never fully released)
+ - add queuing info into struct sg_scsi_id
+@@ -35,19 +37,24 @@
+ - clean up logging of pointers to use %p (for 64 bit architectures)
+ - rework usage of get_user/copy_to_user family of kernel calls
+ - "disown" scsi_command blocks before releasing them
+- Changes since 2.1.30 (990320)
+- - memory tweaks: change flags on kmalloc (GFP_KERNEL to GFP_ATOMIC)
+- - increase max allowable mid-level pool usage
+
++Map of SG verions to the Linux kernels in which they appear:
++ ---------- ----------------------------------
++ original all kernels < 2.2.6
++ 2.1.31 2.2.6 and 2.2.7
++ 2.1.32 2.2.8 and 2.2.9
++ 2.1.34 2.2.10 to 2.2.13
++ 2.1.36 2.2.14 and 2.2.15
++ 2.1.37 2.2.16
++ 3.0.13 optional version 3 sg driver for 2.2 series
++ 3.1.13 2.3.99-pre5, version 3 sg driver for 2.3 series
+
+ New features and changes:
+- - per file descriptor (fd) write-read sequencing and command queues.
+- - command queuing supported (SG_MAX_QUEUE is maximum per fd).
++ - per file descriptor (fd) write-read sequencing
++ - command queuing supported
+ - scatter-gather supported (allowing potentially megabyte transfers).
+- - the SCSI target, host and driver status are returned
+- in unused fields of sg_header (maintaining its original size).
+- - asynchronous notification support added (SIGPOLL, SIGIO) for
+- read()s (write()s should never block).
++ - more SCSI status information returned
++ - asynchronous notification support added (SIGPOLL, SIGIO)
+ - pack_id logic added so read() can wait for a specific pack_id.
+ - uses memory > ISA_DMA_THRESHOLD if adapter allows it (e.g. a
+ pci scsi adapter).
+@@ -68,61 +75,21 @@
+ calling the ioctl of the same name is a more flexible and
+ safer approach.
+ - adds several ioctl calls, see ioctl section below.
+-
+- Good documentation on the original "sg" device interface and usage can be
+- found in the Linux HOWTO document: "SCSI Programming HOWTO" (version 0.5)
+- by Heiko Eissfeldt; last updated 7 May 1996. Here is a quick summary of
+- sg basics:
+- An SG device is accessed by writing SCSI commands plus any associated
+- outgoing data to it; the resulting status codes and any incoming data
+- are then obtained by a read call. The device can be opened O_NONBLOCK
+- (non-blocking) and poll() used to monitor its progress. The device may be
+- opened O_EXCL which excludes other "sg" users from this device (but not
+- "sd", "st" or "sr" users). The buffer given to the write() call is made
+- up as follows:
+- - struct sg_header image (see below)
+- - scsi command (6, 10 or 12 bytes long)
+- - data to be written to the device (if any)
+-
+- The buffer received from the corresponding read() call contains:
+- - struct sg_header image (check results + sense_buffer)
+- - data read back from device (if any)
+-
+- The given SCSI command has its LUN field overwritten internally by the
+- value associated with the device that has been opened.
+
+- This device currently uses "indirect IO" in the sense that data is
+- DMAed into kernel buffers from the hardware and afterwards is
+- transferred into the user space (or vice versa if you are writing).
+- Transfer speeds or up to 20 to 30MBytes/sec have been measured using
+- indirect IO. For faster throughputs "direct IO" which cuts out the
+- double handling of data is required. This will also need a new interface.
+-
+- Grabbing memory for those kernel buffers used in this driver for DMA may
+- cause the dreaded ENOMEM error. This error seems to be more prevalent
+- under early 2.2.x kernels than under the 2.0.x kernel series. For a given
+- (large) transfer the memory obtained by this driver must be contiguous or
+- scatter-gather must be used (if supported by the adapter). [Furthermore,
+- ISA SCSI adapters can only use memory below the 16MB level on a i386.]
+-
+- When a "sg" device is open()ed O_RDWR then this driver will attempt to
+- reserve a buffer of SG_DEF_RESERVED_SIZE that will be used by subsequent
+- write()s on this file descriptor as long as:
+- - it is not already in use (eg when command queuing is in use)
+- - the write() does not call for a buffer size larger than the
+- reserved size.
+- In these cases the write() will attempt to find the memory it needs for
+- DMA buffers dynamically and in the worst case will fail with ENOMEM.
+- The amount of memory actually reserved depends on various dynamic factors
+- and can be checked with the SG_GET_RESERVED_SIZE ioctl(). [In a very
+- tight memory situation it may yield 0!] The size of the reserved buffer
+- can be changed with the SG_SET_RESERVED_SIZE ioctl(). It should be
+- followed with a call to the SG_GET_RESERVED_SIZE ioctl() to find out how
+- much was actually reserved.
+-
+- More documentation plus test and utility programs can be found at
+- http://www.torque.net/sg
++ Documentation
++ =============
++ A web site for SG device drivers can be found at:
++ http://www.torque.net/sg [alternatively check the MAINTAINERS file]
++ The main documents are still based on 2.x versions:
++ http://www.torque.net/sg/p/scsi-generic.txt
++ http://www.torque.net/sg/p/scsi-generic_long.txt
++ The first document can also be found in the kernel source tree, probably at:
++ /usr/src/linux/Documentation/scsi-generic.txt .
++ Documentation on the changes and additions in 3.x version of the sg driver
++ can be found at: http://www.torque.net/sg/p/scsi-generic_v3.txt
++ Utility and test programs are also available at that web site.
+ */
++
+
+ #define SG_MAX_SENSE 16 /* too little, unlikely to change in 2.2.x */
+
+@@ -213,9 +180,13 @@
+ #define SG_NEXT_CMD_LEN 0x2283 /* override SCSI command length with given
+ number on the next write() on this file descriptor */
+
+-/* Returns -EBUSY if occupied else takes as input: 0 -> do nothing,
+- 1 -> device reset or 2 -> bus reset (not operational yet) */
++/* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */
+ #define SG_SCSI_RESET 0x2284
++/* Associated values that can be given to SG_SCSI_RESET follow */
++#define SG_SCSI_RESET_NOTHING 0
++#define SG_SCSI_RESET_DEVICE 1
++#define SG_SCSI_RESET_BUS 2
++#define SG_SCSI_RESET_HOST 3
+
+
+ #define SG_SCATTER_SZ (8 * 4096) /* PAGE_SIZE not available to user */
+--- linux/drivers/scsi/sg.c Thu Jan 13 20:40:23 2000
++++ linux/drivers/scsi/sg.c2137 Thu May 4 01:24:01 2000
+@@ -7,7 +7,7 @@
+ * Original driver (sg.c):
+ * Copyright (C) 1992 Lawrence Foard
+ * 2.x extensions to driver:
+- * Copyright (C) 1998, 1999 Douglas Gilbert
++ * Copyright (C) 1998 - 2000 Douglas Gilbert
+ *
+ * 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
+@@ -16,8 +16,8 @@
+ *
+ * Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book.
+ */
+- static char * sg_version_str = "Version: 2.1.36 (991218)";
+- static int sg_version_num = 20136; /* 2 digits for each component */
++ static char * sg_version_str = "Version: 2.1.37 (20000504)";
++ static int sg_version_num = 20137; /* 2 digits for each component */
+ /*
+ * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
+ * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
+@@ -100,7 +100,7 @@
+ static void sg_detach(Scsi_Device *);
+
+
+-struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", NULL, 0xff,
++struct Scsi_Device_Template sg_template = {NULL, "generic", "sg", NULL, 0xff,
+ SCSI_GENERIC_MAJOR, 0, 0, 0, 0,
+ sg_detect, sg_init,
+ sg_finish, sg_attach, sg_detach};
+@@ -609,8 +609,29 @@
+ return -EBUSY;
+ result = get_user(val, (int *)arg);
+ if (result) return result;
+- /* Don't do anything till scsi mod level visibility */
+- return 0;
++ if (SG_SCSI_RESET_NOTHING == val)
++ return 0;
++#ifdef SCSI_TRY_RESET_DEVICE
++ switch (val)
++ {
++ case SG_SCSI_RESET_DEVICE:
++ val = SCSI_TRY_RESET_DEVICE;
++ break;
++ case SG_SCSI_RESET_BUS:
++ val = SCSI_TRY_RESET_BUS;
++ break;
++ case SG_SCSI_RESET_HOST:
++ val = SCSI_TRY_RESET_HOST;
++ break;
++ default:
++ return -EINVAL;
++ }
++ if(! capable(CAP_SYS_ADMIN)) return -EACCES;
++ return (scsi_reset_provider(sdp->device, val) == SUCCESS) ? 0 : -EIO;
++#else
++ SCSI_LOG_TIMEOUT(1, printk("sg_ioctl: SG_RESET_SCSI not supported\n"));
++ result = -EINVAL;
++#endif
+ case SCSI_IOCTL_SEND_COMMAND:
+ /* Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the
+ user already has read/write access to the generic device and so
+@@ -1124,6 +1145,8 @@
+
+ SCSI_LOG_TIMEOUT(4, printk("sg_start_req: max_buff_size=%d\n",
+ max_buff_size));
++ if (max_buff_size <= 0)
++ return 0;
+ if ((! sg_res_in_use(sfp)) && (max_buff_size <= rsv_schp->bufflen)) {
+ sg_link_reserve(sfp, srp, max_buff_size);
+ sg_write_xfer(req_schp, inp, num_write_xfer);
+@@ -1351,6 +1374,8 @@
+ Sg_scatter_hold * rsv_schp = &sfp->reserve;
+
+ SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size));
++ /* round request up to next highest SG_SECTOR_SZ byte boundary */
++ size = (size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK);
+ if (rsv_schp->use_sg > 0) {
+ int k, num;
+ int rem = size;
+@@ -1431,12 +1456,12 @@
+ static Sg_request * sg_add_request(Sg_fd * sfp)
+ {
+ int k;
+- Sg_request * resp = NULL;
+- Sg_request * rp;
++ Sg_request * resp = sfp->headrp;
++ Sg_request * rp = sfp->req_arr;
+
+- resp = sfp->headrp;
+- rp = sfp->req_arr;
+ if (! resp) {
++ memset(rp, 0, sizeof(Sg_request));
++ rp->parentfp = sfp;
+ resp = rp;
+ sfp->headrp = resp;
+ }
+@@ -1444,12 +1469,15 @@
+ if (0 == sfp->cmd_q)
+ resp = NULL; /* command queuing disallowed */
+ else {
+- for (k = 0, rp; k < SG_MAX_QUEUE; ++k, ++rp) {
++ for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
+ if (! rp->parentfp)
+ break;
+ }
+ if (k < SG_MAX_QUEUE) {
+- while (resp->nextrp) resp = resp->nextrp;
++ memset(rp, 0, sizeof(Sg_request));
++ rp->parentfp = sfp;
++ while (resp->nextrp)
++ resp = resp->nextrp;
+ resp->nextrp = rp;
+ resp = rp;
+ }
+@@ -1458,11 +1486,7 @@
+ }
+ }
+ if (resp) {
+- resp->parentfp = sfp;
+ resp->nextrp = NULL;
+- resp->res_used = 0;
+- memset(&resp->data, 0, sizeof(Sg_scatter_hold));
+- memset(&resp->header, 0, sizeof(struct sg_header));
+ resp->my_cmdp = NULL;
+ }
+ return resp;
+@@ -1478,14 +1502,14 @@
+ return 0;
+ prev_rp = sfp->headrp;
+ if (srp == prev_rp) {
+- prev_rp->parentfp = NULL;
+ sfp->headrp = prev_rp->nextrp;
++ prev_rp->parentfp = NULL;
+ return 1;
+ }
+ while ((rp = prev_rp->nextrp)) {
+ if (srp == rp) {
+- rp->parentfp = NULL;
+ prev_rp->nextrp = rp->nextrp;
++ rp->parentfp = NULL;
+ return 1;
+ }
+ prev_rp = rp;