-This is the new release of a module network device driver for General
-Instruments (also known as NextLevel) SB1000 cable modem board (also
-called internal SURFboard).
-I have tested and I am running this module on kernel 2.0.33.
-Steven N. Hirsch <shirsch@adelphia.net> gave me a diff patch
-(sb1000-1.1.2_127.patch to be applied with 'patch -p') that allows
-you to compile and run the driver with kernel versions 2.1.x.
-Thanks very much Steve!
-
-Here you'll the following files:
-
-- README
-- Makefile
-- sb1000.c the actual device driver
-- cmconfig.c an ifconfig-like program to correctly set the SB1000
-- cmping.c a ping-like program to test your connection
-- ftptest.c a small program to test your connection speed with FTP
- (requires ftplib version >= 3.0)
-
-The directory ppp/ contains the files I am using to connect to MediaOne
-here in Jacksonville, to show how you can use the driver and the cmconfig
-program.
-
-Clemmitt Sigler wrote a very good and useful web page and installation
-script (for Adelphia PowerLink users but easy to port to other ISPs)
-about this SB1000 driver for Linux.
-You can find it here:
- http://home.adelphia.net/~siglercm/sb1000.html
-Thanks very much Clemmitt!
-
-To install and run it:
-- cd sb1000-1.1.2
-- make
-- make install
-- configure the SB1000 card using the isapnp tools setting the correct
- I/O's and IRQ. You can find more info about the isapnp tools at:
- http://www.roestock.demon.co.uk/isapnptools/
- (once you're happy with it, you may want to set the configuration
- at boot time in one of the /etc/init.d/ scripts)
- IMPORTANT NOTICE: after configuring isapnp, please look in the file
- /etc/isapnp.conf for the line beginning with:
- (READPORT
- if it says: '(READPORT 0x0203)' (which should be the default), then
- go to the next step. If instead it says something like:
- '(READPORT 0x020b)' or '(READPORT 0x<another number>)', then please
- follow the instructions at the end of this README file before going
- to the next step.
-- install the PPP configuration files in the /etc/ppp directory; you
- definitely have to change the file ppp@gi-on (the start up file),
- setting the correct login name, the phone number for the PPP connection
- and the frequency (k stands for kHz, M for MHz) for the cablemodem.
- You'll also have to change the last line in the pap-secrets file
- writing your login and password there (read the whole file for more
- site specific configurations).
- You may have to change the firewall file to suit your needs (IPs and
- ports allowed to connect).
-- start the PPP connection with ppp@gi-on and see what happens; you may
- want to set 'pppd' (the last command in the ppp@gi-on file) to debug
- mode adding 'debug' at the end of the command ('pppd' prints its info in
- the file /var/log/messages and/or /var/log/ppp.log). To make sure 'chat'
- s not having problems you may want to add a '-v' (verbose) after the 'chat'
- command in 'ppp-on-dialer' and check the results in /var/log/messages)
-- if everything is working fine you should see after a few seconds a message
- likes this:
- cm0: sb1000 at (0x120,0x310), csn 1, S/N 0x2a0d16d8, IRQ 9.
- sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net)
- and ifconfig -a should show you two new interfaces: ppp0 and cm0.
- Typing 'cmconfig cm0' will show you more info about the cablemodem interface.
-- please let me know if you see any other message coming from 'cm0' in
- your '/var/log/messages' or '/var/log/debug' file, to help me debug the
- code
-- also let me know if you have any problem; if everything works (hopefully),
- let me know which speed you can reach downloading the 5Mb test file using
- this driver.
-- if everything seems to work fine but your computer locks up after a while
- (and typically during a lengthy download through the cablemodem), you may
- need to add a short delay in the driver to 'slow down' the SURFboard
- because your PC might not be able to keep up with the transfer rate of
- the SB1000. To do this, edit the 'Makefile' and look for the 'SB1000_DELAY'
- define: uncomment those 'CFLAGS' lines (and comment the default ones)
- and try setting the delay to something like 60 microseconds with:
- '-DSB1000_DELAY=60'; if it still doesn't work or you like playing with
- the driver, you may try other numbers: remember though that the higher
- the delay, the slower the driver (which slows down the rest of the PC
- too when it is actively used). Thanks to Ed Daiga for this tip!
-
-This release has a few things fixed and a better handling of the frame errors.
-
-I also have slightly modified the 'cablemodem' script in the 'ppp' so
-you may interested in having a look at it: I basically have added filtering
-out broadcast messages (you shouldn't get them with a point-to-point
-interface and so far the ones I have received were from hosts trying to
-attack my system) and lower debug levels for the driver to avoid seeing
-the 'frame error' messages (so far noone has noticed any problem with the
-driver even with those messages).
-
-For questions, infos, etc, feel free to email me at:
- fventuri@mediaone.net
-
-Good luck,
-Franco Venturi
-
-Thanks to Edge for his useful comments and to Steven N. Hirsch
-for his patch to run the driver with 2.1.x kernels.
-Thanks also to Ed Daiga for his help in finding that adding a delay
-in the driver fixes some lock up problems with some slow PCs.
-Many thanks to Clemmitt Sigler for his (much needed) web page about the
-SB1000 driver for Linux.
-An interesting URL for Linux + MediaOne (although with an external modem)
-is: http://rlz.ne.mediaone.net/linux/home.shtml
-Today, Sep 22 1998, I finished writing a short utility (ftptest.c) to
-'measure' your cablemodem speed connection in Linux, downloading to
-memory the same file several times. To compile it you need ftplib, version
-3 or above. To run it, type:
- ftptest URL n
-where URL is in the form: ftp://ftp.site.local.isp/pub/testfile
-and n is the number of simultaneous FTP connections that you want to run
-
----------------------------------------------------------------------------
-IMPORTANT NOTICE: if in your file /etc/isapnp.conf, you found something
-like '(READPORT 0x020b)' or '(READPORT 0x<another number>)', (anything
-different from the default 0x0203), you have to change the READ_DATA_PORT
-parameter in the sb1000.c file as follows.
- - edit the sb1000.c file, look for:
- READ_DATA_PORT
- (it should be around line 127 in version 1.1.2)
- - change the value of READ_DATA_PORT to the same value found in
- /etc/isapnp.conf; for instance, if you found a: '(READPORT 0x020b)',
- then in sb1000.c you should have:
- static const int READ_DATA_PORT = 0x20b;
- - save sb1000.c
- - compile and install again the driver
- (i.e. do a 'make' and a 'make install').
+sb1000 is a module network device driver for the General Instrument (also known
+as NextLevel) SURFboard1000 internal cable modem board. This is an ISA card
+which is used by a number of cable TV companies to provide cable modem access.
+It's a one-way downstream-only cable modem, meaning that your upstream net link
+is provided by your regular phone modem.
+
+This driver was written by Franco Venturi <fventuri@mediaone.net>. He deserves
+a great deal of thanks for this wonderful piece of code!
+
+-----------------------------------------------------------------------------
+
+Support for this device is now a part of the standard Linux kernel. The
+driver source code file is drivers/net/sb1000.c. In addition to this
+you will need:
+
+1.) The "cmconfig" program. This is a utility which supplements "ifconfig"
+to configure the cable modem and network interface (usually called "cm0");
+and
+
+2.) Several PPP scripts which live in /etc/ppp to make connecting via your
+cable modem easy.
+
+ These utilities can be obtained from:
+
+ http://www.jacksonville.net/~fventuri/
+
+ in Franco's original source code distribution .tar.gz file. Support for
+ the sb1000 driver can be found at:
+
+ http://home.adelphia.net/~siglercm/sb1000.html
+ http://linuxpower.cx/~cable/
+
+ along with these utilties.
+
+3.) The standard isapnp tools. These are necessary to configure your SB1000
+card at boot time (or afterwards by hand) since it's a PnP card.
+
+ If you don't have these installed as a standard part of your Linux
+ distribution, you can find them at:
+
+ http://www.roestock.demon.co.uk/isapnptools/
+
+ or check your Linux distribution binary CD or their web site. For help with
+ isapnp, pnpdump, or /etc/isapnp.conf, go to:
+
+ http://www.roestock.demon.co.uk/isapnptools/isapnpfaq.html
+
+-----------------------------------------------------------------------------
+
+To make the SB1000 card work, follow these steps:
+
+1.) Run `make config', or `make menuconfig', or `make xconfig', whichever
+you prefer, in the top kernel tree directory to set up your kernel
+configuration. Make sure to say "Y" to "Prompt for development drivers"
+and to say "M" to the sb1000 driver. Also say "Y" or "M" to all the standard
+networking questions to get TCP/IP and PPP networking support.
+
+2.) *BEFORE* you build the kernel, edit drivers/net/sb1000.c. Make sure
+to redefine the value of READ_DATA_PORT to match the I/O address used
+by isapnp to access your PnP cards. This is the value of READPORT in
+/etc/isapnp.conf or given by the output of pnpdump.
+
+3.) Build and install the kernel and modules as usual.
+
+4.) Boot your new kernel following the usual procedures.
+
+5.) Set up to configure the new SB1000 PnP card by capturing the output
+of "pnpdump" to a file and editing this file to set the correct I/O ports,
+IRQ, and DMA settings for all your PnP cards. Make sure none of the settings
+conflict with one another. Then test this configuration by running the
+"isapnp" command with your new config file as the input. Check for
+errors and fix as necessary. (As an aside, I use I/O ports 0x110 and
+0x310 and IRQ 11 for my SB1000 card and these work well for me. YMMV.)
+Then save the finished config file as /etc/isapnp.conf for proper configuration
+on subsequent reboots.
+
+6.) Download the original file sb1000-1.1.2.tar.gz from Franco's site or one of
+the others referenced above. As root, unpack it into a temporary directory and
+do a `make cmconfig' and then `install -c cmconfig /usr/local/sbin'. Don't do
+`make install' because it expects to find all the utilities built and ready for
+installation, not just cmconfig.
+
+7.) As root, copy all the files under the ppp/ subdirectory in Franco's
+tar file into /etc/ppp, being careful not to overwrite any files that are
+already in there. Then modify ppp@gi-on to set the correct login name,
+phone number, and frequency for the cable modem. Also edit pap-secrets
+to specify your login name and password and any site-specific information
+you need.
+
+8.) Be sure to modify /etc/ppp/firewall to use ipchains instead of
+the older ipfwadm commands from the 2.0.x kernels. There's a neat utility to
+convert ipfwadm commands to ipchains commands:
+
+ http://users.dhp.com/~whisper/ipfwadm2ipchains/
+
+You may also wish to modify the firewall script to implement a different
+firewalling scheme.
+
+9.) Start the PPP connection via the script /etc/ppp/ppp@gi-on. You must be
+root to do this. It's better to use a utility like sudo to execute
+frequently used commands like this with root permissions if possible. If you
+connect successfully the cable modem interface will come up and you'll see a
+driver message like this at the console:
+
+ cm0: sb1000 at (0x110,0x310), csn 1, S/N 0x2a0d16d8, IRQ 11.
+ sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net)
+
+The "ifconfig" command should show two new interfaces, ppp0 and cm0.
+The command "cmconfig cm0" will give you information about the cable modem
+interface.
+
+10.) Try pinging a site via `ping -c 5 www.yahoo.com', for example. You should
+see packets received.
+
+11.) If you can't get site names (like www.yahoo.com) to resolve into
+IP addresses (like 204.71.200.67), be sure your /etc/resolv.conf file
+has no syntax errors and has the right nameserver IP addresses in it.
+If this doesn't help, try something like `ping -c 5 204.71.200.67' to
+see if the networking is running but the DNS resolution is where the
+problem lies.
+
+12.) If you still have problems, go to the support web sites mentioned above
+and read the information and documentation there.
+
+-----------------------------------------------------------------------------
+
+Common problems:
+
+1.) Packets go out on the ppp0 interface but don't come back on the cm0
+interface. It looks like I'm connected but I can't even ping any
+numerical IP addresses. (This happens predominantly on Debian systems due
+to a default boot-time configuration script.)
+
+Solution -- As root `echo 0 > /proc/sys/net/ipv4/conf/cm0/rp_filter' so it
+can share the same IP address as the ppp0 interface. Note that this
+command should probably be added to the /etc/ppp/cablemodem script
+*right*between* the "/sbin/ifconfig" and "/sbin/cmconfig" commands.
+You may need to do this to /proc/sys/net/ipv4/conf/ppp0/rp_filter as well.
+If you do this to /proc/sys/net/ipv4/conf/default/rp_filter on each reboot
+(in rc.local or some such) then any interfaces can share the same IP
+addresses.
+
+2.) I get "unresolved symbol" error messages on executing `insmod sb1000.o'.
+
+Solution -- You probably have a non-matching kernel source tree and
+/usr/include/linux and /usr/include/asm header files. Make sure you
+install the correct versions of the header files in these two directories.
+Then rebuild and reinstall the kernel.
+
+3.) When isapnp runs it reports an error, and my SB1000 card isn't working.
+
+Solution -- There's a problem with later versions of isapnp using the "(CHECK)"
+option in the lines that allocate the two I/O addresses for the SB1000 card.
+This first popped up on RH 6.0. Delete "(CHECK)" for the SB1000 I/O addresses.
+Make sure they don't conflict with any other pieces of hardware first! Then
+rerun isapnp and go from there.
+
+4.) I can't execute the /etc/ppp/ppp@gi-on file.
+
+Solution -- As root do `chmod ug+x /etc/ppp/ppp@gi-on'.
+
+5.) The firewall script isn't working (with 2.2.x and higher kernels).
+
+Solution -- Use the ipfwadm2ipchains script referenced above to convert the
+/etc/ppp/firewall script from the deprecated ipfwadm commands to ipchains.
+
+6.) I'm getting *tons* of firewall deny messages in the /var/kern.log,
+/var/messages, and/or /var/syslog files, and they're filling up my /var
+partition!!!
+
+Solution -- First, tell your ISP that you're receiving DoS (Denial of Service)
+and/or portscanning (UDP connection attempts) attacks! Look over the deny
+messages to figure out what the attack is and where it's coming from. Next,
+edit /etc/ppp/cablemodem and make sure the ",nobroadcast" option is turned on
+to the "cmconfig" command (uncomment that line). If you're not receiving these
+denied packets on your broadcast interface (IP address xxx.yyy.zzz.255
+typically), then someone is attacking your machine in particular. Be careful
+out there....
+
+7.) Everything seems to work fine but my computer locks up after a while
+(and typically during a lengthy download through the cable modem)!
+
+Solution -- You may need to add a short delay in the driver to 'slow down' the
+SURFboard because your PC might not be able to keep up with the transfer rate
+of the SB1000. To do this, it's probably best to download Franco's
+sb1000-1.1.2.tar.gz archive and build and install sb1000.o manually. You'll
+want to edit the 'Makefile' and look for the 'SB1000_DELAY'
+define. Uncomment those 'CFLAGS' lines (and comment out the default ones)
+and try setting the delay to something like 60 microseconds with:
+'-DSB1000_DELAY=60'. Then do `make' and as root `make install' and try
+it out. If it still doesn't work or you like playing with the driver, you may
+try other numbers. Remember though that the higher the delay, the slower the
+driver (which slows down the rest of the PC too when it is actively
+used). Thanks to Ed Daiga for this tip!
+
+-----------------------------------------------------------------------------
+
+Credits: This README came from Franco Venturi's original README file which is
+still supplied with his driver .tar.gz archive. I and all other sb1000 users
+owe Franco a tremendous "Thank you!" Additional thanks goes to Carl Patten
+and Ralph Bonnell who are now managing the Linux SB1000 web site, and to
+the SB1000 users who reported and helped debug the common problems listed
+above.
+
+
+ Clemmitt Sigler
+ csigler@vt.edu
genksyms_smp_prefix :=
endif
+#
+# Differ 1 and 2Gig kernels to avoid module misload errors
+#
+
+ifdef CONFIG_2GB
+ifdef CONFIG_SMP
+ genksyms_smp_prefix := -p smp2gig_
+else
+ genksyms_smp_prefix := -p 2gig_
+endif
+endif
+
$(MODINCL)/%.ver: %.c
@if [ ! -r $(MODINCL)/$*.stamp -o $(MODINCL)/$*.stamp -ot $< ]; then \
echo '$(CC) $(CFLAGS) -E -D__GENKSYMS__ $<'; \
@$(MAKEBOOT) clean
archmrproper:
+ rm -f arch/i386/vmlinux.lds
archdep:
@$(MAKEBOOT) dep
setup.o: setup.s
$(AS86) -o $@ $<
-setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h
+setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
bsetup: bsetup.o
bsetup.o: bsetup.s
$(AS86) -o $@ $<
-bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h
+bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
$(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
bootsect: bootsect.o
/*
* Local variables
*/
-static asmlinkage struct {
+static struct {
unsigned long offset;
unsigned short segment;
} apm_bios_entry;
}
-static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
+static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt, int pll)
{
u16 vscale, hscale;
u32 xsf, sr;
u16 inter;
u8 crop, vtc;
struct tvnorm *tvn;
+ unsigned long flags;
if (!width || !height)
return;
+
+ save_flags(flags);
+ cli();
tvn=&tvnorms[btv->win.norm];
btwrite(1, BT848_VBI_PACK_DEL);
btv->pll.pll_ofreq = tvn->Fsc;
- set_pll(btv);
+ if(pll)
+ set_pll(btv);
btwrite(fmt, BT848_COLOR_FMT);
#ifdef __sparc__
hdelay, vdelay, crop);
bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, vactive,
hdelay, vdelay, crop);
+ restore_flags(flags);
}
else
btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL);
- bt848_set_geo(btv, btv->win.width, btv->win.height, format);
+ bt848_set_geo(btv, btv->win.width, btv->win.height, format, 1);
}
/*
btv->risc_jmp[11]=cpu_to_le32(btv->gre);
bt848_set_geo(btv, btv->gwidth,
btv->gheight,
- btv->gfmt);
+ btv->gfmt, 0);
} else {
bt848_set_risc_jmps(btv);
btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI);
btand(~BT848_VSCALE_COMB, BT848_O_VSCALE_HI);
bt848_set_geo(btv, btv->win.width,
btv->win.height,
- btv->win.color_fmt);
+ btv->win.color_fmt, 0);
}
wake_up_interruptible(&btv->capq);
break;
btv->risc_jmp[11]=cpu_to_le32(btv->gre);
btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP);
bt848_set_geo(btv, btv->gwidth, btv->gheight,
- btv->gfmt);
+ btv->gfmt, 0);
}
}
if (astat&BT848_INT_OCERR)
remap[bttv_num]|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, remap[bttv_num]);
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &dw);
- btv->dev->base_address[0] = btv->bt848_adr;
+ btv->dev->base_address[0] = btv->bt848_adr = dw;
}
btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
static unsigned long printing = 0;
const ushort *start;
ushort cnt = 0;
- ushort myx = x;
+ ushort myx;
/* console busy or not yet initialized */
if (!printable || test_and_set_bit(0, &printing))
if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
currcons = kmsg_redirect - 1;
+ /* read `x' only after setting currecons properly (otherwise
+ the `x' macro will read the x of the foreground console). */
+ myx = x;
+
if (!vc_cons_allocated(currcons)) {
/* impossible */
printk("vt_console_print: tty %d not allocated ??\n", currcons+1);
lp_table[minor].irq_missed = 1;
schedule_timeout(timeout);
lp_parport_claim(minor);
- } else
+ }
+ else
schedule_timeout(timeout);
}
if (LP_POLLED(minor) || LP_PREEMPTED(minor)) {
current->state = TASK_INTERRUPTIBLE;
lp_parport_release(minor);
+ current->state = TASK_INTERRUPTIBLE;
schedule_timeout(LP_TIMEOUT_POLLED);
lp_parport_claim(minor);
lp_table[minor].irq_missed = 1;
/* Data available. */
/* Hack: Wait 10ms (between events 6 and 7) */
+ current->state = TASK_INTERRUPTIBLE;
schedule_timeout((HZ+99)/100);
break;
}
retval = 0;
n = MIN(*nr, MIN(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail));
if (n) {
+ mb();
retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
n -= retval;
tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
return 0;
}
-static void shutdown_mediavision(void)
-{
- release_region(io_port,3);
- release_region(0x9A01, 1);
-}
-
/*
* Module stuff
*/
MODULE_PARM(io_port,"i");
MODULE_PARM(mem_base,"i");
+static void shutdown_mediavision(void)
+{
+ release_region(io_port,3);
+ release_region(0x9A01, 1);
+}
+
void cleanup_module(void)
{
shutdown_mediavision();
unsigned long flags;
int e1, e2;
int i;
+ struct async_struct *info;
/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
save_flags(flags);
for (i = 0; i < NR_PORTS; i++) {
if (rs_table[i].type != PORT_UNKNOWN)
release_region(rs_table[i].port, 8);
+ info = rs_table[i].info;
+ if (info) {
+ rs_table[i].info = NULL;
+ kfree_s(info, sizeof(struct async_struct));
+ }
}
if (tmp_buf) {
free_page((unsigned long) tmp_buf);
{
int retval;
struct tty_driver *p;
- int found = 0;
+ int i, found = 0;
+ struct termios *tp;
const char *othername = NULL;
if (*driver->refcount)
if (driver->next)
driver->next->prev = driver->prev;
+ /*
+ * Free the termios and termios_locked structures because
+ * we don't want to get memory leaks when modular tty
+ * drivers are removed from the kernel.
+ */
+ for (i = 0; i < driver->num; i++) {
+ tp = driver->termios[i];
+ if (tp) {
+ driver->termios[i] = NULL;
+ kfree_s(tp, sizeof(struct termios));
+ }
+ tp = driver->termios_locked[i];
+ if (tp) {
+ driver->termios_locked[i] = NULL;
+ kfree_s(tp, sizeof(struct termios));
+ }
+ }
proc_tty_unregister_driver(driver);
return 0;
}
// 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,0xc2,623},
16*170.00,16*450.00,0x02,0x04,0x01,0x8e,0xc2,623},
{"Temic 4036 FY5 NTSC", TEMIC, NTSC,
- 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732},
- {"Alps HSBH1", TEMIC, NTSC,
- 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,0xc2,732},
+ 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732},
+ {"Alps TSBH1",TEMIC,NTSC,
+ 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,0xc2,732},
+ {"Alps TSBE1",TEMIC,PAL,
+ 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,0xc2,732},
};
/* ---------------------------------------------------------------------- */
/*
* For now we only try and attach these tuners to the BT848
- * bus. This same module will however work different species
- * of card using these chips. Just change the constraints
+ * or ZORAN bus. This same module will however work different
+ * species of card using these chips. Just change the constraints
* (i2c doesn't have a totally clash free 'address' space)
*/
- if(device->bus->id!=I2C_BUSID_BT848)
+ if(device->bus->id!=I2C_BUSID_BT848 ||
+ device->bus->id!=I2C_BUSID_ZORAN)
return -EINVAL;
device->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL);
#ifdef CONFIG_ARCNET_1051
/* Initialize the RFC1051-encap protocol driver */
lp->sdev=(struct device *)kmalloc(sizeof(struct device)+10,GFP_KERNEL);
- if(lp->sdev = NULL)
+ if(lp->sdev == NULL)
{
if(lp->edev)
kfree(lp->edev);
{
/* This is a little weird: set the shared memory window by doing a
read. The low address bits specify the starting page. */
- mem_base[start_page];
+ readb(mem_base+start_page);
inb(port + E21_MEM_ENABLE);
outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON);
}
/* datagram completed: send to upper level */
skb_trim(skb, dlen);
netif_rx(skb);
+ stats->rx_bytes+=dlen;
stats->rx_packets++;
lp->rx_bytes += dlen;
lp->rx_skb[ns] = 0;
for ( i = ( 0x1 << ( num_bits - 1 ) ); i; i >>= 1 ) {
TLan_ClearBit( TLAN_NET_SIO_MCLK, sio );
- TLan_GetBit( TLAN_NET_SIO_MCLK, sio );
+ (void) TLan_GetBit( TLAN_NET_SIO_MCLK, sio );
if ( data & i )
TLan_SetBit( TLAN_NET_SIO_MDATA, sio );
else
TLan_ClearBit( TLAN_NET_SIO_MDATA, sio );
TLan_SetBit( TLAN_NET_SIO_MCLK, sio );
- TLan_GetBit( TLAN_NET_SIO_MCLK, sio );
+ (void) TLan_GetBit( TLAN_NET_SIO_MCLK, sio );
}
} /* TLan_MiiSendData */
if (pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l) ||
/* some broken boards return 0 if a slot is empty: */
- l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) {
- is_multi = 0;
+ l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
continue;
- }
dev = kmalloc(sizeof(*dev), GFP_ATOMIC);
if(dev==NULL)
#define AS_FIRMWARE_DEAD -1
#define AS_LOOP_DOWN 0
#define AS_LOOP_GOOD 1
-#define AS_REDO_PORTDB 2
+#define AS_REDO_FABRIC_PORTDB 2
+#define AS_REDO_LOOP_PORTDB 4
struct isp2x00_hostdata {
u_char revision;
}
printk("qlogicfc%d : Fabric found.\n", hostdata->host_id);
-
- memset(&req, 0, sizeof(req));
-
- req.len = 8;
- req.response_low = virt_to_bus_low32(sns_response);
- req.response_high = virt_to_bus_high32(sns_response);
- req.sub_len = 22;
- req.data[0] = 0x17;
- req.data[1] = 0x02;
- req.data[8] = (u_char) (hostdata->port_id & 0xff);
- req.data[9] = (u_char) (hostdata->port_id >> 8 & 0xff);
- req.data[10] = (u_char) (hostdata->port_id >> 16 & 0xff);
- req.data[13] = 0x01;
- param[0] = MBOX_SEND_SNS;
- param[1] = 30;
- param[2] = virt_to_bus_low32(&req) >> 16;
- param[3] = virt_to_bus_low32(&req);
- param[6] = virt_to_bus_high32(&req) >> 16;
- param[7] = virt_to_bus_high32(&req);
+ if (hostdata->adapter_state & AS_REDO_LOOP_PORTDB){
+ memset(&req, 0, sizeof(req));
- isp2x00_mbox_command(host, param);
+ req.len = 8;
+ req.response_low = virt_to_bus_low32(sns_response);
+ req.response_high = virt_to_bus_high32(sns_response);
+ req.sub_len = 22;
+ req.data[0] = 0x17;
+ req.data[1] = 0x02;
+ req.data[8] = (u_char) (hostdata->port_id & 0xff);
+ req.data[9] = (u_char) (hostdata->port_id >> 8 & 0xff);
+ req.data[10] = (u_char) (hostdata->port_id >> 16 & 0xff);
+ req.data[13] = 0x01;
+ param[0] = MBOX_SEND_SNS;
+ param[1] = 30;
+ param[2] = virt_to_bus_low32(&req) >> 16;
+ param[3] = virt_to_bus_low32(&req);
+ param[6] = virt_to_bus_high32(&req) >> 16;
+ param[7] = virt_to_bus_high32(&req);
+
+ isp2x00_mbox_command(host, param);
- if (param[0] != MBOX_COMMAND_COMPLETE)
- printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id);
+ if (param[0] != MBOX_COMMAND_COMPLETE)
+ printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id);
+ }
port_id = hostdata->port_id;
while (!done) {
DEBUG(isp2x00_print_scsi_cmd(Cmnd));
- if (hostdata->adapter_state == AS_REDO_PORTDB) {
- hostdata->adapter_state = AS_LOOP_GOOD;
+ if (hostdata->adapter_state & AS_REDO_FABRIC_PORTDB || hostdata->adapter_state & AS_REDO_LOOP_PORTDB) {
isp2x00_make_portdb(host);
+ hostdata->adapter_state = AS_LOOP_GOOD;
printk("qlogicfc%d : Port Database\n", hostdata->host_id);
for (i = 0; hostdata->port_db[i].wwn != 0; i++) {
printk("wwn: %08x%08x scsi_id: %x loop_id: %x\n", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i, hostdata->port_db[i].loop_id);
}
switch (Cmnd->cmnd[0]) {
+ case TEST_UNIT_READY:
+ case START_STOP:
+ break;
case WRITE_10:
case WRITE_6:
case WRITE_BUFFER:
case LOOP_UP:
case POINT_TO_POINT_UP:
printk("qlogicfc%d : link is up\n", hostdata->host_id);
- hostdata->adapter_state = AS_REDO_PORTDB;
+ hostdata->adapter_state = AS_REDO_FABRIC_PORTDB | AS_REDO_LOOP_PORTDB;
break;
case LOOP_DOWN:
printk("qlogicfc%d : link is down\n", hostdata->host_id);
case CONNECTION_MODE:
printk("received CONNECTION_MODE irq %x\n", inw(host->io_port + MBOX1));
break;
- case LIP_OCCURED:
case CHANGE_NOTIFICATION:
+ if (hostdata->adapter_state == AS_LOOP_GOOD)
+ hostdata->adapter_state = AS_REDO_FABRIC_PORTDB;
+ break;
+ case LIP_OCCURED:
case PORT_DB_CHANGED:
case LIP_RECEIVED:
if (hostdata->adapter_state == AS_LOOP_GOOD)
- hostdata->adapter_state = AS_REDO_PORTDB;
+ hostdata->adapter_state = AS_REDO_LOOP_PORTDB;
break;
case SYSTEM_ERROR:
printk("qlogicfc%d : The firmware just choked.\n", hostdata->host_id);
rscsi_disks[i].capacity = 0;
} else {
printk ("scsi : deleting disk entry.\n");
+ sd_detach(rscsi_disks[i].device);
rscsi_disks[i].device = NULL;
- sd_template.nr_dev--;
- SD_GENDISK(i).nr_real--;
/* Wake up a process waiting for device */
wake_up(&SCpnt->device->device_wait);
scsi_release_command(SCpnt);
SCpnt = NULL;
+ scsi_free(buffer, 512);
+ spin_unlock_irq(&io_request_lock);
return i;
}
#endif
sd_gendisks->part[start].nr_sects = CAPACITY;
+ if (!rscsi_disks[target].device) return -EBUSY;
resetup_one_dev(&SD_GENDISK(target),
target % SCSI_DISKS_PER_MAJOR);
int soundpro = 0;
#endif
-static volatile char irq2dev[17] = {
+static volatile signed char irq2dev[17] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1
};
void attach_ms_sound(struct address_info *hw_config)
{
- static char interrupt_bits[12] =
+ static signed char interrupt_bits[12] =
{
-1, -1, -1, -1, -1, 0x00, -1, 0x08, -1, 0x10, 0x18, 0x20
};
- char bits, dma2_bit = 0;
+ signed char bits;
+ char dma2_bit = 0;
static char dma_bits[4] =
{
printk(KERN_WARNING "Sound: DMA buffers not available\n");
return -ENOSPC; /* Memory allocation failed during boot */
}
- if (sound_open_dma(dmap->dma, adev->name)) {
+ if (dmap->dma >= 0 && sound_open_dma(dmap->dma, adev->name)) {
printk(KERN_WARNING "Unable to grab(2) DMA%d for the audio driver\n", dmap->dma);
return -EBUSY;
}
{
unsigned long flags;
- sound_close_dma(dmap->dma);
+ if (dmap->dma >= 0) {
+ sound_close_dma(dmap->dma);
+ flags=claim_dma_lock();
+ disable_dma(dmap->dma);
+ release_dma_lock(flags);
+ }
if (dmap->flags & DMA_BUSY)
dmap->dma_mode = DMODE_NONE;
dmap->flags &= ~DMA_BUSY;
- flags=claim_dma_lock();
- disable_dma(dmap->dma);
- release_dma_lock(flags);
-
if (sound_dmap_flag == DMAP_FREE_ON_CLOSE)
sound_free_dmap(dmap);
}
{
#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
unsigned char conf;
- static char irq_bits[] = {
+ static signed char irq_bits[] = {
-1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4
};
static unsigned setpll(struct sv_state *s, unsigned char reg, unsigned rate)
{
unsigned long flags;
- unsigned char r, m, n;
+ unsigned char r, m=0, n=0;
unsigned xm, xn, xr, xd, metric = ~0U;
- /* the warnings about m and n used uninitialized are bogus and may safely be ignored */
if (rate < 625000/ADCMULT)
rate = 625000/ADCMULT;
unsigned long fd_offset;
unsigned long rlim;
int retval;
+ static unsigned long error_time=0;
ex = *((struct exec *) bprm->buf); /* exec-header */
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
#ifdef __i386__
if (N_MAGIC(ex) == ZMAGIC && fd_offset != BLOCK_SIZE) {
- printk(KERN_NOTICE "N_TXTOFF != BLOCK_SIZE. See a.out.h.\n");
+ if((jiffies-error_time) >5)
+ {
+ printk(KERN_NOTICE "N_TXTOFF != BLOCK_SIZE. See a.out.h.\n");
+ error_time=jiffies;
+ }
return -ENOEXEC;
}
bprm->dentry->d_inode->i_op &&
bprm->dentry->d_inode->i_op->bmap &&
(fd_offset < bprm->dentry->d_inode->i_sb->s_blocksize)) {
- printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n");
+ if((jiffies-error_time) >5)
+ {
+ printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n");
+ error_time=jiffies;
+ }
return -ENOEXEC;
}
#endif
}
p -= len;
pos = p;
- while (len) {
+ while (len>0) {
char *pag;
int offset, bytes_to_copy;
break;
}
mark_buffer_dirty(bh, 0);
- update_vm_cache(inode, pos, bh->b_data + offset, c);
+ update_vm_cache_conditional(inode, pos, bh->b_data + offset, c,
+ (unsigned long) buf);
pos += c;
written += c;
buf += c;
flags = iattr->ia_attr_flags;
if (flags & ATTR_FLAG_SYNCRONOUS) {
inode->i_flags |= MS_SYNCHRONOUS;
- inode->u.ext2_i.i_flags = EXT2_SYNC_FL;
+ inode->u.ext2_i.i_flags |= EXT2_SYNC_FL;
} else {
inode->i_flags &= ~MS_SYNCHRONOUS;
inode->u.ext2_i.i_flags &= ~EXT2_SYNC_FL;
}
if (flags & ATTR_FLAG_NOATIME) {
inode->i_flags |= MS_NOATIME;
- inode->u.ext2_i.i_flags = EXT2_NOATIME_FL;
+ inode->u.ext2_i.i_flags |= EXT2_NOATIME_FL;
} else {
inode->i_flags &= ~MS_NOATIME;
inode->u.ext2_i.i_flags &= ~EXT2_NOATIME_FL;
}
if (flags & ATTR_FLAG_APPEND) {
inode->i_flags |= S_APPEND;
- inode->u.ext2_i.i_flags = EXT2_APPEND_FL;
+ inode->u.ext2_i.i_flags |= EXT2_APPEND_FL;
} else {
inode->i_flags &= ~S_APPEND;
inode->u.ext2_i.i_flags &= ~EXT2_APPEND_FL;
}
if (flags & ATTR_FLAG_IMMUTABLE) {
inode->i_flags |= S_IMMUTABLE;
- inode->u.ext2_i.i_flags = EXT2_IMMUTABLE_FL;
+ inode->u.ext2_i.i_flags |= EXT2_IMMUTABLE_FL;
} else {
inode->i_flags &= ~S_IMMUTABLE;
inode->u.ext2_i.i_flags &= ~EXT2_IMMUTABLE_FL;
unhashed = 0;
while ((tmp = tmp->next) != head) {
struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
+ if (!list_empty(&dentry->d_subdirs))
+ shrink_dcache_parent(dentry);
dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
dentry->d_count, !list_empty(&dentry->d_hash));
dput(dentry);
goto restart;
}
- if (!list_empty(&dentry->d_hash))
+ if (list_empty(&dentry->d_hash))
unhashed++;
}
return unhashed;
#endif
#define spin_lock_init(lock) do { } while(0)
-#define spin_lock(lock) do { } while(0)
+#define spin_lock(lock) (void)(lock) /* Not "unused variable". */
#define spin_trylock(lock) (1)
#define spin_unlock_wait(lock) do { } while(0)
#define spin_unlock(lock) do { } while(0)
#define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
#endif
-#define read_lock(lock) do { } while(0)
+#define read_lock(lock) (void)(lock) /* Not "unused variable." */
#define read_unlock(lock) do { } while(0)
-#define write_lock(lock) do { } while(0)
+#define write_lock(lock) (void)(lock) /* Not "unused variable." */
#define write_unlock(lock) do { } while(0)
#define read_lock_irq(lock) cli()
#define read_unlock_irq(lock) sti()
#define I2C_BUSID_BT848 1 /* I2C bus on a BT848 */
/* 2 is used in 2.3.x */
#define I2C_BUSID_BUZ 3 /* I2C bus on a BUZ */
+#define I2C_BUSID_ZORAN 4 /* I2C bus on a Zoran */
/*
* struct for a driver for a i2c chip (tuner, soundprocessor,
__wait_on_page(page);
}
+extern void update_vm_cache_conditional(struct inode *, unsigned long, const char *, int, unsigned long);
extern void update_vm_cache(struct inode *, unsigned long, const char *, int);
#endif
EXPORT_SYMBOL(max_mapnr);
EXPORT_SYMBOL(high_memory);
EXPORT_SYMBOL(update_vm_cache);
+EXPORT_SYMBOL(update_vm_cache_conditional);
EXPORT_SYMBOL(vmtruncate);
EXPORT_SYMBOL(find_vma);
EXPORT_SYMBOL(get_unmapped_area);
* elsewhere, in preparation for a serial line console (someday).
* Ted Ts'o, 2/11/93.
* Modified for sysctl support, 1/8/97, Chris Horn.
+ * Fixed SMP synchronization, 08/08/99, Manfred Spraul
+ * manfreds@colorfullife.com
*/
#include <linux/mm.h>
#include <asm/uaccess.h>
#define LOG_BUF_LEN (16384)
+#define LOG_BUF_MASK (LOG_BUF_LEN-1)
static char buf[1024];
int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL;
int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
+spinlock_t console_lock = SPIN_LOCK_UNLOCKED;
+
struct console *console_drivers = NULL;
static char log_buf[LOG_BUF_LEN];
static unsigned long log_start = 0;
*/
int do_syslog(int type, char * buf, int len)
{
- unsigned long i, j, count, flags;
+ unsigned long i, j, limit, count;
int do_clear = 0;
char c;
int error = -EPERM;
- lock_kernel();
error = 0;
switch (type) {
case 0: /* Close log */
if (error)
goto out;
i = 0;
+ spin_lock_irq(&console_lock);
while (log_size && i < len) {
- c = *((char *) log_buf+log_start);
+ c = log_buf[log_start & LOG_BUF_MASK];
log_start++;
log_size--;
- log_start &= LOG_BUF_LEN-1;
- sti();
+ spin_unlock_irq(&console_lock);
__put_user(c,buf);
buf++;
i++;
- cli();
+ spin_lock_irq(&console_lock);
}
- sti();
+ spin_unlock_irq(&console_lock);
error = i;
break;
case 4: /* Read/clear last kernel messages */
error = verify_area(VERIFY_WRITE,buf,len);
if (error)
goto out;
- /*
- * The logged_chars, log_start, and log_size values may
- * change from an interrupt, so we disable interrupts.
- */
- __save_flags(flags);
- __cli();
+ spin_lock_irq(&console_lock);
count = len;
if (count > LOG_BUF_LEN)
count = LOG_BUF_LEN;
if (count > logged_chars)
count = logged_chars;
- j = log_start + log_size - count;
- __restore_flags(flags);
- for (i = 0; i < count; i++) {
- c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
- __put_user(c, buf++);
- }
if (do_clear)
logged_chars = 0;
+ limit = log_start + log_size;
+ /*
+ * __put_user() could sleep, and while we sleep
+ * printk() could overwrite the messages
+ * we try to copy to user space. Therefore
+ * the messages are copied in reverse. <manfreds>
+ */
+ for(i=0;i < count;i++) {
+ j = limit-1-i;
+ if (j+LOG_BUF_LEN < log_start+log_size)
+ break;
+ c = log_buf[ j & LOG_BUF_MASK ];
+ spin_unlock_irq(&console_lock);
+ __put_user(c,&buf[count-1-i]);
+ spin_lock_irq(&console_lock);
+ }
+ spin_unlock_irq(&console_lock);
error = i;
+ if(i != count) {
+ int offset = count-error;
+ /* buffer overflow during copy, correct user buffer. */
+ for(i=0;i<error;i++) {
+ __get_user(c,&buf[i+offset]);
+ __put_user(c,&buf[i]);
+ }
+ }
+
break;
case 5: /* Clear ring buffer */
+ spin_lock_irq(&console_lock);
logged_chars = 0;
+ spin_unlock_irq(&console_lock);
break;
case 6: /* Disable logging to console */
+ spin_lock_irq(&console_lock);
console_loglevel = minimum_console_loglevel;
+ spin_unlock_irq(&console_lock);
break;
case 7: /* Enable logging to console */
+ spin_lock_irq(&console_lock);
console_loglevel = default_console_loglevel;
+ spin_unlock_irq(&console_lock);
break;
case 8:
error = -EINVAL;
goto out;
if (len < minimum_console_loglevel)
len = minimum_console_loglevel;
+ spin_lock_irq(&console_lock);
console_loglevel = len;
+ spin_unlock_irq(&console_lock);
error = 0;
break;
default:
break;
}
out:
- unlock_kernel();
return error;
}
return do_syslog(type, buf, len);
}
-
-spinlock_t console_lock;
-
asmlinkage int printk(const char *fmt, ...)
{
va_list args;
}
line_feed = 0;
for (; p < buf_end; p++) {
- log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)] = *p;
+ log_buf[(log_start+log_size) & LOG_BUF_MASK] = *p;
if (log_size < LOG_BUF_LEN)
log_size++;
- else {
+ else
log_start++;
- log_start &= LOG_BUF_LEN-1;
- }
+
logged_chars++;
if (*p == '\n') {
line_feed = 1;
void console_print(const char *s)
{
- struct console *c = console_drivers;
+ struct console *c;
+ unsigned long flags;
int len = strlen(s);
+ spin_lock_irqsave(&console_lock,flags);
+ c = console_drivers;
while(c) {
if ((c->flags & CON_ENABLED) && c->write)
c->write(c, s, len);
c = c->next;
}
+ spin_unlock_irqrestore(&console_lock,flags);
}
void unblank_console(void)
{
- struct console *c = console_drivers;
+ struct console *c;
+ unsigned long flags;
+
+ spin_lock_irqsave(&console_lock,flags);
+ c = console_drivers;
while(c) {
if ((c->flags & CON_ENABLED) && c->unblank)
c->unblank();
c = c->next;
}
+ spin_unlock_irqrestore(&console_lock,flags);
}
/*
*/
void register_console(struct console * console)
{
- int i,j,len;
- int p = log_start;
+ int i, j,len;
+ int p;
char buf[16];
signed char msg_level = -1;
char *q;
+ unsigned long flags;
/*
* See if we want to use this console driver. If we
* Put this console in the list - keep the
* preferred driver at the head of the list.
*/
+ spin_lock_irqsave(&console_lock,flags);
if ((console->flags & CON_CONSDEV) || console_drivers == NULL) {
console->next = console_drivers;
console_drivers = console;
console->next = console_drivers->next;
console_drivers->next = console;
}
- if ((console->flags & CON_PRINTBUFFER) == 0) return;
-
+ if ((console->flags & CON_PRINTBUFFER) == 0)
+ goto done;
/*
* Print out buffered log messages.
*/
+ p = log_start & LOG_BUF_MASK;
+
for (i=0,j=0; i < log_size; i++) {
buf[j++] = log_buf[p];
- p++; p &= LOG_BUF_LEN-1;
+ p = (p+1) & LOG_BUF_MASK;
if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1)
continue;
buf[j] = 0;
q = buf;
len = j;
if (msg_level < 0) {
- msg_level = buf[1] - '0';
- q = buf + 3;
- len -= 3;
+ if(buf[0] == '<' &&
+ buf[1] >= '0' &&
+ buf[1] <= '7' &&
+ buf[2] == '>') {
+ msg_level = buf[1] - '0';
+ q = buf + 3;
+ len -= 3;
+ } else
+ {
+ msg_level = default_message_loglevel;
+ }
}
if (msg_level < console_loglevel)
console->write(console, q, len);
msg_level = -1;
j = 0;
}
+done:
+ spin_unlock_irqrestore(&console_lock,flags);
}
int unregister_console(struct console * console)
{
struct console *a,*b;
-
+ unsigned long flags;
+ int res = 1;
+
+ spin_lock_irqsave(&console_lock,flags);
if (console_drivers == console) {
console_drivers=console->next;
- return (0);
- }
- for (a=console_drivers->next, b=console_drivers ;
- a; b=a, a=b->next) {
- if (a == console) {
- b->next = a->next;
- return 0;
- }
+ res = 0;
+ } else
+ {
+ for (a=console_drivers->next, b=console_drivers ;
+ a; b=a, a=b->next) {
+ if (a == console) {
+ b->next = a->next;
+ res = 0;
+ break;
+ }
+ }
}
- return (1);
+ spin_unlock_irqrestore(&console_lock,flags);
+ return res;
}
/*
/*
* Update a page cache copy, when we're doing a "write()" system call
* See also "update_vm_cache()".
+ *
+ * This function is conditional in that it checks whether the original
+ * source of the data is the same as the ultimate destination, and
+ * aborts the update if so.
+ *
+ * The "source_address" is the virtual address of the original location
+ * of the data we are injecting. For writes from user mode, it is the
+ * user VA. However, for filemap_sync writes, "source_address", it is
+ * the page cache address. In both cases, "buf" points to the copy we
+ * have already made in kernel space and we use that pointer for the
+ * transfer. source_address just allows us to detect an update_vm_cache
+ * which is being sourced from the copy of the data already in the page
+ * cache.
+ *
+ * This prevents munmap() and msync() from stomping all over shared
+ * memory maps. --sct
*/
-void update_vm_cache(struct inode * inode, unsigned long pos, const char * buf, int count)
+
+void update_vm_cache_conditional(struct inode * inode, unsigned long pos, const char * buf, int count, unsigned long source_address)
{
unsigned long offset, len;
len = count;
page = find_page(inode, pos);
if (page) {
- wait_on_page(page);
- memcpy((void *) (offset + page_address(page)), buf, len);
+ char *dest = (char*) (offset + page_address(page));
+
+ if (dest != source_address) {
+ wait_on_page(page);
+ memcpy(dest, buf, len);
+ }
page_cache_release(page);
}
count -= len;
} while (count);
}
+void update_vm_cache(struct inode * inode, unsigned long pos, const char * buf, int count)
+{
+ update_vm_cache_conditional(inode, pos, buf, count, 0);
+}
+
+
static inline void add_to_page_cache(struct page * page,
struct inode * inode, unsigned long offset,
struct page **hash)
while (count) {
unsigned long bytes, pgpos, offset;
+ char * dest;
+
/*
* Try to find the page in the cache. If it isn't there,
* allocate a free page.
* the writer needs to increment the page use counts until he
* is done with the page.
*/
- bytes -= copy_from_user((u8*)page_address(page) + offset, buf, bytes);
+ dest = (char *) page_address(page) + offset;
+ if (dest != buf) /* See comment in update_vm_cache_cond. */
+ bytes -= copy_from_user(dest, buf, bytes);
status = -EFAULT;
if (bytes)
status = inode->i_op->updatepage(file, page, offset, bytes, sync);
if (len > TASK_SIZE)
return 0;
- if (!addr) {
- addr = current->rlim[RLIMIT_DATA].rlim_cur;
- if (addr >= RLIM_INFINITY)
- addr = TASK_UNMAPPED_BASE;
- }
+ if (!addr)
+ addr = TASK_UNMAPPED_BASE;
addr = PAGE_ALIGN(addr);
for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
{
/* < 8 hops && input itfc not in list */
*l = intrfc->if_netnum; /* insert recvd netnum into list */
+ ipx->ipx_tctrl++;
/* xmit on all other interfaces... */
for(ifcs = ipx_interfaces; ifcs != NULL; ifcs = ifcs->if_next)
{