## Automatically generated incremental diff ## From: linux-2.4.19-pre6 ## To: linux-2.4.19-pre7 ## Robot: $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $ diff -urN linux-2.4.19-pre6/Documentation/Configure.help linux-2.4.19-pre7/Documentation/Configure.help --- linux-2.4.19-pre6/Documentation/Configure.help Mon Apr 15 21:53:23 2002 +++ linux-2.4.19-pre7/Documentation/Configure.help Mon Apr 15 21:54:16 2002 @@ -2904,14 +2904,6 @@ If unsure, say N. -HCI EMU (virtual device) driver -CONFIG_BLUEZ_HCIEMU - Bluetooth Virtual HCI device driver. - This driver is required if you want to use HCI Emulation software. - - Say Y here to compile support for Virtual HCI devices into the - kernel or say M to compile it as module (hci_usb.o). - # Choice: alphatype Alpha system type CONFIG_ALPHA_GENERIC @@ -3190,14 +3182,6 @@ say N here to save some memory. You can also say Y if you have an "intelligent" multiport card such as Cyclades, Digiboards, etc. -Support for serial ports defined by ACPI tables -CONFIG_SERIAL_ACPI - Legacy free machines may not have serial ports at the legacy COM1, - COM2 etc addresses. Serial ports on such machines are described by - the ACPI tables SPCR (Serial Port Console Redirection) table and - DBGP (Debug Port) table. Say Y here if you want to include support - for these serial ports. - Support for sharing serial interrupts CONFIG_SERIAL_SHARE_IRQ Some serial boards have hardware support which allows multiple dumb @@ -3394,6 +3378,10 @@ You should say Y here if you use XFree86 3.3.6 or 4.x and want to use GLX or DRI. If unsure, say N. +CONFIG_AGP_HP_ZX1 + This option gives you AGP GART support for the HP ZX1 chipset + for IA64 processors. + Support for ISA-bus hardware CONFIG_ISA Find out whether you have ISA slots on your motherboard. ISA is the @@ -5538,18 +5526,19 @@ (see ipchains(8), "-m" argument). AppleTalk interfaces support -CONFIG_APPLETALK - AppleTalk is the way Apple computers speak to each other on a - network. If your Linux box is connected to such a network and you - want to join the conversation, say Y. +CONFIG_DEV_APPLETALK + AppleTalk is the protocol that Apple computers can use to communicate + on a network. If your Linux box is connected to such a network, and wish + to do IP over it, or you have a LocalTalk card and wish to use it to + connect to the AppleTalk network, say Y. AppleTalk protocol support CONFIG_ATALK - AppleTalk is the way Apple computers speak to each other on a - network. If your Linux box is connected to such a network and you - want to join the conversation, say Y. You will need to use the - netatalk package so that your Linux box can act as a print and file - server for Macs as well as access AppleTalk printers. Check out + AppleTalk is the protocol that Apple computers can use to communicate + on a network. If your Linux box is connected to such a network and you + wish to connect to it, say Y. You will need to use the netatalk package + so that your Linux box can act as a print and file server for Macs as + well as access AppleTalk printers. Check out on the WWW for details. EtherTalk is the name used for AppleTalk over Ethernet and the cheaper and slower LocalTalk is AppleTalk over a proprietary Apple @@ -14621,9 +14610,16 @@ other useful pieces of information. Sometimes this information is not present or incorrect. - Unless you expect to boot on a PReP system, there is not need to + Unless you expect to boot on a PReP system, there is no need to select Y. +PReP residual data available in /proc/residual +CONFIG_PROC_PREPRESIDUAL + Enabling this option will create a /proc/residual file which allows + you to get at the residual data on PReP systems. You will need a tool + (lsresidual) to parse it. If you aren't on a PReP system, you don't + want this. + /dev file system support CONFIG_DEVFS_FS This is support for devfs, a virtual file system (like /proc) which @@ -20116,11 +20112,12 @@ Bluetooth can be found at . Linux Bluetooth subsystem consist of several layers: - HCI Core (device and connection manager, scheduler) + BlueZ Core (HCI device and connection manager, scheduler) HCI Device drivers (interface to the hardware) L2CAP Module (L2CAP protocol) + SCO Module (SCO links) - Say Y here to enable Linux Bluetooth support and to build HCI Core + Say Y here to enable Linux Bluetooth support and to build BlueZ Core layer. To use Linux Bluetooth subsystem, you will need several user-space @@ -20128,7 +20125,7 @@ Bluetooth kernel modules are provided in the BlueZ package. For more information, see . - If you want to compile HCI Core as module (hci.o) say M here. + If you want to compile BlueZ Core as module (bluez.o) say M here. L2CAP protocol support CONFIG_BLUEZ_L2CAP @@ -20139,15 +20136,33 @@ Say Y here to compile L2CAP support into the kernel or say M to compile it as module (l2cap.o). +SCO links support +CONFIG_BLUEZ_SCO + SCO link provides voice transport over Bluetooth. SCO support is + required for voice applications like Headset and Audio. + + Say Y here to compile SCO support into the kernel or say M to + compile it as module (sco.o). + HCI UART driver CONFIG_BLUEZ_HCIUART Bluetooth HCI UART driver. This driver is required if you want to use Bluetooth devices with - serial port interface. + serial port interface. You will also need this driver if you have + UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card + adapter and BrainBoxes Bluetooth PC Card. Say Y here to compile support for Bluetooth UART devices into the kernel or say M to compile it as module (hci_uart.o). +HCI UART (H4) protocol support +CONFIG_BLUEZ_HCIUART_H4 + UART (H4) is serial protocol for communication between Bluetooth + device and host. This protocol is required for most UART based + Bluetooth device (including PCMCIA and CF). + + Say Y here to compile support for HCI UART (H4) protocol. + HCI USB driver CONFIG_BLUEZ_HCIUSB Bluetooth HCI USB driver. @@ -20157,7 +20172,24 @@ Say Y here to compile support for Bluetooth USB devices into the kernel or say M to compile it as module (hci_usb.o). -HCI VHCI virtual HCI device driver +HCI USB firmware download support +CONFIG_BLUEZ_USB_FW_LOAD + Firmware download support for Bluetooth USB devices. + This support is required for devices like Broadcom BCM2033. + + HCI USB driver uses external firmware downloader program provided + in BlueFW package. + For more information, see . + +HCI USB zero packet support +CONFIG_BLUEZ_USB_ZERO_PACKET + Support for USB zero packets. + This option is provided only as a work around for buggy Bluetooth USB + devices. Do _not_ enable it unless you know for sure that your device + requires zero packets. + Most people should say N here. + +HCI VHCI Virtual HCI device driver CONFIG_BLUEZ_HCIVHCI Bluetooth Virtual HCI device driver. This driver is required if you want to use HCI Emulation software. @@ -20165,6 +20197,16 @@ Say Y here to compile support for virtual HCI devices into the kernel or say M to compile it as module (hci_vhci.o). +HCI DTL1 (PC Card) device driver +CONFIG_BLUEZ_HCIDTL1 + Bluetooth HCI DTL1 (PC Card) driver. + This driver provides support for Bluetooth PCMCIA devices with + Nokia DTL1 interface: + Nokia Bluetooth PC Card, Socketcom Bluetooth CF module + + Say Y here to compile support for HCI DTL1 devices into the + kernel or say M to compile it as module (dtl1_cs.o). + # The following options are for Linux when running on the Hitachi # SuperH family of RISC microprocessors. @@ -22682,12 +22724,12 @@ you are concerned with the code size or don't want to see these messages. -Compile kernel without frame pointer -CONFIG_NO_FRAME_POINTER - If you say Y here, the resulting kernel will be slightly smaller and - faster. However, when a problem occurs with the kernel, the - information that is reported is severely limited. Most people - should say N here. +Compile kernel with frame pointer +CONFIG_FRAME_POINTER + If you say Y here, the resulting kernel will be slightly larger and + slower, but it will give very useful debugging information. If you + don't debug the kernel, you can say N, but we may not be able to + solve problems without frame pointers. Verbose user fault messages CONFIG_DEBUG_USER diff -urN linux-2.4.19-pre6/Documentation/DocBook/Makefile linux-2.4.19-pre7/Documentation/DocBook/Makefile --- linux-2.4.19-pre6/Documentation/DocBook/Makefile Mon Apr 15 21:53:23 2002 +++ linux-2.4.19-pre7/Documentation/DocBook/Makefile Mon Apr 15 21:54:16 2002 @@ -23,6 +23,8 @@ html: $(HTML) +man: kernel-api-man + %.eps: %.fig fig2dev -Leps $< $@ diff -urN linux-2.4.19-pre6/Documentation/filesystems/devfs/ChangeLog linux-2.4.19-pre7/Documentation/filesystems/devfs/ChangeLog --- linux-2.4.19-pre6/Documentation/filesystems/devfs/ChangeLog Mon Apr 15 21:53:23 2002 +++ linux-2.4.19-pre7/Documentation/filesystems/devfs/ChangeLog Mon Apr 15 21:54:17 2002 @@ -1910,3 +1910,9 @@ - Ported to kernel 2.4.19-pre5 - Updated README from master HTML file +=============================================================================== +Changes for patch v199.12 + +- Updated README from master HTML file + +- Changed fs/devfs/util.c to kdev_t compatibility macros diff -urN linux-2.4.19-pre6/Documentation/filesystems/devfs/README linux-2.4.19-pre7/Documentation/filesystems/devfs/README --- linux-2.4.19-pre6/Documentation/filesystems/devfs/README Mon Apr 15 21:53:23 2002 +++ linux-2.4.19-pre7/Documentation/filesystems/devfs/README Mon Apr 15 21:54:17 2002 @@ -3,7 +3,7 @@ Linux Devfs (Device File System) FAQ Richard Gooch -29-MAR-2002 +4-APR-2002 Document languages: @@ -1786,6 +1786,15 @@ +make sure you have enabled debugging output when configuring your +kernel. You will need to set (at least) the following config options: + +CONFIG_DEVFS_DEBUG=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SLAB=y + + + please make sure you have the latest devfs patches applied. The latest kernel version might not have the latest devfs patches applied yet (Linus is very busy) @@ -1794,7 +1803,10 @@ save a copy of your complete kernel logs (preferably by using the dmesg programme) for later inclusion in your bug report. You may need to use the -s switch to increase the -internal buffer size so you can capture all the boot messages +internal buffer size so you can capture all the boot messages. +Don't edit or trim the dmesg output + + try booting with devfs=dall passed to the kernel boot diff -urN linux-2.4.19-pre6/Documentation/i810_rng.txt linux-2.4.19-pre7/Documentation/i810_rng.txt --- linux-2.4.19-pre6/Documentation/i810_rng.txt Thu Apr 19 09:34:05 2001 +++ linux-2.4.19-pre7/Documentation/i810_rng.txt Mon Apr 15 21:54:17 2002 @@ -70,6 +70,10 @@ Change history: + Version 0.9.7: + * Support other i8xx chipsets too (by adding 82801BA(M) and + 82801CA(M) detection) + Version 0.9.6: * Internal driver cleanups, prep for 1.0.0 release. diff -urN linux-2.4.19-pre6/Documentation/isdn/README.HiSax linux-2.4.19-pre7/Documentation/isdn/README.HiSax --- linux-2.4.19-pre6/Documentation/isdn/README.HiSax Mon Aug 13 16:35:28 2001 +++ linux-2.4.19-pre7/Documentation/isdn/README.HiSax Mon Apr 15 21:54:17 2002 @@ -52,6 +52,7 @@ Sedlbauer Speed Star/Speed Star2 (PCMCIA) Sedlbauer ISDN-Controller PC/104 USR Sportster internal TA (compatible Stollmann tina-pp V3) +USR internal TA PCI ith Kommunikationstechnik GmbH MIC 16 ISA card Traverse Technologie NETjet PCI S0 card and NETspider U card Ovislink ISDN sc100-p card (NETjet driver) diff -urN linux-2.4.19-pre6/MAINTAINERS linux-2.4.19-pre7/MAINTAINERS --- linux-2.4.19-pre6/MAINTAINERS Mon Apr 15 21:53:23 2002 +++ linux-2.4.19-pre7/MAINTAINERS Mon Apr 15 21:54:17 2002 @@ -552,14 +552,12 @@ S: Maintained EXT2 FILE SYSTEM -P: Remy Card -M: Remy.Card@linux.org -L: linux-kernel@vger.kernel.org +L: ext2-devel@lists.sourceforge.net S: Maintained EXT3 FILE SYSTEM -P: Remy Card, Stephen Tweedie -M: sct@redhat.com, akpm@zip.com.au, adilger@turbolinux.com +P: Stephen Tweedie, Andrew Morton +M: sct@redhat.com, akpm@zip.com.au, adilger@clusterfs.com L: ext3-users@redhat.com S: Maintained @@ -1686,6 +1684,13 @@ L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net S: Maintained + +USB RTL8150 DRIVER +P: Petko Manolov +M: petkan@users.sourceforge.net +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained USB SE401 DRIVER P: Jeroen Vreeken diff -urN linux-2.4.19-pre6/Makefile linux-2.4.19-pre7/Makefile --- linux-2.4.19-pre6/Makefile Mon Apr 15 21:53:23 2002 +++ linux-2.4.19-pre7/Makefile Mon Apr 15 21:54:17 2002 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 19 -EXTRAVERSION = -pre6 +EXTRAVERSION = -pre7 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -14,7 +14,7 @@ TOPDIR := $(shell /bin/pwd) HPATH = $(TOPDIR)/include -FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net +FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net $(HPATH)/math-emu HOSTCC = gcc HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer @@ -144,7 +144,7 @@ DRIVERS-$(CONFIG_DRM_OLD) += drivers/char/drm-4.0/drm.o DRIVERS-$(CONFIG_NUBUS) += drivers/nubus/nubus.a DRIVERS-$(CONFIG_NET_FC) += drivers/net/fc/fc.o -DRIVERS-$(CONFIG_APPLETALK) += drivers/net/appletalk/appletalk.o +DRIVERS-$(CONFIG_DEV_APPLETALK) += drivers/net/appletalk/appletalk.o DRIVERS-$(CONFIG_TR) += drivers/net/tokenring/tr.o DRIVERS-$(CONFIG_WAN) += drivers/net/wan/wan.o DRIVERS-$(CONFIG_ARCNET) += drivers/net/arcnet/arcnetdrv.o @@ -170,7 +170,7 @@ DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus_all.o DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/driver.o DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a -DRIVERS-$(CONFIG_ALL_PPC) += drivers/macintosh/macintosh.o +DRIVERS-$(CONFIG_PPC) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a @@ -204,10 +204,15 @@ drivers/zorro/devlist.h drivers/zorro/gen-devlist \ drivers/sound/bin2hex drivers/sound/hex2hex \ drivers/atm/fore200e_mkfirm drivers/atm/{pca,sba}*{.bin,.bin1,.bin2} \ + drivers/scsi/aic7xxx/aicasm/aicasm \ drivers/scsi/aic7xxx/aicasm/aicasm_gram.c \ + drivers/scsi/aic7xxx/aicasm/aicasm_gram.h \ + drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.c \ + drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.h \ + drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.c \ drivers/scsi/aic7xxx/aicasm/aicasm_scan.c \ + drivers/scsi/aic7xxx/aicasm/aicdb.h \ drivers/scsi/aic7xxx/aicasm/y.tab.h \ - drivers/scsi/aic7xxx/aicasm/aicasm \ drivers/scsi/53c700_d.h \ net/khttpd/make_times_h \ net/khttpd/times.h \ @@ -468,6 +473,11 @@ htmldocs: sgmldocs $(MAKE) -C Documentation/DocBook html +mandocs: + chmod 755 $(TOPDIR)/scripts/kernel-doc + chmod 755 $(TOPDIR)/scripts/split-man + $(MAKE) -C Documentation/DocBook man + sums: find . -type f -print | sort | xargs sum > .SUMS diff -urN linux-2.4.19-pre6/Rules.make linux-2.4.19-pre7/Rules.make --- linux-2.4.19-pre6/Rules.make Mon Apr 15 21:53:23 2002 +++ linux-2.4.19-pre7/Rules.make Mon Apr 15 21:54:17 2002 @@ -176,7 +176,7 @@ _modinst__: dummy ifneq "$(strip $(ALL_MOBJS))" "" mkdir -p $(MODLIB)/kernel/$(MOD_DESTDIR) - cp $(ALL_MOBJS) $(MODLIB)/kernel/$(MOD_DESTDIR)$(MOD_TARGET) + cp $(ALL_MOBJS) $(MODLIB)/kernel/$(MOD_DESTDIR) endif .PHONY: modules_install diff -urN linux-2.4.19-pre6/arch/alpha/config.in linux-2.4.19-pre7/arch/alpha/config.in --- linux-2.4.19-pre6/arch/alpha/config.in Mon Apr 15 21:53:23 2002 +++ linux-2.4.19-pre7/arch/alpha/config.in Mon Apr 15 21:54:17 2002 @@ -399,9 +399,7 @@ source drivers/usb/Config.in source drivers/input/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -urN linux-2.4.19-pre6/arch/alpha/kernel/srm_env.c linux-2.4.19-pre7/arch/alpha/kernel/srm_env.c --- linux-2.4.19-pre6/arch/alpha/kernel/srm_env.c Sun Oct 21 10:20:57 2001 +++ linux-2.4.19-pre7/arch/alpha/kernel/srm_env.c Mon Apr 15 21:54:17 2002 @@ -1,27 +1,20 @@ /* - * srm_env.c - Access to SRC environment variables through - * the linux procfs + * srm_env.c - Access to SRC environment + * variables through linux' procfs * - * (C)2001, Jan-Benedict Glaw + * Copyright (C) 2001-2002 Jan-Benedict Glaw * * This driver is at all a modified version of Erik Mouw's - * ./linux/Documentation/DocBook/procfs_example.c, so: thanky + * ./linux/Documentation/DocBook/procfs_example.c, so: thank * you, Erik! He can be reached via email at * . It is based on an idea - * provided by DEC^WCompaq's "Jumpstart" CD. They included - * a patch like this as well. Thanks for idea! - * - * - * This software has been developed while working on the LART - * computing board (http://www.lart.tudelft.nl/). The - * development has been sponsored by the Mobile Multi-media - * Communications (http://www.mmc.tudelft.nl/) and Ubiquitous - * Communications (http://www.ubicom.tudelft.nl/) projects. + * provided by DEC^WCompaq^WIntel's "Jumpstart" CD. They + * included a patch like this as well. Thanks for idea! * * This program is free software; you can redistribute * it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software - * Foundation version 2. + * Public License version 2 as published by the Free Software + * Foundation. * * This program is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied @@ -36,6 +29,19 @@ * */ +/* + * Changelog + * + * Tue, 9 Apr 2002 18:44:40 +0200 + * - Implement access by variable name and additionally + * by number. This is done by creating two subdirectories + * where one holds all names (like the old directory + * did) and the other holding 256 files named like "0", + * "1" and so on. + * - Call this "Version 0.0.3" + * + */ + #include #include #include @@ -43,11 +49,13 @@ #include #include #include +#include -#define DIRNAME "srm_environment" /* Subdir in /proc/ */ -#define VERSION "0.0.2" /* Module version */ -#define NAME "srm_env" /* Module name */ -#define DEBUG +#define BASE_DIR "srm_environment" /* Subdir in /proc/ */ +#define NAMED_DIR "named_variables" /* Subdir for known variables */ +#define NUMBERED_DIR "numbered_variables" /* Subdir for all variables */ +#define VERSION "0.0.3" /* Module version */ +#define NAME "srm_env" /* Module name */ MODULE_AUTHOR("Jan-Benedict Glaw "); MODULE_DESCRIPTION("Accessing Alpha SRM environment through procfs interface"); @@ -60,8 +68,12 @@ struct proc_dir_entry *proc_entry; } srm_env_t; -static struct proc_dir_entry *directory; -static srm_env_t srm_entries[] = { +static struct proc_dir_entry *base_dir; +static struct proc_dir_entry *named_dir; +static struct proc_dir_entry *numbered_dir; +static char number[256][4]; + +static srm_env_t srm_named_entries[] = { { "auto_action", ENV_AUTO_ACTION }, { "boot_dev", ENV_BOOT_DEV }, { "bootdef_dev", ENV_BOOTDEF_DEV }, @@ -79,10 +91,11 @@ { "tty_dev", ENV_TTY_DEV }, { NULL, 0 }, }; +static srm_env_t srm_numbered_entries[256]; -static int srm_env_read(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ +static int +srm_env_read(char *page, char **start, off_t off, int count, int *eof, + void *data) { int nbytes; unsigned long ret; srm_env_t *entry; @@ -107,10 +120,9 @@ return nbytes; } - -static int srm_env_write(struct file *file, const char *buffer, - unsigned long count, void *data) -{ +static int +srm_env_write(struct file *file, const char *buffer, unsigned long count, + void *data) { #define BUFLEN 512 int nbytes; srm_env_t *entry; @@ -126,8 +138,8 @@ MOD_DEC_USE_COUNT; return -ENOMEM; } - - //memcpy(aligned_buffer, buffer, nbytes) + + /* memcpy(aligned_buffer, buffer, nbytes) */ if(copy_from_user(buf, buffer, count)) { MOD_DEC_USE_COUNT; @@ -149,55 +161,142 @@ return nbytes; } -static void srm_env_cleanup(void) -{ +static void +srm_env_cleanup(void) { srm_env_t *entry; + unsigned long var_num; - if(directory) { - entry = srm_entries; - while(entry->name != NULL && entry->id != 0) { - if(entry->proc_entry) { - remove_proc_entry(entry->name, directory); - entry->proc_entry = NULL; + if(base_dir) { + /* + * Remove named entries + */ + if(named_dir) { + entry = srm_named_entries; + while(entry->name != NULL && entry->id != 0) { + if(entry->proc_entry) { + remove_proc_entry(entry->name, + named_dir); + entry->proc_entry = NULL; + } + entry++; } - entry++; + remove_proc_entry(NAMED_DIR, base_dir); } - remove_proc_entry(DIRNAME, NULL); + + /* + * Remove numbered entries + */ + if(numbered_dir) { + for(var_num = 0; var_num <= 255; var_num++) { + entry = &srm_numbered_entries[var_num]; + + if(entry->proc_entry) { + remove_proc_entry(entry->name, + numbered_dir); + entry->proc_entry = NULL; + entry->name = NULL; + } + } + remove_proc_entry(NUMBERED_DIR, base_dir); + } + + remove_proc_entry(BASE_DIR, NULL); } return; } -static int __init srm_env_init(void) -{ +static int __init +srm_env_init(void) { srm_env_t *entry; - + unsigned long var_num; + + /* + * Check system + */ if(!alpha_using_srm) { printk(KERN_INFO "%s: This Alpha system doesn't " "know about SRM...\n", __FUNCTION__); return -ENODEV; } - directory = proc_mkdir(DIRNAME, NULL); - if(directory == NULL) - return -ENOMEM; - - directory->owner = THIS_MODULE; - - /* Now create all the nodes... */ - entry = srm_entries; + /* + * Init numbers + */ + for(var_num = 0; var_num <= 255; var_num++) + sprintf(number[var_num], "%ld", var_num); + + /* + * Create base directory + */ + base_dir = proc_mkdir(BASE_DIR, NULL); + if(base_dir == NULL) { + printk(KERN_ERR "Couldn't create base dir /proc/%s\n", + BASE_DIR); + goto cleanup; + } + base_dir->owner = THIS_MODULE; + + /* + * Create per-name subdirectory + */ + named_dir = proc_mkdir(NAMED_DIR, base_dir); + if(named_dir == NULL) { + printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n", + BASE_DIR, NAMED_DIR); + goto cleanup; + } + named_dir->owner = THIS_MODULE; + + /* + * Create per-number subdirectory + */ + numbered_dir = proc_mkdir(NUMBERED_DIR, base_dir); + if(numbered_dir == NULL) { + printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n", + BASE_DIR, NUMBERED_DIR); + goto cleanup; + + } + numbered_dir->owner = THIS_MODULE; + + /* + * Create all named nodes + */ + entry = srm_named_entries; while(entry->name != NULL && entry->id != 0) { - entry->proc_entry = create_proc_entry(entry->name, 0644, - directory); + entry->proc_entry = create_proc_entry(entry->name, + 0644, named_dir); if(entry->proc_entry == NULL) goto cleanup; - entry->proc_entry->data = entry; + + entry->proc_entry->data = (void *)entry; + entry->proc_entry->owner = THIS_MODULE; entry->proc_entry->read_proc = srm_env_read; entry->proc_entry->write_proc = srm_env_write; - entry->proc_entry->owner = THIS_MODULE; + entry++; } - + + /* + * Create all numbered nodes + */ + for(var_num = 0; var_num <= 255; var_num++) { + entry = &srm_numbered_entries[var_num]; + entry->name = number[var_num]; + + entry->proc_entry = create_proc_entry(entry->name, + 0644, numbered_dir); + if(entry->proc_entry == NULL) + goto cleanup; + + entry->id = var_num; + entry->proc_entry->data = (void *)entry; + entry->proc_entry->owner = THIS_MODULE; + entry->proc_entry->read_proc = srm_env_read; + entry->proc_entry->write_proc = srm_env_write; + } + printk(KERN_INFO "%s: version %s loaded successfully\n", NAME, VERSION); return 0; @@ -207,9 +306,8 @@ return -ENOMEM; } - -static void __exit srm_env_exit(void) -{ +static void __exit +srm_env_exit(void) { srm_env_cleanup(); printk(KERN_INFO "%s: unloaded successfully\n", NAME); return; diff -urN linux-2.4.19-pre6/arch/arm/Makefile linux-2.4.19-pre7/arch/arm/Makefile --- linux-2.4.19-pre6/arch/arm/Makefile Mon Apr 15 21:53:24 2002 +++ linux-2.4.19-pre7/arch/arm/Makefile Mon Apr 15 21:54:17 2002 @@ -11,10 +11,6 @@ GZFLAGS :=-9 CFLAGS +=-fno-common -pipe -ifneq ($(CONFIG_NO_FRAME_POINTER),y) -CFLAGS :=$(CFLAGS:-fomit-frame-pointer=) -endif - ifeq ($(CONFIG_DEBUG_INFO),y) CFLAGS +=-g endif diff -urN linux-2.4.19-pre6/arch/arm/config.in linux-2.4.19-pre7/arch/arm/config.in --- linux-2.4.19-pre6/arch/arm/config.in Mon Apr 15 21:53:24 2002 +++ linux-2.4.19-pre7/arch/arm/config.in Mon Apr 15 21:54:17 2002 @@ -629,16 +629,16 @@ source drivers/usb/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Kernel hacking' -# Always compile kernel with framepointer (until 2.4 real comes out) -# Bug reports aren't much use without this. -bool 'Compile kernel without frame pointer' CONFIG_NO_FRAME_POINTER +# RMK wants arm kernels compiled with frame pointers so hardwire this to y. If +# you know what you are doing and are willing to live without stack traces, you +# can get a slightly smaller kernel by setting this option to n, but then RMK +# will have to kill you ;). +define_bool CONFIG_FRAME_POINTER y bool 'Verbose user fault messages' CONFIG_DEBUG_USER bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26 diff -urN linux-2.4.19-pre6/arch/arm/def-configs/adsbitsy linux-2.4.19-pre7/arch/arm/def-configs/adsbitsy --- linux-2.4.19-pre6/arch/arm/def-configs/adsbitsy Thu Oct 25 13:53:44 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/adsbitsy Mon Apr 15 21:54:17 2002 @@ -663,7 +663,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/anakin linux-2.4.19-pre7/arch/arm/def-configs/anakin --- linux-2.4.19-pre6/arch/arm/def-configs/anakin Sun Aug 12 11:13:59 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/anakin Mon Apr 15 21:54:17 2002 @@ -454,7 +454,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/assabet linux-2.4.19-pre7/arch/arm/def-configs/assabet --- linux-2.4.19-pre6/arch/arm/def-configs/assabet Thu Oct 25 13:53:44 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/assabet Mon Apr 15 21:54:17 2002 @@ -956,7 +956,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/badge4 linux-2.4.19-pre7/arch/arm/def-configs/badge4 --- linux-2.4.19-pre6/arch/arm/def-configs/badge4 Mon Apr 15 21:53:24 2002 +++ linux-2.4.19-pre7/arch/arm/def-configs/badge4 Mon Apr 15 21:54:17 2002 @@ -1120,7 +1120,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y # CONFIG_NO_PGT_CACHE is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/cerfcube linux-2.4.19-pre7/arch/arm/def-configs/cerfcube --- linux-2.4.19-pre6/arch/arm/def-configs/cerfcube Thu Oct 25 13:53:44 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/cerfcube Mon Apr 15 21:54:18 2002 @@ -876,7 +876,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/cerfpda linux-2.4.19-pre7/arch/arm/def-configs/cerfpda --- linux-2.4.19-pre6/arch/arm/def-configs/cerfpda Thu Oct 25 13:53:44 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/cerfpda Mon Apr 15 21:54:18 2002 @@ -970,7 +970,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/cerfpod linux-2.4.19-pre7/arch/arm/def-configs/cerfpod --- linux-2.4.19-pre6/arch/arm/def-configs/cerfpod Thu Oct 25 13:53:44 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/cerfpod Mon Apr 15 21:54:18 2002 @@ -897,7 +897,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/clps7500 linux-2.4.19-pre7/arch/arm/def-configs/clps7500 --- linux-2.4.19-pre6/arch/arm/def-configs/clps7500 Sat May 19 17:43:05 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/clps7500 Mon Apr 15 21:54:18 2002 @@ -511,7 +511,7 @@ # # Kernel hacking # -# CONFIG_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y # CONFIG_DEBUG_ERRORS is not set # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/ebsa110 linux-2.4.19-pre7/arch/arm/def-configs/ebsa110 --- linux-2.4.19-pre6/arch/arm/def-configs/ebsa110 Sun Aug 12 11:13:59 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/ebsa110 Mon Apr 15 21:54:18 2002 @@ -594,7 +594,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/epxa10db linux-2.4.19-pre7/arch/arm/def-configs/epxa10db --- linux-2.4.19-pre6/arch/arm/def-configs/epxa10db Thu Oct 25 13:53:44 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/epxa10db Mon Apr 15 21:54:18 2002 @@ -651,7 +651,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y diff -urN linux-2.4.19-pre6/arch/arm/def-configs/flexanet linux-2.4.19-pre7/arch/arm/def-configs/flexanet --- linux-2.4.19-pre6/arch/arm/def-configs/flexanet Mon Apr 15 21:53:24 2002 +++ linux-2.4.19-pre7/arch/arm/def-configs/flexanet Mon Apr 15 21:54:18 2002 @@ -895,7 +895,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set # CONFIG_NO_PGT_CACHE is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/fortunet linux-2.4.19-pre7/arch/arm/def-configs/fortunet --- linux-2.4.19-pre6/arch/arm/def-configs/fortunet Mon Apr 15 21:53:24 2002 +++ linux-2.4.19-pre7/arch/arm/def-configs/fortunet Mon Apr 15 21:54:18 2002 @@ -576,7 +576,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set # CONFIG_NO_PGT_CACHE is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/freebird linux-2.4.19-pre7/arch/arm/def-configs/freebird --- linux-2.4.19-pre6/arch/arm/def-configs/freebird Sun Aug 12 11:13:59 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/freebird Mon Apr 15 21:54:18 2002 @@ -614,7 +614,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/freebird_new linux-2.4.19-pre7/arch/arm/def-configs/freebird_new --- linux-2.4.19-pre6/arch/arm/def-configs/freebird_new Sun Aug 12 11:13:59 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/freebird_new Mon Apr 15 21:54:18 2002 @@ -634,7 +634,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/frodo linux-2.4.19-pre7/arch/arm/def-configs/frodo --- linux-2.4.19-pre6/arch/arm/def-configs/frodo Mon Apr 15 21:53:24 2002 +++ linux-2.4.19-pre7/arch/arm/def-configs/frodo Mon Apr 15 21:54:18 2002 @@ -602,7 +602,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set # CONFIG_NO_PGT_CACHE is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/graphicsclient linux-2.4.19-pre7/arch/arm/def-configs/graphicsclient --- linux-2.4.19-pre6/arch/arm/def-configs/graphicsclient Thu Oct 25 13:53:44 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/graphicsclient Mon Apr 15 21:54:18 2002 @@ -731,7 +731,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/graphicsmaster linux-2.4.19-pre7/arch/arm/def-configs/graphicsmaster --- linux-2.4.19-pre6/arch/arm/def-configs/graphicsmaster Thu Oct 25 13:53:44 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/graphicsmaster Mon Apr 15 21:54:18 2002 @@ -744,7 +744,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/h3600 linux-2.4.19-pre7/arch/arm/def-configs/h3600 --- linux-2.4.19-pre6/arch/arm/def-configs/h3600 Thu Oct 25 13:53:44 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/h3600 Mon Apr 15 21:54:18 2002 @@ -948,7 +948,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/integrator linux-2.4.19-pre7/arch/arm/def-configs/integrator --- linux-2.4.19-pre6/arch/arm/def-configs/integrator Sun Aug 12 11:13:59 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/integrator Mon Apr 15 21:54:18 2002 @@ -652,7 +652,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/jornada720 linux-2.4.19-pre7/arch/arm/def-configs/jornada720 --- linux-2.4.19-pre6/arch/arm/def-configs/jornada720 Mon Apr 15 21:53:24 2002 +++ linux-2.4.19-pre7/arch/arm/def-configs/jornada720 Mon Apr 15 21:54:18 2002 @@ -890,7 +890,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set # CONFIG_NO_PGT_CACHE is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/lart linux-2.4.19-pre7/arch/arm/def-configs/lart --- linux-2.4.19-pre6/arch/arm/def-configs/lart Thu Oct 25 13:53:44 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/lart Mon Apr 15 21:54:18 2002 @@ -892,7 +892,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/neponset linux-2.4.19-pre7/arch/arm/def-configs/neponset --- linux-2.4.19-pre6/arch/arm/def-configs/neponset Thu Oct 25 13:53:45 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/neponset Mon Apr 15 21:54:18 2002 @@ -950,7 +950,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/pangolin linux-2.4.19-pre7/arch/arm/def-configs/pangolin --- linux-2.4.19-pre6/arch/arm/def-configs/pangolin Thu Oct 25 13:53:45 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/pangolin Mon Apr 15 21:54:18 2002 @@ -741,7 +741,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y diff -urN linux-2.4.19-pre6/arch/arm/def-configs/pfs168_mqtft linux-2.4.19-pre7/arch/arm/def-configs/pfs168_mqtft --- linux-2.4.19-pre6/arch/arm/def-configs/pfs168_mqtft Sun Aug 12 11:13:59 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/pfs168_mqtft Mon Apr 15 21:54:18 2002 @@ -783,7 +783,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y diff -urN linux-2.4.19-pre6/arch/arm/def-configs/pfs168_mqvga linux-2.4.19-pre7/arch/arm/def-configs/pfs168_mqvga --- linux-2.4.19-pre6/arch/arm/def-configs/pfs168_mqvga Sun Aug 12 11:13:59 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/pfs168_mqvga Mon Apr 15 21:54:18 2002 @@ -783,7 +783,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y diff -urN linux-2.4.19-pre6/arch/arm/def-configs/pfs168_sastn linux-2.4.19-pre7/arch/arm/def-configs/pfs168_sastn --- linux-2.4.19-pre6/arch/arm/def-configs/pfs168_sastn Sun Aug 12 11:13:59 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/pfs168_sastn Mon Apr 15 21:54:18 2002 @@ -774,7 +774,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y diff -urN linux-2.4.19-pre6/arch/arm/def-configs/pfs168_satft linux-2.4.19-pre7/arch/arm/def-configs/pfs168_satft --- linux-2.4.19-pre6/arch/arm/def-configs/pfs168_satft Sun Aug 12 11:13:59 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/pfs168_satft Mon Apr 15 21:54:18 2002 @@ -783,7 +783,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y diff -urN linux-2.4.19-pre6/arch/arm/def-configs/pleb linux-2.4.19-pre7/arch/arm/def-configs/pleb --- linux-2.4.19-pre6/arch/arm/def-configs/pleb Sun Aug 12 17:36:24 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/pleb Mon Apr 15 21:54:18 2002 @@ -524,7 +524,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/rpc linux-2.4.19-pre7/arch/arm/def-configs/rpc --- linux-2.4.19-pre6/arch/arm/def-configs/rpc Sun Aug 12 11:13:59 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/rpc Mon Apr 15 21:54:18 2002 @@ -839,7 +839,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/shannon linux-2.4.19-pre7/arch/arm/def-configs/shannon --- linux-2.4.19-pre6/arch/arm/def-configs/shannon Mon Apr 15 21:53:24 2002 +++ linux-2.4.19-pre7/arch/arm/def-configs/shannon Mon Apr 15 21:54:18 2002 @@ -727,7 +727,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/shark linux-2.4.19-pre7/arch/arm/def-configs/shark --- linux-2.4.19-pre6/arch/arm/def-configs/shark Thu Oct 25 13:53:45 2001 +++ linux-2.4.19-pre7/arch/arm/def-configs/shark Mon Apr 15 21:54:18 2002 @@ -956,7 +956,7 @@ # # Kernel hacking # -CONFIG_NO_FRAME_POINTER=y +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -urN linux-2.4.19-pre6/arch/arm/def-configs/system3 linux-2.4.19-pre7/arch/arm/def-configs/system3 --- linux-2.4.19-pre6/arch/arm/def-configs/system3 Mon Apr 15 21:53:24 2002 +++ linux-2.4.19-pre7/arch/arm/def-configs/system3 Mon Apr 15 21:54:18 2002 @@ -961,7 +961,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y # CONFIG_NO_PGT_CACHE is not set diff -urN linux-2.4.19-pre6/arch/arm/kernel/entry-header.S linux-2.4.19-pre7/arch/arm/kernel/entry-header.S --- linux-2.4.19-pre6/arch/arm/kernel/entry-header.S Thu Oct 11 09:04:57 2001 +++ linux-2.4.19-pre7/arch/arm/kernel/entry-header.S Mon Apr 15 21:54:18 2002 @@ -13,7 +13,7 @@ #endif .macro zero_fp -#ifndef CONFIG_NO_FRAME_POINTER +#ifdef CONFIG_FRAME_POINTER mov fp, #0 #endif .endm diff -urN linux-2.4.19-pre6/arch/arm/lib/backtrace.S linux-2.4.19-pre7/arch/arm/lib/backtrace.S --- linux-2.4.19-pre6/arch/arm/lib/backtrace.S Thu Oct 25 13:53:45 2001 +++ linux-2.4.19-pre7/arch/arm/lib/backtrace.S Mon Apr 15 21:54:18 2002 @@ -26,7 +26,7 @@ ENTRY(c_backtrace) -#ifdef CONFIG_NO_FRAME_POINTER +#ifndef CONFIG_FRAME_POINTER mov pc, lr #else diff -urN linux-2.4.19-pre6/arch/i386/config.in linux-2.4.19-pre7/arch/i386/config.in --- linux-2.4.19-pre6/arch/i386/config.in Mon Apr 15 21:53:25 2002 +++ linux-2.4.19-pre7/arch/i386/config.in Mon Apr 15 21:54:18 2002 @@ -410,9 +410,7 @@ source drivers/usb/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -urN linux-2.4.19-pre6/arch/i386/kernel/apic.c linux-2.4.19-pre7/arch/i386/kernel/apic.c --- linux-2.4.19-pre6/arch/i386/kernel/apic.c Mon Feb 25 11:37:52 2002 +++ linux-2.4.19-pre7/arch/i386/kernel/apic.c Mon Apr 15 21:54:18 2002 @@ -679,7 +679,15 @@ for (i = 0; i < nr_ioapics; i++) { if (smp_found_config) { ioapic_phys = mp_ioapics[i].mpc_apicaddr; + if (!ioapic_phys) { + printk(KERN_ERR "WARNING: bogus zero IO-APIC address found in MPTABLE, disabling IO/APIC support!\n"); + + smp_found_config = 0; + skip_ioapic_setup = 1; + goto fake_ioapic_page; + } } else { +fake_ioapic_page: ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); ioapic_phys = __pa(ioapic_phys); } diff -urN linux-2.4.19-pre6/arch/i386/kernel/dmi_scan.c linux-2.4.19-pre7/arch/i386/kernel/dmi_scan.c --- linux-2.4.19-pre6/arch/i386/kernel/dmi_scan.c Mon Apr 15 21:53:25 2002 +++ linux-2.4.19-pre7/arch/i386/kernel/dmi_scan.c Mon Apr 15 21:54:18 2002 @@ -354,6 +354,7 @@ * The MP1.4 table is right however and so SMP kernels tend to work. */ +extern int skip_ioapic_setup; static __init int broken_pirq(struct dmi_blacklist *d) { printk(KERN_INFO " *** Possibly defective BIOS detected (irqtable)\n"); @@ -361,6 +362,9 @@ printk(KERN_INFO " *** If you see IRQ problems, in paticular SCSI resets and hangs at boot\n"); printk(KERN_INFO " *** contact your hardware vendor and ask about updates.\n"); printk(KERN_INFO " *** Building an SMP kernel may evade the bug some of the time.\n"); +#ifdef CONFIG_X86_UP_APIC + skip_ioapic_setup = 0; +#endif return 0; } @@ -563,6 +567,12 @@ MATCH(DMI_BIOS_DATE, "08/25/00"), NO_MATCH } }, + { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-Z505LS (with updated BIOS) */ + MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), + MATCH(DMI_BIOS_VERSION, "R0209Z3"), + MATCH(DMI_BIOS_DATE, "05/12/01"), NO_MATCH + } }, + { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-F104K */ MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), MATCH(DMI_BIOS_VERSION, "R0204K2"), diff -urN linux-2.4.19-pre6/arch/i386/kernel/entry.S linux-2.4.19-pre7/arch/i386/kernel/entry.S --- linux-2.4.19-pre6/arch/i386/kernel/entry.S Mon Apr 15 21:53:25 2002 +++ linux-2.4.19-pre7/arch/i386/kernel/entry.S Mon Apr 15 21:54:19 2002 @@ -635,6 +635,10 @@ .long SYMBOL_NAME(sys_ni_syscall) /* reserved for lremovexattr */ .long SYMBOL_NAME(sys_ni_syscall) /* reserved for fremovexattr */ .long SYMBOL_NAME(sys_tkill) + .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sendfile64 */ + .long SYMBOL_NAME(sys_ni_syscall) /* 240 reserved for futex */ + .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sched_setaffinity */ + .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sched_getaffinity */ .rept NR_syscalls-(.-sys_call_table)/4 .long SYMBOL_NAME(sys_ni_syscall) diff -urN linux-2.4.19-pre6/arch/i386/kernel/io_apic.c linux-2.4.19-pre7/arch/i386/kernel/io_apic.c --- linux-2.4.19-pre6/arch/i386/kernel/io_apic.c Mon Apr 15 21:53:25 2002 +++ linux-2.4.19-pre7/arch/i386/kernel/io_apic.c Mon Apr 15 21:54:19 2002 @@ -191,15 +191,27 @@ #define MAX_PIRQS 8 int pirq_entries [MAX_PIRQS]; int pirqs_enabled; -int skip_ioapic_setup; +#ifdef CONFIG_X86_UP_APIC +int skip_ioapic_setup=1; +#else +int skip_ioapic_setup=0; +#endif -static int __init ioapic_setup(char *str) +static int __init noioapic_setup(char *str) { skip_ioapic_setup = 1; return 1; } -__setup("noapic", ioapic_setup); +__setup("noapic", noioapic_setup); + +static int __init ioapic_setup(char *str) +{ + skip_ioapic_setup = 0; + return 1; +} + +__setup("apic", ioapic_setup); static int __init ioapic_pirq_setup(char *str) { diff -urN linux-2.4.19-pre6/arch/i386/kernel/pci-irq.c linux-2.4.19-pre7/arch/i386/kernel/pci-irq.c --- linux-2.4.19-pre6/arch/i386/kernel/pci-irq.c Mon Apr 15 21:53:25 2002 +++ linux-2.4.19-pre7/arch/i386/kernel/pci-irq.c Mon Apr 15 21:54:19 2002 @@ -461,7 +461,12 @@ { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set }, { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, pirq_piix_get, pirq_piix_set }, { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set }, + { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, pirq_piix_get, pirq_piix_set }, + { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, pirq_piix_get, pirq_piix_set }, { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set }, + { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, pirq_piix_get, pirq_piix_set }, + { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, pirq_piix_get, pirq_piix_set }, + { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, pirq_piix_get, pirq_piix_set }, { "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set }, diff -urN linux-2.4.19-pre6/arch/i386/kernel/setup.c linux-2.4.19-pre7/arch/i386/kernel/setup.c --- linux-2.4.19-pre6/arch/i386/kernel/setup.c Mon Apr 15 21:53:25 2002 +++ linux-2.4.19-pre7/arch/i386/kernel/setup.c Mon Apr 15 21:54:19 2002 @@ -141,6 +141,9 @@ /* For PCI or other memory-mapped resources */ unsigned long pci_mem_start = 0x10000000; +/* user-defined highmem size */ +static unsigned int highmem_pages = -1; + /* * Setup options */ @@ -411,6 +414,22 @@ } } +void __init limit_regions (unsigned long long size) +{ + int i; + unsigned long long current_size = 0; + + for (i = 0; i < e820.nr_map; i++) { + if (e820.map[i].type == E820_RAM) { + current_size += e820.map[i].size; + if (current_size >= size) { + e820.map[i].size -= current_size-size; + e820.nr_map = i + 1; + return; + } + } + } +} static void __init add_memory_region(unsigned long long start, unsigned long long size, int type) { @@ -712,7 +731,7 @@ { char c = ' ', *to = command_line, *from = COMMAND_LINE; int len = 0; - int usermem = 0; + int userdef = 0; /* Save unparsed command line copy for /proc/cmdline */ memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); @@ -735,37 +754,36 @@ } else if (!memcmp(from+4, "exactmap", 8)) { from += 8+4; e820.nr_map = 0; - usermem = 1; + userdef = 1; } else { /* If the user specifies memory size, we - * blow away any automatically generated - * size + * limit the BIOS-provided memory map to + * that size. exactmap can be used to specify + * the exact map. mem=number can be used to + * trim the existing memory map. */ unsigned long long start_at, mem_size; - if (usermem == 0) { - /* first time in: zap the whitelist - * and reinitialize it with the - * standard low-memory region. - */ - e820.nr_map = 0; - usermem = 1; - add_memory_region(0, LOWMEMSIZE(), E820_RAM); - } mem_size = memparse(from+4, &from); - if (*from == '@') + if (*from == '@') { start_at = memparse(from+1, &from); - else { - start_at = HIGH_MEMORY; - mem_size -= HIGH_MEMORY; - usermem=0; + add_memory_region(start_at, mem_size, E820_RAM); + } else { + limit_regions(mem_size); + userdef=1; } - add_memory_region(start_at, mem_size, E820_RAM); } } /* acpismp=force forces parsing and use of the ACPI SMP table */ - if (c == ' ' && !memcmp(from, "acpismp=force", 13)) + if (c == ' ' && !memcmp(from, "acpismp=force", 13)) enable_acpi_smp_table = 1; + /* + * highmem=size forces highmem to be exactly 'size' bytes. + * This works even on boxes that have no highmem otherwise. + * This also works to reduce highmem size on bigger boxes. + */ + if (c == ' ' && !memcmp(from, "highmem=", 8)) + highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT; c = *(from++); if (!c) @@ -776,7 +794,7 @@ } *to = '\0'; *cmdline_p = command_line; - if (usermem) { + if (userdef) { printk(KERN_INFO "user-defined physical RAM map:\n"); print_memory_map("user"); } @@ -863,6 +881,14 @@ */ max_low_pfn = max_pfn; if (max_low_pfn > MAXMEM_PFN) { + if (highmem_pages == -1) + highmem_pages = max_pfn - MAXMEM_PFN; + if (highmem_pages + MAXMEM_PFN < max_pfn) + max_pfn = MAXMEM_PFN + highmem_pages; + if (highmem_pages + MAXMEM_PFN > max_pfn) { + printk("only %luMB highmem pages available, ignoring highmem size of %uMB.\n", pages_to_mb(max_pfn - MAXMEM_PFN), pages_to_mb(highmem_pages)); + highmem_pages = 0; + } max_low_pfn = MAXMEM_PFN; #ifndef CONFIG_HIGHMEM /* Maximum memory usable is what is directly addressable */ @@ -881,16 +907,37 @@ } #endif /* !CONFIG_X86_PAE */ #endif /* !CONFIG_HIGHMEM */ + } else { + if (highmem_pages == -1) + highmem_pages = 0; +#if CONFIG_HIGHMEM + if (highmem_pages >= max_pfn) { + printk(KERN_ERR "highmem size specified (%uMB) is bigger than pages available (%luMB)!.\n", pages_to_mb(highmem_pages), pages_to_mb(max_pfn)); + highmem_pages = 0; + } + if (highmem_pages) { + if (max_low_pfn-highmem_pages < 64*1024*1024/PAGE_SIZE){ + printk(KERN_ERR "highmem size %uMB results in smaller than 64MB lowmem, ignoring it.\n", pages_to_mb(highmem_pages)); + highmem_pages = 0; + } + max_low_pfn -= highmem_pages; + } +#else + if (highmem_pages) + printk(KERN_ERR "ignoring highmem size on non-highmem kernel!\n"); +#endif } #ifdef CONFIG_HIGHMEM highstart_pfn = highend_pfn = max_pfn; - if (max_pfn > MAXMEM_PFN) { - highstart_pfn = MAXMEM_PFN; - printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", - pages_to_mb(highend_pfn - highstart_pfn)); + if (max_pfn > max_low_pfn) { + highstart_pfn = max_low_pfn; } + printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", + pages_to_mb(highend_pfn - highstart_pfn)); #endif + printk(KERN_NOTICE "%ldMB LOWMEM available.\n", + pages_to_mb(max_low_pfn)); /* * Initialize the boot-time allocator (with low memory only): */ diff -urN linux-2.4.19-pre6/arch/ia64/kernel/efi.c linux-2.4.19-pre7/arch/ia64/kernel/efi.c --- linux-2.4.19-pre6/arch/ia64/kernel/efi.c Fri Nov 9 14:26:17 2001 +++ linux-2.4.19-pre7/arch/ia64/kernel/efi.c Mon Apr 15 21:54:19 2002 @@ -346,6 +346,9 @@ } else if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == 0) { efi.sal_systab = __va(config_tables[i].table); printk(" SALsystab=0x%lx", config_tables[i].table); + } else if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) { + efi.hcdp = __va(config_tables[i].table); + printk(" HCDP=0x%lx", config_tables[i].table); } } printk("\n"); diff -urN linux-2.4.19-pre6/arch/ia64/kernel/setup.c linux-2.4.19-pre7/arch/ia64/kernel/setup.c --- linux-2.4.19-pre6/arch/ia64/kernel/setup.c Mon Apr 15 21:53:26 2002 +++ linux-2.4.19-pre7/arch/ia64/kernel/setup.c Mon Apr 15 21:54:19 2002 @@ -347,6 +347,10 @@ /* Parse the ACPI tables */ acpi_parse(efi.acpi); } + if (efi.hcdp) { + /* Setup the serial ports described by HCDP */ + setup_serial_hcdp(efi.hcdp); + } #ifdef CONFIG_VT # if defined(CONFIG_VGA_CONSOLE) diff -urN linux-2.4.19-pre6/arch/ppc/8260_io/Config.in linux-2.4.19-pre7/arch/ppc/8260_io/Config.in --- linux-2.4.19-pre6/arch/ppc/8260_io/Config.in Sun Sep 17 09:48:05 2000 +++ linux-2.4.19-pre7/arch/ppc/8260_io/Config.in Mon Apr 15 21:54:22 2002 @@ -1,9 +1,10 @@ # # MPC8260 Communication options # +mainmenu_option next_comment +comment 'MPC8260 Communication Options' +bool 'Enable SCC Console' CONFIG_SCC_CONSOLE if [ "$CONFIG_NET_ETHERNET" = "y" ]; then - mainmenu_option next_comment - comment 'MPC8260 Communication Options' bool 'CPM SCC Ethernet' CONFIG_SCC_ENET if [ "$CONFIG_SCC_ENET" = "y" ]; then bool 'Ethernet on SCC1' CONFIG_SCC1_ENET @@ -21,5 +22,5 @@ bool 'Ethernet on FCC2' CONFIG_FCC2_ENET bool 'Ethernet on FCC3' CONFIG_FCC3_ENET fi - endmenu fi +endmenu diff -urN linux-2.4.19-pre6/arch/ppc/boot/common/ns16550.c linux-2.4.19-pre7/arch/ppc/boot/common/ns16550.c --- linux-2.4.19-pre6/arch/ppc/boot/common/ns16550.c Mon Apr 15 21:53:31 2002 +++ linux-2.4.19-pre7/arch/ppc/boot/common/ns16550.c Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ns16550.c 1.14 01/11/02 10:46:07 trini + * BK Id: SCCS/s.ns16550.c 1.16 03/13/02 09:17:06 trini */ /* * COM1 NS16550 support @@ -63,7 +63,7 @@ else { /* Input clock. */ outb(com_port + (UART_DLL << shift), - (BASE_BAUD / SERIAL_BAUD)); + (BASE_BAUD / SERIAL_BAUD) & 0xFF); outb(com_port + (UART_DLM << shift), (BASE_BAUD / SERIAL_BAUD) >> 8); /* 8 data, 1 stop, no parity */ diff -urN linux-2.4.19-pre6/arch/ppc/config.in linux-2.4.19-pre7/arch/ppc/config.in --- linux-2.4.19-pre6/arch/ppc/config.in Mon Apr 15 21:53:31 2002 +++ linux-2.4.19-pre7/arch/ppc/config.in Mon Apr 15 21:54:22 2002 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.config.in 1.47 12/01/01 20:09:06 benh +# BK Id: SCCS/s.config.in 1.51 03/07/02 13:36:31 trini # # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. @@ -197,6 +197,7 @@ bool 'Support for RTAS (RunTime Abstraction Services) in /proc' CONFIG_PPC_RTAS bool 'Support for early boot text console (BootX or OpenFirmware only)' CONFIG_BOOTX_TEXT bool 'Support for PReP Residual Data' CONFIG_PREP_RESIDUAL + dep_bool ' Support for reading of PReP Residual Data in /proc' CONFIG_PROC_PREPRESIDUAL $CONFIG_PREP_RESIDUAL fi bool 'Default bootloader kernel arguments' CONFIG_CMDLINE_BOOL @@ -392,9 +393,7 @@ source drivers/usb/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -urN linux-2.4.19-pre6/arch/ppc/configs/IVMS8_defconfig linux-2.4.19-pre7/arch/ppc/configs/IVMS8_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/IVMS8_defconfig Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/configs/IVMS8_defconfig Mon Apr 15 21:54:22 2002 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -48,6 +49,7 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y +CONFIG_EMBEDDEDBOOT=y # # General setup @@ -96,6 +98,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set @@ -119,8 +122,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -134,6 +135,7 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -146,6 +148,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -242,7 +256,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -394,11 +407,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set @@ -411,6 +428,7 @@ # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -435,6 +453,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y @@ -452,6 +471,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -509,6 +530,10 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set @@ -571,6 +596,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -584,6 +610,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/SM850_defconfig linux-2.4.19-pre7/arch/ppc/configs/SM850_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/SM850_defconfig Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/configs/SM850_defconfig Mon Apr 15 21:54:22 2002 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -49,6 +50,7 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y +CONFIG_EMBEDDEDBOOT=y # # General setup @@ -97,6 +99,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set @@ -120,8 +123,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -135,6 +136,7 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -147,6 +149,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -200,7 +214,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -352,11 +365,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set @@ -369,6 +386,7 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -393,6 +411,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y @@ -410,6 +429,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -471,6 +492,10 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set @@ -533,6 +558,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -546,6 +572,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/SPD823TS_defconfig linux-2.4.19-pre7/arch/ppc/configs/SPD823TS_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/SPD823TS_defconfig Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/configs/SPD823TS_defconfig Mon Apr 15 21:54:22 2002 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -48,6 +49,7 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y +CONFIG_EMBEDDEDBOOT=y # # General setup @@ -96,6 +98,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set @@ -119,8 +122,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -134,6 +135,7 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -146,6 +148,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -199,7 +213,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -351,11 +364,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set @@ -368,6 +385,7 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -392,6 +410,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y @@ -409,6 +428,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -470,6 +491,10 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set @@ -532,6 +557,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -545,6 +571,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/TQM823L_defconfig linux-2.4.19-pre7/arch/ppc/configs/TQM823L_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/TQM823L_defconfig Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/configs/TQM823L_defconfig Mon Apr 15 21:54:22 2002 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -49,6 +50,7 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y +CONFIG_EMBEDDEDBOOT=y # # General setup @@ -97,6 +99,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set @@ -120,8 +123,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -135,6 +136,7 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -147,6 +149,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -200,7 +214,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -352,11 +365,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set @@ -369,6 +386,7 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -393,6 +411,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y @@ -410,6 +429,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -471,6 +492,10 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set @@ -533,6 +558,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -546,6 +572,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/TQM850L_defconfig linux-2.4.19-pre7/arch/ppc/configs/TQM850L_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/TQM850L_defconfig Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/configs/TQM850L_defconfig Mon Apr 15 21:54:22 2002 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -49,6 +50,7 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y +CONFIG_EMBEDDEDBOOT=y # # General setup @@ -97,6 +99,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set @@ -120,8 +123,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -135,6 +136,7 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -147,6 +149,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -200,7 +214,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -352,11 +365,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set @@ -369,6 +386,7 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -393,6 +411,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y @@ -410,6 +429,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -471,6 +492,10 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set @@ -533,6 +558,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -546,6 +572,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/TQM860L_defconfig linux-2.4.19-pre7/arch/ppc/configs/TQM860L_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/TQM860L_defconfig Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/configs/TQM860L_defconfig Mon Apr 15 21:54:22 2002 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -49,6 +50,7 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y +CONFIG_EMBEDDEDBOOT=y # # General setup @@ -97,6 +99,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set @@ -120,8 +123,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -135,6 +136,7 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -147,6 +149,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -243,7 +257,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -395,11 +408,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set @@ -412,6 +429,7 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -436,6 +454,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y @@ -453,6 +472,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -518,6 +539,10 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set @@ -580,6 +605,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -593,6 +619,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/apus_defconfig linux-2.4.19-pre7/arch/ppc/configs/apus_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/apus_defconfig Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/configs/apus_defconfig Mon Apr 15 21:54:22 2002 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -66,6 +67,7 @@ CONFIG_PARPORT_AMIGA=m # CONFIG_PARPORT_MFC3 is not set # CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_GSC is not set # CONFIG_PARPORT_SUNBPP is not set # CONFIG_PARPORT_OTHER is not set # CONFIG_PARPORT_1284 is not set @@ -115,6 +117,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=m @@ -139,8 +142,6 @@ # CONFIG_PACKET=m CONFIG_PACKET_MMAP=y -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set CONFIG_NETLINK_DEV=m CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -152,6 +153,7 @@ # CONFIG_IP_PNP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y @@ -168,6 +170,7 @@ CONFIG_IP_NF_MATCH_MARK=m CONFIG_IP_NF_MATCH_MULTIPORT=m CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_AH_ESP=m CONFIG_IP_NF_MATCH_LENGTH=m CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_MATCH_TCPMSS=m @@ -188,6 +191,7 @@ CONFIG_IP_NF_TARGET_TOS=m CONFIG_IP_NF_TARGET_MARK=m CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m CONFIG_IP_NF_TARGET_TCPMSS=m CONFIG_IP_NF_COMPAT_IPCHAINS=m CONFIG_IP_NF_NAT_NEEDED=y @@ -202,6 +206,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -304,6 +320,7 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set @@ -327,6 +344,7 @@ # CONFIG_SCSI_IMM is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_SYM53C8XX is not set # CONFIG_SCSI_PAS16 is not set @@ -392,7 +410,6 @@ # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -483,6 +500,7 @@ # CONFIG_FB_PM2_FIFO_DISCONNECT is not set # CONFIG_FB_PM2_PCI is not set CONFIG_FB_PM2_CVPPC=y +# CONFIG_FB_PM3 is not set CONFIG_FB_CYBER2000=y CONFIG_FB_AMIGA=y CONFIG_FB_AMIGA_OCS=y @@ -507,6 +525,7 @@ # CONFIG_FB_SIS is not set # CONFIG_FB_3DFX is not set # CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set # CONFIG_FB_VIRTUAL is not set CONFIG_FBCON_ADVANCED=y # CONFIG_FBCON_MFB is not set @@ -650,11 +669,15 @@ CONFIG_AUTOFS4_FS=m # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set CONFIG_AFFS_FS=y CONFIG_HFS_FS=y # CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y # CONFIG_UMSDOS_FS is not set @@ -667,6 +690,7 @@ CONFIG_RAMFS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set CONFIG_MINIX_FS=y # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -691,6 +715,7 @@ # Network File Systems # CONFIG_CODA_FS=m +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y CONFIG_NFS_V3=y # CONFIG_ROOT_NFS is not set @@ -710,6 +735,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +CONFIG_ZLIB_FS_INFLATE=y # # Partition Types @@ -757,6 +784,7 @@ CONFIG_NLS_CODEPAGE_949=m CONFIG_NLS_CODEPAGE_874=m CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m CONFIG_NLS_CODEPAGE_1251=m CONFIG_NLS_ISO8859_1=m CONFIG_NLS_ISO8859_2=m @@ -910,6 +938,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -923,6 +952,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/bseip_defconfig linux-2.4.19-pre7/arch/ppc/configs/bseip_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/bseip_defconfig Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/configs/bseip_defconfig Mon Apr 15 21:54:22 2002 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -46,6 +47,7 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y +CONFIG_EMBEDDEDBOOT=y # # General setup @@ -94,6 +96,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set @@ -118,8 +121,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -134,6 +135,7 @@ # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set @@ -146,6 +148,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -199,7 +213,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -351,11 +364,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set @@ -368,6 +385,7 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -392,6 +410,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y @@ -409,6 +428,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -470,6 +491,10 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set @@ -532,6 +557,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -545,6 +571,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/common_defconfig linux-2.4.19-pre7/arch/ppc/configs/common_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/common_defconfig Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/configs/common_defconfig Mon Apr 15 21:54:22 2002 @@ -74,6 +74,7 @@ CONFIG_PPC_RTAS=y CONFIG_BOOTX_TEXT=y CONFIG_PREP_RESIDUAL=y +CONFIG_PROC_PREPRESIDUAL=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="console=ttyS0,9600 console=tty0 root=/dev/sda2" @@ -96,6 +97,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set @@ -149,6 +151,7 @@ CONFIG_IP_NF_MATCH_MARK=m CONFIG_IP_NF_MATCH_MULTIPORT=m CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_AH_ESP=m CONFIG_IP_NF_MATCH_LENGTH=m CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_MATCH_TCPMSS=m @@ -167,6 +170,7 @@ CONFIG_IP_NF_NAT_FTP=m # CONFIG_IP_NF_MANGLE is not set # CONFIG_IP_NF_TARGET_LOG is not set +CONFIG_IP_NF_TARGET_ULOG=m CONFIG_IP_NF_TARGET_TCPMSS=m CONFIG_IP_NF_COMPAT_IPCHAINS=m CONFIG_IP_NF_NAT_NEEDED=y @@ -181,6 +185,18 @@ # # CONFIG_IPX is not set CONFIG_ATALK=m + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -316,6 +332,7 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set CONFIG_SCSI_AIC7XXX=m CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 CONFIG_AIC7XXX_RESET_DELAY_MS=15000 @@ -380,13 +397,6 @@ # ARCnet devices # # CONFIG_ARCNET is not set - -# -# Appletalk devices -# -# CONFIG_LTPC is not set -# CONFIG_COPS is not set -# CONFIG_IPDDP is not set # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set @@ -405,7 +415,6 @@ # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -436,6 +445,7 @@ # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set @@ -530,6 +540,7 @@ # CONFIG_FB_RIVA is not set # CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set # CONFIG_FB_CYBER2000 is not set CONFIG_FB_OF=y CONFIG_FB_CONTROL=y @@ -554,6 +565,7 @@ # CONFIG_FB_SIS is not set CONFIG_FB_3DFX=y # CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -812,6 +824,7 @@ # CONFIG_NLS_CODEPAGE_949 is not set # CONFIG_NLS_CODEPAGE_874 is not set # CONFIG_NLS_ISO8859_8 is not set +CONFIG_NLS_CODEPAGE_1250=m # CONFIG_NLS_CODEPAGE_1251 is not set CONFIG_NLS_ISO8859_1=m # CONFIG_NLS_ISO8859_2 is not set @@ -944,6 +957,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set CONFIG_USB_SERIAL_VISOR=m +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -957,6 +971,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/est8260_defconfig linux-2.4.19-pre7/arch/ppc/configs/est8260_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/est8260_defconfig Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/configs/est8260_defconfig Mon Apr 15 21:54:22 2002 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -30,6 +31,7 @@ CONFIG_SERIAL_CONSOLE=y CONFIG_EST8260=y # CONFIG_SMP is not set +CONFIG_EMBEDDEDBOOT=y # # General setup @@ -77,6 +79,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set @@ -101,8 +104,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -117,6 +118,7 @@ # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set @@ -129,6 +131,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -182,7 +196,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -335,11 +348,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set @@ -352,6 +369,7 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -376,6 +394,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y @@ -393,6 +412,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -419,6 +440,7 @@ # # MPC8260 Communication Options # +# CONFIG_SCC_CONSOLE is not set CONFIG_SCC_ENET=y CONFIG_SCC1_ENET=y # CONFIG_FEC_ENET is not set @@ -440,6 +462,10 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set @@ -502,6 +528,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -515,6 +542,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/gemini_defconfig linux-2.4.19-pre7/arch/ppc/configs/gemini_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/gemini_defconfig Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/configs/gemini_defconfig Mon Apr 15 21:54:22 2002 @@ -86,6 +86,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set @@ -143,6 +144,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -200,6 +213,7 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set @@ -272,7 +286,6 @@ # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -600,6 +613,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -613,6 +627,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/ibmchrp_defconfig linux-2.4.19-pre7/arch/ppc/configs/ibmchrp_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/ibmchrp_defconfig Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/configs/ibmchrp_defconfig Mon Apr 15 21:54:22 2002 @@ -68,6 +68,7 @@ CONFIG_PPC_RTAS=y # CONFIG_BOOTX_TEXT is not set # CONFIG_PREP_RESIDUAL is not set +# CONFIG_PROC_PREPRESIDUAL is not set # CONFIG_CMDLINE_BOOL is not set # @@ -89,6 +90,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set @@ -142,6 +144,7 @@ CONFIG_IP_NF_MATCH_MARK=m CONFIG_IP_NF_MATCH_MULTIPORT=m CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_AH_ESP=m CONFIG_IP_NF_MATCH_LENGTH=m CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_MATCH_TCPMSS=m @@ -160,6 +163,7 @@ CONFIG_IP_NF_NAT_FTP=m # CONFIG_IP_NF_MANGLE is not set # CONFIG_IP_NF_TARGET_LOG is not set +CONFIG_IP_NF_TARGET_ULOG=m CONFIG_IP_NF_TARGET_TCPMSS=m CONFIG_IP_NF_COMPAT_IPCHAINS=m CONFIG_IP_NF_NAT_NEEDED=y @@ -174,6 +178,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -231,6 +247,7 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set @@ -305,7 +322,6 @@ # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -334,6 +350,7 @@ # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set @@ -413,6 +430,7 @@ # CONFIG_FB_RIVA is not set # CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set # CONFIG_FB_CYBER2000 is not set CONFIG_FB_OF=y # CONFIG_FB_CONTROL is not set @@ -434,6 +452,7 @@ # CONFIG_FB_SIS is not set CONFIG_FB_3DFX=y # CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -681,6 +700,7 @@ # CONFIG_NLS_CODEPAGE_949 is not set # CONFIG_NLS_CODEPAGE_874 is not set # CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set CONFIG_NLS_ISO8859_1=m # CONFIG_NLS_ISO8859_2 is not set @@ -782,6 +802,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -795,6 +816,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/mbx_defconfig linux-2.4.19-pre7/arch/ppc/configs/mbx_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/mbx_defconfig Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/configs/mbx_defconfig Mon Apr 15 21:54:22 2002 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -46,6 +47,7 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y +CONFIG_EMBEDDEDBOOT=y # # General setup @@ -94,6 +96,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set @@ -116,7 +119,7 @@ # Networking options # # CONFIG_PACKET is not set -# CONFIG_NETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y @@ -129,6 +132,7 @@ # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_IPV6 is not set @@ -141,6 +145,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -182,6 +198,7 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set # # Ethernet (10 or 100Mbit) @@ -193,7 +210,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -344,11 +360,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set @@ -361,6 +381,7 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -385,6 +406,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y @@ -402,6 +424,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -463,6 +487,10 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set @@ -525,6 +553,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -538,6 +567,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/oak_defconfig linux-2.4.19-pre7/arch/ppc/configs/oak_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/oak_defconfig Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/configs/oak_defconfig Mon Apr 15 21:54:22 2002 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -79,6 +80,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set @@ -102,7 +104,7 @@ # Networking options # # CONFIG_PACKET is not set -# CONFIG_NETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y @@ -116,6 +118,7 @@ # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set @@ -128,6 +131,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -169,6 +184,7 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set # # Ethernet (10 or 100Mbit) @@ -180,7 +196,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -332,11 +347,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set @@ -349,6 +368,7 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -373,6 +393,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y @@ -390,6 +411,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -421,6 +444,10 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set @@ -483,6 +510,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -496,6 +524,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/pmac_defconfig linux-2.4.19-pre7/arch/ppc/configs/pmac_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/pmac_defconfig Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/configs/pmac_defconfig Mon Apr 15 21:54:22 2002 @@ -78,6 +78,7 @@ CONFIG_PPC_RTAS=y CONFIG_BOOTX_TEXT=y # CONFIG_PREP_RESIDUAL is not set +# CONFIG_PROC_PREPRESIDUAL is not set # CONFIG_CMDLINE_BOOL is not set # @@ -99,6 +100,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set @@ -152,6 +154,7 @@ CONFIG_IP_NF_MATCH_MARK=m CONFIG_IP_NF_MATCH_MULTIPORT=m CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_AH_ESP=m CONFIG_IP_NF_MATCH_LENGTH=m CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_MATCH_TCPMSS=m @@ -170,6 +173,7 @@ CONFIG_IP_NF_NAT_FTP=m # CONFIG_IP_NF_MANGLE is not set # CONFIG_IP_NF_TARGET_LOG is not set +CONFIG_IP_NF_TARGET_ULOG=m CONFIG_IP_NF_TARGET_TCPMSS=m CONFIG_IP_NF_COMPAT_IPCHAINS=m CONFIG_IP_NF_NAT_NEEDED=y @@ -184,6 +188,18 @@ # # CONFIG_IPX is not set CONFIG_ATALK=m + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -319,6 +335,7 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set CONFIG_SCSI_AIC7XXX=m CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 CONFIG_AIC7XXX_RESET_DELAY_MS=15000 @@ -404,13 +421,6 @@ # ARCnet devices # # CONFIG_ARCNET is not set - -# -# Appletalk devices -# -# CONFIG_LTPC is not set -# CONFIG_COPS is not set -# CONFIG_IPDDP is not set # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set @@ -429,7 +439,6 @@ # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set CONFIG_SUNGEM=y # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -460,6 +469,7 @@ # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set @@ -566,7 +576,13 @@ CONFIG_IRNET=m CONFIG_IRCOMM=m # CONFIG_IRDA_ULTRA is not set -# CONFIG_IRDA_OPTIONS is not set + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +# CONFIG_IRDA_DEBUG is not set # # Infrared-port device drivers @@ -617,6 +633,7 @@ # CONFIG_FB_RIVA is not set # CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set # CONFIG_FB_CYBER2000 is not set CONFIG_FB_OF=y CONFIG_FB_CONTROL=y @@ -641,6 +658,7 @@ # CONFIG_FB_SIS is not set CONFIG_FB_3DFX=y # CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -908,6 +926,7 @@ # CONFIG_NLS_CODEPAGE_949 is not set # CONFIG_NLS_CODEPAGE_874 is not set # CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set CONFIG_NLS_ISO8859_1=m # CONFIG_NLS_ISO8859_2 is not set @@ -1040,6 +1059,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set CONFIG_USB_SERIAL_VISOR=m +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -1053,6 +1073,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/power3_defconfig linux-2.4.19-pre7/arch/ppc/configs/power3_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/power3_defconfig Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/configs/power3_defconfig Mon Apr 15 21:54:22 2002 @@ -76,6 +76,7 @@ CONFIG_PPC_RTAS=y # CONFIG_BOOTX_TEXT is not set # CONFIG_PREP_RESIDUAL is not set +# CONFIG_PROC_PREPRESIDUAL is not set # CONFIG_CMDLINE_BOOL is not set # @@ -97,6 +98,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set @@ -145,6 +147,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -202,6 +216,7 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set @@ -278,7 +293,6 @@ # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -307,6 +321,7 @@ # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set +# CONFIG_8139_NEW_RX_RESET is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set @@ -386,6 +401,7 @@ # CONFIG_FB_RIVA is not set # CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set # CONFIG_FB_CYBER2000 is not set CONFIG_FB_OF=y # CONFIG_FB_CONTROL is not set @@ -409,6 +425,7 @@ # CONFIG_FB_SIS is not set # CONFIG_FB_3DFX is not set # CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -652,6 +669,7 @@ # CONFIG_NLS_CODEPAGE_949 is not set # CONFIG_NLS_CODEPAGE_874 is not set # CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set CONFIG_NLS_ISO8859_1=y # CONFIG_NLS_ISO8859_2 is not set @@ -804,6 +822,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -817,6 +836,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/rpxcllf_defconfig linux-2.4.19-pre7/arch/ppc/configs/rpxcllf_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/rpxcllf_defconfig Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/configs/rpxcllf_defconfig Mon Apr 15 21:54:22 2002 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -46,6 +47,7 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y +CONFIG_EMBEDDEDBOOT=y # # General setup @@ -94,6 +96,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set @@ -118,8 +121,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -134,6 +135,7 @@ # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set @@ -146,6 +148,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -199,7 +213,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -351,11 +364,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set @@ -368,6 +385,7 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -392,6 +410,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y @@ -409,6 +428,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -471,6 +492,10 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set @@ -533,6 +558,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -546,6 +572,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/rpxlite_defconfig linux-2.4.19-pre7/arch/ppc/configs/rpxlite_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/rpxlite_defconfig Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/configs/rpxlite_defconfig Mon Apr 15 21:54:22 2002 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -46,6 +47,7 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y +CONFIG_EMBEDDEDBOOT=y # # General setup @@ -94,6 +96,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set @@ -118,8 +121,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -134,6 +135,7 @@ # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set @@ -146,6 +148,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -199,7 +213,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -351,11 +364,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set @@ -368,6 +385,7 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -392,6 +410,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y @@ -409,6 +428,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -468,6 +489,10 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set @@ -530,6 +555,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -543,6 +569,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/configs/walnut_defconfig linux-2.4.19-pre7/arch/ppc/configs/walnut_defconfig --- linux-2.4.19-pre6/arch/ppc/configs/walnut_defconfig Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/configs/walnut_defconfig Mon Apr 15 21:54:22 2002 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -79,6 +80,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set @@ -102,7 +104,7 @@ # Networking options # # CONFIG_PACKET is not set -# CONFIG_NETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y @@ -116,6 +118,7 @@ # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set @@ -128,6 +131,18 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_COPS_DAYNA is not set +# CONFIG_COPS_TANGENT is not set +# CONFIG_IPDDP is not set +# CONFIG_IPDDP_ENCAP is not set +# CONFIG_IPDDP_DECAP is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -169,6 +184,7 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set # # Ethernet (10 or 100Mbit) @@ -180,7 +196,6 @@ # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -336,11 +351,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set @@ -353,6 +372,7 @@ # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -377,6 +397,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y @@ -394,6 +415,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -425,6 +448,10 @@ # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# # CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set @@ -487,6 +514,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -500,6 +528,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set diff -urN linux-2.4.19-pre6/arch/ppc/kernel/Makefile linux-2.4.19-pre7/arch/ppc/kernel/Makefile --- linux-2.4.19-pre6/arch/ppc/kernel/Makefile Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/Makefile Mon Apr 15 21:54:22 2002 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.36 12/01/01 20:09:06 benh +# BK Id: SCCS/s.Makefile 1.40 04/09/02 21:01:57 paulus # # # Makefile for the linux kernel. @@ -15,6 +15,10 @@ EXTRA_AFLAGS := -Wa,-mppc64bridge endif +# Code in these files is used before the kernel is moved to its final position +CFLAGS_prom_init.o += -mrelocatable-lib +CFLAGS_btext.o += -mrelocatable-lib + # Start off with 'head.o', change as needed. HEAD-y := head.o HEAD-$(CONFIG_4xx) := head_4xx.o @@ -56,10 +60,11 @@ obj-$(CONFIG_PCI) += apus_pci.o endif obj-$(CONFIG_ALL_PPC) += pmac_pic.o pmac_setup.o pmac_time.o prom.o \ - pmac_feature.o pmac_pci.o chrp_setup.o \ - chrp_time.o chrp_pci.o open_pic.o \ - indirect_pci.o i8259.o prep_pci.o \ - prep_time.o prep_nvram.o prep_setup.o + prom_init.o pmac_feature.o pmac_pci.o \ + chrp_setup.o chrp_time.o chrp_pci.o \ + open_pic.o indirect_pci.o i8259.o \ + prep_pci.o prep_time.o prep_nvram.o \ + prep_setup.o obj-$(CONFIG_NVRAM) += pmac_nvram.o obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o obj-$(CONFIG_PMAC_PBOOK) += sleep.o diff -urN linux-2.4.19-pre6/arch/ppc/kernel/btext.c linux-2.4.19-pre7/arch/ppc/kernel/btext.c --- linux-2.4.19-pre6/arch/ppc/kernel/btext.c Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/btext.c Mon Apr 15 21:54:22 2002 @@ -44,10 +44,9 @@ static unsigned char vga_font[cmapsz]; -int boot_text_mapped = 1; +int boot_text_mapped; -boot_infos_t *disp_bi; -boot_infos_t fake_bi; +boot_infos_t disp_bi; extern char *klimit; @@ -69,48 +68,47 @@ void __init btext_init(boot_infos_t *bi) { - unsigned long offset = reloc_offset(); - - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y) = 0; - RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8; - RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16; - RELOC(disp_bi) = PTRUNRELOC(bi); + g_loc_X = 0; + g_loc_Y = 0; + g_max_loc_X = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8; + g_max_loc_Y = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16; + disp_bi = *bi; + boot_text_mapped = 1; } void __init -btext_welcome(boot_infos_t* bi) +btext_welcome(void) { - unsigned long offset = reloc_offset(); unsigned long flags; unsigned long pvr; - - btext_drawstring(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n")); - btext_drawstring(RELOC("\nlinked at : 0x")); + boot_infos_t* bi = &disp_bi; + + btext_drawstring("Welcome to Linux, kernel " UTS_RELEASE "\n"); + btext_drawstring("\nlinked at : 0x"); btext_drawhex(KERNELBASE); - btext_drawstring(RELOC("\nframe buffer at : 0x")); + btext_drawstring("\nframe buffer at : 0x"); btext_drawhex((unsigned long)bi->dispDeviceBase); - btext_drawstring(RELOC(" (phys), 0x")); + btext_drawstring(" (phys), 0x"); btext_drawhex((unsigned long)bi->logicalDisplayBase); - btext_drawstring(RELOC(" (log)")); - btext_drawstring(RELOC("\nklimit : 0x")); - btext_drawhex((unsigned long)RELOC(klimit)); - btext_drawstring(RELOC("\nMSR : 0x")); + btext_drawstring(" (log)"); + btext_drawstring("\nklimit : 0x"); + btext_drawhex((unsigned long)klimit); + btext_drawstring("\nMSR : 0x"); __asm__ __volatile__ ("mfmsr %0" : "=r" (flags)); btext_drawhex(flags); __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr)); pvr >>= 16; if (pvr > 1) { - btext_drawstring(RELOC("\nHID0 : 0x")); + btext_drawstring("\nHID0 : 0x"); __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags)); btext_drawhex(flags); } if (pvr == 8 || pvr == 12 || pvr == 0x800c) { - btext_drawstring(RELOC("\nICTC : 0x")); + btext_drawstring("\nICTC : 0x"); __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags)); btext_drawhex(flags); } - btext_drawstring(RELOC("\n\n")); + btext_drawstring("\n\n"); } /* Calc BAT values for mapping the display and store them @@ -131,33 +129,28 @@ void __init btext_prepare_BAT(void) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); + boot_infos_t* bi = &disp_bi; unsigned long vaddr = KERNELBASE + 0x10000000; unsigned long addr; unsigned long lowbits; - if (!RELOC(disp_bi)) { - RELOC(boot_text_mapped) = 0; - return; - } addr = (unsigned long)bi->dispDeviceBase; if (!addr) { - RELOC(boot_text_mapped) = 0; + boot_text_mapped = 0; return; } if (PVR_VER(mfspr(PVR)) != 1) { /* 603, 604, G3, G4, ... */ lowbits = addr & ~0xFF000000UL; addr &= 0xFF000000UL; - RELOC(disp_BAT[0]) = vaddr | (BL_16M<<2) | 2; - RELOC(disp_BAT[1]) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); + disp_BAT[0] = vaddr | (BL_16M<<2) | 2; + disp_BAT[1] = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); } else { /* 601 */ lowbits = addr & ~0xFF800000UL; addr &= 0xFF800000UL; - RELOC(disp_BAT[0]) = vaddr | (_PAGE_NO_CACHE | PP_RWXX) | 4; - RELOC(disp_BAT[1]) = addr | BL_8M | 0x40; + disp_BAT[0] = vaddr | (_PAGE_NO_CACHE | PP_RWXX) | 4; + disp_BAT[1] = addr | BL_8M | 0x40; } bi->logicalDisplayBase = (void *) (vaddr + lowbits); } @@ -169,15 +162,12 @@ btext_setup_display(int width, int height, int depth, int pitch, unsigned long address) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi; + boot_infos_t* bi = &disp_bi; - RELOC(disp_bi) = &fake_bi; - bi = PTRRELOC((&fake_bi)); - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y) = 0; - RELOC(g_max_loc_X) = width / 8; - RELOC(g_max_loc_Y) = height / 16; + g_loc_X = 0; + g_loc_Y = 0; + g_max_loc_X = width / 8; + g_max_loc_Y = height / 16; bi->logicalDisplayBase = (unsigned char *)address; bi->dispDeviceBase = (unsigned char *)address; bi->dispDeviceRowBytes = pitch; @@ -185,6 +175,7 @@ bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; bi->dispDeviceRect[2] = width; bi->dispDeviceRect[3] = height; + boot_text_mapped = 1; } /* Here's a small text engine to use during early boot @@ -202,16 +193,18 @@ map_boot_text(void) { unsigned long base, offset, size; - if (disp_bi == 0) + boot_infos_t *bi = &disp_bi; + + if (bi->dispDeviceBase == 0) return; - base = ((unsigned long) disp_bi->dispDeviceBase) & 0xFFFFF000UL; - offset = ((unsigned long) disp_bi->dispDeviceBase) - base; - size = disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3] + offset - + disp_bi->dispDeviceRect[0]; - disp_bi->logicalDisplayBase = ioremap(base, size); - if (disp_bi->logicalDisplayBase == 0) + base = ((unsigned long) bi->dispDeviceBase) & 0xFFFFF000UL; + offset = ((unsigned long) bi->dispDeviceBase) - base; + size = bi->dispDeviceRowBytes * bi->dispDeviceRect[3] + offset + + bi->dispDeviceRect[0]; + bi->logicalDisplayBase = ioremap(base, size); + if (bi->logicalDisplayBase == 0) return; - disp_bi->logicalDisplayBase += offset; + bi->logicalDisplayBase += offset; boot_text_mapped = 1; } @@ -234,22 +227,24 @@ btext_update_display(unsigned long phys, int width, int height, int depth, int pitch) { - if (disp_bi == 0) + boot_infos_t *bi = &disp_bi; + + if (bi->dispDeviceBase == 0) return; /* check it's the same frame buffer (within 256MB) */ - if ((phys ^ (unsigned long)disp_bi->dispDeviceBase) & 0xf0000000) + if ((phys ^ (unsigned long)bi->dispDeviceBase) & 0xf0000000) return; - disp_bi->dispDeviceBase = (__u8 *) phys; - disp_bi->dispDeviceRect[0] = 0; - disp_bi->dispDeviceRect[1] = 0; - disp_bi->dispDeviceRect[2] = width; - disp_bi->dispDeviceRect[3] = height; - disp_bi->dispDeviceDepth = depth; - disp_bi->dispDeviceRowBytes = pitch; + bi->dispDeviceBase = (__u8 *) phys; + bi->dispDeviceRect[0] = 0; + bi->dispDeviceRect[1] = 0; + bi->dispDeviceRect[2] = width; + bi->dispDeviceRect[3] = height; + bi->dispDeviceDepth = depth; + bi->dispDeviceRowBytes = pitch; if (boot_text_mapped) { - iounmap(disp_bi->logicalDisplayBase); + iounmap(bi->logicalDisplayBase); boot_text_mapped = 0; } map_boot_text(); @@ -261,8 +256,7 @@ void BTEXT btext_clearscreen(void) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); + boot_infos_t* bi = &disp_bi; unsigned long *base = (unsigned long *)calc_base(bi, 0, 0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3)) >> 2; @@ -284,8 +278,7 @@ void BTEXT btext_flushscreen(void) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); + boot_infos_t* bi = &disp_bi; unsigned long *base = (unsigned long *)calc_base(bi, 0, 0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3)) >> 2; @@ -306,8 +299,7 @@ static BTEXT void scrollscreen(void) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); + boot_infos_t* bi = &disp_bi; unsigned long *src = (unsigned long *)calc_base(bi,0,16); unsigned long *dst = (unsigned long *)calc_base(bi,0,0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * @@ -341,49 +333,48 @@ void BTEXT btext_drawchar(char c) { - unsigned long offset = reloc_offset(); int cline = 0, x; - if (!RELOC(boot_text_mapped)) + if (!boot_text_mapped) return; switch (c) { case '\b': - if (RELOC(g_loc_X) > 0) - --RELOC(g_loc_X); + if (g_loc_X > 0) + --g_loc_X; break; case '\t': - RELOC(g_loc_X) = (RELOC(g_loc_X) & -8) + 8; + g_loc_X = (g_loc_X & -8) + 8; break; case '\r': - RELOC(g_loc_X) = 0; + g_loc_X = 0; break; case '\n': - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y)++; + g_loc_X = 0; + g_loc_Y++; cline = 1; break; default: - draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y)); + draw_byte(c, g_loc_X++, g_loc_Y); } - if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) { - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y)++; + if (g_loc_X >= g_max_loc_X) { + g_loc_X = 0; + g_loc_Y++; cline = 1; } #ifndef NO_SCROLL - while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) { + while (g_loc_Y >= g_max_loc_Y) { scrollscreen(); - RELOC(g_loc_Y)--; + g_loc_Y--; } #else /* wrap around from bottom to top of screen so we don't waste time scrolling each line. -- paulus. */ - if (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) - RELOC(g_loc_Y) = 0; + if (g_loc_Y >= g_max_loc_Y) + g_loc_Y = 0; if (cline) { - for (x = 0; x < RELOC(g_max_loc_X); ++x) - draw_byte(' ', x, RELOC(g_loc_Y)); + for (x = 0; x < g_max_loc_X; ++x) + draw_byte(' ', x, g_loc_Y); } #endif } @@ -391,9 +382,7 @@ void BTEXT btext_drawstring(const char *c) { - unsigned long offset = reloc_offset(); - - if (!RELOC(boot_text_mapped)) + if (!boot_text_mapped) return; while (*c) btext_drawchar(*c++); @@ -403,28 +392,26 @@ btext_drawhex(unsigned long v) { static char hex_table[] = "0123456789abcdef"; - unsigned long offset = reloc_offset(); - if (!RELOC(boot_text_mapped)) + if (!boot_text_mapped) return; - btext_drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]); - btext_drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]); - btext_drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]); - btext_drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]); - btext_drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]); - btext_drawchar(RELOC(hex_table)[(v >> 8) & 0x0000000FUL]); - btext_drawchar(RELOC(hex_table)[(v >> 4) & 0x0000000FUL]); - btext_drawchar(RELOC(hex_table)[(v >> 0) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 8) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 4) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 0) & 0x0000000FUL]); btext_drawchar(' '); } static void BTEXT draw_byte(unsigned char c, long locX, long locY) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); + boot_infos_t* bi = &disp_bi; unsigned char *base = calc_base(bi, locX << 3, locY << 4); - unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16]; + unsigned char *font = &vga_font[((unsigned long)c) * 16]; int rb = bi->dispDeviceRowBytes; switch(bi->dispDeviceDepth) { @@ -497,8 +484,7 @@ int l, bits; int fg = 0xFFFFFFFFUL; int bg = 0x00000000UL; - unsigned long offset = reloc_offset(); - unsigned long *eb = RELOC(expand_bits_16); + unsigned long *eb = expand_bits_16; for (l = 0; l < 16; ++l) { @@ -517,8 +503,7 @@ int l, bits; int fg = 0x0F0F0F0FUL; int bg = 0x00000000UL; - unsigned long offset = reloc_offset(); - unsigned long *eb = RELOC(expand_bits_8); + unsigned long *eb = expand_bits_8; for (l = 0; l < 16; ++l) { diff -urN linux-2.4.19-pre6/arch/ppc/kernel/chrp_setup.c linux-2.4.19-pre7/arch/ppc/kernel/chrp_setup.c --- linux-2.4.19-pre6/arch/ppc/kernel/chrp_setup.c Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/chrp_setup.c Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.chrp_setup.c 1.40 12/19/01 09:45:54 trini + * BK Id: SCCS/s.chrp_setup.c 1.42 04/09/02 21:43:09 paulus */ /* * linux/arch/ppc/kernel/setup.c @@ -374,7 +374,7 @@ openpic_init(1, NUM_8259_INTERRUPTS, chrp_int_ack_special, nmi_irq); for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ ) irq_desc[i].handler = &i8259_pic; - i8259_init(NULL); + i8259_init(0); #if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON) /* see if there is a keyboard in the device tree with a parent of type "adb" */ diff -urN linux-2.4.19-pre6/arch/ppc/kernel/cputable.c linux-2.4.19-pre7/arch/ppc/kernel/cputable.c --- linux-2.4.19-pre6/arch/ppc/kernel/cputable.c Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/cputable.c Mon Apr 15 21:54:22 2002 @@ -63,21 +63,24 @@ }, { /* 603 */ 0xffff0000, 0x00030000, "603", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_603 }, { /* 603e */ 0xffff0000, 0x00060000, "603e", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_603 }, { /* 603ev */ 0xffff0000, 0x00070000, "603ev", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_603 @@ -117,7 +120,7 @@ { /* 740/750 (0x4202, don't support TAU ?) */ 0xffffffff, 0x00084202, "740/750", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_HPTE_TABLE, + CPU_FTR_L2CR | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750 @@ -125,7 +128,7 @@ { /* 745/755 */ 0xfffff000, 0x00083000, "745/755", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE, + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750 @@ -133,7 +136,7 @@ { /* 750CX */ 0xffffff00, 0x00082200, "750CX", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE, + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750 @@ -141,7 +144,7 @@ { /* 740/750 (L2CR bit need fixup for 740) */ 0xffff0000, 0x00080000, "740/750", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE, + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP, COMMON_PPC, 32, 32, __setup_cpu_750 @@ -149,7 +152,8 @@ { /* 7400 rev 1.1 ? (no TAU) */ 0xffffffff, 0x000c1101, "7400 (1.1)", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE, + CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | + CPU_FTR_CAN_NAP, COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, 32, 32, __setup_cpu_7400 @@ -157,7 +161,8 @@ { /* 7400 */ 0xffff0000, 0x000c0000, "7400", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE, + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | + CPU_FTR_CAN_NAP, COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, 32, 32, __setup_cpu_7400 @@ -165,7 +170,8 @@ { /* 7410 */ 0xffff0000, 0x800c0000, "7410", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE, + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | + CPU_FTR_CAN_NAP, COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, 32, 32, __setup_cpu_7410 @@ -173,7 +179,7 @@ { /* 7450 2.0 - no doze/nap */ 0xffffffff, 0x80000200, "7450", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450, COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, 32, 32, @@ -181,8 +187,17 @@ }, { /* 7450 others */ 0xffff0000, 0x80000000, "7450", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | - CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | + CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450, + COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, + 32, 32, + __setup_cpu_7450 + }, + { /* 7455 */ + 0xffff0000, 0x80010000, "7455", + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450, COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, 32, 32, diff -urN linux-2.4.19-pre6/arch/ppc/kernel/head.S linux-2.4.19-pre7/arch/ppc/kernel/head.S --- linux-2.4.19-pre6/arch/ppc/kernel/head.S Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/head.S Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.head.S 1.34 12/02/01 11:35:27 benh + * BK Id: SCCS/s.head.S 1.37 04/09/02 21:43:09 paulus */ /* * PowerPC version @@ -217,11 +217,17 @@ SYNC RFI /* enables MMU */ -#ifdef CONFIG_SMP +/* + * We need __secondary_hold as a place to hold the other cpus on + * an SMP machine, even when we are running a UP kernel. + */ + . = 0xc0 /* for prep bootloader */ + li r3,1 /* MTX only has 1 cpu */ .globl __secondary_hold __secondary_hold: /* tell the master we're here */ stw r3,4(0) +#ifdef CONFIG_SMP 100: lwz r4,0(0) /* wait until we're told to start */ cmpw 0,r4,r3 @@ -229,7 +235,9 @@ /* our cpu # was at addr 0 - go */ mr r24,r3 /* cpu # */ b __secondary_start -#endif +#else + b . +#endif /* CONFIG_SMP */ /* * Exception entry code. This code runs with address translation @@ -301,6 +309,10 @@ #endif /* Machine check */ +BEGIN_FTR_SECTION + DSSALL + sync +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) /* Data access exception. */ @@ -1592,6 +1604,10 @@ li r0,NUM_USER_SEGMENTS mtctr r0 li r4,0 +BEGIN_FTR_SECTION + DSSALL + sync +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) 3: #ifdef CONFIG_PPC64BRIDGE slbie r4 @@ -1601,7 +1617,7 @@ rlwinm r3,r3,0,8,3 /* clear out any overflow from VSID field */ addis r4,r4,0x1000 /* address of next segment */ bdnz 3b - SYNC_601 + sync isync blr diff -urN linux-2.4.19-pre6/arch/ppc/kernel/head_8xx.S linux-2.4.19-pre7/arch/ppc/kernel/head_8xx.S --- linux-2.4.19-pre6/arch/ppc/kernel/head_8xx.S Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/kernel/head_8xx.S Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.head_8xx.S 1.23 09/16/01 19:32:54 trini + * BK Id: SCCS/s.head_8xx.S 1.25 01/08/02 16:41:27 trini */ /* * arch/ppc/kernel/except_8xx.S @@ -521,6 +521,34 @@ andis. r21, r20, 0x0200 /* If set, indicates store op */ beq 2f + /* The EA of a data TLB miss is automatically stored in the MD_EPN + * register. The EA of a data TLB error is automatically stored in + * the DAR, but not the MD_EPN register. We must copy the 20 most + * significant bits of the EA from the DAR to MD_EPN before we + * start walking the page tables. We also need to copy the CASID + * value from the M_CASID register. + * Addendum: The EA of a data TLB error is _supposed_ to be stored + * in DAR, but it seems that this doesn't happen in some cases, such + * as when the error is due to a dcbi instruction to a page with a + * TLB that doesn't have the changed bit set. In such cases, there + * does not appear to be any way to recover the EA of the error + * since it is neither in DAR nor MD_EPN. As a workaround, the + * _PAGE_HWWRITE bit is set for all kernel data pages when the PTEs + * are initialized in mapin_ram(). This will avoid the problem, + * assuming we only use the dcbi instruction on kernel addresses. + */ + mfspr r20, DAR + rlwinm r21, r20, 0, 0, 19 + ori r21, r21, MD_EVALID + mfspr r20, M_CASID + rlwimi r21, r20, 0, 28, 31 +#ifdef CONFIG_8xx_CPU6 + li r3, 0x3780 + stw r3, 12(r0) + lwz r3, 12(r0) +#endif + mtspr MD_EPN, r21 + mfspr r20, M_TWB /* Get level 1 table entry address */ /* If we are faulting a kernel address, we have to use the diff -urN linux-2.4.19-pre6/arch/ppc/kernel/idle.c linux-2.4.19-pre7/arch/ppc/kernel/idle.c --- linux-2.4.19-pre6/arch/ppc/kernel/idle.c Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/idle.c Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.idle.c 1.18 12/01/01 20:09:06 benh + * BK Id: SCCS/s.idle.c 1.20 03/19/02 15:04:39 benh */ /* * Idle daemon for PowerPC. Idle daemon will handle any action @@ -49,7 +49,9 @@ { int do_power_save = 0; - if (cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_CAN_DOZE) + /* Check if CPU can powersave */ + if (cur_cpu_spec[smp_processor_id()]->cpu_features & + (CPU_FTR_CAN_DOZE | CPU_FTR_CAN_NAP)) do_power_save = 1; /* endless loop with no priority at all */ @@ -227,6 +229,8 @@ } #endif /* 0 */ +#define DSSALL .long (0x1f<<26)+(0x10<<21)+(0x336<<1) + void power_save(void) { unsigned long hid0; @@ -235,7 +239,7 @@ /* 7450 has no DOZE mode mode, we return if powersave_nap * isn't enabled */ - if (!nap && cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_SPEC7450) + if (!(nap || (cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_CAN_DOZE))) return; /* * Disable interrupts to prevent a lost wakeup @@ -252,10 +256,23 @@ _nmask_and_or_msr(MSR_EE, 0); if (!current->need_resched) { - asm("mfspr %0,1008" : "=r" (hid0) :); + __asm__ __volatile__("mfspr %0,1008" : "=r" (hid0) :); hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE); hid0 |= (powersave_nap? HID0_NAP: HID0_DOZE) | HID0_DPM; - asm("mtspr 1008,%0" : : "r" (hid0)); + __asm__ __volatile__("mtspr 1008,%0" : : "r" (hid0)); + /* Flush pending data streams, consider this instruction + * exist on all altivec capable CPUs + */ + __asm__ __volatile__( + "98: " stringify(DSSALL) "\n" + " sync\n" + "99:\n" + ".section __ftr_fixup,\"a\"\n" + " .long %0\n" + " .long %1\n" + " .long 98b\n" + " .long 99b\n" + ".previous" : : "i" (CPU_FTR_ALTIVEC), "i" (CPU_FTR_ALTIVEC)); /* set the POW bit in the MSR, and enable interrupts * so we wake up sometime! */ diff -urN linux-2.4.19-pre6/arch/ppc/kernel/l2cr.S linux-2.4.19-pre7/arch/ppc/kernel/l2cr.S --- linux-2.4.19-pre6/arch/ppc/kernel/l2cr.S Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/l2cr.S Mon Apr 15 21:54:22 2002 @@ -134,6 +134,8 @@ The bit moved on the 7450..... ****/ + /* TODO: use HW flush assist when available */ + lis r4,0x0002 mtctr r4 li r4,0 @@ -154,10 +156,18 @@ 2: /* Set up the L2CR configuration bits (and switch L2 off) */ + /* CPU errata: Make sure the mtspr below is already in the + * L1 icache + */ + b 20f +21: sync mtspr L2CR,r3 sync - + b 22f +20: + b 21b +22: /* Before we perform the global invalidation, we must disable dynamic * power management via HID0[DPM] to work around a processor bug where * DPM can possibly interfere with the state machine in the processor @@ -223,5 +233,147 @@ END_FTR_SECTION_IFSET(CPU_FTR_L2CR) blr + +/* + * Here is a similar routine for dealing with the L3 cache + * on the 745x family of chips + */ + +_GLOBAL(_set_L3CR) + /* Make sure this is a 745x chip */ +BEGIN_FTR_SECTION + li r3,-1 + blr +END_FTR_SECTION_IFCLR(CPU_FTR_L3CR) + + /* Turn off interrupts and data relocation. */ + mfmsr r7 /* Save MSR in r7 */ + rlwinm r4,r7,0,17,15 + rlwinm r4,r4,0,28,26 /* Turn off DR bit */ + sync + mtmsr r4 + isync + + /* Stop DST streams */ + DSSALL + + /* Get the current enable bit of the L3CR into r4 */ + mfspr r4,SPRN_L3CR + + /* Tweak some bits */ + rlwinm r5,r3,0,0,0 /* r5 contains the new enable bit */ + rlwinm r3,r3,0,22,20 /* Turn off the invalidate bit */ + rlwinm r3,r3,0,1,31 /* Turn off the enable bit */ + rlwinm r3,r3,0,5,3 /* Turn off the clken bit */ + /* Check to see if we need to flush */ + rlwinm. r4,r4,0,0,0 + beq 2f + + /* Flush the cache. First, read the first 4MB of memory (physical) to + * put new data in the cache. (Actually we only need + * the size of the L3 cache plus the size of the L1+L2 cache, but 4MB will + * cover everything just to be safe). + */ + + /* TODO: use HW flush assist */ + + lis r4,0x0002 + mtctr r4 + li r4,0 +1: + lwzx r0,r0,r4 + addi r4,r4,32 /* Go to start of next cache line */ + bdnz 1b + + /* Now, flush the first 4MB of memory */ + lis r4,0x0002 + mtctr r4 + li r4,0 + sync +1: + dcbf r0,r4 + addi r4,r4,32 /* Go to start of next cache line */ + bdnz 1b + +2: + /* Set up the L3CR configuration bits (and switch L3 off) */ + sync + mtspr SPRN_L3CR,r3 + sync + + /* Before we perform the global invalidation, we must disable dynamic + * power management via HID0[DPM] to work around a processor bug where + * DPM can possibly interfere with the state machine in the processor + * that invalidates the L3 cache tags. Hrm... This is necessary for L2, + * is it for L3 as well ? --BenH. + */ + mfspr r8,HID0 /* Save HID0 in r8 */ + rlwinm r4,r8,0,12,10 /* Turn off HID0[DPM] */ + sync + mtspr HID0,r4 /* Disable DPM */ + sync + + oris r3,r3,L3CR_L3RES@h /* Set reserved bit 5 */ + mtspr SPRN_L3CR,r3 + sync + oris r3,r3,L3CR_L3CLKEN@h /* Set clken */ + mtspr SPRN_L3CR,r3 + sync + + /* Wait for stabilize */ + li r0,128 + mtctr r0 +1: bdnz 1b + + /* Perform a global invalidation */ + ori r3,r3,0x0400 + sync + mtspr SPRN_L3CR,r3 + sync + isync + + /* We wait for the L3I bit to clear...... */ +10: mfspr r3,SPRN_L3CR + andi. r4,r3,0x0400 + bne 10b + + /* Clear CLKEN */ + rlwinm r3,r3,0,5,3 /* Turn off the clken bit */ + mtspr SPRN_L3CR,r3 + sync + + /* Wait for stabilize */ + li r0,128 + mtctr r0 +1: bdnz 1b + + /* Restore HID0[DPM] to whatever it was before */ + sync + mtspr 1008,r8 + sync + + /* See if we need to enable the cache */ + cmplwi r5,0 + beq 4f + + /* Enable the cache */ + oris r3,r3,(L3CR_L3E | L3CR_L3CLKEN)@h + mtspr SPRN_L3CR,r3 + sync + + /* Restore MSR (restores EE and DR bits to original state) */ +4: SYNC + mtmsr r7 + isync + blr + +_GLOBAL(_get_L3CR) + /* Return the L3CR contents */ + li r3,0 +BEGIN_FTR_SECTION + mfspr r3,SPRN_L3CR +END_FTR_SECTION_IFSET(CPU_FTR_L3CR) + blr + /* --- End of PowerLogix code --- */ diff -urN linux-2.4.19-pre6/arch/ppc/kernel/misc.S linux-2.4.19-pre7/arch/ppc/kernel/misc.S --- linux-2.4.19-pre6/arch/ppc/kernel/misc.S Mon Apr 15 21:53:31 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/misc.S Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.misc.S 1.36 12/01/01 20:09:06 benh + * BK Id: SCCS/s.misc.S 1.41 04/09/02 21:01:58 paulus */ /* * This file contains miscellaneous low-level functions. @@ -39,7 +39,6 @@ * Returns (address we're running at) - (address we were linked at) * for use before the text and data are mapped to KERNELBASE. */ - _GLOBAL(reloc_offset) mflr r0 bl 1f @@ -51,6 +50,62 @@ blr /* + * add_reloc_offset(x) returns x + reloc_offset(). + */ +_GLOBAL(add_reloc_offset) + mflr r0 + bl 1f +1: mflr r5 + lis r4,1b@ha + addi r4,r4,1b@l + subf r5,r4,r5 + add r3,r3,r5 + mtlr r0 + blr + +/* + * sub_reloc_offset(x) returns x - reloc_offset(). + */ +_GLOBAL(sub_reloc_offset) + mflr r0 + bl 1f +1: mflr r5 + lis r4,1b@ha + addi r4,r4,1b@l + subf r5,r4,r5 + subf r3,r5,r3 + mtlr r0 + blr + +/* + * reloc_got2 runs through the .got2 section adding an offset + * to each entry. + */ +_GLOBAL(reloc_got2) + mflr r11 + lis r7,__got2_start@ha + addi r7,r7,__got2_start@l + lis r8,__got2_end@ha + addi r8,r8,__got2_end@l + subf r8,r7,r8 + srwi. r8,r8,2 + beqlr + mtctr r8 + bl 1f +1: mflr r0 + lis r4,1b@ha + addi r4,r4,1b@l + subf r0,r4,r0 + add r7,r0,r7 +2: lwz r0,0(r7) + add r0,r0,r3 + stw r0,0(r7) + addi r7,r7,4 + bdnz 2b + mtlr r11 + blr + +/* * identify_cpu, * called with r3 = data offset and r4 = CPU number * doesn't change r3 @@ -281,7 +336,8 @@ mfmsr r0 /* Get current msr */ andc r0,r0,r3 /* And off the bits set in r3 (first parm) */ or r0,r0,r4 /* Or on the bits in r4 (second parm) */ - SYNC /* Some chip revs have problems here... */ + sync /* Some chip revs have problems here... */ + isync mtmsr r0 /* Update machine state */ isync blr /* Done */ @@ -309,14 +365,19 @@ #endif /* CONFIG_SMP */ sync tlbia - sync #ifdef CONFIG_SMP +BEGIN_FTR_SECTION + DSSALL +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) + sync TLBSYNC li r0,0 stw r0,0(r9) /* clear hash_table_lock */ mtmsr r10 SYNC -#endif +#else /* CONFIG_SMP */ + sync +#endif /* CONFIG_SMP */ blr /* diff -urN linux-2.4.19-pre6/arch/ppc/kernel/pmac_feature.c linux-2.4.19-pre7/arch/ppc/kernel/pmac_feature.c --- linux-2.4.19-pre6/arch/ppc/kernel/pmac_feature.c Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/pmac_feature.c Mon Apr 15 21:54:22 2002 @@ -193,13 +193,14 @@ } static int __pmac -generic_scc_enable(struct device_node* node, u32 enable_mask, u32 reset_mask, - int param, int value) +ohare_htw_scc_enable(struct device_node* node, int param, int value) { struct macio_chip* macio; unsigned long chan_mask; unsigned long fcr; unsigned long flags; + int htw; + unsigned long rmask; macio = macio_find(node, 0); if (!macio) @@ -211,20 +212,32 @@ else return -ENODEV; + htw = (macio->type == macio_heathrow || macio->type == macio_paddington + || macio->type == macio_gatwick); if (value) { +#ifdef CONFIG_ADB_PMU + if ((param & 0xfff) == PMAC_SCC_IRDA) + pmu_enable_irled(1); +#endif /* CONFIG_ADB_PMU */ LOCK(flags); fcr = MACIO_IN32(OHARE_FCR); /* Check if scc cell need enabling */ if (!(fcr & OH_SCC_ENABLE)) { - fcr |= enable_mask; - MACIO_OUT32(OHARE_FCR, fcr); - fcr |= reset_mask; - MACIO_OUT32(OHARE_FCR, fcr); + fcr |= OH_SCC_ENABLE; + if (htw) { + fcr &= ~HRW_SCC_TRANS_EN_N; + MACIO_OUT32(OHARE_FCR, fcr); + fcr |= (rmask = HRW_RESET_SCC); + MACIO_OUT32(OHARE_FCR, fcr); + } else { + fcr |= (rmask = OH_SCC_RESET); + MACIO_OUT32(OHARE_FCR, fcr); + } UNLOCK(flags); (void)MACIO_IN32(OHARE_FCR); mdelay(15); LOCK(flags); - fcr &= ~reset_mask; + fcr &= ~rmask; MACIO_OUT32(OHARE_FCR, fcr); } if (chan_mask & MACIO_FLAG_SCCA_ON) @@ -247,31 +260,20 @@ fcr &= ~OH_SCCB_IO; MACIO_OUT32(OHARE_FCR, fcr); if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) { - fcr &= ~enable_mask; + fcr &= ~OH_SCC_ENABLE; + if (htw) + fcr |= HRW_SCC_TRANS_EN_N; MACIO_OUT32(OHARE_FCR, fcr); } macio->flags &= ~(chan_mask); UNLOCK(flags); mdelay(10); - } - return 0; -} - -static int __pmac -ohare_scc_enable(struct device_node* node, int param, int value) -{ - int rc; - #ifdef CONFIG_ADB_PMU - if (value && (param & 0xfff) == PMAC_SCC_IRDA) - pmu_enable_irled(1); + if ((param & 0xfff) == PMAC_SCC_IRDA) + pmu_enable_irled(0); #endif /* CONFIG_ADB_PMU */ - rc = generic_scc_enable(node, OH_SCC_ENABLE, OH_SCC_RESET, param, value); -#ifdef CONFIG_ADB_PMU - if ((param & 0xfff) == PMAC_SCC_IRDA && (rc || !value)) - pmu_enable_irled(0); -#endif /* CONFIG_ADB_PMU */ - return rc; + } + return 0; } static int __pmac @@ -341,27 +343,6 @@ } static int __pmac -heathrow_scc_enable(struct device_node* node, int param, int value) -{ - int rc; - -#ifdef CONFIG_ADB_PMU - if (value && param == PMAC_SCC_IRDA) - pmu_enable_irled(1); -#endif /* CONFIG_ADB_PMU */ - /* Fixme: It's possible that wallstreet (heathrow) is different - * than other paddington machines. I still have to figure that - * out exactly, for now, the paddington values are used - */ - rc = generic_scc_enable(node, HRW_SCC_ENABLE, PADD_RESET_SCC, param, value); -#ifdef CONFIG_ADB_PMU - if (param == PMAC_SCC_IRDA && (rc || !value)) - pmu_enable_irled(0); -#endif /* CONFIG_ADB_PMU */ - return rc; -} - -static int __pmac heathrow_modem_enable(struct device_node* node, int param, int value) { struct macio_chip* macio; @@ -382,16 +363,10 @@ if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE && pmac_mb.model_id != PMAC_TYPE_YIKES) { LOCK(flags); - /* We use the paddington values as they seem to work properly - * on the wallstreet (heathrow) as well. I can't tell why we - * had to flip them on older feature.c, the fact is that new - * code uses the paddington values which are also the ones used - * in Darwin, and that works on wallstreet ! - */ if (value) - MACIO_BIC(HEATHROW_FCR, PADD_MODEM_POWER_N); + MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N); else - MACIO_BIS(HEATHROW_FCR, PADD_MODEM_POWER_N); + MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N); UNLOCK(flags); (void)MACIO_IN32(HEATHROW_FCR); mdelay(250); @@ -406,7 +381,7 @@ UNLOCK(flags); mdelay(250); LOCK(flags); MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1); (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); - UNLOCK(flags); mdelay(250); LOCK(flags); + UNLOCK(flags); mdelay(250); } return 0; } @@ -614,11 +589,14 @@ /* This seems to be necessary as well or the fan * keeps coming up and battery drains fast */ MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE); + /* Make sure eth is down even if module or sleep + * won't work properly */ + MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET); } /* Make sure modem is shut down */ MACIO_OUT8(HRW_GPIO_MODEM_RESET, MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1); - MACIO_BIS(HEATHROW_FCR, PADD_MODEM_POWER_N); + MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N); MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE); /* Let things settle */ @@ -810,7 +788,7 @@ UNLOCK(flags); mdelay(250); LOCK(flags); MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); (void)MACIO_IN8(KL_GPIO_MODEM_RESET); - UNLOCK(flags); mdelay(250); LOCK(flags); + UNLOCK(flags); mdelay(250); } return 0; } @@ -1467,7 +1445,7 @@ UNLOCK(flags); mdelay(250); LOCK(flags); MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); (void)MACIO_IN8(KL_GPIO_MODEM_RESET); - UNLOCK(flags); mdelay(250); LOCK(flags); + UNLOCK(flags); mdelay(250); } return 0; } @@ -1483,7 +1461,8 @@ return pmac_mb.board_flags; case PMAC_MB_INFO_NAME: /* hack hack hack... but should work */ - return (int)pmac_mb.model_name; + *((const char **)value) = pmac_mb.model_name; + break; } return 0; } @@ -1505,7 +1484,7 @@ * to have issues with turning on/off those asic cells */ static struct feature_table_entry ohare_features[] __pmacdata = { - { PMAC_FTR_SCC_ENABLE, ohare_scc_enable }, + { PMAC_FTR_SCC_ENABLE, ohare_htw_scc_enable }, { PMAC_FTR_SWIM3_ENABLE, ohare_floppy_enable }, { PMAC_FTR_MESH_ENABLE, ohare_mesh_enable }, { PMAC_FTR_IDE_ENABLE, ohare_ide_enable}, @@ -1531,7 +1510,7 @@ * powerbooks. */ static struct feature_table_entry heathrow_laptop_features[] __pmacdata = { - { PMAC_FTR_SCC_ENABLE, heathrow_scc_enable }, + { PMAC_FTR_SCC_ENABLE, ohare_htw_scc_enable }, { PMAC_FTR_MODEM_ENABLE, heathrow_modem_enable }, { PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable }, { PMAC_FTR_MESH_ENABLE, heathrow_mesh_enable }, @@ -1547,7 +1526,7 @@ * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4. */ static struct feature_table_entry paddington_features[] __pmacdata = { - { PMAC_FTR_SCC_ENABLE, heathrow_scc_enable }, + { PMAC_FTR_SCC_ENABLE, ohare_htw_scc_enable }, { PMAC_FTR_MODEM_ENABLE, heathrow_modem_enable }, { PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable }, { PMAC_FTR_MESH_ENABLE, heathrow_mesh_enable }, @@ -1621,6 +1600,10 @@ PMAC_TYPE_PSURGE, NULL, 0 }, + { "AAPL,ShinerESB", "Apple Network Server", + PMAC_TYPE_ANS, NULL, + 0 + }, { "AAPL,e407", "Alchemy", PMAC_TYPE_ALCHEMY, NULL, 0 @@ -1661,10 +1644,18 @@ PMAC_TYPE_PANGEA_IMAC, pangea_features, PMAC_MB_CAN_SLEEP }, + { "PowerBook4,2", "iBook 2 with 14\" LCD", + PMAC_TYPE_IBOOK2, pangea_features, + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER + }, { "PowerBook4,1", "iBook 2", PMAC_TYPE_IBOOK2, pangea_features, PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER }, + { "PowerMac4,2", "Flat panel iMac", + PMAC_TYPE_FLAT_PANEL_IMAC, pangea_features, + PMAC_MB_CAN_SLEEP + }, { "PowerMac1,1", "Blue&White G3", PMAC_TYPE_YOSEMITE, paddington_features, 0 @@ -1737,13 +1728,12 @@ feature_call func = NULL; va_list args; - if (!pmac_mb.features) - return -ENODEV; - for (i=0; pmac_mb.features[i].function; i++) - if (pmac_mb.features[i].selector == selector) { - func = pmac_mb.features[i].function; - break; - } + if (pmac_mb.features) + for (i=0; pmac_mb.features[i].function; i++) + if (pmac_mb.features[i].selector == selector) { + func = pmac_mb.features[i].function; + break; + } if (!func) for (i=0; any_features[i].function; i++) if (any_features[i].selector == selector) { @@ -2062,11 +2052,21 @@ } } - /* On all machines, switch sound off */ + /* On all machines that support sound PM, switch sound off */ if (macio_chips[0].of_node) pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE, macio_chips[0].of_node, 0, 0); + /* While on some desktop G3s, we turn it back on */ + if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow + && (pmac_mb.model_id == PMAC_TYPE_GOSSAMER || + pmac_mb.model_id == PMAC_TYPE_SILK)) { + struct macio_chip* macio = &macio_chips[0]; + MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE); + MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N); + } + + /* On all machines, switch modem & serial ports off */ np = find_devices("ch-a"); while(np) { diff -urN linux-2.4.19-pre6/arch/ppc/kernel/pmac_pci.c linux-2.4.19-pre7/arch/ppc/kernel/pmac_pci.c --- linux-2.4.19-pre6/arch/ppc/kernel/pmac_pci.c Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/pmac_pci.c Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pmac_pci.c 1.31 01/20/02 23:53:11 benh + * BK Id: SCCS/s.pmac_pci.c 1.33 03/19/02 15:53:55 benh */ /* * Support for PCI bridges found on Power Macintoshes. @@ -258,21 +258,12 @@ rev = in_8(bp->cfg_data); if (rev != BANDIT_REVID) printk(KERN_WARNING - "Unknown revision %d for bandit at %08lx\n", - rev, bp->io_base_phys); + "Unknown revision %d for bandit\n", rev); } else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) { printk(KERN_WARNING "bandit isn't? (%x)\n", vendev); return; } - /* read the revision id */ - out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID); - udelay(2); - rev = in_8(bp->cfg_data); - if (rev != BANDIT_REVID) - printk(KERN_WARNING "Unknown revision %d for bandit at %08lx\n", - rev, bp->io_base_phys); - /* read the word at offset 0x50 */ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC); udelay(2); @@ -282,8 +273,7 @@ magic |= BANDIT_COHERENT; udelay(2); out_le32((volatile unsigned int *)bp->cfg_data, magic); - printk(KERN_INFO "Cache coherency enabled for bandit/PSX at %08lx\n", - bp->io_base_phys); + printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n"); } diff -urN linux-2.4.19-pre6/arch/ppc/kernel/pmac_setup.c linux-2.4.19-pre7/arch/ppc/kernel/pmac_setup.c --- linux-2.4.19-pre6/arch/ppc/kernel/pmac_setup.c Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/pmac_setup.c Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pmac_setup.c 1.45 12/01/01 20:09:06 benh + * BK Id: SCCS/s.pmac_setup.c 1.53 04/09/02 21:01:58 paulus */ /* * linux/arch/ppc/kernel/setup.c @@ -140,26 +140,6 @@ #ifdef CONFIG_SMP extern struct smp_ops_t psurge_smp_ops; extern struct smp_ops_t core99_smp_ops; - -volatile static long int core99_l2_cache; -void __init -core99_init_l2(void) -{ - int cpu = smp_processor_id(); - - if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR)) - return; - - if (cpu == 0){ - core99_l2_cache = _get_L2CR(); - printk("CPU0: L2CR is %lx\n", core99_l2_cache); - } else { - printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR()); - _set_L2CR(0); - _set_L2CR(core99_l2_cache); - printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache); - } -} #endif /* CONFIG_SMP */ /* @@ -189,7 +169,15 @@ struct device_node *np; char *pp; int plen; + int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO, + NULL, PMAC_MB_INFO_MODEL, 0); + unsigned int mbflags = (unsigned int)pmac_call_feature(PMAC_FTR_GET_MB_INFO, + NULL, PMAC_MB_INFO_FLAGS, 0); + char* mbname; + if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, (int)&mbname) != 0) + mbname = "Unknown"; + /* find motherboard type */ seq_printf(m, "machine\t\t: "); np = find_devices("device-tree"); @@ -213,6 +201,10 @@ } else seq_printf(m, "PowerMac\n"); + /* print parsed model */ + seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname); + seq_printf(m, "pmac flags\t: %08x\n", mbflags); + /* find l2 cache info */ np = find_devices("l2-cache"); if (np == 0) @@ -352,11 +344,6 @@ printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n", ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000) ? "enabled" : "disabled"); - -#ifdef CONFIG_SMP - /* somewhat of a hack */ - core99_init_l2(); -#endif #ifdef CONFIG_KGDB zs_kgdb_hook(0); @@ -473,7 +460,7 @@ } } } -#endif +#endif /* CONFIG_SCSI */ #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) kdev_t __init @@ -664,7 +651,7 @@ * Read in a property describing some pieces of memory. */ -static void __init +static int __init get_mem_prop(char *name, struct mem_pieces *mp) { struct reg_property *rp; @@ -677,7 +664,7 @@ if (ip == NULL) { printk(KERN_ERR "error: couldn't get %s property on /memory\n", name); - abort(); + return 0; } s /= (nsc + nac) * 4; rp = mp->regions; @@ -696,6 +683,7 @@ /* Make sure the pieces are sorted. */ mem_pieces_sort(mp); mem_pieces_coalesce(mp); + return 1; } /* @@ -711,12 +699,6 @@ unsigned long a, total; struct mem_pieces phys_mem; - memory_node = find_devices("memory"); - if (memory_node == NULL) { - printk(KERN_ERR "can't find memory node\n"); - abort(); - } - /* * Find out where physical memory is, and check that it * starts at 0 and is contiguous. It seems that RAM is @@ -727,8 +709,9 @@ * more complicated (or else you end up wasting space * in mem_map). */ - get_mem_prop("reg", &phys_mem); - if (phys_mem.n_regions == 0) + memory_node = find_devices("memory"); + if (memory_node == NULL || !get_mem_prop("reg", &phys_mem) + || phys_mem.n_regions == 0) panic("No RAM??"); a = phys_mem.regions[0].address; if (a != 0) @@ -841,15 +824,12 @@ } #ifdef CONFIG_BOOTX_TEXT -extern void drawchar(char c); -extern void drawstring(const char *c); -extern boot_infos_t *disp_bi; void __init pmac_progress(char *s, unsigned short hex) { - if (disp_bi == 0) - return; - btext_drawstring(s); - btext_drawchar('\n'); + if (boot_text_mapped) { + btext_drawstring(s); + btext_drawchar('\n'); + } } #endif /* CONFIG_BOOTX_TEXT */ diff -urN linux-2.4.19-pre6/arch/ppc/kernel/pmac_smp.c linux-2.4.19-pre7/arch/ppc/kernel/pmac_smp.c --- linux-2.4.19-pre6/arch/ppc/kernel/pmac_smp.c Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/pmac_smp.c Mon Apr 15 21:54:22 2002 @@ -47,6 +47,7 @@ #include #include #include +#include #include "open_pic.h" @@ -105,8 +106,140 @@ #define PSURGE_QUAD_COTTON 2 #define PSURGE_QUAD_ICEGRASS 3 -/* l2 cache stuff for dual G4 macs */ -extern void core99_init_l2(void); +volatile static long int core99_l2_cache; +volatile static long int core99_l3_cache; + +static void __init +core99_init_caches(void) +{ + int cpu = smp_processor_id(); + + if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR)) + return; + + if (cpu == 0){ + core99_l2_cache = _get_L2CR(); + printk("CPU0: L2CR is %lx\n", core99_l2_cache); + } else { + printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR()); + _set_L2CR(0); + _set_L2CR(core99_l2_cache); + printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache); + } + + if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR)) + return; + + if (cpu == 0){ + core99_l3_cache = _get_L3CR(); + printk("CPU0: L3CR is %lx\n", core99_l3_cache); + } else { + printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR()); + _set_L3CR(0); + _set_L3CR(core99_l3_cache); + printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache); + } +} + +/* Some CPU registers have to be saved from the first CPU and + * applied to others. Note that we override what is setup by + * the cputable intentionally. + */ + +#define reg_hid0 0 +#define reg_hid1 1 +#define reg_msscr0 2 +#define reg_msssr0 3 +#define reg_ictrl 4 +#define reg_ldstcr 5 +#define reg_ldstdb 6 +#define reg_count 7 + +static unsigned long cpu_regs[reg_count]; + +static void __pmac +cpu_setup_grab(void) +{ + unsigned int pvers = mfspr(SPRN_PVR)>>16; + + /* Read cache setting of CPU 0 */ + core99_init_caches(); + + /* 7400/7410/7450 */ + if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) { + cpu_regs[reg_hid0] = mfspr(SPRN_HID0); + cpu_regs[reg_msscr0] = mfspr(SPRN_MSSCR0); + cpu_regs[reg_msssr0] = mfspr(SPRN_MSSSR0); + } + /* 7450 only */ + if (pvers == 0x8000) { + cpu_regs[reg_hid1] = mfspr(SPRN_HID1); + cpu_regs[reg_ictrl] = mfspr(SPRN_ICTRL); + cpu_regs[reg_ldstcr] = mfspr(SPRN_LDSTCR); + cpu_regs[reg_ldstdb] = mfspr(SPRN_LDSTDB); + } + flush_dcache_range((unsigned long)cpu_regs, (unsigned long)&cpu_regs[reg_count]); +} + +static void __pmac +cpu_setup_apply(int cpu_nr) +{ + unsigned int pvers = mfspr(SPRN_PVR)>>16; + + /* Apply cache setting from CPU 0 */ + core99_init_caches(); + + /* 7400/7410/7450 */ + if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) { + unsigned long tmp; + __asm__ __volatile__ ( + "lwz %0,4*"stringify(reg_hid0)"(%1)\n" + "sync\n" + "mtspr "stringify(SPRN_HID0)", %0\n" + "isync;sync\n" + "lwz %0, 4*"stringify(reg_msscr0)"(%1)\n" + "sync\n" + "mtspr "stringify(SPRN_MSSCR0)", %0\n" + "isync;sync\n" +// "lwz %0, "stringify(reg_msssr0)"(%1)\n" +// "sync\n" +// "mtspr "stringify(SPRN_MSSSR0)", %0\n" +// "isync;sync\n" + : "=&r" (tmp) : "r" (cpu_regs)); + } + /* 7410 only */ + if (pvers == 0x800c) { + unsigned long tmp; + __asm__ __volatile__ ( + "li %0, 0\n" + "sync\n" + "mtspr "stringify(SPRN_L2CR2)", %0\n" + "isync;sync\n" + : "=&r" (tmp)); + } + /* 7450 only */ + if (pvers == 0x8000) { + unsigned long tmp; + __asm__ __volatile__ ( + "lwz %0, 4*"stringify(reg_hid1)"(%1)\n" + "sync\n" + "mtspr "stringify(SPRN_HID1)", %0\n" + "isync;sync\n" + "lwz %0, 4*"stringify(reg_ictrl)"(%1)\n" + "sync\n" + "mtspr "stringify(SPRN_ICTRL)", %0\n" + "isync;sync\n" + "lwz %0, 4*"stringify(reg_ldstcr)"(%1)\n" + "sync\n" + "mtspr "stringify(SPRN_LDSTCR)", %0\n" + "isync;sync\n" + "lwz %0, 4*"stringify(reg_ldstdb)"(%1)\n" + "sync\n" + "mtspr "stringify(SPRN_LDSTDB)", %0\n" + "isync;sync\n" + : "=&r" (tmp) : "r" (cpu_regs)); + } +} /* * Set and clear IPIs for powersurge. @@ -383,6 +516,7 @@ { struct device_node *cpus; int i, ncpus = 1; + extern int powersave_nap; if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); cpus = find_type_devices("cpu"); @@ -394,6 +528,8 @@ openpic_request_IPIs(); for (i = 1; i < ncpus; ++i) smp_hw_index[i] = i; + powersave_nap = 0; + cpu_setup_grab(); } return ncpus; @@ -404,17 +540,11 @@ { unsigned long save_vector, new_vector; unsigned long flags; -#if 1 /* New way... */ + volatile unsigned long *vector = ((volatile unsigned long *)(KERNELBASE+0x100)); if (nr < 1 || nr > 3) return; -#else - volatile unsigned long *vector - = ((volatile unsigned long *)(KERNELBASE+0x500)); - if (nr != 1) - return; -#endif if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); local_irq_save(flags); @@ -463,13 +593,15 @@ static void __init smp_core99_setup_cpu(int cpu_nr) { + /* Setup some registers */ + if (cpu_nr != 0) + cpu_setup_apply(cpu_nr); + /* Setup openpic */ do_openpic_setup_cpu(); - /* Setup L2 */ - if (cpu_nr != 0) - core99_init_l2(); - else + /* Setup L2/L3 */ + if (cpu_nr == 0) if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349); } diff -urN linux-2.4.19-pre6/arch/ppc/kernel/ppc_asm.h linux-2.4.19-pre7/arch/ppc/kernel/ppc_asm.h --- linux-2.4.19-pre6/arch/ppc/kernel/ppc_asm.h Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/kernel/ppc_asm.h Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc_asm.h 1.18 10/18/01 15:02:09 trini + * BK Id: SCCS/s.ppc_asm.h 1.20 03/19/02 15:04:39 benh */ /* * arch/ppc/kernel/ppc_asm.h @@ -55,6 +55,7 @@ #define STVX(r,a,b) .long (31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(231<<1) #define MFVSCR(r) .long (4<<26)+((r)<<21)+(770<<1) #define MTVSCR(r) .long (4<<26)+((r)<<11)+(802<<1) +#define DSSALL .long (0x1f<<26)+(0x10<<21)+(0x336<<1) #define SAVE_VR(n,b,base) li b,THREAD_VR0+(16*(n)); STVX(n,b,base) #define SAVE_2VR(n,b,base) SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) diff -urN linux-2.4.19-pre6/arch/ppc/kernel/prep_setup.c linux-2.4.19-pre7/arch/ppc/kernel/prep_setup.c --- linux-2.4.19-pre6/arch/ppc/kernel/prep_setup.c Mon Apr 15 21:53:31 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/prep_setup.c Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.prep_setup.c 1.47 12/19/01 09:45:54 trini + * BK Id: SCCS/s.prep_setup.c 1.52 04/05/02 10:17:22 trini */ /* * linux/arch/ppc/kernel/setup.c @@ -203,15 +203,13 @@ static int __prep prep_show_percpuinfo(struct seq_file *m, int i) { - int len = 0; - /* PREP's without residual data will give incorrect values here */ seq_printf(m, "clock\t\t: "); #ifdef CONFIG_PREP_RESIDUAL if (res->ResidualLength) seq_printf(m, "%ldMHz\n", (res->VitalProductData.ProcessorHz > 1024) ? - res->VitalProductData.ProcessorHz>>20 : + res->VitalProductData.ProcessorHz / 1000000 : res->VitalProductData.ProcessorHz); else #endif /* CONFIG_PREP_RESIDUAL */ @@ -242,13 +240,6 @@ outb(reg, SIO_CONFIG_RD); outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */ - /* - * We need to set up the NvRAM access routines early as prep_init - * has yet to be called - */ - ppc_md.nvram_read_val = prep_nvram_read_val; - ppc_md.nvram_write_val = prep_nvram_write_val; - /* we should determine this according to what we find! -- Cort */ switch ( _prep_type ) { @@ -834,21 +825,6 @@ } #endif -#ifdef CONFIG_BLK_DEV_INITRD - if ( r4 ) - { - initrd_start = r4 + KERNELBASE; - initrd_end = r5 + KERNELBASE; - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - /* Copy cmd_line parameters */ - if ( r6 ) - { - *(char *)(r7 + KERNELBASE) = 0; - strcpy(cmd_line, (char *)(r6 + KERNELBASE)); - } - isa_io_base = PREP_ISA_IO_BASE; isa_mem_base = PREP_ISA_MEM_BASE; pci_dram_offset = PREP_PCI_DRAM_OFFSET; @@ -884,6 +860,9 @@ ppc_md.power_off = prep_power_off; ppc_md.halt = prep_halt; + ppc_md.nvram_read_val = prep_nvram_read_val; + ppc_md.nvram_write_val = prep_nvram_write_val; + ppc_md.time_init = NULL; if (_prep_type == _PREP_IBM) { ppc_md.set_rtc_time = mc146818_set_rtc_time; diff -urN linux-2.4.19-pre6/arch/ppc/kernel/prom.c linux-2.4.19-pre7/arch/ppc/kernel/prom.c --- linux-2.4.19-pre6/arch/ppc/kernel/prom.c Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/prom.c Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.prom.c 1.48 12/19/01 10:50:58 paulus + * BK Id: SCCS/s.prom.c 1.52 04/09/02 21:01:58 paulus */ /* * Procedures for interfacing to the Open Firmware PROM on @@ -11,7 +11,6 @@ * Paul Mackerras August 1996. * Copyright (C) 1996 Paul Mackerras. */ -#include #include #include #include @@ -19,7 +18,6 @@ #include #include #include -#include #include #include @@ -28,37 +26,9 @@ #include #include #include -#include -#include -#include #include -#include -#include -#include -#include #include #include -#include "open_pic.h" - -#ifdef CONFIG_FB -#include -#endif - -/* - * Properties whose value is longer than this get excluded from our - * copy of the device tree. This way we don't waste space storing - * things like "driver,AAPL,MacOS,PowerPC" properties. But this value - * does need to be big enough to ensure that we don't lose things - * like the interrupt-map property on a PCI-PCI bridge. - */ -#define MAX_PROPERTY_LENGTH 4096 - -struct prom_args { - const char *service; - int nargs; - int nret; - void *args[10]; -}; struct pci_address { unsigned a_hi; @@ -72,26 +42,12 @@ unsigned size_lo; }; -struct pci_range { - struct pci_address addr; - unsigned phys; - unsigned size_hi; - unsigned size_lo; -}; - struct isa_reg_property { unsigned space; unsigned address; unsigned size; }; -struct pci_intr_map { - struct pci_address addr; - unsigned dunno; - phandle int_ctrler; - unsigned intr; -}; - typedef unsigned long interpret_func(struct device_node *, unsigned long, int, int); static interpret_func interpret_pci_props; @@ -100,27 +56,7 @@ static interpret_func interpret_macio_props; static interpret_func interpret_root_props; -#ifndef FB_MAX /* avoid pulling in all of the fb stuff */ -#define FB_MAX 8 -#endif -char *prom_display_paths[FB_MAX] __initdata = { 0, }; -phandle prom_display_nodes[FB_MAX] __initdata; -unsigned int prom_num_displays __initdata = 0; -char *of_stdout_device __initdata = 0; -ihandle prom_disp_node __initdata = 0; - -prom_entry prom __initdata = 0; -ihandle prom_chosen __initdata = 0; -ihandle prom_stdout __initdata = 0; - extern char *klimit; -char *bootpath; -char *bootdevice; - -unsigned int rtas_data; /* physical pointer */ -unsigned int rtas_entry; /* physical pointer */ -unsigned int rtas_size; -unsigned int old_rtas; /* Set for a newworld or CHRP machine */ int use_of_interrupt_tree; @@ -129,554 +65,30 @@ int pmac_newworld; -static struct device_node *allnodes; +extern unsigned int rtas_entry; /* physical pointer */ + +extern struct device_node *allnodes; -static void *call_prom(const char *service, int nargs, int nret, ...); -static void prom_exit(void); -static unsigned long copy_device_tree(unsigned long, unsigned long); -static unsigned long inspect_node(phandle, struct device_node *, unsigned long, - unsigned long, struct device_node ***); static unsigned long finish_node(struct device_node *, unsigned long, interpret_func *, int, int); static unsigned long finish_node_interrupts(struct device_node *, unsigned long); -static unsigned long check_display(unsigned long); -static int prom_next_node(phandle *); -static void *early_get_property(unsigned long, unsigned long, char *); static struct device_node *find_phandle(phandle); -#ifdef CONFIG_BOOTX_TEXT -static void setup_disp_fake_bi(ihandle dp); -#endif - extern void enter_rtas(void *); void phys_call_rtas(int, int, int, ...); extern char cmd_line[512]; /* XXX */ -boot_infos_t *boot_infos; +extern boot_infos_t *boot_infos; unsigned long dev_tree_size; -#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long)) - -/* Is boot-info compatible ? */ -#define BOOT_INFO_IS_COMPATIBLE(bi) ((bi)->compatible_version <= BOOT_INFO_VERSION) -#define BOOT_INFO_IS_V2_COMPATIBLE(bi) ((bi)->version >= 2) -#define BOOT_INFO_IS_V4_COMPATIBLE(bi) ((bi)->version >= 4) - -/* - * Note that prom_init() and anything called from prom_init() must - * use the RELOC/PTRRELOC macros to access any static data in - * memory, since the kernel may be running at an address that is - * different from the address that it was linked at. - * (Note that strings count as static variables.) - */ - -static void __init -prom_exit() -{ - struct prom_args args; - unsigned long offset = reloc_offset(); - - args.service = "exit"; - args.nargs = 0; - args.nret = 0; - RELOC(prom)(&args); - for (;;) /* should never get here */ - ; -} - -void __init -prom_enter(void) -{ - struct prom_args args; - unsigned long offset = reloc_offset(); - - args.service = RELOC("enter"); - args.nargs = 0; - args.nret = 0; - RELOC(prom)(&args); -} - -static void * __init -call_prom(const char *service, int nargs, int nret, ...) -{ - va_list list; - int i; - unsigned long offset = reloc_offset(); - struct prom_args prom_args; - - prom_args.service = service; - prom_args.nargs = nargs; - prom_args.nret = nret; - va_start(list, nret); - for (i = 0; i < nargs; ++i) - prom_args.args[i] = va_arg(list, void *); - va_end(list); - for (i = 0; i < nret; ++i) - prom_args.args[i + nargs] = 0; - RELOC(prom)(&prom_args); - return prom_args.args[nargs]; -} - -void __init -prom_print(const char *msg) -{ - const char *p, *q; - unsigned long offset = reloc_offset(); - - if (RELOC(prom_stdout) == 0) - return; - - for (p = msg; *p != 0; p = q) { - for (q = p; *q != 0 && *q != '\n'; ++q) - ; - if (q > p) - call_prom(RELOC("write"), 3, 1, RELOC(prom_stdout), - p, q - p); - if (*q != 0) { - ++q; - call_prom(RELOC("write"), 3, 1, RELOC(prom_stdout), - RELOC("\r\n"), 2); - } - } -} - -static void __init -prom_print_hex(unsigned int v) -{ - char buf[16]; - int i, c; - - for (i = 0; i < 8; ++i) { - c = (v >> ((7-i)*4)) & 0xf; - c += (c >= 10)? ('a' - 10): '0'; - buf[i] = c; - } - buf[i] = ' '; - buf[i+1] = 0; - prom_print(buf); -} - -unsigned long smp_chrp_cpu_nr __initdata = 0; - -#ifdef CONFIG_SMP -/* - * With CHRP SMP we need to use the OF to start the other - * processors so we can't wait until smp_boot_cpus (the OF is - * trashed by then) so we have to put the processors into - * a holding pattern controlled by the kernel (not OF) before - * we destroy the OF. - * - * This uses a chunk of high memory, puts some holding pattern - * code there and sends the other processors off to there until - * smp_boot_cpus tells them to do something. We do that by using - * physical address 0x0. The holding pattern checks that address - * until its cpu # is there, when it is that cpu jumps to - * __secondary_start(). smp_boot_cpus() takes care of setting those - * values. - * - * We also use physical address 0x4 here to tell when a cpu - * is in its holding pattern code. - * - * -- Cort - */ -static void __init -prom_hold_cpus(unsigned long mem) -{ - extern void __secondary_hold(void); - unsigned long i; - int cpu; - phandle node; - unsigned long offset = reloc_offset(); - char type[16], *path; - unsigned int reg; - - /* - * XXX: hack to make sure we're chrp, assume that if we're - * chrp we have a device_type property -- Cort - */ - node = call_prom(RELOC("finddevice"), 1, 1, RELOC("/")); - if ( (int)call_prom(RELOC("getprop"), 4, 1, node, - RELOC("device_type"),type, sizeof(type)) <= 0) - return; - - /* copy the holding pattern code to someplace safe (0) */ - /* the holding pattern is now within the first 0x100 - bytes of the kernel image -- paulus */ - memcpy((void *)0, (void *)(KERNELBASE + offset), 0x100); - flush_icache_range(0, 0x100); - - /* look for cpus */ - *(unsigned long *)(0x0) = 0; - asm volatile("dcbf 0,%0": : "r" (0) : "memory"); - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), - type, sizeof(type)); - if (strcmp(type, RELOC("cpu")) != 0) - continue; - path = (char *) mem; - memset(path, 0, 256); - if ((int) call_prom(RELOC("package-to-path"), 3, 1, - node, path, 255) < 0) - continue; - reg = -1; - call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"), - ®, sizeof(reg)); - cpu = RELOC(smp_chrp_cpu_nr)++; - RELOC(smp_hw_index)[cpu] = reg; - /* XXX: hack - don't start cpu 0, this cpu -- Cort */ - if (cpu == 0) - continue; - prom_print(RELOC("starting cpu ")); - prom_print(path); - *(ulong *)(0x4) = 0; - call_prom(RELOC("start-cpu"), 3, 0, node, - __pa(__secondary_hold), cpu); - prom_print(RELOC("...")); - for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ ) - ; - if (*(ulong *)(0x4) == cpu) - prom_print(RELOC("ok\n")); - else { - prom_print(RELOC("failed: ")); - prom_print_hex(*(ulong *)0x4); - prom_print(RELOC("\n")); - } - } -} -#endif /* CONFIG_SMP */ - -void __init -bootx_init(unsigned long r4, unsigned long phys) -{ - boot_infos_t *bi = (boot_infos_t *) r4; - unsigned long space; - unsigned long ptr, x; - char *model; - unsigned long offset = reloc_offset(); - - RELOC(boot_infos) = PTRUNRELOC(bi); - if (!BOOT_INFO_IS_V2_COMPATIBLE(bi)) - bi->logicalDisplayBase = 0; - -#ifdef CONFIG_BOOTX_TEXT - btext_init(bi); - - /* - * Test if boot-info is compatible. Done only in config - * CONFIG_BOOTX_TEXT since there is nothing much we can do - * with an incompatible version, except display a message - * and eventually hang the processor... - * - * I'll try to keep enough of boot-info compatible in the - * future to always allow display of this message; - */ - if (!BOOT_INFO_IS_COMPATIBLE(bi)) { - btext_drawstring(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n")); - btext_flushscreen(); - } -#endif /* CONFIG_BOOTX_TEXT */ - - /* New BootX enters kernel with MMU off, i/os are not allowed - here. This hack will have been done by the boostrap anyway. - */ - if (bi->version < 4) { - /* - * XXX If this is an iMac, turn off the USB controller. - */ - model = (char *) early_get_property - (r4 + bi->deviceTreeOffset, 4, RELOC("model")); - if (model - && (strcmp(model, RELOC("iMac,1")) == 0 - || strcmp(model, RELOC("PowerMac1,1")) == 0)) { - out_le32((unsigned *)0x80880008, 1); /* XXX */ - } - } - - /* Move klimit to enclose device tree, args, ramdisk, etc... */ - if (bi->version < 5) { - space = bi->deviceTreeOffset + bi->deviceTreeSize; - if (bi->ramDisk) - space = bi->ramDisk + bi->ramDiskSize; - } else - space = bi->totalParamsSize; - RELOC(klimit) = PTRUNRELOC((char *) bi + space); - - /* New BootX will have flushed all TLBs and enters kernel with - MMU switched OFF, so this should not be useful anymore. - */ - if (bi->version < 4) { - /* - * Touch each page to make sure the PTEs for them - * are in the hash table - the aim is to try to avoid - * getting DSI exceptions while copying the kernel image. - */ - for (ptr = (KERNELBASE + offset) & PAGE_MASK; - ptr < (unsigned long)bi + space; ptr += PAGE_SIZE) - x = *(volatile unsigned long *)ptr; - } - -#ifdef CONFIG_BOOTX_TEXT - /* - * Note that after we call prepare_disp_BAT, we can't do - * prom_draw*, flushscreen or clearscreen until we turn the MMU - * on, since prepare_disp_BAT sets disp_bi->logicalDisplayBase - * to a virtual address. - */ - btext_prepare_BAT(); -#endif -} - -#ifdef CONFIG_PPC64BRIDGE -/* - * Set up a hash table with a set of entries in it to map the - * first 64MB of RAM. This is used on 64-bit machines since - * some of them don't have BATs. - * We assume the PTE will fit in the primary PTEG. - */ - -static inline void make_pte(unsigned long htab, unsigned int hsize, - unsigned int va, unsigned int pa, int mode) -{ - unsigned int *pteg; - unsigned int hash, i, vsid; - - vsid = ((va >> 28) * 0x111) << 12; - hash = ((va ^ vsid) >> 5) & 0x7fff80; - pteg = (unsigned int *)(htab + (hash & (hsize - 1))); - for (i = 0; i < 8; ++i, pteg += 4) { - if ((pteg[1] & 1) == 0) { - pteg[1] = vsid | ((va >> 16) & 0xf80) | 1; - pteg[3] = pa | mode; - break; - } - } -} - -extern unsigned long _SDR1; -extern PTE *Hash; -extern unsigned long Hash_size; - -static void __init -prom_alloc_htab(void) -{ - unsigned int hsize; - unsigned long htab; - unsigned int addr; - unsigned long offset = reloc_offset(); - - /* - * Because of OF bugs we can't use the "claim" client - * interface to allocate memory for the hash table. - * This code is only used on 64-bit PPCs, and the only - * 64-bit PPCs at the moment are RS/6000s, and their - * OF is based at 0xc00000 (the 12M point), so we just - * arbitrarily use the 0x800000 - 0xc00000 region for the - * hash table. - * -- paulus. - */ -#ifdef CONFIG_POWER4 - hsize = 4 << 20; /* POWER4 has no BATs */ -#else - hsize = 2 << 20; -#endif /* CONFIG_POWER4 */ - htab = (8 << 20); - RELOC(Hash) = (void *)(htab + KERNELBASE); - RELOC(Hash_size) = hsize; - RELOC(_SDR1) = htab + __ilog2(hsize) - 18; - - /* - * Put in PTEs for the first 64MB of RAM - */ - cacheable_memzero((void *)htab, hsize); - for (addr = 0; addr < 0x4000000; addr += 0x1000) - make_pte(htab, hsize, addr + KERNELBASE, addr, - _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX); -} -#endif /* CONFIG_PPC64BRIDGE */ - -static void __init -prom_instantiate_rtas(void) -{ - ihandle prom_rtas; - unsigned int i; - struct prom_args prom_args; - unsigned long offset = reloc_offset(); - - prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas")); - if (prom_rtas == (void *) -1) - return; - - RELOC(rtas_size) = 0; - call_prom(RELOC("getprop"), 4, 1, prom_rtas, - RELOC("rtas-size"), &RELOC(rtas_size), sizeof(rtas_size)); - prom_print(RELOC("instantiating rtas")); - if (RELOC(rtas_size) == 0) { - RELOC(rtas_data) = 0; - } else { - /* - * Ask OF for some space for RTAS. - * Actually OF has bugs so we just arbitrarily - * use memory at the 6MB point. - */ - RELOC(rtas_data) = 6 << 20; - prom_print(RELOC(" at ")); - prom_print_hex(RELOC(rtas_data)); - } - - prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas")); - prom_print(RELOC("...")); - prom_args.service = RELOC("call-method"); - prom_args.nargs = 3; - prom_args.nret = 2; - prom_args.args[0] = RELOC("instantiate-rtas"); - prom_args.args[1] = prom_rtas; - prom_args.args[2] = (void *) RELOC(rtas_data); - RELOC(prom)(&prom_args); - i = 0; - if (prom_args.args[3] == 0) - i = (unsigned int)prom_args.args[4]; - RELOC(rtas_entry) = i; - if ((RELOC(rtas_entry) == -1) || (RELOC(rtas_entry) == 0)) - prom_print(RELOC(" failed\n")); - else - prom_print(RELOC(" done\n")); -} - -/* - * We enter here early on, when the Open Firmware prom is still - * handling exceptions and the MMU hash table for us. - */ -unsigned long __init -prom_init(int r3, int r4, prom_entry pp) -{ - unsigned long mem; - ihandle prom_mmu; - unsigned long offset = reloc_offset(); - int l; - char *p, *d; - unsigned long phys; - - /* Default */ - phys = offset + KERNELBASE; - - /* First get a handle for the stdout device */ - RELOC(prom) = pp; - RELOC(prom_chosen) = call_prom(RELOC("finddevice"), 1, 1, - RELOC("/chosen")); - if (RELOC(prom_chosen) == (void *)-1) - prom_exit(); - if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), - RELOC("stdout"), &RELOC(prom_stdout), - sizeof(prom_stdout)) <= 0) - prom_exit(); - - /* Get the full OF pathname of the stdout device */ - mem = (unsigned long) RELOC(klimit) + offset; - p = (char *) mem; - memset(p, 0, 256); - call_prom(RELOC("instance-to-path"), 3, 1, RELOC(prom_stdout), p, 255); - RELOC(of_stdout_device) = PTRUNRELOC(p); - mem += strlen(p) + 1; - - /* Get the boot device and translate it to a full OF pathname. */ - p = (char *) mem; - l = (int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), - RELOC("bootpath"), p, 1<<20); - if (l > 0) { - p[l] = 0; /* should already be null-terminated */ - RELOC(bootpath) = PTRUNRELOC(p); - mem += l + 1; - d = (char *) mem; - *d = 0; - call_prom(RELOC("canon"), 3, 1, p, d, 1<<20); - RELOC(bootdevice) = PTRUNRELOC(d); - mem = ALIGN(mem + strlen(d) + 1); - } - - prom_instantiate_rtas(); - -#ifdef CONFIG_PPC64BRIDGE - /* - * Find out how much memory we have and allocate a - * suitably-sized hash table. - */ - prom_alloc_htab(); -#endif - - mem = check_display(mem); - - prom_print(RELOC("copying OF device tree...")); - mem = copy_device_tree(mem, mem + (1<<20)); - prom_print(RELOC("done\n")); - -#ifdef CONFIG_SMP - prom_hold_cpus(mem); -#endif - - RELOC(klimit) = (char *) (mem - offset); - - /* If we are already running at 0xc0000000, we assume we were loaded by - * an OF bootloader which did set a BAT for us. This breaks OF translate - * so we force phys to be 0 - */ - if (offset == 0) - phys = 0; - else { - if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), - RELOC("mmu"), &prom_mmu, sizeof(prom_mmu)) <= 0) { - prom_print(RELOC(" no MMU found\n")); - } else { - int nargs; - struct prom_args prom_args; - nargs = 4; - prom_args.service = RELOC("call-method"); - prom_args.nargs = nargs; - prom_args.nret = 4; - prom_args.args[0] = RELOC("translate"); - prom_args.args[1] = prom_mmu; - prom_args.args[2] = (void *)(offset + KERNELBASE); - prom_args.args[3] = (void *)1; - RELOC(prom)(&prom_args); - - /* We assume the phys. address size is 3 cells */ - if (prom_args.args[nargs] != 0) - prom_print(RELOC(" (translate failed)\n")); - else - phys = (unsigned long)prom_args.args[nargs+3]; - } - } - -#ifdef CONFIG_BOOTX_TEXT - if (RELOC(prom_disp_node) != 0) - setup_disp_fake_bi(RELOC(prom_disp_node)); -#endif - - /* Use quiesce call to get OF to shut down any devices it's using */ - prom_print(RELOC("Calling quiesce ...\n")); - call_prom(RELOC("quiesce"), 0, 0); - -#ifdef CONFIG_BOOTX_TEXT - if (RELOC(prom_disp_node) != 0) - btext_prepare_BAT(); -#endif - - prom_print(RELOC("returning ")); - prom_print_hex(phys); - prom_print(RELOC(" from prom_init\n")); - RELOC(prom_stdout) = 0; - - return phys; -} - -void phys_call_rtas(int service, int nargs, int nret, ...) +void __openfirmware +phys_call_rtas(int service, int nargs, int nret, ...) { va_list list; union { unsigned long words[16]; double align; } u; - unsigned long offset = reloc_offset(); void (*rtas)(void *, unsigned long); int i; @@ -688,340 +100,8 @@ u.words[i+3] = va_arg(list, unsigned long); va_end(list); - rtas = (void (*)(void *, unsigned long)) RELOC(rtas_entry); - rtas(&u, RELOC(rtas_data)); -} - -static int __init -prom_set_color(ihandle ih, int i, int r, int g, int b) -{ - struct prom_args prom_args; - unsigned long offset = reloc_offset(); - - prom_args.service = RELOC("call-method"); - prom_args.nargs = 6; - prom_args.nret = 1; - prom_args.args[0] = RELOC("color!"); - prom_args.args[1] = ih; - prom_args.args[2] = (void *) i; - prom_args.args[3] = (void *) b; - prom_args.args[4] = (void *) g; - prom_args.args[5] = (void *) r; - RELOC(prom)(&prom_args); - return (int) prom_args.args[6]; -} - -/* - * If we have a display that we don't know how to drive, - * we will want to try to execute OF's open method for it - * later. However, OF will probably fall over if we do that - * we've taken over the MMU. - * So we check whether we will need to open the display, - * and if so, open it now. - */ -static unsigned long __init -check_display(unsigned long mem) -{ - phandle node; - ihandle ih; - int i; - unsigned long offset = reloc_offset(); - char type[16], *path; - static unsigned char default_colors[] = { - 0x00, 0x00, 0x00, - 0x00, 0x00, 0xaa, - 0x00, 0xaa, 0x00, - 0x00, 0xaa, 0xaa, - 0xaa, 0x00, 0x00, - 0xaa, 0x00, 0xaa, - 0xaa, 0xaa, 0x00, - 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, - 0x55, 0x55, 0xff, - 0x55, 0xff, 0x55, - 0x55, 0xff, 0xff, - 0xff, 0x55, 0x55, - 0xff, 0x55, 0xff, - 0xff, 0xff, 0x55, - 0xff, 0xff, 0xff - }; - - RELOC(prom_disp_node) = 0; - - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), - type, sizeof(type)); - if (strcmp(type, RELOC("display")) != 0) - continue; - /* It seems OF doesn't null-terminate the path :-( */ - path = (char *) mem; - memset(path, 0, 256); - if ((int) call_prom(RELOC("package-to-path"), 3, 1, - node, path, 255) < 0) - continue; - - /* - * If this display is the device that OF is using for stdout, - * move it to the front of the list. - */ - mem += strlen(path) + 1; - i = RELOC(prom_num_displays)++; - if (RELOC(of_stdout_device) != 0 && i > 0 - && strcmp(PTRRELOC(RELOC(of_stdout_device)), path) == 0) { - for (; i > 0; --i) { - RELOC(prom_display_paths[i]) - = RELOC(prom_display_paths[i-1]); - RELOC(prom_display_nodes[i]) - = RELOC(prom_display_nodes[i-1]); - } - } - RELOC(prom_display_paths[i]) = PTRUNRELOC(path); - RELOC(prom_display_nodes[i]) = node; - if (i == 0) - RELOC(prom_disp_node) = node; - if (RELOC(prom_num_displays) >= FB_MAX) - break; - } - -try_again: - /* - * Open the first display and set its colormap. - */ - if (RELOC(prom_num_displays) > 0) { - path = PTRRELOC(RELOC(prom_display_paths[0])); - prom_print(RELOC("opening display ")); - prom_print(path); - ih = call_prom(RELOC("open"), 1, 1, path); - if (ih == 0 || ih == (ihandle) -1) { - prom_print(RELOC("... failed\n")); - for (i=1; i 0) - RELOC(prom_disp_node) = RELOC(prom_display_nodes[0]); - else - RELOC(prom_disp_node) = NULL; - goto try_again; - } else { - prom_print(RELOC("... ok\n")); - /* - * Setup a usable color table when the appropriate - * method is available. - * Should update this to use set-colors. - */ - for (i = 0; i < 32; i++) - if (prom_set_color(ih, i, RELOC(default_colors)[i*3], - RELOC(default_colors)[i*3+1], - RELOC(default_colors)[i*3+2]) != 0) - break; - -#ifdef CONFIG_FB - for (i = 0; i < LINUX_LOGO_COLORS; i++) - if (prom_set_color(ih, i + 32, - RELOC(linux_logo_red)[i], - RELOC(linux_logo_green)[i], - RELOC(linux_logo_blue)[i]) != 0) - break; -#endif /* CONFIG_FB */ - } - } - - return ALIGN(mem); -} - -/* This function will enable the early boot text when doing OF booting. This - * way, xmon output should work too - */ -#ifdef CONFIG_BOOTX_TEXT -static void __init -setup_disp_fake_bi(ihandle dp) -{ - int width = 640, height = 480, depth = 8, pitch; - unsigned address; - unsigned long offset = reloc_offset(); - struct pci_reg_property addrs[8]; - int i, naddrs; - char name[32]; - char *getprop = RELOC("getprop"); - - prom_print(RELOC("Initializing fake screen: ")); - - memset(name, 0, sizeof(name)); - call_prom(getprop, 4, 1, dp, RELOC("name"), name, sizeof(name)); - name[sizeof(name)-1] = 0; - prom_print(name); - prom_print(RELOC("\n")); - call_prom(getprop, 4, 1, dp, RELOC("width"), &width, sizeof(width)); - call_prom(getprop, 4, 1, dp, RELOC("height"), &height, sizeof(height)); - call_prom(getprop, 4, 1, dp, RELOC("depth"), &depth, sizeof(depth)); - pitch = width * ((depth + 7) / 8); - call_prom(getprop, 4, 1, dp, RELOC("linebytes"), - &pitch, sizeof(pitch)); - if (pitch == 1) - pitch = 0x1000; /* for strange IBM display */ - address = 0; - call_prom(getprop, 4, 1, dp, RELOC("address"), - &address, sizeof(address)); - if (address == 0) { - /* look for an assigned address with a size of >= 1MB */ - naddrs = (int) call_prom(getprop, 4, 1, dp, - RELOC("assigned-addresses"), - addrs, sizeof(addrs)); - naddrs /= sizeof(struct pci_reg_property); - for (i = 0; i < naddrs; ++i) { - if (addrs[i].size_lo >= (1 << 20)) { - address = addrs[i].addr.a_lo; - /* use the BE aperture if possible */ - if (addrs[i].size_lo >= (16 << 20)) - address += (8 << 20); - break; - } - } - if (address == 0) { - prom_print(RELOC("Failed to get address\n")); - return; - } - } - /* kludge for valkyrie */ - if (strcmp(name, RELOC("valkyrie")) == 0) - address += 0x1000; - - btext_setup_display(width, height, depth, pitch, address); -} -#endif - -static int __init -prom_next_node(phandle *nodep) -{ - phandle node; - unsigned long offset = reloc_offset(); - - if ((node = *nodep) != 0 - && (*nodep = call_prom(RELOC("child"), 1, 1, node)) != 0) - return 1; - if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0) - return 1; - for (;;) { - if ((node = call_prom(RELOC("parent"), 1, 1, node)) == 0) - return 0; - if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0) - return 1; - } -} - -/* - * Make a copy of the device tree from the PROM. - */ -static unsigned long __init -copy_device_tree(unsigned long mem_start, unsigned long mem_end) -{ - phandle root; - unsigned long new_start; - struct device_node **allnextp; - unsigned long offset = reloc_offset(); - - root = call_prom(RELOC("peer"), 1, 1, (phandle)0); - if (root == (phandle)0) { - prom_print(RELOC("couldn't get device tree root\n")); - prom_exit(); - } - allnextp = &RELOC(allnodes); - mem_start = ALIGN(mem_start); - new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp); - *allnextp = 0; - return new_start; -} - -static unsigned long __init -inspect_node(phandle node, struct device_node *dad, - unsigned long mem_start, unsigned long mem_end, - struct device_node ***allnextpp) -{ - int l; - phandle child; - struct device_node *np; - struct property *pp, **prev_propp; - char *prev_name, *namep; - unsigned char *valp; - unsigned long offset = reloc_offset(); - - np = (struct device_node *) mem_start; - mem_start += sizeof(struct device_node); - memset(np, 0, sizeof(*np)); - np->node = node; - **allnextpp = PTRUNRELOC(np); - *allnextpp = &np->allnext; - if (dad != 0) { - np->parent = PTRUNRELOC(dad); - /* we temporarily use the `next' field as `last_child'. */ - if (dad->next == 0) - dad->child = PTRUNRELOC(np); - else - dad->next->sibling = PTRUNRELOC(np); - dad->next = np; - } - - /* get and store all properties */ - prev_propp = &np->properties; - prev_name = RELOC(""); - for (;;) { - pp = (struct property *) mem_start; - namep = (char *) (pp + 1); - pp->name = PTRUNRELOC(namep); - if ((int) call_prom(RELOC("nextprop"), 3, 1, node, prev_name, - namep) <= 0) - break; - mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1); - prev_name = namep; - valp = (unsigned char *) mem_start; - pp->value = PTRUNRELOC(valp); - pp->length = (int) - call_prom(RELOC("getprop"), 4, 1, node, namep, - valp, mem_end - mem_start); - if (pp->length < 0) - continue; -#ifdef MAX_PROPERTY_LENGTH - if (pp->length > MAX_PROPERTY_LENGTH) - continue; /* ignore this property */ -#endif - mem_start = ALIGN(mem_start + pp->length); - *prev_propp = PTRUNRELOC(pp); - prev_propp = &pp->next; - } - if (np->node != NULL) { - /* Add a "linux,phandle" property" */ - pp = (struct property *) mem_start; - *prev_propp = PTRUNRELOC(pp); - prev_propp = &pp->next; - namep = (char *) (pp + 1); - pp->name = PTRUNRELOC(namep); - strcpy(namep, RELOC("linux,phandle")); - mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1); - pp->value = (unsigned char *) PTRUNRELOC(&np->node); - pp->length = sizeof(np->node); - } - *prev_propp = NULL; - - /* get the node's full name */ - l = (int) call_prom(RELOC("package-to-path"), 3, 1, node, - (char *) mem_start, mem_end - mem_start); - if (l >= 0) { - np->full_name = PTRUNRELOC((char *) mem_start); - *(char *)(mem_start + l) = 0; - mem_start = ALIGN(mem_start + l + 1); - } - - /* do all our children */ - child = call_prom(RELOC("child"), 1, 1, node); - while (child != (void *)0) { - mem_start = inspect_node(child, np, mem_start, mem_end, - allnextpp); - child = call_prom(RELOC("peer"), 1, 1, child); - } - - return mem_start; + rtas = (void (*)(void *, unsigned long)) rtas_entry; + rtas(&u, rtas_data); } /* @@ -1086,26 +166,6 @@ klimit = (char *) mem; } -/* - * early_get_property is used to access the device tree image prepared - * by BootX very early on, before the pointers in it have been relocated. - */ -static void * __init -early_get_property(unsigned long base, unsigned long node, char *prop) -{ - struct device_node *np = (struct device_node *)(base + node); - struct property *pp; - - for (pp = np->properties; pp != 0; pp = pp->next) { - pp = (struct property *) (base + (unsigned long)pp); - if (strcmp((char *)((unsigned long)pp->name + base), - prop) == 0) { - return (void *)((unsigned long)pp->value + base); - } - } - return 0; -} - static unsigned long __init finish_node(struct device_node *np, unsigned long mem_start, interpret_func *ifunc, int naddrc, int nsizec) @@ -1136,19 +196,6 @@ if (ip != NULL) nsizec = *ip; - /* - * The F50 sets the name to 'display' and 'compatible' to what we - * expect for the name. -- Cort - * - * But sometimes you get a 'display' name for non-OF cards, and thus - * no compatible property. And very rarely we won't have a name - * property either. -- Tom - */ - if (!strcmp(np->name, "display")) - np->name = get_property(np, "compatible", 0); - if (!np->name) - np->name = get_property(np, "name", 0); - if (np->parent == NULL) ifunc = interpret_root_props; else if (np->type == 0) @@ -2145,11 +1192,11 @@ u.words[i+3] = va_arg(list, unsigned long); va_end(list); - /* Shouldn't we enable kernel FP here ? enter_rtas will play - * with MSR_FE0|MSR_FE1|MSR_FP so I assume rtas might use - * floating points. If that's the case, then we need to make - * sure any lazy FP context is backed up - * --BenH + /* + * RTAS doesn't use floating point. + * Or at least, according to the CHRP spec we enter RTAS + * with FP disabled, and it doesn't change the FP registers. + * -- paulus. */ spin_lock_irqsave(&rtas_lock, s); enter_rtas((void *)__pa(&u)); @@ -2160,13 +1207,3 @@ outputs[i] = u.words[i+nargs+4]; return u.words[nargs+3]; } - -void __init -abort() -{ -#ifdef CONFIG_XMON - xmon(NULL); -#endif - for (;;) - prom_exit(); -} diff -urN linux-2.4.19-pre6/arch/ppc/kernel/prom_init.c linux-2.4.19-pre7/arch/ppc/kernel/prom_init.c --- linux-2.4.19-pre6/arch/ppc/kernel/prom_init.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/arch/ppc/kernel/prom_init.c Mon Apr 15 21:54:22 2002 @@ -0,0 +1,892 @@ +/* + * Procedures for interfacing to the Open Firmware PROM on + * Power Macintosh computers. + * + * In particular, we are interested in the device tree + * and in using some of its services (exit, write to stdout). + * + * Paul Mackerras August 1996. + * Copyright (C) 1996 Paul Mackerras. + */ +/* + * Note that prom_init() and anything called from prom_init() + * may be running at an address that is different from the address + * that it was linked at. References to static data items are + * handled by compiling this file with -mrelocatable-lib. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_FB +#include +#endif + +/* + * Properties whose value is longer than this get excluded from our + * copy of the device tree. This way we don't waste space storing + * things like "driver,AAPL,MacOS,PowerPC" properties. But this value + * does need to be big enough to ensure that we don't lose things + * like the interrupt-map property on a PCI-PCI bridge. + */ +#define MAX_PROPERTY_LENGTH 4096 + +#ifndef FB_MAX /* avoid pulling in all of the fb stuff */ +#define FB_MAX 8 +#endif + +#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long)) + +struct prom_args { + const char *service; + int nargs; + int nret; + void *args[10]; +}; + +struct pci_address { + unsigned a_hi; + unsigned a_mid; + unsigned a_lo; +}; + +struct pci_reg_property { + struct pci_address addr; + unsigned size_hi; + unsigned size_lo; +}; + +struct pci_range { + struct pci_address addr; + unsigned phys; + unsigned size_hi; + unsigned size_lo; +}; + +struct isa_reg_property { + unsigned space; + unsigned address; + unsigned size; +}; + +struct pci_intr_map { + struct pci_address addr; + unsigned dunno; + phandle int_ctrler; + unsigned intr; +}; + +static void prom_exit(void); +static void *call_prom(const char *service, int nargs, int nret, ...); +static void *call_prom_ret(const char *service, int nargs, int nret, + void **rets, ...); +static void prom_print_hex(unsigned int v); +static int prom_set_color(ihandle ih, int i, int r, int g, int b); +static int prom_next_node(phandle *nodep); +static unsigned long check_display(unsigned long mem); +static void setup_disp_fake_bi(ihandle dp); +static unsigned long copy_device_tree(unsigned long mem_start, + unsigned long mem_end); +static unsigned long inspect_node(phandle node, struct device_node *dad, + unsigned long mem_start, unsigned long mem_end, + struct device_node ***allnextpp); +static void prom_hold_cpus(unsigned long mem); +static void prom_instantiate_rtas(void); +static void * early_get_property(unsigned long base, unsigned long node, + char *prop); + +prom_entry prom __initdata = 0; +ihandle prom_chosen __initdata = 0; +ihandle prom_stdout __initdata = 0; + +char *prom_display_paths[FB_MAX] __initdata = { 0, }; +phandle prom_display_nodes[FB_MAX] __initdata; +unsigned int prom_num_displays __initdata = 0; +static char *of_stdout_device __initdata = 0; +static ihandle prom_disp_node __initdata = 0; + +unsigned int rtas_data; /* physical pointer */ +unsigned int rtas_entry; /* physical pointer */ +unsigned int rtas_size; +unsigned int old_rtas; + +boot_infos_t *boot_infos; +char *bootpath; +char *bootdevice; +struct device_node *allnodes; + +extern char *klimit; +extern char _stext; + +static void __init +prom_exit(void) +{ + struct prom_args args; + + args.service = "exit"; + args.nargs = 0; + args.nret = 0; + prom(&args); + for (;;) /* should never get here */ + ; +} + +static void * __init +call_prom(const char *service, int nargs, int nret, ...) +{ + va_list list; + int i; + struct prom_args prom_args; + + prom_args.service = service; + prom_args.nargs = nargs; + prom_args.nret = nret; + va_start(list, nret); + for (i = 0; i < nargs; ++i) + prom_args.args[i] = va_arg(list, void *); + va_end(list); + for (i = 0; i < nret; ++i) + prom_args.args[i + nargs] = 0; + prom(&prom_args); + return prom_args.args[nargs]; +} + +static void * __init +call_prom_ret(const char *service, int nargs, int nret, void **rets, ...) +{ + va_list list; + int i; + struct prom_args prom_args; + + prom_args.service = service; + prom_args.nargs = nargs; + prom_args.nret = nret; + va_start(list, rets); + for (i = 0; i < nargs; ++i) + prom_args.args[i] = va_arg(list, void *); + va_end(list); + for (i = 0; i < nret; ++i) + prom_args.args[i + nargs] = 0; + prom(&prom_args); + for (i = 1; i < nret; ++i) + rets[i-1] = prom_args.args[nargs + i]; + return prom_args.args[nargs]; +} + +void __init +prom_print(const char *msg) +{ + const char *p, *q; + + if (prom_stdout == 0) + return; + + for (p = msg; *p != 0; p = q) { + for (q = p; *q != 0 && *q != '\n'; ++q) + ; + if (q > p) + call_prom("write", 3, 1, prom_stdout, p, q - p); + if (*q != 0) { + ++q; + call_prom("write", 3, 1, prom_stdout, "\r\n", 2); + } + } +} + +static void __init +prom_print_hex(unsigned int v) +{ + char buf[16]; + int i, c; + + for (i = 0; i < 8; ++i) { + c = (v >> ((7-i)*4)) & 0xf; + c += (c >= 10)? ('a' - 10): '0'; + buf[i] = c; + } + buf[i] = ' '; + buf[i+1] = 0; + prom_print(buf); +} + +static int __init +prom_set_color(ihandle ih, int i, int r, int g, int b) +{ + struct prom_args prom_args; + + prom_args.service = "call-method"; + prom_args.nargs = 6; + prom_args.nret = 1; + prom_args.args[0] = "color!"; + prom_args.args[1] = ih; + prom_args.args[2] = (void *) i; + prom_args.args[3] = (void *) b; + prom_args.args[4] = (void *) g; + prom_args.args[5] = (void *) r; + prom(&prom_args); + return (int) prom_args.args[6]; +} + +static int __init +prom_next_node(phandle *nodep) +{ + phandle node; + + if ((node = *nodep) != 0 + && (*nodep = call_prom("child", 1, 1, node)) != 0) + return 1; + if ((*nodep = call_prom("peer", 1, 1, node)) != 0) + return 1; + for (;;) { + if ((node = call_prom("parent", 1, 1, node)) == 0) + return 0; + if ((*nodep = call_prom("peer", 1, 1, node)) != 0) + return 1; + } +} + +/* + * If we have a display that we don't know how to drive, + * we will want to try to execute OF's open method for it + * later. However, OF will probably fall over if we do that + * we've taken over the MMU. + * So we check whether we will need to open the display, + * and if so, open it now. + */ +static unsigned long __init +check_display(unsigned long mem) +{ + phandle node; + ihandle ih; + int i; + char type[16], *path; + static unsigned char default_colors[] = { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0xaa, + 0x00, 0xaa, 0x00, + 0x00, 0xaa, 0xaa, + 0xaa, 0x00, 0x00, + 0xaa, 0x00, 0xaa, + 0xaa, 0xaa, 0x00, + 0xaa, 0xaa, 0xaa, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0xff, + 0x55, 0xff, 0x55, + 0x55, 0xff, 0xff, + 0xff, 0x55, 0x55, + 0xff, 0x55, 0xff, + 0xff, 0xff, 0x55, + 0xff, 0xff, 0xff + }; + + prom_disp_node = 0; + + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + call_prom("getprop", 4, 1, node, "device_type", + type, sizeof(type)); + if (strcmp(type, "display") != 0) + continue; + /* It seems OF doesn't null-terminate the path :-( */ + path = (char *) mem; + memset(path, 0, 256); + if ((int) call_prom("package-to-path", 3, 1, + node, path, 255) < 0) + continue; + + /* + * If this display is the device that OF is using for stdout, + * move it to the front of the list. + */ + mem += strlen(path) + 1; + i = prom_num_displays++; + if (of_stdout_device != 0 && i > 0 + && strcmp(of_stdout_device, path) == 0) { + for (; i > 0; --i) { + prom_display_paths[i] + = prom_display_paths[i-1]; + prom_display_nodes[i] + = prom_display_nodes[i-1]; + } + } + prom_display_paths[i] = path; + prom_display_nodes[i] = node; + if (i == 0) + prom_disp_node = node; + if (prom_num_displays >= FB_MAX) + break; + } + +try_again: + /* + * Open the first display and set its colormap. + */ + if (prom_num_displays > 0) { + path = prom_display_paths[0]; + prom_print("opening display "); + prom_print(path); + ih = call_prom("open", 1, 1, path); + if (ih == 0 || ih == (ihandle) -1) { + prom_print("... failed\n"); + for (i=1; i 0) + prom_disp_node = prom_display_nodes[0]; + else + prom_disp_node = NULL; + goto try_again; + } else { + prom_print("... ok\n"); + /* + * Setup a usable color table when the appropriate + * method is available. + * Should update this to use set-colors. + */ + for (i = 0; i < 32; i++) + if (prom_set_color(ih, i, default_colors[i*3], + default_colors[i*3+1], + default_colors[i*3+2]) != 0) + break; + +#ifdef CONFIG_FB + for (i = 0; i < LINUX_LOGO_COLORS; i++) + if (prom_set_color(ih, i + 32, + linux_logo_red[i], + linux_logo_green[i], + linux_logo_blue[i]) != 0) + break; +#endif /* CONFIG_FB */ + } + } + + return ALIGN(mem); +} + +/* This function will enable the early boot text when doing OF booting. This + * way, xmon output should work too + */ +static void __init +setup_disp_fake_bi(ihandle dp) +{ +#ifdef CONFIG_BOOTX_TEXT + int width = 640, height = 480, depth = 8, pitch; + unsigned address; + struct pci_reg_property addrs[8]; + int i, naddrs; + char name[32]; + char *getprop = "getprop"; + + prom_print("Initializing fake screen: "); + + memset(name, 0, sizeof(name)); + call_prom(getprop, 4, 1, dp, "name", name, sizeof(name)); + name[sizeof(name)-1] = 0; + prom_print(name); + prom_print("\n"); + call_prom(getprop, 4, 1, dp, "width", &width, sizeof(width)); + call_prom(getprop, 4, 1, dp, "height", &height, sizeof(height)); + call_prom(getprop, 4, 1, dp, "depth", &depth, sizeof(depth)); + pitch = width * ((depth + 7) / 8); + call_prom(getprop, 4, 1, dp, "linebytes", + &pitch, sizeof(pitch)); + if (pitch == 1) + pitch = 0x1000; /* for strange IBM display */ + address = 0; + call_prom(getprop, 4, 1, dp, "address", + &address, sizeof(address)); + if (address == 0) { + /* look for an assigned address with a size of >= 1MB */ + naddrs = (int) call_prom(getprop, 4, 1, dp, + "assigned-addresses", + addrs, sizeof(addrs)); + naddrs /= sizeof(struct pci_reg_property); + for (i = 0; i < naddrs; ++i) { + if (addrs[i].size_lo >= (1 << 20)) { + address = addrs[i].addr.a_lo; + /* use the BE aperture if possible */ + if (addrs[i].size_lo >= (16 << 20)) + address += (8 << 20); + break; + } + } + if (address == 0) { + prom_print("Failed to get address\n"); + return; + } + } + /* kludge for valkyrie */ + if (strcmp(name, "valkyrie") == 0) + address += 0x1000; + + btext_setup_display(width, height, depth, pitch, address); + + btext_prepare_BAT(); +#endif /* CONFIG_BOOTX_TEXT */ +} + +/* + * Make a copy of the device tree from the PROM. + */ +static unsigned long __init +copy_device_tree(unsigned long mem_start, unsigned long mem_end) +{ + phandle root; + unsigned long new_start; + struct device_node **allnextp; + + root = call_prom("peer", 1, 1, (phandle)0); + if (root == (phandle)0) { + prom_print("couldn't get device tree root\n"); + prom_exit(); + } + allnextp = &allnodes; + mem_start = ALIGN(mem_start); + new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp); + *allnextp = 0; + return new_start; +} + +static unsigned long __init +inspect_node(phandle node, struct device_node *dad, + unsigned long mem_start, unsigned long mem_end, + struct device_node ***allnextpp) +{ + int l; + phandle child; + struct device_node *np; + struct property *pp, **prev_propp; + char *prev_name, *namep; + unsigned char *valp; + + np = (struct device_node *) mem_start; + mem_start += sizeof(struct device_node); + memset(np, 0, sizeof(*np)); + np->node = node; + **allnextpp = PTRUNRELOC(np); + *allnextpp = &np->allnext; + if (dad != 0) { + np->parent = PTRUNRELOC(dad); + /* we temporarily use the `next' field as `last_child'. */ + if (dad->next == 0) + dad->child = PTRUNRELOC(np); + else + dad->next->sibling = PTRUNRELOC(np); + dad->next = np; + } + + /* get and store all properties */ + prev_propp = &np->properties; + prev_name = ""; + for (;;) { + pp = (struct property *) mem_start; + namep = (char *) (pp + 1); + pp->name = PTRUNRELOC(namep); + if ((int) call_prom("nextprop", 3, 1, node, prev_name, + namep) <= 0) + break; + mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1); + prev_name = namep; + valp = (unsigned char *) mem_start; + pp->value = PTRUNRELOC(valp); + pp->length = (int) + call_prom("getprop", 4, 1, node, namep, + valp, mem_end - mem_start); + if (pp->length < 0) + continue; +#ifdef MAX_PROPERTY_LENGTH + if (pp->length > MAX_PROPERTY_LENGTH) + continue; /* ignore this property */ +#endif + mem_start = ALIGN(mem_start + pp->length); + *prev_propp = PTRUNRELOC(pp); + prev_propp = &pp->next; + } + if (np->node != NULL) { + /* Add a "linux,phandle" property" */ + pp = (struct property *) mem_start; + *prev_propp = PTRUNRELOC(pp); + prev_propp = &pp->next; + namep = (char *) (pp + 1); + pp->name = PTRUNRELOC(namep); + strcpy(namep, "linux,phandle"); + mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1); + pp->value = (unsigned char *) PTRUNRELOC(&np->node); + pp->length = sizeof(np->node); + } + *prev_propp = NULL; + + /* get the node's full name */ + l = (int) call_prom("package-to-path", 3, 1, node, + (char *) mem_start, mem_end - mem_start); + if (l >= 0) { + np->full_name = PTRUNRELOC((char *) mem_start); + *(char *)(mem_start + l) = 0; + mem_start = ALIGN(mem_start + l + 1); + } + + /* do all our children */ + child = call_prom("child", 1, 1, node); + while (child != (void *)0) { + mem_start = inspect_node(child, np, mem_start, mem_end, + allnextpp); + child = call_prom("peer", 1, 1, child); + } + + return mem_start; +} + +unsigned long smp_chrp_cpu_nr __initdata = 0; + +/* + * With CHRP SMP we need to use the OF to start the other + * processors so we can't wait until smp_boot_cpus (the OF is + * trashed by then) so we have to put the processors into + * a holding pattern controlled by the kernel (not OF) before + * we destroy the OF. + * + * This uses a chunk of high memory, puts some holding pattern + * code there and sends the other processors off to there until + * smp_boot_cpus tells them to do something. We do that by using + * physical address 0x0. The holding pattern checks that address + * until its cpu # is there, when it is that cpu jumps to + * __secondary_start(). smp_boot_cpus() takes care of setting those + * values. + * + * We also use physical address 0x4 here to tell when a cpu + * is in its holding pattern code. + * + * -- Cort + * + * Note that we have to do this if we have more than one CPU, + * even if this is a UP kernel. Otherwise when we trash OF + * the other CPUs will start executing some random instructions + * and crash the system. -- paulus + */ +static void __init +prom_hold_cpus(unsigned long mem) +{ + extern void __secondary_hold(void); + unsigned long i; + int cpu; + phandle node; + char type[16], *path; + unsigned int reg; + + /* + * XXX: hack to make sure we're chrp, assume that if we're + * chrp we have a device_type property -- Cort + */ + node = call_prom("finddevice", 1, 1, "/"); + if ((int)call_prom("getprop", 4, 1, node, + "device_type",type, sizeof(type)) <= 0) + return; + + /* copy the holding pattern code to someplace safe (0) */ + /* the holding pattern is now within the first 0x100 + bytes of the kernel image -- paulus */ + memcpy((void *)0, &_stext, 0x100); + flush_icache_range(0, 0x100); + + /* look for cpus */ + *(unsigned long *)(0x0) = 0; + asm volatile("dcbf 0,%0": : "r" (0) : "memory"); + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + call_prom("getprop", 4, 1, node, "device_type", + type, sizeof(type)); + if (strcmp(type, "cpu") != 0) + continue; + path = (char *) mem; + memset(path, 0, 256); + if ((int) call_prom("package-to-path", 3, 1, + node, path, 255) < 0) + continue; + reg = -1; + call_prom("getprop", 4, 1, node, "reg", ®, sizeof(reg)); + cpu = smp_chrp_cpu_nr++; +#ifdef CONFIG_SMP + smp_hw_index[cpu] = reg; +#endif /* CONFIG_SMP */ + /* XXX: hack - don't start cpu 0, this cpu -- Cort */ + if (cpu == 0) + continue; + prom_print("starting cpu "); + prom_print(path); + *(ulong *)(0x4) = 0; + call_prom("start-cpu", 3, 0, node, + (char *)__secondary_hold - &_stext, cpu); + prom_print("..."); + for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ ) + ; + if (*(ulong *)(0x4) == cpu) + prom_print("ok\n"); + else { + prom_print("failed: "); + prom_print_hex(*(ulong *)0x4); + prom_print("\n"); + } + } +} + +static void __init +prom_instantiate_rtas(void) +{ + ihandle prom_rtas; + unsigned int i; + struct prom_args prom_args; + + prom_rtas = call_prom("finddevice", 1, 1, "/rtas"); + if (prom_rtas == (void *) -1) + return; + + rtas_size = 0; + call_prom("getprop", 4, 1, prom_rtas, + "rtas-size", &rtas_size, sizeof(rtas_size)); + prom_print("instantiating rtas"); + if (rtas_size == 0) { + rtas_data = 0; + } else { + /* + * Ask OF for some space for RTAS. + * Actually OF has bugs so we just arbitrarily + * use memory at the 6MB point. + */ + rtas_data = 6 << 20; + prom_print(" at "); + prom_print_hex(rtas_data); + } + + prom_rtas = call_prom("open", 1, 1, "/rtas"); + prom_print("..."); + prom_args.service = "call-method"; + prom_args.nargs = 3; + prom_args.nret = 2; + prom_args.args[0] = "instantiate-rtas"; + prom_args.args[1] = prom_rtas; + prom_args.args[2] = (void *) rtas_data; + prom(&prom_args); + i = 0; + if (prom_args.args[3] == 0) + i = (unsigned int)prom_args.args[4]; + rtas_entry = i; + if ((rtas_entry == -1) || (rtas_entry == 0)) + prom_print(" failed\n"); + else + prom_print(" done\n"); +} + +/* + * We enter here early on, when the Open Firmware prom is still + * handling exceptions and the MMU hash table for us. + */ +unsigned long __init +prom_init(int r3, int r4, prom_entry pp) +{ + unsigned long mem; + ihandle prom_mmu; + unsigned long offset = reloc_offset(); + int i, l; + char *p, *d; + unsigned long phys; + void *result[3]; + + /* Default */ + phys = (unsigned long) &_stext; + + /* First get a handle for the stdout device */ + prom = pp; + prom_chosen = call_prom("finddevice", 1, 1, + "/chosen"); + if (prom_chosen == (void *)-1) + prom_exit(); + if ((int) call_prom("getprop", 4, 1, prom_chosen, + "stdout", &prom_stdout, + sizeof(prom_stdout)) <= 0) + prom_exit(); + + /* Get the full OF pathname of the stdout device */ + mem = (unsigned long) klimit + offset; + p = (char *) mem; + memset(p, 0, 256); + call_prom("instance-to-path", 3, 1, prom_stdout, p, 255); + of_stdout_device = p; + mem += strlen(p) + 1; + + /* Get the boot device and translate it to a full OF pathname. */ + p = (char *) mem; + l = (int) call_prom("getprop", 4, 1, prom_chosen, + "bootpath", p, 1<<20); + if (l > 0) { + p[l] = 0; /* should already be null-terminated */ + bootpath = PTRUNRELOC(p); + mem += l + 1; + d = (char *) mem; + *d = 0; + call_prom("canon", 3, 1, p, d, 1<<20); + bootdevice = PTRUNRELOC(d); + mem = ALIGN(mem + strlen(d) + 1); + } + + prom_instantiate_rtas(); + + mem = check_display(mem); + + prom_print("copying OF device tree..."); + mem = copy_device_tree(mem, mem + (1<<20)); + prom_print("done\n"); + + prom_hold_cpus(mem); + + klimit = (char *) (mem - offset); + + /* If we are already running at 0xc0000000, we assume we were + * loaded by an OF bootloader which did set a BAT for us. + * This breaks OF translate so we force phys to be 0. + */ + if (offset == 0) + phys = 0; + else if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu", + &prom_mmu, sizeof(prom_mmu)) <= 0) { + prom_print(" no MMU found\n"); + } else if ((int)call_prom_ret("call-method", 4, 4, result, "translate", + prom_mmu, &_stext, 1) != 0) { + prom_print(" (translate failed)\n"); + } else { + /* We assume the phys. address size is 3 cells */ + phys = (unsigned long)result[2]; + } + + if (prom_disp_node != 0) + setup_disp_fake_bi(prom_disp_node); + + /* Use quiesce call to get OF to shut down any devices it's using */ + prom_print("Calling quiesce ...\n"); + call_prom("quiesce", 0, 0); + + /* Relocate various pointers which will be used once the + kernel is running at the address it was linked at. */ + for (i = 0; i < prom_num_displays; ++i) + prom_display_paths[i] = PTRUNRELOC(prom_display_paths[i]); + + prom_print("returning 0x"); + prom_print_hex(phys); + prom_print("from prom_init\n"); + prom_stdout = 0; + + return phys; +} + +/* + * early_get_property is used to access the device tree image prepared + * by BootX very early on, before the pointers in it have been relocated. + */ +static void * __init +early_get_property(unsigned long base, unsigned long node, char *prop) +{ + struct device_node *np = (struct device_node *)(base + node); + struct property *pp; + + for (pp = np->properties; pp != 0; pp = pp->next) { + pp = (struct property *) (base + (unsigned long)pp); + if (strcmp((char *)((unsigned long)pp->name + base), + prop) == 0) { + return (void *)((unsigned long)pp->value + base); + } + } + return 0; +} + +/* Is boot-info compatible ? */ +#define BOOT_INFO_IS_COMPATIBLE(bi) ((bi)->compatible_version <= BOOT_INFO_VERSION) +#define BOOT_INFO_IS_V2_COMPATIBLE(bi) ((bi)->version >= 2) +#define BOOT_INFO_IS_V4_COMPATIBLE(bi) ((bi)->version >= 4) + +void __init +bootx_init(unsigned long r4, unsigned long phys) +{ + boot_infos_t *bi = (boot_infos_t *) r4; + unsigned long space; + unsigned long ptr, x; + char *model; + + boot_infos = PTRUNRELOC(bi); + if (!BOOT_INFO_IS_V2_COMPATIBLE(bi)) + bi->logicalDisplayBase = 0; + +#ifdef CONFIG_BOOTX_TEXT + btext_init(bi); + + /* + * Test if boot-info is compatible. Done only in config + * CONFIG_BOOTX_TEXT since there is nothing much we can do + * with an incompatible version, except display a message + * and eventually hang the processor... + * + * I'll try to keep enough of boot-info compatible in the + * future to always allow display of this message; + */ + if (!BOOT_INFO_IS_COMPATIBLE(bi)) { + btext_drawstring(" !!! WARNING - Incompatible version of BootX !!!\n\n\n"); + btext_flushscreen(); + } +#endif /* CONFIG_BOOTX_TEXT */ + + /* New BootX enters kernel with MMU off, i/os are not allowed + here. This hack will have been done by the boostrap anyway. + */ + if (bi->version < 4) { + /* + * XXX If this is an iMac, turn off the USB controller. + */ + model = (char *) early_get_property + (r4 + bi->deviceTreeOffset, 4, "model"); + if (model + && (strcmp(model, "iMac,1") == 0 + || strcmp(model, "PowerMac1,1") == 0)) { + out_le32((unsigned *)0x80880008, 1); /* XXX */ + } + } + + /* Move klimit to enclose device tree, args, ramdisk, etc... */ + if (bi->version < 5) { + space = bi->deviceTreeOffset + bi->deviceTreeSize; + if (bi->ramDisk) + space = bi->ramDisk + bi->ramDiskSize; + } else + space = bi->totalParamsSize; + klimit = PTRUNRELOC((char *) bi + space); + + /* New BootX will have flushed all TLBs and enters kernel with + MMU switched OFF, so this should not be useful anymore. + */ + if (bi->version < 4) { + /* + * Touch each page to make sure the PTEs for them + * are in the hash table - the aim is to try to avoid + * getting DSI exceptions while copying the kernel image. + */ + for (ptr = ((unsigned long) &_stext) & PAGE_MASK; + ptr < (unsigned long)bi + space; ptr += PAGE_SIZE) + x = *(volatile unsigned long *)ptr; + } + +#ifdef CONFIG_BOOTX_TEXT + /* + * Note that after we call btext_prepare_BAT, we can't do + * prom_draw*, flushscreen or clearscreen until we turn the MMU + * on, since btext_prepare_BAT sets disp_bi.logicalDisplayBase + * to a virtual address. + */ + btext_prepare_BAT(); +#endif +} diff -urN linux-2.4.19-pre6/arch/ppc/kernel/ptrace.c linux-2.4.19-pre7/arch/ppc/kernel/ptrace.c --- linux-2.4.19-pre6/arch/ppc/kernel/ptrace.c Mon Nov 26 05:29:17 2001 +++ linux-2.4.19-pre7/arch/ppc/kernel/ptrace.c Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ptrace.c 1.12 11/23/01 16:38:30 paulus + * BK Id: SCCS/s.ptrace.c 1.14 01/17/02 23:05:50 paulus */ /* * linux/arch/ppc/kernel/ptrace.c @@ -71,6 +71,64 @@ return -EIO; } +#ifdef CONFIG_ALTIVEC +/* + * Get contents of AltiVec register state in task TASK + */ +static inline int get_vrregs(unsigned long *data, struct task_struct *task) +{ + int i, j; + + if (!access_ok(VERIFY_WRITE, data, 133 * sizeof(unsigned long))) + return -EFAULT; + + /* copy AltiVec registers VR[0] .. VR[31] */ + for (i = 0; i < 32; i++) + for (j = 0; j < 4; j++, data++) + if (__put_user(task->thread.vr[i].u[j], data)) + return -EFAULT; + + /* copy VSCR */ + for (i = 0; i < 4; i++, data++) + if (__put_user(task->thread.vscr.u[i], data)) + return -EFAULT; + + /* copy VRSAVE */ + if (__put_user(task->thread.vrsave, data)) + return -EFAULT; + + return 0; +} + +/* + * Write contents of AltiVec register state into task TASK. + */ +static inline int set_vrregs(struct task_struct *task, unsigned long *data) +{ + int i, j; + + if (!access_ok(VERIFY_READ, data, 133 * sizeof(unsigned long))) + return -EFAULT; + + /* copy AltiVec registers VR[0] .. VR[31] */ + for (i = 0; i < 32; i++) + for (j = 0; j < 4; j++, data++) + if (__get_user(task->thread.vr[i].u[j], data)) + return -EFAULT; + + /* copy VSCR */ + for (i = 0; i < 4; i++, data++) + if (__get_user(task->thread.vscr.u[i], data)) + return -EFAULT; + + /* copy VRSAVE */ + if (__get_user(task->thread.vrsave, data)) + return -EFAULT; + + return 0; +} +#endif + static inline void set_single_step(struct task_struct *task) { @@ -259,6 +317,24 @@ ret = ptrace_detach(child, data); break; +#ifdef CONFIG_ALTIVEC + case PTRACE_GETVRREGS: + /* Get the child altivec register state. */ + if (child->thread.regs->msr & MSR_VEC) + giveup_altivec(child); + ret = get_vrregs((unsigned long *)data, child); + break; + + case PTRACE_SETVRREGS: + /* Set the child altivec register state. */ + /* this is to clear the MSR_VEC bit to force a reload + * of register state from memory */ + if (child->thread.regs->msr & MSR_VEC) + giveup_altivec(child); + ret = set_vrregs(child, (unsigned long *)data); + break; +#endif + default: ret = -EIO; break; diff -urN linux-2.4.19-pre6/arch/ppc/kernel/residual.c linux-2.4.19-pre7/arch/ppc/kernel/residual.c --- linux-2.4.19-pre6/arch/ppc/kernel/residual.c Mon Oct 8 11:43:01 2001 +++ linux-2.4.19-pre7/arch/ppc/kernel/residual.c Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.residual.c 1.13 09/11/01 16:54:34 trini + * BK Id: SCCS/s.residual.c 1.15 02/05/02 18:08:35 trini */ /* * Code to deal with the PReP residual data. @@ -876,3 +876,38 @@ }; return 0; /* not found */ } + +#ifdef CONFIG_PROC_PREPRESIDUAL +static int proc_prep_residual_read(char * buf, char ** start, off_t off, + int count, int *eof, void *data) +{ + int n; + + n = res->ResidualLength - off; + if (n < 0) { + *eof = 1; + n = 0; + } + else { + if (n > count) + n = count; + else + *eof = 1; + + memcpy(buf, (char *)res + off, n); + *start = buf; + } + + return n; +} + +void __init +proc_prep_residual_init(void) +{ + if (res->ResidualLength) + create_proc_read_entry("residual", S_IRUGO, NULL, + proc_prep_residual_read, NULL); +} + +__initcall(proc_prep_residual_init); +#endif diff -urN linux-2.4.19-pre6/arch/ppc/kernel/setup.c linux-2.4.19-pre7/arch/ppc/kernel/setup.c --- linux-2.4.19-pre6/arch/ppc/kernel/setup.c Mon Apr 15 21:53:31 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/setup.c Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.setup.c 1.70 02/15/02 09:27:13 trini + * BK Id: SCCS/s.setup.c 1.74 04/09/02 21:01:58 paulus */ /* * Common prep/pmac/chrp boot and setup code. @@ -52,6 +52,7 @@ extern void bootx_init(unsigned long r4, unsigned long phys); extern void identify_cpu(unsigned long offset, unsigned long cpu); extern void do_cpu_ftr_fixups(unsigned long offset); +extern void reloc_got2(unsigned long offset); #ifdef CONFIG_XMON extern void xmon_map_scc(void); @@ -291,22 +292,22 @@ do_cpu_ftr_fixups(offset); #if defined(CONFIG_ALL_PPC) + reloc_got2(offset); + /* If we came here from BootX, clear the screen, * set up some pointers and return. */ - if ((r3 == 0x426f6f58) && (r5 == 0)) { + if ((r3 == 0x426f6f58) && (r5 == 0)) bootx_init(r4, phys); - return phys; - } - /* check if we're prep, return if we are */ - if ( *(unsigned long *)(0) == 0xdeadc0de ) - return phys; - - /* + /* + * don't do anything on prep * for now, don't use bootinfo because it breaks yaboot 0.5 * and assume that if we didn't find a magic number, we have OF */ - phys = prom_init(r3, r4, (prom_entry)r5); + else if (*(unsigned long *)(0) != 0xdeadc0de) + phys = prom_init(r3, r4, (prom_entry)r5); + + reloc_got2(-offset); #endif return phys; @@ -343,11 +344,9 @@ unsigned long r6, unsigned long r7) { #ifdef CONFIG_BOOTX_TEXT - extern boot_infos_t *disp_bi; - - if (disp_bi) { + if (boot_text_mapped) { btext_clearscreen(); - btext_welcome(disp_bi); + btext_welcome(); } #endif @@ -409,15 +408,14 @@ char *p; #ifdef CONFIG_BLK_DEV_INITRD - if (r3 && r4 && r4 != 0xdeadbeef) - { - if (r3 < KERNELBASE) - r3 += KERNELBASE; - initrd_start = r3; - initrd_end = r3 + r4; - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); - initrd_below_start_ok = 1; - } + if (r3 && r4 && r4 != 0xdeadbeef) { + if (r3 < KERNELBASE) + r3 += KERNELBASE; + initrd_start = r3; + initrd_end = r3 + r4; + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + initrd_below_start_ok = 1; + } #endif chosen = find_devices("chosen"); if (chosen != NULL) { diff -urN linux-2.4.19-pre6/arch/ppc/kernel/sleep.S linux-2.4.19-pre7/arch/ppc/kernel/sleep.S --- linux-2.4.19-pre6/arch/ppc/kernel/sleep.S Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/kernel/sleep.S Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.sleep.S 1.18 12/02/01 12:38:54 benh + * BK Id: SCCS/s.sleep.S 1.20 03/19/02 15:04:39 benh */ /* * This file contains sleep low-level functions for PowerBook G3. @@ -13,10 +13,10 @@ * */ -#include "ppc_asm.tmpl" #include #include #include +#include "ppc_asm.h" #define MAGIC 0x4c617273 /* 'Lars' */ @@ -49,9 +49,6 @@ #define SL_R12 0x8c /* r12 to r31 */ #define SL_SIZE (SL_R12 + 80) -#define tophys(rd,rs) addis rd,rs,-KERNELBASE@h -#define tovirt(rd,rs) addis rd,rs,KERNELBASE@h - .text .align 5 @@ -190,6 +187,10 @@ addi r3,r3,sleep_storage@l stw r5,0(r3) + BEGIN_FTR_SECTION + DSSALL + sync + END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) /* * Flush the L1 data cache by reading the first 128kB of RAM diff -urN linux-2.4.19-pre6/arch/ppc/kernel/smp.c linux-2.4.19-pre7/arch/ppc/kernel/smp.c --- linux-2.4.19-pre6/arch/ppc/kernel/smp.c Fri Dec 21 09:41:53 2001 +++ linux-2.4.19-pre7/arch/ppc/kernel/smp.c Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.smp.c 1.37 11/23/01 16:38:30 paulus + * BK Id: SCCS/s.smp.c 1.40 03/28/02 16:54:23 hozer */ /* * Smp support for ppc. @@ -65,7 +65,6 @@ int start_secondary(void *); extern int cpu_idle(void *unused); void smp_call_function_interrupt(void); -void smp_message_pass(int target, int msg, unsigned long data, int wait); /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers. * @@ -76,11 +75,14 @@ #define PPC_MSG_INVALIDATE_TLB 2 #define PPC_MSG_XMON_BREAK 3 -#define smp_message_pass(t,m,d,w) \ - do { if (smp_ops) \ - atomic_inc(&ipi_sent); \ - smp_ops->message_pass((t),(m),(d),(w)); \ - } while(0) +static inline void +smp_message_pass(int target, int msg, unsigned long data, int wait) +{ + if (smp_ops){ + atomic_inc(&ipi_sent); + smp_ops->message_pass(target,msg,data,wait); + } +} /* * Common functions @@ -121,16 +123,18 @@ } } +#ifdef CONFIG_750_SMP /* * 750's don't broadcast tlb invalidates so * we have to emulate that behavior. * -- Cort */ -void smp_send_tlb_invalidate(int cpu) +void smp_ppc750_send_tlb_invalidate(int cpu) { if ( PVR_VER(mfspr(PVR)) == 8 ) smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_INVALIDATE_TLB, 0, 0); } +#endif void smp_send_reschedule(int cpu) { @@ -309,6 +313,20 @@ return; } +#ifndef CONFIG_750_SMP + /* check for 750's, they just don't work with linux SMP. + * If you actually have 750 SMP hardware and want to try to get + * it to work, send me a patch to make it work and + * I'll make CONFIG_750_SMP a config option. -- Troy (hozer@drgw.net) + */ + if ( PVR_VER(mfspr(PVR)) == 8 ){ + printk("SMP not supported on 750 cpus. %s line %d\n", + __FILE__, __LINE__); + return; + } +#endif + + /* Probe arch for CPUs */ cpu_nr = smp_ops->probe(); diff -urN linux-2.4.19-pre6/arch/ppc/kernel/syscalls.c linux-2.4.19-pre7/arch/ppc/kernel/syscalls.c --- linux-2.4.19-pre6/arch/ppc/kernel/syscalls.c Fri Nov 2 17:43:54 2001 +++ linux-2.4.19-pre7/arch/ppc/kernel/syscalls.c Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.syscalls.c 1.11 10/16/01 15:58:42 trini + * BK Id: SCCS/s.syscalls.c 1.13 03/13/02 09:12:22 trini */ /* * linux/arch/ppc/kernel/sys_ppc.c @@ -223,11 +223,12 @@ unsigned long fd, off_t offset) { int err = -EINVAL; + unsigned long off = offset; if (offset & ~PAGE_MASK) goto out; - err = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + err = do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT); out: return err; } diff -urN linux-2.4.19-pre6/arch/ppc/mm/init.c linux-2.4.19-pre7/arch/ppc/mm/init.c --- linux-2.4.19-pre6/arch/ppc/mm/init.c Mon Apr 15 21:53:31 2002 +++ linux-2.4.19-pre7/arch/ppc/mm/init.c Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.init.c 1.40 01/25/02 15:15:24 benh + * BK Id: SCCS/s.init.c 1.43 03/12/02 12:13:51 paulus */ /* * PowerPC version @@ -570,9 +570,6 @@ /* remove the RTAS pages from the available memory */ if (rtas_data) mem_pieces_remove(&phys_avail, rtas_data, rtas_size, 1); - /* remove the sysmap pages from the available memory */ - if (sysmap) - mem_pieces_remove(&phys_avail, __pa(sysmap), sysmap_size, 1); /* Because of some uninorth weirdness, we need a page of * memory as high as possible (it must be outside of the * bus address seen as the AGP aperture). It will be used @@ -588,6 +585,9 @@ agp_special_page = (unsigned long)__va(agp_special_page); } #endif /* CONFIG_ALL_PPC */ + /* remove the sysmap pages from the available memory */ + if (sysmap) + mem_pieces_remove(&phys_avail, __pa(sysmap), sysmap_size, 1); } /* Mark some memory as reserved by removing it from phys_avail. */ diff -urN linux-2.4.19-pre6/arch/ppc/mm/pgtable.c linux-2.4.19-pre7/arch/ppc/mm/pgtable.c --- linux-2.4.19-pre6/arch/ppc/mm/pgtable.c Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/mm/pgtable.c Mon Apr 15 21:54:22 2002 @@ -275,17 +275,17 @@ f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED; #if defined(CONFIG_KGDB) || defined(CONFIG_XMON) /* Allows stub to set breakpoints everywhere */ - f |= _PAGE_RW | _PAGE_DIRTY; -#else + f |= _PAGE_WRENABLE; +#else /* !CONFIG_KGDB && !CONFIG_XMON */ if ((char *) v < _stext || (char *) v >= etext) - f |= _PAGE_RW | _PAGE_DIRTY; + f |= _PAGE_WRENABLE; #ifdef CONFIG_PPC_STD_MMU else /* On the powerpc (not all), no user access forces R/W kernel access */ f |= _PAGE_USER; #endif /* CONFIG_PPC_STD_MMU */ -#endif /* CONFIG_KGDB */ +#endif /* CONFIG_KGDB || CONFIG_XMON */ map_page(v, p, f); v += PAGE_SIZE; p += PAGE_SIZE; diff -urN linux-2.4.19-pre6/arch/ppc/vmlinux.lds linux-2.4.19-pre7/arch/ppc/vmlinux.lds --- linux-2.4.19-pre6/arch/ppc/vmlinux.lds Tue Aug 28 06:58:33 2001 +++ linux-2.4.19-pre7/arch/ppc/vmlinux.lds Mon Apr 15 21:54:22 2002 @@ -33,6 +33,9 @@ *(.text) *(.fixup) *(.got1) + __got2_start = .; + *(.got2) + __got2_end = .; } _etext = .; PROVIDE (etext = .); diff -urN linux-2.4.19-pre6/arch/ppc/xmon/start.c linux-2.4.19-pre7/arch/ppc/xmon/start.c --- linux-2.4.19-pre6/arch/ppc/xmon/start.c Mon Feb 25 11:37:55 2002 +++ linux-2.4.19-pre7/arch/ppc/xmon/start.c Mon Apr 15 21:54:22 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.start.c 1.18 12/01/01 20:09:07 benh + * BK Id: SCCS/s.start.c 1.20 04/09/02 21:01:58 paulus */ /* * Copyright (C) 1996 Paul Mackerras. @@ -67,8 +67,6 @@ unsigned long addr; #ifdef CONFIG_BOOTX_TEXT if (!machine_is_compatible("iMac")) { - extern boot_infos_t *disp_bi; - /* see if there is a keyboard in the device tree with a parent of type "adb" */ for (np = find_devices("keyboard"); np; np = np->next) @@ -79,11 +77,11 @@ /* needs to be hacked if xmon_printk is to be used from within find_via_pmu() */ #ifdef CONFIG_ADB_PMU - if (np != NULL && disp_bi && find_via_pmu()) + if (np != NULL && boot_text_mapped && find_via_pmu()) use_screen = 1; #endif #ifdef CONFIG_ADB_CUDA - if (np != NULL && disp_bi && find_via_cuda()) + if (np != NULL && boot_text_mapped && find_via_cuda()) use_screen = 1; #endif } diff -urN linux-2.4.19-pre6/arch/sparc/boot/Makefile linux-2.4.19-pre7/arch/sparc/boot/Makefile --- linux-2.4.19-pre6/arch/sparc/boot/Makefile Sat Feb 26 20:46:44 2000 +++ linux-2.4.19-pre7/arch/sparc/boot/Makefile Mon Apr 15 21:54:23 2002 @@ -22,7 +22,7 @@ clean: rm -f btfixupprep piggyback tftpboot.img btfix.o btfix.s -BTOBJS := $(HEAD) init/main.o init/version.o +BTOBJS := $(HEAD) init/main.o init/version.o init/do_mounts.o BTLIBS := $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \ $(DRIVERS) $(NETWORKS) diff -urN linux-2.4.19-pre6/arch/sparc/config.in linux-2.4.19-pre7/arch/sparc/config.in --- linux-2.4.19-pre6/arch/sparc/config.in Mon Jun 11 19:15:27 2001 +++ linux-2.4.19-pre7/arch/sparc/config.in Mon Apr 15 21:54:23 2002 @@ -251,9 +251,7 @@ source fs/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Watchdog' diff -urN linux-2.4.19-pre6/arch/sparc64/config.in linux-2.4.19-pre7/arch/sparc64/config.in --- linux-2.4.19-pre6/arch/sparc64/config.in Mon Apr 15 21:53:33 2002 +++ linux-2.4.19-pre7/arch/sparc64/config.in Mon Apr 15 21:54:24 2002 @@ -283,9 +283,7 @@ source drivers/usb/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - source net/bluetooth/Config.in -fi +source net/bluetooth/Config.in mainmenu_option next_comment comment 'Watchdog' diff -urN linux-2.4.19-pre6/arch/sparc64/defconfig linux-2.4.19-pre7/arch/sparc64/defconfig --- linux-2.4.19-pre6/arch/sparc64/defconfig Mon Apr 15 21:53:33 2002 +++ linux-2.4.19-pre7/arch/sparc64/defconfig Mon Apr 15 21:54:24 2002 @@ -105,6 +105,7 @@ # CONFIG_FB_RADEON is not set # CONFIG_FB_ATY128 is not set # CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set # CONFIG_FB_3DFX is not set # CONFIG_FB_VOODOO1 is not set # CONFIG_FB_TRIDENT is not set @@ -312,7 +313,6 @@ # CONFIG_BLK_DEV_HPT366 is not set CONFIG_BLK_DEV_NS87415=y # CONFIG_BLK_DEV_OPTI621 is not set -# CONFIG_BLK_DEV_PDC_ADMA is not set # CONFIG_BLK_DEV_PDC202XX is not set # CONFIG_PDC202XX_BURST is not set # CONFIG_PDC202XX_FORCE is not set @@ -322,7 +322,6 @@ # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_IDE_CHIPSETS is not set -# CONFIG_BLK_DEV_ELEVATOR_NOOP is not set CONFIG_IDEDMA_AUTO=y # CONFIG_IDEDMA_IVB is not set # CONFIG_DMA_NONPCI is not set @@ -400,10 +399,6 @@ # CONFIG_FUSION=m # CONFIG_FUSION_BOOT is not set - -# -# (ability to boot linux kernel from Fusion device is DISABLED!) -# CONFIG_FUSION_ISENSE=m CONFIG_FUSION_CTL=m CONFIG_FUSION_LAN=m @@ -427,7 +422,11 @@ # # CONFIG_IEEE1394_VIDEO1394 is not set CONFIG_IEEE1394_SBP2=m +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_DV1394=m CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_CMP=m +CONFIG_IEEE1394_AMDTP=m # CONFIG_IEEE1394_VERBOSEDEBUG is not set # @@ -617,7 +616,7 @@ # CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set # CONFIG_TMPFS is not set -CONFIG_RAMFS=m +CONFIG_RAMFS=y CONFIG_ISO9660_FS=m CONFIG_JOLIET=y # CONFIG_ZISOFS is not set @@ -787,6 +786,7 @@ # USB Human Interface Devices (HID) # CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y # CONFIG_USB_HIDDEV is not set CONFIG_USB_WACOM=m @@ -815,6 +815,7 @@ # USB Network adaptors # CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m CONFIG_USB_KAWETH=m CONFIG_USB_CATC=m CONFIG_USB_CDCETHER=m diff -urN linux-2.4.19-pre6/arch/sparc64/kernel/process.c linux-2.4.19-pre7/arch/sparc64/kernel/process.c --- linux-2.4.19-pre6/arch/sparc64/kernel/process.c Mon Feb 25 11:37:56 2002 +++ linux-2.4.19-pre7/arch/sparc64/kernel/process.c Mon Apr 15 21:54:24 2002 @@ -422,10 +422,11 @@ struct thread_struct *t = ¤t->thread; if (current->mm) { + unsigned long pgd_cache = 0UL; + if (t->flags & SPARC_FLAG_32BIT) { struct mm_struct *mm = current->mm; pgd_t *pgd0 = &mm->pgd[0]; - unsigned long pgd_cache; if (pgd_none(*pgd0)) { pmd_t *page = pmd_alloc_one_fast(NULL, 0); @@ -434,13 +435,13 @@ pgd_set(pgd0, page); } pgd_cache = pgd_val(*pgd0) << 11UL; - __asm__ __volatile__("stxa %0, [%1] %2\n\t" - "membar #Sync" - : /* no outputs */ - : "r" (pgd_cache), - "r" (TSB_REG), - "i" (ASI_DMMU)); } + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (pgd_cache), + "r" (TSB_REG), + "i" (ASI_DMMU)); } t->w_saved = 0; diff -urN linux-2.4.19-pre6/arch/sparc64/math-emu/math.c linux-2.4.19-pre7/arch/sparc64/math-emu/math.c --- linux-2.4.19-pre6/arch/sparc64/math-emu/math.c Mon Dec 20 22:05:52 1999 +++ linux-2.4.19-pre7/arch/sparc64/math-emu/math.c Mon Apr 15 21:54:24 2002 @@ -57,6 +57,12 @@ #define FSTOD 0x0c9 #define FSTOI 0x0d1 #define FDTOI 0x0d2 +#define FXTOS 0x084 /* Only Ultra-III generates this. */ +#define FXTOD 0x088 /* Only Ultra-III generates this. */ +#if 0 /* Optimized inline in sparc64/kernel/entry.S */ +#define FITOS 0x0c4 /* Only Ultra-III generates this. */ +#endif +#define FITOD 0x0c8 /* Only Ultra-III generates this. */ /* FPOP2 */ #define FCMPQ 0x053 #define FCMPEQ 0x057 @@ -175,7 +181,7 @@ long XR, xfsr; if(tstate & TSTATE_PRIV) - die_if_kernel("FPQuad from kernel", regs); + die_if_kernel("unfinished/unimplemented FPop from kernel", regs); if(current->thread.flags & SPARC_FLAG_32BIT) pc = (u32)pc; if (get_user(insn, (u32 *)pc) != -EFAULT) { @@ -217,6 +223,14 @@ case FSTOD: TYPE(2,2,1,1,1,0,0); break; case FSTOI: TYPE(2,1,0,1,1,0,0); break; case FDTOI: TYPE(2,1,0,2,1,0,0); break; + + /* Only Ultra-III generates these */ + case FXTOS: TYPE(2,1,1,2,0,0,0); break; + case FXTOD: TYPE(2,2,1,2,0,0,0); break; +#if 0 /* Optimized inline in sparc64/kernel/entry.S */ + case FITOS: TYPE(2,1,1,1,0,0,0); break; +#endif + case FITOD: TYPE(2,2,1,1,0,0,0); break; } } else if ((insn & 0xc1f80000) == 0x81a80000) /* FPOP2 */ { @@ -420,6 +434,13 @@ /* int to float */ case FITOQ: IR = rs2->s; FP_FROM_INT_Q (QR, IR, 32, int); break; case FXTOQ: XR = rs2->d; FP_FROM_INT_Q (QR, XR, 64, long); break; + /* Only Ultra-III generates these */ + case FXTOS: XR = rs2->d; FP_FROM_INT_S (SR, XR, 64, long); break; + case FXTOD: XR = rs2->d; FP_FROM_INT_D (DR, XR, 64, long); break; +#if 0 /* Optimized inline in sparc64/kernel/entry.S */ + case FITOS: IR = rs2->s; FP_FROM_INT_S (SR, IR, 32, int); break; +#endif + case FITOD: IR = rs2->s; FP_FROM_INT_D (DR, IR, 32, int); break; /* float to float */ case FSTOD: FP_CONV (D, S, 1, 1, DR, SB); break; case FSTOQ: FP_CONV (Q, S, 2, 1, QR, SB); break; diff -urN linux-2.4.19-pre6/drivers/bluetooth/Config.in linux-2.4.19-pre7/drivers/bluetooth/Config.in --- linux-2.4.19-pre6/drivers/bluetooth/Config.in Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/drivers/bluetooth/Config.in Mon Apr 15 21:54:26 2002 @@ -2,7 +2,18 @@ comment 'Bluetooth device drivers' dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB +if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then + bool ' Firmware download support' CONFIG_BLUEZ_USB_FW_LOAD + bool ' USB zero packet support' CONFIG_BLUEZ_USB_ZERO_PACKET +fi + dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ -dep_tristate 'HCI VHCI virtual HCI device driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ +if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then + bool ' UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4 +fi + +dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ + +dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ endmenu diff -urN linux-2.4.19-pre6/drivers/bluetooth/Makefile linux-2.4.19-pre7/drivers/bluetooth/Makefile --- linux-2.4.19-pre6/drivers/bluetooth/Makefile Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/drivers/bluetooth/Makefile Mon Apr 15 21:54:26 2002 @@ -4,8 +4,18 @@ O_TARGET := bluetooth.o +list-multi := hci_uart.o + obj-$(CONFIG_BLUEZ_HCIUSB) += hci_usb.o -obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o obj-$(CONFIG_BLUEZ_HCIVHCI) += hci_vhci.o +obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o +uart-y := hci_ldisc.o +uart-$(CONFIG_BLUEZ_HCIUART_H4) += hci_h4.o + +obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o + include $(TOPDIR)/Rules.make + +hci_uart.o: $(uart-y) + $(LD) -r -o $@ $(uart-y) diff -urN linux-2.4.19-pre6/drivers/bluetooth/dtl1_cs.c linux-2.4.19-pre7/drivers/bluetooth/dtl1_cs.c --- linux-2.4.19-pre6/drivers/bluetooth/dtl1_cs.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/drivers/bluetooth/dtl1_cs.c Mon Apr 15 21:54:26 2002 @@ -0,0 +1,939 @@ +/* + * + * A driver for Nokia Connectivity Card DTL-1 devices + * + * Copyright (C) 2001-2002 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + +/* ======================== Module parameters ======================== */ + + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0xffff; +static int irq_list[4] = { -1 }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +MODULE_AUTHOR("Marcel Holtmann "); +MODULE_DESCRIPTION("BlueZ driver for Nokia Connectivity Card DTL-1"); +MODULE_LICENSE("GPL"); + + + +/* ======================== Local structures ======================== */ + + +typedef struct dtl1_info_t { + dev_link_t link; + dev_node_t node; + + struct hci_dev hdev; + + spinlock_t lock; /* For serializing operations */ + + unsigned long flowmask; /* HCI flow mask */ + int ri_latch; + + struct sk_buff_head txq; + unsigned long tx_state; + + unsigned long rx_state; + unsigned long rx_count; + struct sk_buff *rx_skb; + +} dtl1_info_t; + + +void dtl1_config(dev_link_t *link); +void dtl1_release(u_long arg); +int dtl1_event(event_t event, int priority, event_callback_args_t *args); + +static dev_info_t dev_info = "dtl1_cs"; + +dev_link_t *dtl1_attach(void); +void dtl1_detach(dev_link_t *); + +dev_link_t *dev_list = NULL; + + +/* Transmit states */ +#define XMIT_SENDING 1 +#define XMIT_WAKEUP 2 +#define XMIT_WAITING 8 + +/* Receiver States */ +#define RECV_WAIT_NSH 0 +#define RECV_WAIT_DATA 1 + + +typedef struct { + u8 type; + u8 zero; + u16 len; +} __attribute__ ((packed)) nsh_t; /* Nokia Specific Header */ + +#define NSHL 4 /* Nokia Specific Header Length */ + + + +/* ======================== Interrupt handling ======================== */ + + +static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) { + + int actual = 0; + + + /* Tx FIFO should be empty */ + if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) + return 0; + + + /* Fill FIFO with current frame */ + while ((fifo_size-- > 0) && (actual < len)) { + /* Transmit next byte */ + outb(buf[actual], iobase + UART_TX); + actual++; + } + + + return actual; + +} + + +static void dtl1_write_wakeup(dtl1_info_t *info) { + + if (!info) { + printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n"); + return; + } + + + if (test_bit(XMIT_WAITING, &(info->tx_state))) { + set_bit(XMIT_WAKEUP, &(info->tx_state)); + return; + } + + if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { + set_bit(XMIT_WAKEUP, &(info->tx_state)); + return; + } + + + do { + register unsigned int iobase = info->link.io.BasePort1; + register struct sk_buff *skb; + register int len; + + clear_bit(XMIT_WAKEUP, &(info->tx_state)); + + if (!(info->link.state & DEV_PRESENT)) + return; + + + if (!(skb = skb_dequeue(&(info->txq)))) + break; + + + /* Send frame */ + len = dtl1_write(iobase, 32, skb->data, skb->len); + + if (len == skb->len) { + set_bit(XMIT_WAITING, &(info->tx_state)); + kfree_skb(skb); + } + else { + skb_pull(skb, len); + skb_queue_head(&(info->txq), skb); + } + + info->hdev.stat.byte_tx += len; + + } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); + + + clear_bit(XMIT_SENDING, &(info->tx_state)); + +} + + +static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb) { + + u8 flowmask = *(u8 *)skb->data; + int i; + + + printk(KERN_INFO "dtl1_cs: Nokia control data = "); + for (i = 0; i < skb->len; i++) { + printk("%02x ", skb->data[i]); + } + printk("\n"); + + + /* transition to active state */ + if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) { + clear_bit(XMIT_WAITING, &(info->tx_state)); + dtl1_write_wakeup(info); + } + + info->flowmask = flowmask; + + + kfree_skb(skb); + +} + + +static void dtl1_receive(dtl1_info_t *info) { + + unsigned int iobase; + nsh_t *nsh; + int boguscount = 0; + + + if (!info) { + printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n"); + return; + } + + + iobase = info->link.io.BasePort1; + + do { + info->hdev.stat.byte_rx++; + + /* Allocate packet */ + if (info->rx_skb == NULL) + if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n"); + info->rx_state = RECV_WAIT_NSH; + info->rx_count = NSHL; + return; + } + + + *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); + nsh = (nsh_t *)info->rx_skb->data; + + info->rx_count--; + + + if (info->rx_count == 0) { + + switch (info->rx_state) { + case RECV_WAIT_NSH: + info->rx_state = RECV_WAIT_DATA; + info->rx_count = nsh->len + (nsh->len & 0x0001); + break; + case RECV_WAIT_DATA: + info->rx_skb->pkt_type = nsh->type; + + /* remove PAD byte if it exists */ + if (nsh->len & 0x0001) { + info->rx_skb->tail--; + info->rx_skb->len--; + } + + /* remove NSH */ + skb_pull(info->rx_skb, NSHL); + + + switch (info->rx_skb->pkt_type) { + case 0x80: + /* control data for the Nokia Card */ + dtl1_control(info, info->rx_skb); + break; + case 0x82: + case 0x83: + case 0x84: + /* send frame to the HCI layer */ + info->rx_skb->dev = (void *)&(info->hdev); + info->rx_skb->pkt_type &= 0x0f; + hci_recv_frame(info->rx_skb); + break; + default: + /* unknown packet */ + printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); + kfree_skb(info->rx_skb); + break; + } + + + info->rx_state = RECV_WAIT_NSH; + info->rx_count = NSHL; + info->rx_skb = NULL; + break; + } + + } + + + /* Make sure we don't stay here to long */ + if (boguscount++ > 32) + break; + + } while (inb(iobase + UART_LSR) & UART_LSR_DR); + + +} + + +void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) { + + dtl1_info_t *info = dev_inst; + unsigned int iobase; + unsigned char msr; + int boguscount = 0; + int iir, lsr; + + + if (!info) { + printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq); + return; + } + + + iobase = info->link.io.BasePort1; + + + spin_lock(&(info->lock)); + + iir = inb(iobase + UART_IIR) & UART_IIR_ID; + while (iir) { + + /* Clear interrupt */ + lsr = inb(iobase + UART_LSR); + + switch (iir) { + case UART_IIR_RLSI: + printk(KERN_NOTICE "dtl1_cs: RLSI\n"); + break; + case UART_IIR_RDI: + /* Receive interrupt */ + dtl1_receive(info); + break; + case UART_IIR_THRI: + if (lsr & UART_LSR_THRE) { + /* Transmitter ready for data */ + dtl1_write_wakeup(info); + } + break; + default: + printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir); + break; + } + + /* Make sure we don't stay here to long */ + if (boguscount++ > 100) + break; + + iir = inb(iobase + UART_IIR) & UART_IIR_ID; + + } + + + msr = inb(iobase + UART_MSR); + + if (info->ri_latch ^ (msr & UART_MSR_RI)) { + info->ri_latch = msr & UART_MSR_RI; + clear_bit(XMIT_WAITING, &(info->tx_state)); + dtl1_write_wakeup(info); + } + + spin_unlock(&(info->lock)); + +} + + + +/* ======================== HCI interface ======================== */ + + +static int dtl1_hci_open(struct hci_dev *hdev) { + + set_bit(HCI_RUNNING, &(hdev->flags)); + + + return 0; + +} + + +static int dtl1_hci_flush(struct hci_dev *hdev) { + + dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data); + + + /* Drop TX queue */ + skb_queue_purge(&(info->txq)); + + + return 0; + +} + + +static int dtl1_hci_close(struct hci_dev *hdev) { + + if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) + return 0; + + + dtl1_hci_flush(hdev); + + + return 0; + +} + + +static int dtl1_hci_send_frame(struct sk_buff *skb) { + + dtl1_info_t *info; + struct hci_dev* hdev = (struct hci_dev *)(skb->dev); + struct sk_buff *s; + nsh_t nsh; + + + if (!hdev) { + printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL)."); + return -ENODEV; + } + + info = (dtl1_info_t *)(hdev->driver_data); + + + switch (skb->pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + nsh.type = 0x81; + break; + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + nsh.type = 0x82; + break; + case HCI_SCODATA_PKT: + hdev->stat.sco_tx++; + nsh.type = 0x83; + break; + }; + + nsh.zero = 0; + nsh.len = skb->len; + + s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); + skb_reserve(s, NSHL); + memcpy(skb_put(s, skb->len), skb->data, skb->len); + if (skb->len & 0x0001) + *skb_put(s, 1) = 0; /* PAD */ + + /* Prepend skb with Nokia frame header and queue */ + memcpy(skb_push(s, NSHL), &nsh, NSHL); + skb_queue_tail(&(info->txq), s); + + + dtl1_write_wakeup(info); + + kfree_skb(skb); + + + return 0; + +} + + +static void dtl1_hci_destruct(struct hci_dev *hdev) { +} + + +static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) { + + return -ENOIOCTLCMD; + +} + + + +/* ======================== Card services HCI interaction ======================== */ + + +int dtl1_open(dtl1_info_t *info) { + + unsigned long flags; + unsigned int iobase = info->link.io.BasePort1; + struct hci_dev *hdev; + + + spin_lock_init(&(info->lock)); + + skb_queue_head_init(&(info->txq)); + + info->rx_state = RECV_WAIT_NSH; + info->rx_count = NSHL; + info->rx_skb = NULL; + + set_bit(XMIT_WAITING, &(info->tx_state)); + + + spin_lock_irqsave(&(info->lock), flags); + + /* Reset UART */ + outb(0, iobase + UART_MCR); + + /* Turn off interrupts */ + outb(0, iobase + UART_IER); + + /* Initialize UART */ + outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ + outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); + + info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI; + + /* Turn on interrupts */ + outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); + + spin_unlock_irqrestore(&(info->lock), flags); + + + /* Timeout before it is safe to send the first HCI packet */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ * 2); + + + /* Initialize and register HCI device */ + + hdev = &(info->hdev); + + hdev->type = HCI_PCCARD; + hdev->driver_data = info; + + hdev->open = dtl1_hci_open; + hdev->close = dtl1_hci_close; + hdev->flush = dtl1_hci_flush; + hdev->send = dtl1_hci_send_frame; + hdev->destruct = dtl1_hci_destruct; + hdev->ioctl = dtl1_hci_ioctl; + + if (hci_register_dev(hdev) < 0) { + printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name); + return -ENODEV; + } + + + return 0; + +} + + +int dtl1_close(dtl1_info_t *info) { + + unsigned long flags; + unsigned int iobase = info->link.io.BasePort1; + struct hci_dev *hdev = &(info->hdev); + + + dtl1_hci_close(hdev); + + + spin_lock_irqsave(&(info->lock), flags); + + /* Reset UART */ + outb(0, iobase + UART_MCR); + + /* Turn off interrupts */ + outb(0, iobase + UART_IER); + + spin_unlock_irqrestore(&(info->lock), flags); + + + if (hci_unregister_dev(hdev) < 0) + printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name); + + + return 0; + +} + + + +/* ======================== Card services ======================== */ + + +static void cs_error(client_handle_t handle, int func, int ret) { + + error_info_t err = { func, ret }; + + + CardServices(ReportError, handle, &err); + +} + + +dev_link_t *dtl1_attach(void) { + + dtl1_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int i, ret; + + + /* Create new info device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return NULL; + memset(info, 0, sizeof(*info)); + + + link = &info->link; + link->priv = info; + + link->release.function = &dtl1_release; + link->release.data = (u_long)link; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts1 = 8; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + + link->irq.Handler = dtl1_interrupt; + link->irq.Instance = info; + + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &dtl1_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + dtl1_detach(link); + return NULL; + } + + + return link; + +} + + +void dtl1_detach(dev_link_t *link) { + + dtl1_info_t *info = link->priv; + dev_link_t **linkp; + int ret; + + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + + if (*linkp == NULL) + return; + + + del_timer(&link->release); + if (link->state & DEV_CONFIG) + dtl1_release((u_long)link); + + + if (link->handle) { + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } + + + /* Unlink device structure, free bits */ + *linkp = link->next; + + kfree(info); + +} + + +static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) { + + int i; + + + i = CardServices(fn, handle, tuple); + if (i != CS_SUCCESS) + return CS_NO_MORE_ITEMS; + + i = CardServices(GetTupleData, handle, tuple); + if (i != CS_SUCCESS) + return i; + + return CardServices(ParseTuple, handle, tuple, parse); + +} + + +#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) +#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) + +void dtl1_config(dev_link_t *link) { + + client_handle_t handle = link->handle; + dtl1_info_t *info = link->priv; + tuple_t tuple; + u_short buf[256]; + cisparse_t parse; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + config_info_t config; + int i, last_ret, last_fn; + + + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + tuple.Attributes = 0; + + /* Get configuration register information */ + tuple.DesiredTuple = CISTPL_CONFIG; + last_ret = first_tuple(handle, &tuple, &parse); + if (last_ret != CS_SUCCESS) { + last_fn = ParseTuple; + goto cs_failed; + } + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + + /* Configure card */ + link->state |= DEV_CONFIG; + i = CardServices(GetConfigurationInfo, handle, &config); + link->conf.Vcc = config.Vcc; + + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + + /* Look for a generic full-sized window */ + link->io.NumPorts1 = 8; + i = first_tuple(handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.NumPorts1 = cf->io.win[0].len; /*yo*/ + link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) + break; + } + i = next_tuple(handle, &tuple, &parse); + } + + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIO, i); + goto failed; + } + + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); + link->irq.AssignedIRQ = 0; + } + + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestConfiguration, i); + goto failed; + } + + + MOD_INC_USE_COUNT; + + if (dtl1_open(info) != 0) + goto failed; + + + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; + + + return; + + +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + dtl1_release((u_long)link); + +} + + +void dtl1_release(u_long arg) { + + dev_link_t *link = (dev_link_t *)arg; + dtl1_info_t *info = link->priv; + + + if (link->state & DEV_PRESENT) + dtl1_close(info); + + MOD_DEC_USE_COUNT; + + + link->dev = NULL; + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; + +} + + +int dtl1_event(event_t event, int priority, event_callback_args_t *args) { + + dev_link_t *link = args->client_data; + dtl1_info_t *info = link->priv; + + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + dtl1_close(info); + mod_timer(&link->release, jiffies + HZ/20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + dtl1_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (DEV_OK(link)) + CardServices(RequestConfiguration, link->handle, &link->conf); + break; + } + + + return 0; + +} + + + +/* ======================== Module initialization ======================== */ + + +int __init init_dtl1_cs(void) { + + servinfo_t serv; + int err; + + + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n"); + return -1; + } + + + err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach); + + + return err; + +} + +void __exit exit_dtl1_cs(void) { + + unregister_pccard_driver(&dev_info); + + while (dev_list != NULL) + dtl1_detach(dev_list); + +} + + +module_init(init_dtl1_cs); +module_exit(exit_dtl1_cs); + +EXPORT_NO_SYMBOLS; diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_h4.c linux-2.4.19-pre7/drivers/bluetooth/hci_h4.c --- linux-2.4.19-pre6/drivers/bluetooth/hci_h4.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/drivers/bluetooth/hci_h4.c Mon Apr 15 21:54:26 2002 @@ -0,0 +1,273 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * BlueZ HCI UART(H4) protocol. + * + * $Id: hci_h4.c,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ + */ +#define VERSION "1.1" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "hci_uart.h" +#include "hci_h4.h" + +#ifndef HCI_UART_DEBUG +#undef DBG +#define DBG( A... ) +#undef DMP +#define DMP( A... ) +#endif + +/* Initialize protocol */ +static int h4_open(struct n_hci *n_hci) +{ + struct h4_struct *h4; + + DBG("n_hci %p", n_hci); + + h4 = kmalloc(sizeof(*h4), GFP_ATOMIC); + if (!h4) + return -ENOMEM; + memset(h4, 0, sizeof(*h4)); + + n_hci->priv = h4; + return 0; +} + +/* Flush protocol data */ +static int h4_flush(struct n_hci *n_hci) +{ + DBG("n_hci %p", n_hci); + return 0; +} + +/* Close protocol */ +static int h4_close(struct n_hci *n_hci) +{ + struct h4_struct *h4 = n_hci->priv; + n_hci->priv = NULL; + + DBG("n_hci %p", n_hci); + + if (h4->rx_skb) + kfree_skb(h4->rx_skb); + + kfree(h4); + return 0; +} + +/* Send data */ +static int h4_send(struct n_hci *n_hci, void *data, int len) +{ + struct tty_struct *tty = n_hci->tty; + + DBG("n_hci %p len %d", n_hci, len); + + /* Send frame to TTY driver */ + tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + return tty->driver.write(tty, 0, data, len); +} + +/* Init frame before queueing (padding, crc, etc) */ +static struct sk_buff* h4_preq(struct n_hci *n_hci, struct sk_buff *skb) +{ + DBG("n_hci %p skb %p", n_hci, skb); + + /* Prepend skb with frame type */ + memcpy(skb_push(skb, 1), &skb->pkt_type, 1); + return skb; +} + +static inline int h4_check_data_len(struct h4_struct *h4, int len) +{ + register int room = skb_tailroom(h4->rx_skb); + + DBG("len %d room %d", len, room); + if (!len) { + DMP(h4->rx_skb->data, h4->rx_skb->len); + hci_recv_frame(h4->rx_skb); + } else if (len > room) { + ERR("Data length is to large"); + kfree_skb(h4->rx_skb); + } else { + h4->rx_state = H4_W4_DATA; + h4->rx_count = len; + return len; + } + + h4->rx_state = H4_W4_PACKET_TYPE; + h4->rx_skb = NULL; + h4->rx_count = 0; + return 0; +} + +/* Recv data */ +static int h4_recv(struct n_hci *n_hci, void *data, int count) +{ + struct h4_struct *h4 = n_hci->priv; + register char *ptr; + hci_event_hdr *eh; + hci_acl_hdr *ah; + hci_sco_hdr *sh; + register int len, type, dlen; + + DBG("n_hci %p count %d rx_state %ld rx_count %ld", n_hci, count, h4->rx_state, h4->rx_count); + + ptr = data; + while (count) { + if (h4->rx_count) { + len = MIN(h4->rx_count, count); + memcpy(skb_put(h4->rx_skb, len), ptr, len); + h4->rx_count -= len; count -= len; ptr += len; + + if (h4->rx_count) + continue; + + switch (h4->rx_state) { + case H4_W4_DATA: + DBG("Complete data"); + + DMP(h4->rx_skb->data, h4->rx_skb->len); + + hci_recv_frame(h4->rx_skb); + + h4->rx_state = H4_W4_PACKET_TYPE; + h4->rx_skb = NULL; + continue; + + case H4_W4_EVENT_HDR: + eh = (hci_event_hdr *) h4->rx_skb->data; + + DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); + + h4_check_data_len(h4, eh->plen); + continue; + + case H4_W4_ACL_HDR: + ah = (hci_acl_hdr *) h4->rx_skb->data; + dlen = __le16_to_cpu(ah->dlen); + + DBG("ACL header: dlen %d", dlen); + + h4_check_data_len(h4, dlen); + continue; + + case H4_W4_SCO_HDR: + sh = (hci_sco_hdr *) h4->rx_skb->data; + + DBG("SCO header: dlen %d", sh->dlen); + + h4_check_data_len(h4, sh->dlen); + continue; + }; + } + + /* H4_W4_PACKET_TYPE */ + switch (*ptr) { + case HCI_EVENT_PKT: + DBG("Event packet"); + h4->rx_state = H4_W4_EVENT_HDR; + h4->rx_count = HCI_EVENT_HDR_SIZE; + type = HCI_EVENT_PKT; + break; + + case HCI_ACLDATA_PKT: + DBG("ACL packet"); + h4->rx_state = H4_W4_ACL_HDR; + h4->rx_count = HCI_ACL_HDR_SIZE; + type = HCI_ACLDATA_PKT; + break; + + case HCI_SCODATA_PKT: + DBG("SCO packet"); + h4->rx_state = H4_W4_SCO_HDR; + h4->rx_count = HCI_SCO_HDR_SIZE; + type = HCI_SCODATA_PKT; + break; + + default: + ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); + n_hci->hdev.stat.err_rx++; + ptr++; count--; + continue; + }; + ptr++; count--; + + /* Allocate packet */ + h4->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); + if (!h4->rx_skb) { + ERR("Can't allocate mem for new packet"); + h4->rx_state = H4_W4_PACKET_TYPE; + h4->rx_count = 0; + return 0; + } + h4->rx_skb->dev = (void *) &n_hci->hdev; + h4->rx_skb->pkt_type = type; + } + return count; +} + +static struct hci_uart_proto h4p = { + id: HCI_UART_H4, + open: h4_open, + close: h4_close, + send: h4_send, + recv: h4_recv, + preq: h4_preq, + flush: h4_flush, +}; + +int h4_init(void) +{ + return hci_uart_register_proto(&h4p); +} + +int h4_deinit(void) +{ + return hci_uart_unregister_proto(&h4p); +} diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_h4.h linux-2.4.19-pre7/drivers/bluetooth/hci_h4.h --- linux-2.4.19-pre6/drivers/bluetooth/hci_h4.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/drivers/bluetooth/hci_h4.h Mon Apr 15 21:54:26 2002 @@ -0,0 +1,43 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * $Id: hci_h4.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ + */ + +#ifdef __KERNEL__ +struct h4_struct { + unsigned long rx_state; + unsigned long rx_count; + struct sk_buff *rx_skb; +}; + +/* H4 receiver States */ +#define H4_W4_PACKET_TYPE 0 +#define H4_W4_EVENT_HDR 1 +#define H4_W4_ACL_HDR 2 +#define H4_W4_SCO_HDR 3 +#define H4_W4_DATA 4 + +#endif /* __KERNEL__ */ diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_ldisc.c linux-2.4.19-pre7/drivers/bluetooth/hci_ldisc.c --- linux-2.4.19-pre6/drivers/bluetooth/hci_ldisc.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/drivers/bluetooth/hci_ldisc.c Mon Apr 15 21:54:26 2002 @@ -0,0 +1,554 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * BlueZ HCI UART driver. + * + * $Id: hci_ldisc.c,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ + */ +#define VERSION "2.0" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "hci_uart.h" + +#ifndef HCI_UART_DEBUG +#undef DBG +#define DBG( A... ) +#undef DMP +#define DMP( A... ) +#endif + +static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; + +int hci_uart_register_proto(struct hci_uart_proto *p) +{ + if (p->id >= HCI_UART_MAX_PROTO) + return -EINVAL; + + if (hup[p->id]) + return -EEXIST; + + hup[p->id] = p; + return 0; +} + +int hci_uart_unregister_proto(struct hci_uart_proto *p) +{ + if (p->id >= HCI_UART_MAX_PROTO) + return -EINVAL; + + if (!hup[p->id]) + return -EINVAL; + + hup[p->id] = NULL; + return 0; +} + +static struct hci_uart_proto *n_hci_get_proto(unsigned int id) +{ + if (id >= HCI_UART_MAX_PROTO) + return NULL; + return hup[id]; +} + +/* ------- Interface to HCI layer ------ */ +/* Initialize device */ +static int n_hci_open(struct hci_dev *hdev) +{ + DBG("%s %p", hdev->name, hdev); + + /* Nothing to do for UART driver */ + + set_bit(HCI_RUNNING, &hdev->flags); + return 0; +} + +/* Reset device */ +static int n_hci_flush(struct hci_dev *hdev) +{ + struct n_hci *n_hci = (struct n_hci *) hdev->driver_data; + struct tty_struct *tty = n_hci->tty; + + DBG("hdev %p tty %p", hdev, tty); + + /* Drop TX queue */ + skb_queue_purge(&n_hci->txq); + + /* Flush any pending characters in the driver and discipline. */ + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + + if (n_hci->proto->flush) + n_hci->proto->flush(n_hci); + + return 0; +} + +/* Close device */ +static int n_hci_close(struct hci_dev *hdev) +{ + DBG("hdev %p", hdev); + + if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) + return 0; + + n_hci_flush(hdev); + return 0; +} + +static int n_hci_tx_wakeup(struct n_hci *n_hci) +{ + struct hci_dev *hdev = &n_hci->hdev; + + if (test_and_set_bit(N_HCI_SENDING, &n_hci->tx_state)) { + set_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state); + return 0; + } + + DBG(""); + do { + register struct sk_buff *skb; + register int len; + + clear_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state); + + if (!(skb = skb_dequeue(&n_hci->txq))) + break; + + len = n_hci->proto->send(n_hci, skb->data, skb->len); + n_hci->hdev.stat.byte_tx += len; + + if (len == skb->len) { + /* Complete frame was sent */ + + switch (skb->pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + break; + + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + break; + + case HCI_SCODATA_PKT: + hdev->stat.cmd_tx++; + break; + }; + + kfree_skb(skb); + } else { + /* Subtract sent part and requeue */ + skb_pull(skb, len); + skb_queue_head(&n_hci->txq, skb); + } + } while (test_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state)); + clear_bit(N_HCI_SENDING, &n_hci->tx_state); + return 0; +} + +/* Send frames from HCI layer */ +static int n_hci_send_frame(struct sk_buff *skb) +{ + struct hci_dev* hdev = (struct hci_dev *) skb->dev; + struct tty_struct *tty; + struct n_hci *n_hci; + + if (!hdev) { + ERR("Frame for uknown device (hdev=NULL)"); + return -ENODEV; + } + + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return -EBUSY; + + n_hci = (struct n_hci *) hdev->driver_data; + tty = n_hci->tty; + + DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len); + + if (n_hci->proto->preq) { + skb = n_hci->proto->preq(n_hci, skb); + if (!skb) + return 0; + } + + skb_queue_tail(&n_hci->txq, skb); + n_hci_tx_wakeup(n_hci); + return 0; +} + +static void n_hci_destruct(struct hci_dev *hdev) +{ + struct n_hci *n_hci; + + if (!hdev) return; + + DBG("%s", hdev->name); + + n_hci = (struct n_hci *) hdev->driver_data; + kfree(n_hci); + + MOD_DEC_USE_COUNT; +} + +/* ------ LDISC part ------ */ +/* n_hci_tty_open + * + * Called when line discipline changed to N_HCI. + * + * Arguments: + * tty pointer to tty info structure + * Return Value: + * 0 if success, otherwise error code + */ +static int n_hci_tty_open(struct tty_struct *tty) +{ + struct n_hci *n_hci = (void *)tty->disc_data; + + DBG("tty %p", tty); + + if (n_hci) + return -EEXIST; + + if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) { + ERR("Can't allocate controll structure"); + return -ENFILE; + } + memset(n_hci, 0, sizeof(struct n_hci)); + + tty->disc_data = n_hci; + n_hci->tty = tty; + + spin_lock_init(&n_hci->rx_lock); + skb_queue_head_init(&n_hci->txq); + + /* Flush any pending characters in the driver and line discipline */ + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + + MOD_INC_USE_COUNT; + return 0; +} + +/* n_hci_tty_close() + * + * Called when the line discipline is changed to something + * else, the tty is closed, or the tty detects a hangup. + */ +static void n_hci_tty_close(struct tty_struct *tty) +{ + struct n_hci *n_hci = (void *)tty->disc_data; + + DBG("tty %p", tty); + + /* Detach from the tty */ + tty->disc_data = NULL; + + if (n_hci) { + struct hci_dev *hdev = &n_hci->hdev; + n_hci_close(hdev); + + if (test_and_clear_bit(N_HCI_PROTO_SET, &n_hci->flags)) { + n_hci->proto->close(n_hci); + hci_unregister_dev(hdev); + } + + MOD_DEC_USE_COUNT; + } +} + +/* n_hci_tty_wakeup() + * + * Callback for transmit wakeup. Called when low level + * device driver can accept more send data. + * + * Arguments: tty pointer to associated tty instance data + * Return Value: None + */ +static void n_hci_tty_wakeup( struct tty_struct *tty ) +{ + struct n_hci *n_hci = (void *)tty->disc_data; + + DBG(""); + + if (!n_hci) + return; + + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + + if (tty != n_hci->tty) + return; + + n_hci_tx_wakeup(n_hci); +} + +/* n_hci_tty_room() + * + * Callback function from tty driver. Return the amount of + * space left in the receiver's buffer to decide if remote + * transmitter is to be throttled. + * + * Arguments: tty pointer to associated tty instance data + * Return Value: number of bytes left in receive buffer + */ +static int n_hci_tty_room (struct tty_struct *tty) +{ + return 65536; +} + +/* n_hci_tty_receive() + * + * Called by tty low level driver when receive data is + * available. + * + * Arguments: tty pointer to tty isntance data + * data pointer to received data + * flags pointer to flags for data + * count count of received data in bytes + * + * Return Value: None + */ +static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count) +{ + struct n_hci *n_hci = (void *)tty->disc_data; + + if (!n_hci || tty != n_hci->tty) + return; + + if (!test_bit(N_HCI_PROTO_SET, &n_hci->flags)) + return; + + spin_lock(&n_hci->rx_lock); + n_hci->proto->recv(n_hci, (void *) data, count); + n_hci->hdev.stat.byte_rx += count; + spin_unlock(&n_hci->rx_lock); + + if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle) + tty->driver.unthrottle(tty); +} + +static int n_hci_register_dev(struct n_hci *n_hci) +{ + struct hci_dev *hdev; + + DBG(""); + + /* Initialize and register HCI device */ + hdev = &n_hci->hdev; + + hdev->type = HCI_UART; + hdev->driver_data = n_hci; + + hdev->open = n_hci_open; + hdev->close = n_hci_close; + hdev->flush = n_hci_flush; + hdev->send = n_hci_send_frame; + hdev->destruct = n_hci_destruct; + + if (hci_register_dev(hdev) < 0) { + ERR("Can't register HCI device %s", hdev->name); + return -ENODEV; + } + MOD_INC_USE_COUNT; + return 0; +} + +static int n_hci_set_proto(struct n_hci *n_hci, int id) +{ + struct hci_uart_proto *p; + int err; + + p = n_hci_get_proto(id); + if (!p) + return -EPROTONOSUPPORT; + + err = p->open(n_hci); + if (err) + return err; + + n_hci->proto = p; + + err = n_hci_register_dev(n_hci); + if (err) { + p->close(n_hci); + return err; + } + return 0; +} + +/* n_hci_tty_ioctl() + * + * Process IOCTL system call for the tty device. + * + * Arguments: + * + * tty pointer to tty instance data + * file pointer to open file object for device + * cmd IOCTL command code + * arg argument for IOCTL call (cmd dependent) + * + * Return Value: Command dependent + */ +static int n_hci_tty_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct n_hci *n_hci = (void *)tty->disc_data; + int err = 0; + + DBG(""); + + /* Verify the status of the device */ + if (!n_hci) + return -EBADF; + + switch (cmd) { + case HCIUARTSETPROTO: + if (!test_and_set_bit(N_HCI_PROTO_SET, &n_hci->flags)) { + err = n_hci_set_proto(n_hci, arg); + if (err) { + clear_bit(N_HCI_PROTO_SET, &n_hci->flags); + return err; + } + tty->low_latency = 1; + } else + return -EBUSY; + + case HCIUARTGETPROTO: + if (test_bit(N_HCI_PROTO_SET, &n_hci->flags)) + return n_hci->proto->id; + return -EUNATCH; + + default: + err = n_tty_ioctl(tty, file, cmd, arg); + break; + }; + + return err; +} + +/* + * We don't provide read/write/poll interface for user space. + */ +static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr) +{ + return 0; +} +static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) +{ + return 0; +} +static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) +{ + return 0; +} + +#ifdef CONFIG_BLUEZ_HCIUART_H4 +int h4_init(void); +int h4_deinit(void); +#endif + +int __init n_hci_init(void) +{ + static struct tty_ldisc n_hci_ldisc; + int err; + + INF("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + VERSION); + INF("Written 2000,2001 by Maxim Krasnyansky "); + + /* Register the tty discipline */ + + memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc)); + n_hci_ldisc.magic = TTY_LDISC_MAGIC; + n_hci_ldisc.name = "n_hci"; + n_hci_ldisc.open = n_hci_tty_open; + n_hci_ldisc.close = n_hci_tty_close; + n_hci_ldisc.read = n_hci_tty_read; + n_hci_ldisc.write = n_hci_tty_write; + n_hci_ldisc.ioctl = n_hci_tty_ioctl; + n_hci_ldisc.poll = n_hci_tty_poll; + n_hci_ldisc.receive_room= n_hci_tty_room; + n_hci_ldisc.receive_buf = n_hci_tty_receive; + n_hci_ldisc.write_wakeup= n_hci_tty_wakeup; + + if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) { + ERR("Can't register HCI line discipline (%d)", err); + return err; + } + +#ifdef CONFIG_BLUEZ_HCIUART_H4 + h4_init(); +#endif + + return 0; +} + +void n_hci_cleanup(void) +{ + int err; + +#ifdef CONFIG_BLUEZ_HCIUART_H4 + h4_deinit(); +#endif + + /* Release tty registration of line discipline */ + if ((err = tty_register_ldisc(N_HCI, NULL))) + ERR("Can't unregister HCI line discipline (%d)", err); +} + +module_init(n_hci_init); +module_exit(n_hci_cleanup); + +MODULE_AUTHOR("Maxim Krasnyansky "); +MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_uart.c linux-2.4.19-pre7/drivers/bluetooth/hci_uart.c --- linux-2.4.19-pre6/drivers/bluetooth/hci_uart.c Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/drivers/bluetooth/hci_uart.c Wed Dec 31 16:00:00 1969 @@ -1,580 +0,0 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * BlueZ HCI UART driver. - * - * $Id: hci_uart.c,v 1.5 2001/07/05 18:42:44 maxk Exp $ - */ -#define VERSION "1.0" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifndef HCI_UART_DEBUG -#undef DBG -#define DBG( A... ) -#undef DMP -#define DMP( A... ) -#endif - -/* ------- Interface to HCI layer ------ */ -/* Initialize device */ -int n_hci_open(struct hci_dev *hdev) -{ - DBG("%s %p", hdev->name, hdev); - - /* Nothing to do for UART driver */ - - hdev->flags |= HCI_RUNNING; - - return 0; -} - -/* Reset device */ -int n_hci_flush(struct hci_dev *hdev) -{ - struct n_hci *n_hci = (struct n_hci *) hdev->driver_data; - struct tty_struct *tty = n_hci->tty; - - DBG("hdev %p tty %p", hdev, tty); - - /* Drop TX queue */ - skb_queue_purge(&n_hci->txq); - - /* Flush any pending characters in the driver and discipline. */ - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - - if (tty->driver.flush_buffer) - tty->driver.flush_buffer(tty); - - return 0; -} - -/* Close device */ -int n_hci_close(struct hci_dev *hdev) -{ - DBG("hdev %p", hdev); - - hdev->flags &= ~HCI_RUNNING; - - n_hci_flush(hdev); - - return 0; -} - -int n_hci_tx_wakeup(struct n_hci *n_hci) -{ - register struct tty_struct *tty = n_hci->tty; - - if (test_and_set_bit(TRANS_SENDING, &n_hci->tx_state)) { - set_bit(TRANS_WAKEUP, &n_hci->tx_state); - return 0; - } - - DBG(""); - do { - register struct sk_buff *skb; - register int len; - - clear_bit(TRANS_WAKEUP, &n_hci->tx_state); - - if (!(skb = skb_dequeue(&n_hci->txq))) - break; - - DMP(skb->data, skb->len); - - /* Send frame to TTY driver */ - tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - len = tty->driver.write(tty, 0, skb->data, skb->len); - - n_hci->hdev.stat.byte_tx += len; - - DBG("sent %d", len); - - if (len == skb->len) { - /* Full frame was sent */ - kfree_skb(skb); - } else { - /* Subtract sent part and requeue */ - skb_pull(skb, len); - skb_queue_head(&n_hci->txq, skb); - } - } while (test_bit(TRANS_WAKEUP, &n_hci->tx_state)); - clear_bit(TRANS_SENDING, &n_hci->tx_state); - - return 0; -} - -/* Send frames from HCI layer */ -int n_hci_send_frame(struct sk_buff *skb) -{ - struct hci_dev* hdev = (struct hci_dev *) skb->dev; - struct tty_struct *tty; - struct n_hci *n_hci; - - if (!hdev) { - ERR("Frame for uknown device (hdev=NULL)"); - return -ENODEV; - } - - if (!(hdev->flags & HCI_RUNNING)) - return -EBUSY; - - n_hci = (struct n_hci *) hdev->driver_data; - tty = n_hci2tty(n_hci); - - DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len); - - switch (skb->pkt_type) { - case HCI_COMMAND_PKT: - hdev->stat.cmd_tx++; - break; - - case HCI_ACLDATA_PKT: - hdev->stat.acl_tx++; - break; - - case HCI_SCODATA_PKT: - hdev->stat.cmd_tx++; - break; - }; - - /* Prepend skb with frame type and queue */ - memcpy(skb_push(skb, 1), &skb->pkt_type, 1); - skb_queue_tail(&n_hci->txq, skb); - - n_hci_tx_wakeup(n_hci); - - return 0; -} - -/* ------ LDISC part ------ */ - -/* n_hci_tty_open - * - * Called when line discipline changed to N_HCI. - * - * Arguments: - * tty pointer to tty info structure - * Return Value: - * 0 if success, otherwise error code - */ -static int n_hci_tty_open(struct tty_struct *tty) -{ - struct n_hci *n_hci = tty2n_hci(tty); - struct hci_dev *hdev; - - DBG("tty %p", tty); - - if (n_hci) - return -EEXIST; - - if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) { - ERR("Can't allocate controll structure"); - return -ENFILE; - } - memset(n_hci, 0, sizeof(struct n_hci)); - - /* Initialize and register HCI device */ - hdev = &n_hci->hdev; - - hdev->type = HCI_UART; - hdev->driver_data = n_hci; - - hdev->open = n_hci_open; - hdev->close = n_hci_close; - hdev->flush = n_hci_flush; - hdev->send = n_hci_send_frame; - - if (hci_register_dev(hdev) < 0) { - ERR("Can't register HCI device %s", hdev->name); - kfree(n_hci); - return -ENODEV; - } - - tty->disc_data = n_hci; - n_hci->tty = tty; - - spin_lock_init(&n_hci->rx_lock); - n_hci->rx_state = WAIT_PACKET_TYPE; - - skb_queue_head_init(&n_hci->txq); - - MOD_INC_USE_COUNT; - - /* Flush any pending characters in the driver and discipline. */ - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - - if (tty->driver.flush_buffer) - tty->driver.flush_buffer(tty); - - return 0; -} - -/* n_hci_tty_close() - * - * Called when the line discipline is changed to something - * else, the tty is closed, or the tty detects a hangup. - */ -static void n_hci_tty_close(struct tty_struct *tty) -{ - struct n_hci *n_hci = tty2n_hci(tty); - struct hci_dev *hdev = &n_hci->hdev; - - DBG("tty %p hdev %p", tty, hdev); - - if (n_hci != NULL) { - n_hci_close(hdev); - - if (hci_unregister_dev(hdev) < 0) { - ERR("Can't unregister HCI device %s",hdev->name); - } - - hdev->driver_data = NULL; - tty->disc_data = NULL; - kfree(n_hci); - - MOD_DEC_USE_COUNT; - } -} - -/* n_hci_tty_wakeup() - * - * Callback for transmit wakeup. Called when low level - * device driver can accept more send data. - * - * Arguments: tty pointer to associated tty instance data - * Return Value: None - */ -static void n_hci_tty_wakeup( struct tty_struct *tty ) -{ - struct n_hci *n_hci = tty2n_hci(tty); - - DBG(""); - - if (!n_hci) - return; - - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - - if (tty != n_hci->tty) - return; - - n_hci_tx_wakeup(n_hci); -} - -/* n_hci_tty_room() - * - * Callback function from tty driver. Return the amount of - * space left in the receiver's buffer to decide if remote - * transmitter is to be throttled. - * - * Arguments: tty pointer to associated tty instance data - * Return Value: number of bytes left in receive buffer - */ -static int n_hci_tty_room (struct tty_struct *tty) -{ - return 65536; -} - -static inline int n_hci_check_data_len(struct n_hci *n_hci, int len) -{ - register int room = skb_tailroom(n_hci->rx_skb); - - DBG("len %d room %d", len, room); - if (!len) { - DMP(n_hci->rx_skb->data, n_hci->rx_skb->len); - hci_recv_frame(n_hci->rx_skb); - } else if (len > room) { - ERR("Data length is to large"); - kfree_skb(n_hci->rx_skb); - n_hci->hdev.stat.err_rx++; - } else { - n_hci->rx_state = WAIT_DATA; - n_hci->rx_count = len; - return len; - } - - n_hci->rx_state = WAIT_PACKET_TYPE; - n_hci->rx_skb = NULL; - n_hci->rx_count = 0; - return 0; -} - -static inline void n_hci_rx(struct n_hci *n_hci, const __u8 * data, char *flags, int count) -{ - register const char *ptr; - hci_event_hdr *eh; - hci_acl_hdr *ah; - hci_sco_hdr *sh; - register int len, type, dlen; - - DBG("count %d state %ld rx_count %ld", count, n_hci->rx_state, n_hci->rx_count); - - n_hci->hdev.stat.byte_rx += count; - - ptr = data; - while (count) { - if (n_hci->rx_count) { - len = MIN(n_hci->rx_count, count); - memcpy(skb_put(n_hci->rx_skb, len), ptr, len); - n_hci->rx_count -= len; count -= len; ptr += len; - - if (n_hci->rx_count) - continue; - - switch (n_hci->rx_state) { - case WAIT_DATA: - DBG("Complete data"); - - DMP(n_hci->rx_skb->data, n_hci->rx_skb->len); - - hci_recv_frame(n_hci->rx_skb); - - n_hci->rx_state = WAIT_PACKET_TYPE; - n_hci->rx_skb = NULL; - continue; - - case WAIT_EVENT_HDR: - eh = (hci_event_hdr *) n_hci->rx_skb->data; - - DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); - - n_hci_check_data_len(n_hci, eh->plen); - continue; - - case WAIT_ACL_HDR: - ah = (hci_acl_hdr *) n_hci->rx_skb->data; - dlen = __le16_to_cpu(ah->dlen); - - DBG("ACL header: dlen %d", dlen); - - n_hci_check_data_len(n_hci, dlen); - continue; - - case WAIT_SCO_HDR: - sh = (hci_sco_hdr *) n_hci->rx_skb->data; - - DBG("SCO header: dlen %d", sh->dlen); - - n_hci_check_data_len(n_hci, sh->dlen); - continue; - }; - } - - /* WAIT_PACKET_TYPE */ - switch (*ptr) { - case HCI_EVENT_PKT: - DBG("Event packet"); - n_hci->rx_state = WAIT_EVENT_HDR; - n_hci->rx_count = HCI_EVENT_HDR_SIZE; - type = HCI_EVENT_PKT; - break; - - case HCI_ACLDATA_PKT: - DBG("ACL packet"); - n_hci->rx_state = WAIT_ACL_HDR; - n_hci->rx_count = HCI_ACL_HDR_SIZE; - type = HCI_ACLDATA_PKT; - break; - - case HCI_SCODATA_PKT: - DBG("SCO packet"); - n_hci->rx_state = WAIT_SCO_HDR; - n_hci->rx_count = HCI_SCO_HDR_SIZE; - type = HCI_SCODATA_PKT; - break; - - default: - ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); - n_hci->hdev.stat.err_rx++; - ptr++; count--; - continue; - }; - ptr++; count--; - - /* Allocate packet */ - if (!(n_hci->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { - ERR("Can't allocate mem for new packet"); - - n_hci->rx_state = WAIT_PACKET_TYPE; - n_hci->rx_count = 0; - return; - } - n_hci->rx_skb->dev = (void *) &n_hci->hdev; - n_hci->rx_skb->pkt_type = type; - } -} - -/* n_hci_tty_receive() - * - * Called by tty low level driver when receive data is - * available. - * - * Arguments: tty pointer to tty isntance data - * data pointer to received data - * flags pointer to flags for data - * count count of received data in bytes - * - * Return Value: None - */ -static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count) -{ - struct n_hci *n_hci = tty2n_hci(tty); - - if (!n_hci || tty != n_hci->tty) - return; - - spin_lock(&n_hci->rx_lock); - n_hci_rx(n_hci, data, flags, count); - spin_unlock(&n_hci->rx_lock); - - if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle) - tty->driver.unthrottle(tty); -} - -/* n_hci_tty_ioctl() - * - * Process IOCTL system call for the tty device. - * - * Arguments: - * - * tty pointer to tty instance data - * file pointer to open file object for device - * cmd IOCTL command code - * arg argument for IOCTL call (cmd dependent) - * - * Return Value: Command dependent - */ -static int n_hci_tty_ioctl (struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - struct n_hci *n_hci = tty2n_hci(tty); - int error = 0; - - DBG(""); - - /* Verify the status of the device */ - if (!n_hci) - return -EBADF; - - switch (cmd) { - default: - error = n_tty_ioctl(tty, file, cmd, arg); - break; - }; - - return error; -} - -/* - * We don't provide read/write/poll interface for user space. - */ -static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr) -{ - return 0; -} -static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) -{ - return 0; -} -static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) -{ - return 0; -} - -int __init n_hci_init(void) -{ - static struct tty_ldisc n_hci_ldisc; - int err; - - INF("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", - VERSION); - INF("Written 2000,2001 by Maxim Krasnyansky "); - - /* Register the tty discipline */ - - memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc)); - n_hci_ldisc.magic = TTY_LDISC_MAGIC; - n_hci_ldisc.name = "n_hci"; - n_hci_ldisc.open = n_hci_tty_open; - n_hci_ldisc.close = n_hci_tty_close; - n_hci_ldisc.read = n_hci_tty_read; - n_hci_ldisc.write = n_hci_tty_write; - n_hci_ldisc.ioctl = n_hci_tty_ioctl; - n_hci_ldisc.poll = n_hci_tty_poll; - n_hci_ldisc.receive_room= n_hci_tty_room; - n_hci_ldisc.receive_buf = n_hci_tty_receive; - n_hci_ldisc.write_wakeup= n_hci_tty_wakeup; - - if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) { - ERR("Can't register HCI line discipline (%d)", err); - return err; - } - - return 0; -} - -void n_hci_cleanup(void) -{ - int err; - - /* Release tty registration of line discipline */ - if ((err = tty_register_ldisc(N_HCI, NULL))) - ERR("Can't unregister HCI line discipline (%d)", err); -} - -module_init(n_hci_init); -module_exit(n_hci_cleanup); - -MODULE_AUTHOR("Maxim Krasnyansky "); -MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION); -MODULE_LICENSE("GPL"); diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_uart.h linux-2.4.19-pre7/drivers/bluetooth/hci_uart.h --- linux-2.4.19-pre6/drivers/bluetooth/hci_uart.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/drivers/bluetooth/hci_uart.h Mon Apr 15 21:54:26 2002 @@ -0,0 +1,80 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * $Id: hci_uart.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ + */ + +#ifndef N_HCI +#define N_HCI 15 +#endif + +/* Ioctls */ +#define HCIUARTSETPROTO _IOW('U', 200, int) +#define HCIUARTGETPROTO _IOR('U', 201, int) + +/* UART protocols */ +#define HCI_UART_MAX_PROTO 3 + +#define HCI_UART_H4 0 +#define HCI_UART_BCSP 1 +#define HCI_UART_NCSP 2 + +#ifdef __KERNEL__ +struct n_hci; + +struct hci_uart_proto { + unsigned int id; + int (*open)(struct n_hci *n_hci); + int (*recv)(struct n_hci *n_hci, void *data, int len); + int (*send)(struct n_hci *n_hci, void *data, int len); + int (*close)(struct n_hci *n_hci); + int (*flush)(struct n_hci *n_hci); + struct sk_buff* (*preq)(struct n_hci *n_hci, struct sk_buff *skb); +}; + +struct n_hci { + struct tty_struct *tty; + struct hci_dev hdev; + unsigned long flags; + + struct hci_uart_proto *proto; + void *priv; + + struct sk_buff_head txq; + unsigned long tx_state; + spinlock_t rx_lock; +}; + +/* N_HCI flag bits */ +#define N_HCI_PROTO_SET 0x00 + +/* TX states */ +#define N_HCI_SENDING 1 +#define N_HCI_TX_WAKEUP 2 + +int hci_uart_register_proto(struct hci_uart_proto *p); +int hci_uart_unregister_proto(struct hci_uart_proto *p); + +#endif /* __KERNEL__ */ diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_usb.c linux-2.4.19-pre7/drivers/bluetooth/hci_usb.c --- linux-2.4.19-pre6/drivers/bluetooth/hci_usb.c Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/drivers/bluetooth/hci_usb.c Mon Apr 15 21:54:26 2002 @@ -28,38 +28,36 @@ * Copyright (c) 2000 Greg Kroah-Hartman * Copyright (c) 2000 Mark Douglas Corner * - * $Id: hci_usb.c,v 1.5 2001/07/05 18:42:44 maxk Exp $ + * $Id: hci_usb.c,v 1.5 2002/03/20 17:51:59 maxk Exp $ */ -#define VERSION "1.0" +#define VERSION "2.0" #include #include +#define __KERNEL_SYSCALLS__ + #include -#include #include #include #include +#include #include -#include #include -#include -#include #include -#include #include #include -#include -#include #include +#include #include #include -#include #include -#include +#include "hci_usb.h" + +#define HCI_MAX_PENDING (HCI_MAX_BULK_RX + HCI_MAX_BULK_TX + 1) #ifndef HCI_USB_DEBUG #undef DBG @@ -68,151 +66,313 @@ #define DMP( A... ) #endif +#ifndef CONFIG_BLUEZ_USB_ZERO_PACKET +#undef USB_ZERO_PACKET +#define USB_ZERO_PACKET 0 +#endif + +static struct usb_driver hci_usb_driver; + static struct usb_device_id usb_bluetooth_ids [] = { + /* Generic Bluetooth USB device */ { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) }, + + /* Ericsson with non-standard id */ + { USB_DEVICE(0x0bdb, 0x1002) }, + { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids); -static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb); -static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb); +static void hci_usb_interrupt(struct urb *urb); +static void hci_usb_rx_complete(struct urb *urb); +static void hci_usb_tx_complete(struct urb *urb); -static void hci_usb_unlink_urbs(struct hci_usb *husb) +static purb_t hci_usb_get_completed(struct hci_usb *husb) { - usb_unlink_urb(husb->read_urb); - usb_unlink_urb(husb->intr_urb); - usb_unlink_urb(husb->ctrl_urb); - usb_unlink_urb(husb->write_urb); + struct sk_buff *skb; + purb_t urb = NULL; + + skb = skb_dequeue(&husb->completed_q); + if (skb) { + urb = ((struct hci_usb_scb *) skb->cb)->urb; + kfree_skb(skb); + } + + DBG("%s urb %p", husb->hdev.name, urb); + return urb; } -static void hci_usb_free_bufs(struct hci_usb *husb) +static int hci_usb_enable_intr(struct hci_usb *husb) { - if (husb->read_urb) { - if (husb->read_urb->transfer_buffer) - kfree(husb->read_urb->transfer_buffer); - usb_free_urb(husb->read_urb); + struct urb *urb; + int pipe, size; + void *buf; + + DBG("%s", husb->hdev.name); + + if (!(urb = usb_alloc_urb(0))) + return -ENOMEM; + + if (!(buf = kmalloc(HCI_MAX_EVENT_SIZE, GFP_KERNEL))) { + usb_free_urb(urb); + return -ENOMEM; } - if (husb->intr_urb) { - if (husb->intr_urb->transfer_buffer) - kfree(husb->intr_urb->transfer_buffer); - usb_free_urb(husb->intr_urb); + husb->intr_urb = urb; + + pipe = usb_rcvintpipe(husb->udev, husb->intr_ep); + size = usb_maxpacket(husb->udev, pipe, usb_pipeout(pipe)); + FILL_INT_URB(urb, husb->udev, pipe, buf, size, + hci_usb_interrupt, husb, husb->intr_interval); + + return usb_submit_urb(urb); +} + +static int hci_usb_disable_intr(struct hci_usb *husb) +{ + struct urb *urb = husb->intr_urb; + struct sk_buff *skb; + + DBG("%s", husb->hdev.name); + + usb_unlink_urb(urb); usb_free_urb(urb); + husb->intr_urb = NULL; + + skb = husb->intr_skb; + if (skb) { + husb->intr_skb = NULL; + kfree_skb(skb); } - if (husb->ctrl_urb) - usb_free_urb(husb->ctrl_urb); + return 0; +} - if (husb->write_urb) - usb_free_urb(husb->write_urb); +static int hci_usb_rx_submit(struct hci_usb *husb, struct urb *urb) +{ + struct hci_usb_scb *scb; + struct sk_buff *skb; + int pipe, size, err; - if (husb->intr_skb) - kfree_skb(husb->intr_skb); + if (!urb && !(urb = usb_alloc_urb(0))) + return -ENOMEM; + + size = HCI_MAX_FRAME_SIZE; + + if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) { + usb_free_urb(urb); + return -ENOMEM; + } + + DBG("%s urb %p", husb->hdev.name, urb); + + skb->dev = (void *) &husb->hdev; + skb->pkt_type = HCI_ACLDATA_PKT; + + scb = (struct hci_usb_scb *) skb->cb; + scb->urb = urb; + + pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep); + + FILL_BULK_URB(urb, husb->udev, pipe, skb->data, size, hci_usb_rx_complete, skb); + urb->transfer_flags = USB_QUEUE_BULK; + + skb_queue_tail(&husb->pending_q, skb); + err = usb_submit_urb(urb); + if (err) { + ERR("%s bulk rx submit failed urb %p err %d", + husb->hdev.name, urb, err); + skb_unlink(skb); + usb_free_urb(urb); + } + return err; } -/* ------- Interface to HCI layer ------ */ /* Initialize device */ -int hci_usb_open(struct hci_dev *hdev) +static int hci_usb_open(struct hci_dev *hdev) { struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; - int status; + int i, err; + long flags; DBG("%s", hdev->name); - husb->read_urb->dev = husb->udev; - if ((status = usb_submit_urb(husb->read_urb))) - DBG("read submit failed. %d", status); - - husb->intr_urb->dev = husb->udev; - if ((status = usb_submit_urb(husb->intr_urb))) - DBG("interrupt submit failed. %d", status); + if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) + return 0; - hdev->flags |= HCI_RUNNING; + write_lock_irqsave(&husb->completion_lock, flags); - return 0; + err = hci_usb_enable_intr(husb); + if (!err) { + for (i = 0; i < HCI_MAX_BULK_TX; i++) + hci_usb_rx_submit(husb, NULL); + } else + clear_bit(HCI_RUNNING, &hdev->flags); + + write_unlock_irqrestore(&husb->completion_lock, flags); + return err; } /* Reset device */ -int hci_usb_flush(struct hci_dev *hdev) +static int hci_usb_flush(struct hci_dev *hdev) { struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; DBG("%s", hdev->name); - /* Drop TX queues */ - skb_queue_purge(&husb->tx_ctrl_q); - skb_queue_purge(&husb->tx_write_q); - + skb_queue_purge(&husb->cmd_q); + skb_queue_purge(&husb->acl_q); return 0; } +static inline void hci_usb_unlink_urbs(struct hci_usb *husb) +{ + struct sk_buff *skb; + purb_t urb; + + DBG("%s", husb->hdev.name); + + while ((skb = skb_dequeue(&husb->pending_q))) { + urb = ((struct hci_usb_scb *) skb->cb)->urb; + usb_unlink_urb(urb); + kfree_skb(skb); + } + + while ((urb = hci_usb_get_completed(husb))) + usb_free_urb(urb); +} + /* Close device */ -int hci_usb_close(struct hci_dev *hdev) +static int hci_usb_close(struct hci_dev *hdev) { struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + long flags; + + if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) + return 0; DBG("%s", hdev->name); - hdev->flags &= ~HCI_RUNNING; + write_lock_irqsave(&husb->completion_lock, flags); + + hci_usb_disable_intr(husb); hci_usb_unlink_urbs(husb); - hci_usb_flush(hdev); + write_unlock_irqrestore(&husb->completion_lock, flags); return 0; } -void hci_usb_ctrl_wakeup(struct hci_usb *husb) +static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb) { - struct sk_buff *skb; + struct hci_usb_scb *scb = (void *) skb->cb; + purb_t urb = hci_usb_get_completed(husb); + devrequest *dr; + int pipe, err; - if (test_and_set_bit(HCI_TX_CTRL, &husb->tx_state)) - return; + if (!urb && !(urb = usb_alloc_urb(0))) + return -ENOMEM; - DBG("%s", husb->hdev.name); + if (!(dr = kmalloc(sizeof(*dr), GFP_ATOMIC))) { + usb_free_urb(urb); + return -ENOMEM; + } + + pipe = usb_sndctrlpipe(husb->udev, 0); - if (!(skb = skb_dequeue(&husb->tx_ctrl_q))) - goto done; + dr->requesttype = HCI_CTRL_REQ; + dr->request = 0; + dr->index = 0; + dr->value = 0; + dr->length = __cpu_to_le16(skb->len); - if (hci_usb_ctrl_msg(husb, skb)){ - kfree_skb(skb); - goto done; - } + FILL_CONTROL_URB(urb, husb->udev, pipe, (void *) dr, + skb->data, skb->len, hci_usb_tx_complete, skb); - DMP(skb->data, skb->len); + DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len); - husb->hdev.stat.byte_tx += skb->len; - return; + scb->urb = urb; -done: - clear_bit(HCI_TX_CTRL, &husb->tx_state); - return; + skb_queue_tail(&husb->pending_q, skb); + err = usb_submit_urb(urb); + if (err) { + ERR("%s ctrl tx submit failed urb %p err %d", + husb->hdev.name, urb, err); + skb_unlink(skb); + usb_free_urb(urb); kfree(dr); + } + return err; } -void hci_usb_write_wakeup(struct hci_usb *husb) +static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb) { - struct sk_buff *skb; + struct hci_usb_scb *scb = (void *) skb->cb; + purb_t urb = hci_usb_get_completed(husb); + int pipe, err; - if (test_and_set_bit(HCI_TX_WRITE, &husb->tx_state)) - return; + if (!urb && !(urb = usb_alloc_urb(0))) + return -ENOMEM; - DBG("%s", husb->hdev.name); + pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep); + + FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, + hci_usb_tx_complete, skb); + urb->transfer_flags = USB_QUEUE_BULK | USB_ZERO_PACKET; - if (!(skb = skb_dequeue(&husb->tx_write_q))) - goto done; + DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len); - if (hci_usb_write_msg(husb, skb)) { - skb_queue_head(&husb->tx_write_q, skb); - goto done; + scb->urb = urb; + + skb_queue_tail(&husb->pending_q, skb); + err = usb_submit_urb(urb); + if (err) { + ERR("%s bulk tx submit failed urb %p err %d", + husb->hdev.name, urb, err); + skb_unlink(skb); + usb_free_urb(urb); } + return err; +} - DMP(skb->data, skb->len); +static void hci_usb_tx_process(struct hci_usb *husb) +{ + struct sk_buff *skb; - husb->hdev.stat.byte_tx += skb->len; - return; + DBG("%s", husb->hdev.name); -done: - clear_bit(HCI_TX_WRITE, &husb->tx_state); - return; + do { + clear_bit(HCI_USB_TX_WAKEUP, &husb->state); + + /* Process ACL queue */ + while (skb_queue_len(&husb->pending_q) < HCI_MAX_PENDING && + (skb = skb_dequeue(&husb->acl_q))) { + if (hci_usb_send_bulk(husb, skb) < 0) { + skb_queue_head(&husb->acl_q, skb); + break; + } + } + + /* Process command queue */ + if (!test_bit(HCI_USB_CTRL_TX, &husb->state) && + (skb = skb_dequeue(&husb->cmd_q)) != NULL) { + set_bit(HCI_USB_CTRL_TX, &husb->state); + if (hci_usb_send_ctrl(husb, skb) < 0) { + skb_queue_head(&husb->cmd_q, skb); + clear_bit(HCI_USB_CTRL_TX, &husb->state); + } + } + } while(test_bit(HCI_USB_TX_WAKEUP, &husb->state)); +} + +static inline void hci_usb_tx_wakeup(struct hci_usb *husb) +{ + /* Serialize TX queue processing to avoid data reordering */ + if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) { + hci_usb_tx_process(husb); + clear_bit(HCI_USB_TX_PROCESS, &husb->state); + } else + set_bit(HCI_USB_TX_WAKEUP, &husb->state); } /* Send frames from HCI layer */ @@ -226,372 +386,397 @@ return -ENODEV; } - if (!(hdev->flags & HCI_RUNNING)) - return 0; + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return -EBUSY; husb = (struct hci_usb *) hdev->driver_data; DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); - switch (skb->pkt_type) { - case HCI_COMMAND_PKT: - skb_queue_tail(&husb->tx_ctrl_q, skb); - hci_usb_ctrl_wakeup(husb); - hdev->stat.cmd_tx++; - return 0; - - case HCI_ACLDATA_PKT: - skb_queue_tail(&husb->tx_write_q, skb); - hci_usb_write_wakeup(husb); - hdev->stat.acl_tx++; - return 0; - - case HCI_SCODATA_PKT: - return -EOPNOTSUPP; - }; - - return 0; -} - -/* ---------- USB ------------- */ - -static void hci_usb_ctrl(struct urb *urb) -{ - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct hci_dev *hdev; - struct hci_usb *husb; - - if (!skb) - return; - hdev = (struct hci_dev *) skb->dev; - husb = (struct hci_usb *) hdev->driver_data; - - DBG("%s", hdev->name); - - if (urb->status) - DBG("%s ctrl status: %d", hdev->name, urb->status); - - clear_bit(HCI_TX_CTRL, &husb->tx_state); - kfree_skb(skb); - - /* Wake up device */ - hci_usb_ctrl_wakeup(husb); -} - -static void hci_usb_bulk_write(struct urb *urb) -{ - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct hci_dev *hdev; - struct hci_usb *husb; - - if (!skb) - return; - hdev = (struct hci_dev *) skb->dev; - husb = (struct hci_usb *) hdev->driver_data; + read_lock(&husb->completion_lock); - DBG("%s", hdev->name); - - if (urb->status) - DBG("%s bulk write status: %d", hdev->name, urb->status); - - clear_bit(HCI_TX_WRITE, &husb->tx_state); - kfree_skb(skb); + switch (skb->pkt_type) { + case HCI_COMMAND_PKT: + skb_queue_tail(&husb->cmd_q, skb); + hdev->stat.cmd_tx++; + break; + + case HCI_ACLDATA_PKT: + skb_queue_tail(&husb->acl_q, skb); + hdev->stat.acl_tx++; + break; - /* Wake up device */ - hci_usb_write_wakeup(husb); + case HCI_SCODATA_PKT: + default: + kfree_skb(skb); + break; + } + hci_usb_tx_wakeup(husb); - return; + read_unlock(&husb->completion_lock); + return 0; } -static void hci_usb_intr(struct urb *urb) +static void hci_usb_interrupt(struct urb *urb) { - struct hci_usb *husb = (struct hci_usb *) urb->context; - unsigned char *data = urb->transfer_buffer; - register int count = urb->actual_length; - register struct sk_buff *skb = husb->intr_skb; + struct hci_usb *husb = (void *) urb->context; + struct hci_usb_scb *scb; + struct sk_buff *skb; hci_event_hdr *eh; - register int len; + __u8 *data = urb->transfer_buffer; + int count = urb->actual_length; + int len = HCI_EVENT_HDR_SIZE; - if (!husb) - return; + DBG("%s urb %p count %d", husb->hdev.name, urb, count); - DBG("%s count %d", husb->hdev.name, count); + if (!test_bit(HCI_RUNNING, &husb->hdev.flags)) + return; if (urb->status || !count) { - DBG("%s intr status %d, count %d", husb->hdev.name, urb->status, count); + DBG("%s intr status %d, count %d", + husb->hdev.name, urb->status, count); return; } - /* Do we really have to handle continuations here ? */ - if (!skb) { - /* New frame */ - if (count < HCI_EVENT_HDR_SIZE) { - DBG("%s bad frame len %d", husb->hdev.name, count); - return; - } + read_lock(&husb->completion_lock); + + husb->hdev.stat.byte_rx += count; + + if (!(skb = husb->intr_skb)) { + /* Start of the frame */ + if (count < HCI_EVENT_HDR_SIZE) + goto bad_len; - eh = (hci_event_hdr *) data; + eh = (hci_event_hdr *) data; len = eh->plen + HCI_EVENT_HDR_SIZE; - if (count > len) { - DBG("%s corrupted frame, len %d", husb->hdev.name, count); - return; - } + if (count > len) + goto bad_len; - /* Allocate skb */ - if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) { - ERR("Can't allocate mem for new packet"); - return; + skb = bluez_skb_alloc(len, GFP_ATOMIC); + if (!skb) { + ERR("%s no memory for event packet", husb->hdev.name); + goto done; } + scb = (void *) skb->cb; + skb->dev = (void *) &husb->hdev; skb->pkt_type = HCI_EVENT_PKT; husb->intr_skb = skb; - husb->intr_count = len; + scb->intr_len = len; } else { /* Continuation */ - if (count > husb->intr_count) { - ERR("%s bad frame len %d (expected %d)", husb->hdev.name, count, husb->intr_count); - - kfree_skb(skb); + scb = (void *) skb->cb; + len = scb->intr_len; + if (count > len) { husb->intr_skb = NULL; - husb->intr_count = 0; - return; + kfree_skb(skb); + goto bad_len; } } memcpy(skb_put(skb, count), data, count); - husb->intr_count -= count; + scb->intr_len -= count; - DMP(data, count); + if (!scb->intr_len) { + /* Complete frame */ + husb->intr_skb = NULL; + hci_recv_frame(skb); + } - if (!husb->intr_count) { - /* Got complete frame */ +done: + read_unlock(&husb->completion_lock); + return; - husb->hdev.stat.byte_rx += skb->len; - hci_recv_frame(skb); +bad_len: + ERR("%s bad frame len %d expected %d", husb->hdev.name, count, len); + husb->hdev.stat.err_rx++; + read_unlock(&husb->completion_lock); +} - husb->intr_skb = NULL; +static void hci_usb_tx_complete(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct hci_dev *hdev = (struct hci_dev *) skb->dev; + struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + + DBG("%s urb %p status %d flags %x", husb->hdev.name, urb, + urb->status, urb->transfer_flags); + + if (urb->pipe == usb_sndctrlpipe(husb->udev, 0)) { + kfree(urb->setup_packet); + clear_bit(HCI_USB_CTRL_TX, &husb->state); } + + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return; + + read_lock(&husb->completion_lock); + + if (!urb->status) + husb->hdev.stat.byte_tx += skb->len; + else + husb->hdev.stat.err_tx++; + + skb_unlink(skb); + skb_queue_tail(&husb->completed_q, skb); + hci_usb_tx_wakeup(husb); + + read_unlock(&husb->completion_lock); + return; } -static void hci_usb_bulk_read(struct urb *urb) +static void hci_usb_rx_complete(struct urb *urb) { - struct hci_usb *husb = (struct hci_usb *) urb->context; - unsigned char *data = urb->transfer_buffer; - int count = urb->actual_length, status; - struct sk_buff *skb; + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct hci_dev *hdev = (struct hci_dev *) skb->dev; + struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + int status, count = urb->actual_length; hci_acl_hdr *ah; - register __u16 dlen; + int dlen, size; - if (!husb) + DBG("%s urb %p status %d count %d flags %x", husb->hdev.name, urb, + urb->status, count, urb->transfer_flags); + + if (!test_bit(HCI_RUNNING, &hdev->flags)) return; - DBG("%s status %d, count %d, flags %x", husb->hdev.name, urb->status, count, urb->transfer_flags); + read_lock(&husb->completion_lock); - if (urb->status) { - /* Do not re-submit URB on critical errors */ - switch (urb->status) { - case -ENOENT: - return; - default: - goto resubmit; - }; - } - if (!count) + if (urb->status || !count) goto resubmit; - DMP(data, count); + husb->hdev.stat.byte_rx += count; - ah = (hci_acl_hdr *) data; - dlen = le16_to_cpu(ah->dlen); + ah = (hci_acl_hdr *) skb->data; + dlen = __le16_to_cpu(ah->dlen); + size = HCI_ACL_HDR_SIZE + dlen; /* Verify frame len and completeness */ - if ((count - HCI_ACL_HDR_SIZE) != dlen) { - ERR("%s corrupted ACL packet: count %d, plen %d", husb->hdev.name, count, dlen); - goto resubmit; - } - - /* Allocate packet */ - if (!(skb = bluez_skb_alloc(count, GFP_ATOMIC))) { - ERR("Can't allocate mem for new packet"); + if (count != size) { + ERR("%s corrupted ACL packet: count %d, dlen %d", + husb->hdev.name, count, dlen); + bluez_dump("hci_usb", skb->data, count); + husb->hdev.stat.err_rx++; goto resubmit; } - memcpy(skb_put(skb, count), data, count); - skb->dev = (void *) &husb->hdev; - skb->pkt_type = HCI_ACLDATA_PKT; - - husb->hdev.stat.byte_rx += skb->len; - + skb_unlink(skb); + skb_put(skb, count); hci_recv_frame(skb); -resubmit: - husb->read_urb->dev = husb->udev; - if ((status = usb_submit_urb(husb->read_urb))) - DBG("%s read URB submit failed %d", husb->hdev.name, status); + hci_usb_rx_submit(husb, urb); - DBG("%s read URB re-submited", husb->hdev.name); + read_unlock(&husb->completion_lock); + return; + +resubmit: + urb->dev = husb->udev; + status = usb_submit_urb(urb); + DBG("%s URB resubmit status %d", husb->hdev.name, status); + read_unlock(&husb->completion_lock); } -static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb) +static void hci_usb_destruct(struct hci_dev *hdev) { - struct urb *urb = husb->ctrl_urb; - devrequest *dr = &husb->dev_req; - int pipe, status; + struct hci_usb *husb; - DBG("%s len %d", husb->hdev.name, skb->len); + if (!hdev) return; - pipe = usb_sndctrlpipe(husb->udev, 0); + DBG("%s", hdev->name); - dr->requesttype = HCI_CTRL_REQ; - dr->request = 0; - dr->index = 0; - dr->value = 0; - dr->length = cpu_to_le16(skb->len); + husb = (struct hci_usb *) hdev->driver_data; + kfree(husb); - FILL_CONTROL_URB(urb, husb->udev, pipe, (void*)dr, skb->data, skb->len, - hci_usb_ctrl, skb); + MOD_DEC_USE_COUNT; +} - if ((status = usb_submit_urb(urb))) { - DBG("%s control URB submit failed %d", husb->hdev.name, status); - return status; - } +#ifdef CONFIG_BLUEZ_USB_FW_LOAD - return 0; -} +/* Support for user mode Bluetooth USB firmware loader */ -static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb) +#define FW_LOADER "/sbin/bluefw" +static int errno; + +static int hci_usb_fw_exec(void *dev) { - struct urb *urb = husb->write_urb; - int pipe, status; + char *envp[] = { "HOME=/", "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; + char *argv[] = { FW_LOADER, dev, NULL }; + int err; - DBG("%s len %d", husb->hdev.name, skb->len); + err = exec_usermodehelper(FW_LOADER, argv, envp); + if (err) + ERR("failed to exec %s %s", FW_LOADER, (char *)dev); + return err; +} - pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep_addr); +static int hci_usb_fw_load(struct usb_device *udev) +{ + sigset_t tmpsig; + char dev[16]; + pid_t pid; + int result; - FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, - hci_usb_bulk_write, skb); - urb->transfer_flags |= USB_QUEUE_BULK; + /* Check if root fs is mounted */ + if (!current->fs->root) { + ERR("root fs not mounted"); + return -EPERM; + } + + sprintf(dev, "%3.3d/%3.3d", udev->bus->busnum, udev->devnum); - if ((status = usb_submit_urb(urb))) { - DBG("%s write URB submit failed %d", husb->hdev.name, status); - return status; + pid = kernel_thread(hci_usb_fw_exec, (void *)dev, 0); + if (pid < 0) { + ERR("fork failed, errno %d\n", -pid); + return pid; } + /* Block signals, everything but SIGKILL/SIGSTOP */ + spin_lock_irq(¤t->sigmask_lock); + tmpsig = current->blocked; + siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + result = waitpid(pid, NULL, __WCLONE); + + /* Allow signals again */ + spin_lock_irq(¤t->sigmask_lock); + current->blocked = tmpsig; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (result != pid) { + ERR("waitpid failed pid %d errno %d\n", pid, -result); + return -result; + } return 0; } +#endif /* CONFIG_BLUEZ_USB_FW_LOAD */ + static void * hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) { - struct usb_endpoint_descriptor *bulk_out_ep, *intr_in_ep, *bulk_in_ep; + struct usb_endpoint_descriptor *bulk_out_ep[HCI_MAX_IFACE_NUM]; + struct usb_endpoint_descriptor *isoc_out_ep[HCI_MAX_IFACE_NUM]; + struct usb_endpoint_descriptor *bulk_in_ep[HCI_MAX_IFACE_NUM]; + struct usb_endpoint_descriptor *isoc_in_ep[HCI_MAX_IFACE_NUM]; + struct usb_endpoint_descriptor *intr_in_ep[HCI_MAX_IFACE_NUM]; struct usb_interface_descriptor *uif; struct usb_endpoint_descriptor *ep; + struct usb_interface *iface, *isoc_iface; struct hci_usb *husb; struct hci_dev *hdev; - int i, size, pipe; - __u8 * buf; + int i, a, e, size, ifn, isoc_ifnum, isoc_alts; DBG("udev %p ifnum %d", udev, ifnum); - /* Check device signature */ - if ((udev->descriptor.bDeviceClass != HCI_DEV_CLASS) || - (udev->descriptor.bDeviceSubClass != HCI_DEV_SUBCLASS)|| - (udev->descriptor.bDeviceProtocol != HCI_DEV_PROTOCOL) ) + /* Check number of endpoints */ + if (udev->actconfig->interface[ifnum].altsetting[0].bNumEndpoints < 3) return NULL; MOD_INC_USE_COUNT; - uif = &udev->actconfig->interface[ifnum].altsetting[0]; - - if (uif->bNumEndpoints != 3) { - DBG("Wrong number of endpoints %d", uif->bNumEndpoints); - MOD_DEC_USE_COUNT; - return NULL; - } - - bulk_out_ep = intr_in_ep = bulk_in_ep = NULL; +#ifdef CONFIG_BLUEZ_USB_FW_LOAD + hci_usb_fw_load(udev); +#endif + memset(bulk_out_ep, 0, sizeof(bulk_out_ep)); + memset(isoc_out_ep, 0, sizeof(isoc_out_ep)); + memset(bulk_in_ep, 0, sizeof(bulk_in_ep)); + memset(isoc_in_ep, 0, sizeof(isoc_in_ep)); + memset(intr_in_ep, 0, sizeof(intr_in_ep)); + + size = 0; + isoc_iface = NULL; + isoc_alts = isoc_ifnum = 0; + /* Find endpoints that we need */ - for ( i = 0; i < uif->bNumEndpoints; ++i) { - ep = &uif->endpoint[i]; - switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_BULK: - if (ep->bEndpointAddress & USB_DIR_IN) - bulk_in_ep = ep; - else - bulk_out_ep = ep; - break; + ifn = MIN(udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM); + for (i = 0; i < ifn; i++) { + iface = &udev->actconfig->interface[i]; + for (a = 0; a < iface->num_altsetting; a++) { + uif = &iface->altsetting[a]; + for (e = 0; e < uif->bNumEndpoints; e++) { + ep = &uif->endpoint[e]; + + switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_INT: + if (ep->bEndpointAddress & USB_DIR_IN) + intr_in_ep[i] = ep; + break; + + case USB_ENDPOINT_XFER_BULK: + if (ep->bEndpointAddress & USB_DIR_IN) + bulk_in_ep[i] = ep; + else + bulk_out_ep[i] = ep; + break; + + case USB_ENDPOINT_XFER_ISOC: + if (ep->wMaxPacketSize < size) + break; + size = ep->wMaxPacketSize; + + isoc_iface = iface; + isoc_alts = a; + isoc_ifnum = i; + + if (ep->bEndpointAddress & USB_DIR_IN) + isoc_in_ep[i] = ep; + else + isoc_out_ep[i] = ep; + break; + } + } + } + } - case USB_ENDPOINT_XFER_INT: - intr_in_ep = ep; - break; - }; + if (!bulk_in_ep[0] || !bulk_out_ep[0] || !intr_in_ep[0]) { + DBG("Bulk endpoints not found"); + goto done; } - if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) { - DBG("Endpoints not found: %p %p %p", bulk_in_ep, bulk_out_ep, intr_in_ep); - MOD_DEC_USE_COUNT; - return NULL; + if (!isoc_in_ep[1] || !isoc_out_ep[1]) { + DBG("Isoc endpoints not found"); + isoc_iface = NULL; } if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) { ERR("Can't allocate: control structure"); - MOD_DEC_USE_COUNT; - return NULL; + goto done; } memset(husb, 0, sizeof(struct hci_usb)); husb->udev = udev; - husb->bulk_out_ep_addr = bulk_out_ep->bEndpointAddress; - - if (!(husb->ctrl_urb = usb_alloc_urb(0))) { - ERR("Can't allocate: control URB"); - goto probe_error; - } - - if (!(husb->write_urb = usb_alloc_urb(0))) { - ERR("Can't allocate: write URB"); - goto probe_error; - } - - if (!(husb->read_urb = usb_alloc_urb(0))) { - ERR("Can't allocate: read URB"); - goto probe_error; - } - - ep = bulk_in_ep; - pipe = usb_rcvbulkpipe(udev, ep->bEndpointAddress); - size = HCI_MAX_FRAME_SIZE; - - if (!(buf = kmalloc(size, GFP_KERNEL))) { - ERR("Can't allocate: read buffer"); - goto probe_error; - } + husb->bulk_out_ep = bulk_out_ep[0]->bEndpointAddress; + husb->bulk_in_ep = bulk_in_ep[0]->bEndpointAddress; - FILL_BULK_URB(husb->read_urb, udev, pipe, buf, size, hci_usb_bulk_read, husb); - husb->read_urb->transfer_flags |= USB_QUEUE_BULK; + husb->intr_ep = intr_in_ep[0]->bEndpointAddress; + husb->intr_interval = intr_in_ep[0]->bInterval; - ep = intr_in_ep; - pipe = usb_rcvintpipe(udev, ep->bEndpointAddress); - size = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); - - if (!(husb->intr_urb = usb_alloc_urb(0))) { - ERR("Can't allocate: interrupt URB"); - goto probe_error; - } + if (isoc_iface) { + if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) { + ERR("Can't set isoc interface settings"); + isoc_iface = NULL; + } + usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb); + husb->isoc_iface = isoc_iface; - if (!(buf = kmalloc(size, GFP_KERNEL))) { - ERR("Can't allocate: interrupt buffer"); - goto probe_error; + husb->isoc_in_ep = isoc_in_ep[1]->bEndpointAddress; + husb->isoc_out_ep = isoc_in_ep[1]->bEndpointAddress; } - FILL_INT_URB(husb->intr_urb, udev, pipe, buf, size, hci_usb_intr, husb, ep->bInterval); - - skb_queue_head_init(&husb->tx_ctrl_q); - skb_queue_head_init(&husb->tx_write_q); + husb->completion_lock = RW_LOCK_UNLOCKED; + + skb_queue_head_init(&husb->acl_q); + skb_queue_head_init(&husb->cmd_q); + skb_queue_head_init(&husb->pending_q); + skb_queue_head_init(&husb->completed_q); /* Initialize and register HCI device */ hdev = &husb->hdev; @@ -602,18 +787,20 @@ hdev->open = hci_usb_open; hdev->close = hci_usb_close; hdev->flush = hci_usb_flush; - hdev->send = hci_usb_send_frame; + hdev->send = hci_usb_send_frame; + hdev->destruct = hci_usb_destruct; if (hci_register_dev(hdev) < 0) { - ERR("Can't register HCI device %s", hdev->name); + ERR("Can't register HCI device"); goto probe_error; } return husb; probe_error: - hci_usb_free_bufs(husb); kfree(husb); + +done: MOD_DEC_USE_COUNT; return NULL; } @@ -630,18 +817,14 @@ hci_usb_close(hdev); - if (hci_unregister_dev(hdev) < 0) { - ERR("Can't unregister HCI device %s", hdev->name); - } - - hci_usb_free_bufs(husb); - kfree(husb); + if (husb->isoc_iface) + usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface); - MOD_DEC_USE_COUNT; + if (hci_unregister_dev(hdev) < 0) + ERR("Can't unregister HCI device %s", hdev->name); } -static struct usb_driver hci_usb_driver = -{ +static struct usb_driver hci_usb_driver = { name: "hci_usb", probe: hci_usb_probe, disconnect: hci_usb_disconnect, diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_usb.h linux-2.4.19-pre7/drivers/bluetooth/hci_usb.h --- linux-2.4.19-pre6/drivers/bluetooth/hci_usb.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/drivers/bluetooth/hci_usb.h Mon Apr 15 21:54:26 2002 @@ -0,0 +1,79 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * $Id: hci_usb.h,v 1.2 2002/03/18 19:10:04 maxk Exp $ + */ + +#ifdef __KERNEL__ + +/* Class, SubClass, and Protocol codes that describe a Bluetooth device */ +#define HCI_DEV_CLASS 0xe0 /* Wireless class */ +#define HCI_DEV_SUBCLASS 0x01 /* RF subclass */ +#define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */ + +#define HCI_CTRL_REQ 0x20 + +#define HCI_MAX_IFACE_NUM 3 + +#define HCI_MAX_BULK_TX 4 +#define HCI_MAX_BULK_RX 1 + +struct hci_usb { + struct hci_dev hdev; + + unsigned long state; + + struct usb_device *udev; + struct usb_interface *isoc_iface; + + __u8 bulk_out_ep; + __u8 bulk_in_ep; + __u8 isoc_out_ep; + __u8 isoc_in_ep; + + __u8 intr_ep; + __u8 intr_interval; + purb_t intr_urb; + struct sk_buff * intr_skb; + + rwlock_t completion_lock; + + struct sk_buff_head cmd_q; // TX Commands + struct sk_buff_head acl_q; // TX ACLs + struct sk_buff_head pending_q; // Pending requests + struct sk_buff_head completed_q; // Completed requests +}; + +struct hci_usb_scb { + struct urb *urb; + int intr_len; +}; + +/* States */ +#define HCI_USB_TX_PROCESS 1 +#define HCI_USB_TX_WAKEUP 2 +#define HCI_USB_CTRL_TX 3 + +#endif /* __KERNEL__ */ diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_vhci.c linux-2.4.19-pre7/drivers/bluetooth/hci_vhci.c --- linux-2.4.19-pre6/drivers/bluetooth/hci_vhci.c Mon Apr 15 21:53:54 2002 +++ linux-2.4.19-pre7/drivers/bluetooth/hci_vhci.c Mon Apr 15 21:54:26 2002 @@ -25,9 +25,9 @@ /* * BlueZ HCI virtual device driver. * - * $Id: hci_vhci.c,v 1.3 2001/08/03 04:19:50 maxk Exp $ + * $Id: hci_vhci.c,v 1.2 2002/03/18 19:16:40 maxk Exp $ */ -#define VERSION "1.0" +#define VERSION "1.1" #include #include @@ -49,33 +49,46 @@ #include #include -#include #include -#include +#include "hci_vhci.h" /* HCI device part */ -int hci_vhci_open(struct hci_dev *hdev) +static int hci_vhci_open(struct hci_dev *hdev) { - hdev->flags |= HCI_RUNNING; + set_bit(HCI_RUNNING, &hdev->flags); return 0; } -int hci_vhci_flush(struct hci_dev *hdev) +static int hci_vhci_flush(struct hci_dev *hdev) { struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data; skb_queue_purge(&hci_vhci->readq); return 0; } -int hci_vhci_close(struct hci_dev *hdev) +static int hci_vhci_close(struct hci_dev *hdev) { - hdev->flags &= ~HCI_RUNNING; + if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) + return 0; + hci_vhci_flush(hdev); return 0; } -int hci_vhci_send_frame(struct sk_buff *skb) +static void hci_vhci_destruct(struct hci_dev *hdev) +{ + struct hci_vhci_struct *vhci; + + if (!hdev) return; + + vhci = (struct hci_vhci_struct *) hdev->driver_data; + kfree(vhci); + + MOD_DEC_USE_COUNT; +} + +static int hci_vhci_send_frame(struct sk_buff *skb) { struct hci_dev* hdev = (struct hci_dev *) skb->dev; struct hci_vhci_struct *hci_vhci; @@ -85,7 +98,7 @@ return -ENODEV; } - if (!(hdev->flags & HCI_RUNNING)) + if (!test_bit(HCI_RUNNING, &hdev->flags)) return -EBUSY; hci_vhci = (struct hci_vhci_struct *) hdev->driver_data; @@ -188,7 +201,7 @@ add_wait_queue(&hci_vhci->read_wait, &wait); while (count) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); /* Read frames from device queue */ if (!(skb = skb_dequeue(&hci_vhci->readq))) { @@ -214,13 +227,17 @@ kfree_skb(skb); break; } - - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&hci_vhci->read_wait, &wait); return ret; } +static loff_t hci_vhci_chr_lseek(struct file * file, loff_t offset, int origin) +{ + return -ESPIPE; +} + static int hci_vhci_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { return -EINVAL; @@ -265,11 +282,13 @@ hdev->close = hci_vhci_close; hdev->flush = hci_vhci_flush; hdev->send = hci_vhci_send_frame; + hdev->destruct = hci_vhci_destruct; if (hci_register_dev(hdev) < 0) { kfree(hci_vhci); return -EBUSY; } + MOD_INC_USE_COUNT; file->private_data = hci_vhci; return 0; @@ -283,15 +302,13 @@ ERR("Can't unregister HCI device %s", hci_vhci->hdev.name); } - kfree(hci_vhci); file->private_data = NULL; - return 0; } static struct file_operations hci_vhci_fops = { owner: THIS_MODULE, - llseek: no_llseek, + llseek: hci_vhci_chr_lseek, read: hci_vhci_chr_read, write: hci_vhci_chr_write, poll: hci_vhci_chr_poll, @@ -332,4 +349,4 @@ MODULE_AUTHOR("Maxim Krasnyansky "); MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_vhci.h linux-2.4.19-pre7/drivers/bluetooth/hci_vhci.h --- linux-2.4.19-pre6/drivers/bluetooth/hci_vhci.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/drivers/bluetooth/hci_vhci.h Mon Apr 15 21:54:26 2002 @@ -0,0 +1,50 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * $Id: hci_vhci.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ + */ + +#ifndef __HCI_VHCI_H +#define __HCI_VHCI_H + +#ifdef __KERNEL__ + +struct hci_vhci_struct { + struct hci_dev hdev; + __u32 flags; + wait_queue_head_t read_wait; + struct sk_buff_head readq; + struct fasync_struct *fasync; +}; + +/* VHCI device flags */ +#define VHCI_FASYNC 0x0010 + +#endif /* __KERNEL__ */ + +#define VHCI_DEV "/dev/vhci" +#define VHCI_MINOR 250 + +#endif /* __HCI_VHCI_H */ diff -urN linux-2.4.19-pre6/drivers/char/Config.in linux-2.4.19-pre7/drivers/char/Config.in --- linux-2.4.19-pre6/drivers/char/Config.in Mon Apr 15 21:53:54 2002 +++ linux-2.4.19-pre7/drivers/char/Config.in Mon Apr 15 21:54:26 2002 @@ -11,14 +11,14 @@ tristate 'Standard/generic (8250/16550 and compatible UARTs) serial support' CONFIG_SERIAL if [ "$CONFIG_SERIAL" = "y" ]; then bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE + if [ "$CONFIG_IA64" = "y" ]; then + bool 'Support for serial console port described by EFI HCDP table' CONFIG_SERIAL_HCDP + fi if [ "$CONFIG_ARCH_ACORN" = "y" ]; then tristate ' Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL fi fi -if [ "$CONFIG_ACPI" = "y" ]; then - bool ' Support for serial ports defined by ACPI tables' CONFIG_SERIAL_ACPI -fi dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS @@ -260,6 +260,7 @@ bool ' Generic SiS support' CONFIG_AGP_SIS bool ' ALI chipset support' CONFIG_AGP_ALI bool ' Serverworks LE/HE support' CONFIG_AGP_SWORKS + dep_bool ' HP ZX1 AGP support' CONFIG_AGP_HP_ZX1 $CONFIG_IA64 fi bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM diff -urN linux-2.4.19-pre6/drivers/char/Makefile linux-2.4.19-pre7/drivers/char/Makefile --- linux-2.4.19-pre6/drivers/char/Makefile Mon Apr 15 21:53:54 2002 +++ linux-2.4.19-pre7/drivers/char/Makefile Mon Apr 15 21:54:26 2002 @@ -138,7 +138,7 @@ obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o obj-$(CONFIG_SERIAL) += $(SERIAL) -obj-$(CONFIG_SERIAL_ACPI) += acpi_serial.o +obj-$(CONFIG_SERIAL_HCDP) += hcdp_serial.o obj-$(CONFIG_SERIAL_21285) += serial_21285.o obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o diff -urN linux-2.4.19-pre6/drivers/char/acpi_serial.c linux-2.4.19-pre7/drivers/char/acpi_serial.c --- linux-2.4.19-pre6/drivers/char/acpi_serial.c Wed Nov 14 11:45:41 2001 +++ linux-2.4.19-pre7/drivers/char/acpi_serial.c Wed Dec 31 16:00:00 1969 @@ -1,203 +0,0 @@ -/* - * linux/drivers/char/acpi_serial.c - * - * Copyright (C) 2000 Hewlett-Packard Co. - * Copyright (C) 2000 Khalid Aziz - * - * Detect and initialize the headless console serial port defined in - * SPCR table and debug serial port defined in DBGP table - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/*#include */ - -#undef SERIAL_DEBUG_ACPI - -/* - * Query ACPI tables for a debug and a headless console serial - * port. If found, add them to rs_table[]. A pointer to either SPCR - * or DBGP table is passed as parameter. This function should be called - * before serial_console_init() is called to make sure the SPCR serial - * console will be available for use. IA-64 kernel calls this function - * from within acpi.c when it encounters SPCR or DBGP tables as it parses - * the ACPI 2.0 tables during bootup. - * - */ -void __init setup_serial_acpi(void *tablep) -{ - acpi_ser_t *acpi_ser_p; - struct serial_struct serial_req; - unsigned long iobase; - int global_sys_irq; - -#ifdef SERIAL_DEBUG_ACPI - printk("Entering setup_serial_acpi()\n"); -#endif - - /* Now get the table */ - if (tablep == NULL) { - return; - } - - acpi_ser_p = (acpi_ser_t *)tablep; - - /* - * Perform a sanity check on the table. Table should have a - * signature of "SPCR" or "DBGP" and it should be atleast 52 bytes - * long. - */ - if ((strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE, - ACPI_SIG_LEN) != 0) && - (strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE, - ACPI_SIG_LEN) != 0)) { - return; - } - if (acpi_ser_p->length < 52) { - return; - } - - iobase = (((u64) acpi_ser_p->base_addr.addrh) << 32) | acpi_ser_p->base_addr.addrl; - global_sys_irq = (acpi_ser_p->global_int[3] << 24) | - (acpi_ser_p->global_int[2] << 16) | - (acpi_ser_p->global_int[1] << 8) | - acpi_ser_p->global_int[0]; - -#ifdef SERIAL_DEBUG_ACPI - printk("setup_serial_acpi(): table pointer = 0x%p\n", acpi_ser_p); - printk(" sig = '%c%c%c%c'\n", - acpi_ser_p->signature[0], - acpi_ser_p->signature[1], - acpi_ser_p->signature[2], - acpi_ser_p->signature[3]); - printk(" length = %d\n", acpi_ser_p->length); - printk(" Rev = %d\n", acpi_ser_p->rev); - printk(" Interface type = %d\n", acpi_ser_p->intfc_type); - printk(" Base address = 0x%lX\n", iobase); - printk(" IRQ = %d\n", acpi_ser_p->irq); - printk(" Global System Int = %d\n", global_sys_irq); - printk(" Baud rate = "); - switch (acpi_ser_p->baud) { - case ACPI_SERIAL_BAUD_9600: - printk("9600\n"); - break; - - case ACPI_SERIAL_BAUD_19200: - printk("19200\n"); - break; - - case ACPI_SERIAL_BAUD_57600: - printk("57600\n"); - break; - - case ACPI_SERIAL_BAUD_115200: - printk("115200\n"); - break; - - default: - printk("Huh (%d)\n", acpi_ser_p->baud); - break; - - } - if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) { - printk(" PCI serial port:\n"); - printk(" Bus %d, Device %d, Vendor ID 0x%x, Dev ID 0x%x\n", - acpi_ser_p->pci_bus, acpi_ser_p->pci_dev, - acpi_ser_p->pci_vendor_id, acpi_ser_p->pci_dev_id); - } -#endif - - /* - * Now build a serial_req structure to update the entry in - * rs_table for the headless console port. - */ - switch (acpi_ser_p->intfc_type) { - case ACPI_SERIAL_INTFC_16550: - serial_req.type = PORT_16550; - serial_req.baud_base = BASE_BAUD; - break; - - case ACPI_SERIAL_INTFC_16450: - serial_req.type = PORT_16450; - serial_req.baud_base = BASE_BAUD; - break; - - default: - serial_req.type = PORT_UNKNOWN; - break; - } - if (strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE, - ACPI_SIG_LEN) == 0) { - serial_req.line = ACPI_SERIAL_CONSOLE_PORT; - } - else if (strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE, - ACPI_SIG_LEN) == 0) { - serial_req.line = ACPI_SERIAL_DEBUG_PORT; - } - /* - * Check if this is an I/O mapped address or a memory mapped address - */ - if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_MEM_SPACE) { - serial_req.port = 0; - serial_req.port_high = 0; - serial_req.iomem_base = (void *)ioremap(iobase, 64); - serial_req.io_type = SERIAL_IO_MEM; - } - else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_IO_SPACE) { - serial_req.port = (unsigned long) iobase & 0xffffffff; - serial_req.port_high = (unsigned long)(((u64)iobase) >> 32); - serial_req.iomem_base = NULL; - serial_req.io_type = SERIAL_IO_PORT; - } - else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) { - printk("WARNING: No support for PCI serial console\n"); - return; - } - - /* - * If the table does not have IRQ information, use 0 for IRQ. - * This will force rs_init() to probe for IRQ. - */ - if (acpi_ser_p->length < 53) { - serial_req.irq = 0; - } - else { - serial_req.flags = ASYNC_SKIP_TEST | ASYNC_BOOT_AUTOCONF | - ASYNC_AUTO_IRQ; - if (acpi_ser_p->int_type & - (ACPI_SERIAL_INT_APIC | ACPI_SERIAL_INT_SAPIC)) { - serial_req.irq = global_sys_irq; - } - else if (acpi_ser_p->int_type & ACPI_SERIAL_INT_PCAT) { - serial_req.irq = acpi_ser_p->irq; - } - else { - /* - * IRQ type not being set would mean UART will - * run in polling mode. Do not probe for IRQ in - * that case. - */ - serial_req.flags = ASYNC_SKIP_TEST|ASYNC_BOOT_AUTOCONF; - } - } - - serial_req.xmit_fifo_size = serial_req.custom_divisor = 0; - serial_req.close_delay = serial_req.hub6 = serial_req.closing_wait = 0; - serial_req.iomem_reg_shift = 0; - if (early_serial_setup(&serial_req) < 0) { - printk("early_serial_setup() for ACPI serial console port failed\n"); - return; - } - -#ifdef SERIAL_DEBUG_ACPI - printk("Leaving setup_serial_acpi()\n"); -#endif -} diff -urN linux-2.4.19-pre6/drivers/char/agp/agp.h linux-2.4.19-pre7/drivers/char/agp/agp.h --- linux-2.4.19-pre6/drivers/char/agp/agp.h Mon Apr 15 21:53:54 2002 +++ linux-2.4.19-pre7/drivers/char/agp/agp.h Mon Apr 15 21:54:26 2002 @@ -125,10 +125,12 @@ }; +#define OUTREG64(mmap, addr, val) __raw_writeq((val), (mmap)+(addr)) #define OUTREG32(mmap, addr, val) __raw_writel((val), (mmap)+(addr)) #define OUTREG16(mmap, addr, val) __raw_writew((val), (mmap)+(addr)) #define OUTREG8(mmap, addr, val) __raw_writeb((val), (mmap)+(addr)) +#define INREG64(mmap, addr) __raw_readq((mmap)+(addr)) #define INREG32(mmap, addr) __raw_readl((mmap)+(addr)) #define INREG16(mmap, addr) __raw_readw((mmap)+(addr)) #define INREG8(mmap, addr) __raw_readb((mmap)+(addr)) @@ -378,4 +380,13 @@ #define SVWRKS_POSTFLUSH 0x14 #define SVWRKS_DIRFLUSH 0x0c +/* HP ZX1 SBA registers */ +#define HP_ZX1_CTRL 0x200 +#define HP_ZX1_IBASE 0x300 +#define HP_ZX1_IMASK 0x308 +#define HP_ZX1_PCOM 0x310 +#define HP_ZX1_TCNFG 0x318 +#define HP_ZX1_PDIR_BASE 0x320 +#define HP_ZX1_CACHE_FLUSH 0x428 + #endif /* _AGP_BACKEND_PRIV_H */ diff -urN linux-2.4.19-pre6/drivers/char/agp/agpgart_be.c linux-2.4.19-pre7/drivers/char/agp/agpgart_be.c --- linux-2.4.19-pre6/drivers/char/agp/agpgart_be.c Mon Apr 15 21:53:54 2002 +++ linux-2.4.19-pre7/drivers/char/agp/agpgart_be.c Mon Apr 15 21:54:26 2002 @@ -3440,6 +3440,368 @@ #endif /* CONFIG_AGP_SWORKS */ +#ifdef CONFIG_AGP_HP_ZX1 + +#ifndef log2 +#define log2(x) ffz(~(x)) +#endif + +#define HP_ZX1_IOVA_BASE GB(1UL) +#define HP_ZX1_IOVA_SIZE GB(1UL) +#define HP_ZX1_GART_SIZE (HP_ZX1_IOVA_SIZE / 2) +#define HP_ZX1_SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL + +#define HP_ZX1_PDIR_VALID_BIT 0x8000000000000000UL +#define HP_ZX1_IOVA_TO_PDIR(va) ((va - hp_private.iova_base) >> \ + hp_private.io_tlb_shift) + +static aper_size_info_fixed hp_zx1_sizes[] = +{ + {0, 0, 0}, /* filled in by hp_zx1_fetch_size() */ +}; + +static gatt_mask hp_zx1_masks[] = +{ + {HP_ZX1_PDIR_VALID_BIT, 0} +}; + +static struct _hp_private { + struct pci_dev *ioc; + volatile u8 *registers; + u64 *io_pdir; // PDIR for entire IOVA + u64 *gatt; // PDIR just for GART (subset of above) + u64 gatt_entries; + u64 iova_base; + u64 gart_base; + u64 gart_size; + u64 io_pdir_size; + int io_pdir_owner; // do we own it, or share it with sba_iommu? + int io_page_size; + int io_tlb_shift; + int io_tlb_ps; // IOC ps config + int io_pages_per_kpage; +} hp_private; + +static int __init hp_zx1_ioc_shared(void) +{ + struct _hp_private *hp = &hp_private; + + printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR shared with sba_iommu\n"); + + /* + * IOC already configured by sba_iommu module; just use + * its setup. We assume: + * - IOVA space is 1Gb in size + * - first 512Mb is IOMMU, second 512Mb is GART + */ + hp->io_tlb_ps = INREG64(hp->registers, HP_ZX1_TCNFG); + switch (hp->io_tlb_ps) { + case 0: hp->io_tlb_shift = 12; break; + case 1: hp->io_tlb_shift = 13; break; + case 2: hp->io_tlb_shift = 14; break; + case 3: hp->io_tlb_shift = 16; break; + default: + printk(KERN_ERR PFX "Invalid IOTLB page size " + "configuration 0x%x\n", hp->io_tlb_ps); + hp->gatt = 0; + hp->gatt_entries = 0; + return -ENODEV; + } + hp->io_page_size = 1 << hp->io_tlb_shift; + hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size; + + hp->iova_base = INREG64(hp->registers, HP_ZX1_IBASE) & ~0x1; + hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - HP_ZX1_GART_SIZE; + + hp->gart_size = HP_ZX1_GART_SIZE; + hp->gatt_entries = hp->gart_size / hp->io_page_size; + + hp->io_pdir = phys_to_virt(INREG64(hp->registers, HP_ZX1_PDIR_BASE)); + hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)]; + + if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) { + hp->gatt = 0; + hp->gatt_entries = 0; + printk(KERN_ERR PFX "No reserved IO PDIR entry found; " + "GART disabled\n"); + return -ENODEV; + } + + return 0; +} + +static int __init hp_zx1_ioc_owner(u8 ioc_rev) +{ + struct _hp_private *hp = &hp_private; + + printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR dedicated to GART\n"); + + /* + * Select an IOV page size no larger than system page size. + */ + if (PAGE_SIZE >= KB(64)) { + hp->io_tlb_shift = 16; + hp->io_tlb_ps = 3; + } else if (PAGE_SIZE >= KB(16)) { + hp->io_tlb_shift = 14; + hp->io_tlb_ps = 2; + } else if (PAGE_SIZE >= KB(8)) { + hp->io_tlb_shift = 13; + hp->io_tlb_ps = 1; + } else { + hp->io_tlb_shift = 12; + hp->io_tlb_ps = 0; + } + hp->io_page_size = 1 << hp->io_tlb_shift; + hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size; + + hp->iova_base = HP_ZX1_IOVA_BASE; + hp->gart_size = HP_ZX1_GART_SIZE; + hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - hp->gart_size; + + hp->gatt_entries = hp->gart_size / hp->io_page_size; + hp->io_pdir_size = (HP_ZX1_IOVA_SIZE / hp->io_page_size) * sizeof(u64); + + return 0; +} + +static int __init hp_zx1_ioc_init(void) +{ + struct _hp_private *hp = &hp_private; + struct pci_dev *ioc; + int i; + u8 ioc_rev; + + ioc = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_IOC, NULL); + if (!ioc) { + printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no IOC\n"); + return -ENODEV; + } + hp->ioc = ioc; + + pci_read_config_byte(ioc, PCI_REVISION_ID, &ioc_rev); + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + if (pci_resource_flags(ioc, i) == IORESOURCE_MEM) { + hp->registers = (u8 *) ioremap(pci_resource_start(ioc, + i), + pci_resource_len(ioc, i)); + break; + } + } + if (!hp->registers) { + printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no CSRs\n"); + + return -ENODEV; + } + + /* + * If the IOTLB is currently disabled, we can take it over. + * Otherwise, we have to share with sba_iommu. + */ + hp->io_pdir_owner = (INREG64(hp->registers, HP_ZX1_IBASE) & 0x1) == 0; + + if (hp->io_pdir_owner) + return hp_zx1_ioc_owner(ioc_rev); + + return hp_zx1_ioc_shared(); +} + +static int hp_zx1_fetch_size(void) +{ + int size; + + size = hp_private.gart_size / MB(1); + hp_zx1_sizes[0].size = size; + agp_bridge.current_size = (void *) &hp_zx1_sizes[0]; + return size; +} + +static int hp_zx1_configure(void) +{ + struct _hp_private *hp = &hp_private; + + agp_bridge.gart_bus_addr = hp->gart_base; + agp_bridge.capndx = pci_find_capability(agp_bridge.dev, PCI_CAP_ID_AGP); + pci_read_config_dword(agp_bridge.dev, + agp_bridge.capndx + PCI_AGP_STATUS, &agp_bridge.mode); + + if (hp->io_pdir_owner) { + OUTREG64(hp->registers, HP_ZX1_PDIR_BASE, + virt_to_phys(hp->io_pdir)); + OUTREG64(hp->registers, HP_ZX1_TCNFG, hp->io_tlb_ps); + OUTREG64(hp->registers, HP_ZX1_IMASK, ~(HP_ZX1_IOVA_SIZE - 1)); + OUTREG64(hp->registers, HP_ZX1_IBASE, hp->iova_base | 0x1); + OUTREG64(hp->registers, HP_ZX1_PCOM, + hp->iova_base | log2(HP_ZX1_IOVA_SIZE)); + INREG64(hp->registers, HP_ZX1_PCOM); + } + + return 0; +} + +static void hp_zx1_cleanup(void) +{ + struct _hp_private *hp = &hp_private; + + if (hp->io_pdir_owner) + OUTREG64(hp->registers, HP_ZX1_IBASE, 0); + iounmap((void *) hp->registers); +} + +static void hp_zx1_tlbflush(agp_memory * mem) +{ + struct _hp_private *hp = &hp_private; + + OUTREG64(hp->registers, HP_ZX1_PCOM, + hp->gart_base | log2(hp->gart_size)); + INREG64(hp->registers, HP_ZX1_PCOM); +} + +static int hp_zx1_create_gatt_table(void) +{ + struct _hp_private *hp = &hp_private; + int i; + + if (hp->io_pdir_owner) { + hp->io_pdir = (u64 *) __get_free_pages(GFP_KERNEL, + get_order(hp->io_pdir_size)); + if (!hp->io_pdir) { + printk(KERN_ERR PFX "Couldn't allocate contiguous " + "memory for I/O PDIR\n"); + hp->gatt = 0; + hp->gatt_entries = 0; + return -ENOMEM; + } + memset(hp->io_pdir, 0, hp->io_pdir_size); + + hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)]; + } + + for (i = 0; i < hp->gatt_entries; i++) { + hp->gatt[i] = (unsigned long) agp_bridge.scratch_page; + } + + return 0; +} + +static int hp_zx1_free_gatt_table(void) +{ + struct _hp_private *hp = &hp_private; + + if (hp->io_pdir_owner) + free_pages((unsigned long) hp->io_pdir, + get_order(hp->io_pdir_size)); + else + hp->gatt[0] = HP_ZX1_SBA_IOMMU_COOKIE; + return 0; +} + +static int hp_zx1_insert_memory(agp_memory * mem, off_t pg_start, int type) +{ + struct _hp_private *hp = &hp_private; + int i, k; + off_t j, io_pg_start; + int io_pg_count; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + + io_pg_start = hp->io_pages_per_kpage * pg_start; + io_pg_count = hp->io_pages_per_kpage * mem->page_count; + if ((io_pg_start + io_pg_count) > hp->gatt_entries) { + return -EINVAL; + } + + j = io_pg_start; + while (j < (io_pg_start + io_pg_count)) { + if (hp->gatt[j]) { + return -EBUSY; + } + j++; + } + + if (mem->is_flushed == FALSE) { + CACHE_FLUSH(); + mem->is_flushed = TRUE; + } + + for (i = 0, j = io_pg_start; i < mem->page_count; i++) { + unsigned long paddr; + + paddr = mem->memory[i]; + for (k = 0; + k < hp->io_pages_per_kpage; + k++, j++, paddr += hp->io_page_size) { + hp->gatt[j] = agp_bridge.mask_memory(paddr, type); + } + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static int hp_zx1_remove_memory(agp_memory * mem, off_t pg_start, int type) +{ + struct _hp_private *hp = &hp_private; + int i, io_pg_start, io_pg_count; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + + io_pg_start = hp->io_pages_per_kpage * pg_start; + io_pg_count = hp->io_pages_per_kpage * mem->page_count; + for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) { + hp->gatt[i] = agp_bridge.scratch_page; + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static unsigned long hp_zx1_mask_memory(unsigned long addr, int type) +{ + return HP_ZX1_PDIR_VALID_BIT | addr; +} + +static unsigned long hp_zx1_unmask_memory(unsigned long addr) +{ + return addr & ~(HP_ZX1_PDIR_VALID_BIT); +} + +static int __init hp_zx1_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = hp_zx1_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.dev_private_data = NULL; + agp_bridge.size_type = FIXED_APER_SIZE; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = hp_zx1_configure; + agp_bridge.fetch_size = hp_zx1_fetch_size; + agp_bridge.cleanup = hp_zx1_cleanup; + agp_bridge.tlb_flush = hp_zx1_tlbflush; + agp_bridge.mask_memory = hp_zx1_mask_memory; + agp_bridge.unmask_memory = hp_zx1_unmask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = hp_zx1_create_gatt_table; + agp_bridge.free_gatt_table = hp_zx1_free_gatt_table; + agp_bridge.insert_memory = hp_zx1_insert_memory; + agp_bridge.remove_memory = hp_zx1_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; + agp_bridge.agp_alloc_page = agp_generic_alloc_page; + agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.cant_use_aperture = 1; + + return hp_zx1_ioc_init(); + + (void) pdev; /* unused */ +} + +#endif /* CONFIG_AGP_HP_ZX1 */ /* per-chipset initialization data. * note -- all chipsets for a single vendor MUST be grouped together @@ -3739,6 +4101,15 @@ via_generic_setup }, #endif /* CONFIG_AGP_VIA */ +#ifdef CONFIG_AGP_HP_ZX1 + { PCI_DEVICE_ID_HP_ZX1_LBA, + PCI_VENDOR_ID_HP, + HP_ZX1, + "HP", + "ZX1", + hp_zx1_setup }, +#endif + { 0, }, /* dummy final entry, always present */ }; @@ -3965,6 +4336,23 @@ #endif /* CONFIG_AGP_SWORKS */ +#ifdef CONFIG_AGP_HP_ZX1 + if (dev->vendor == PCI_VENDOR_ID_HP) { + do { + /* ZX1 LBAs can be either PCI or AGP bridges */ + if (pci_find_capability(dev, PCI_CAP_ID_AGP)) { + printk(KERN_INFO PFX "Detected HP ZX1 AGP " + "chipset at %s\n", dev->slot_name); + agp_bridge.type = HP_ZX1; + agp_bridge.dev = dev; + return hp_zx1_setup(dev); + } + dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, dev); + } while (dev); + return -ENODEV; + } +#endif /* CONFIG_AGP_HP_ZX1 */ + /* find capndx */ cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); if (cap_ptr == 0x00) diff -urN linux-2.4.19-pre6/drivers/char/drm/drm_agpsupport.h linux-2.4.19-pre7/drivers/char/drm/drm_agpsupport.h --- linux-2.4.19-pre6/drivers/char/drm/drm_agpsupport.h Mon Apr 15 21:53:54 2002 +++ linux-2.4.19-pre7/drivers/char/drm/drm_agpsupport.h Mon Apr 15 21:54:26 2002 @@ -317,6 +317,8 @@ break; #endif + case HP_ZX1: head->chipset = "HP ZX1"; break; + default: head->chipset = "Unknown"; break; } #if LINUX_VERSION_CODE <= 0x020408 diff -urN linux-2.4.19-pre6/drivers/char/hcdp_serial.c linux-2.4.19-pre7/drivers/char/hcdp_serial.c --- linux-2.4.19-pre6/drivers/char/hcdp_serial.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/drivers/char/hcdp_serial.c Mon Apr 15 21:54:26 2002 @@ -0,0 +1,221 @@ +/* + * linux/arch/ia64/kernel/hcdp_serial.c + * + * Copyright (C) 2002 Hewlett-Packard Co. + * Copyright (C) 2002 Khalid Aziz + * + * Parse the EFI HCDP table to locate serial console and debug ports + * and initialize them + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef SERIAL_DEBUG_HCDP + +extern struct serial_state rs_table[]; +extern int serial_nr_ports; + +/* + * Parse the HCDP table to find descriptions for headless console and + * debug serial ports and add them to rs_table[]. A pointer to HCDP + * table is passed as parameter. This function should be called + * before serial_console_init() is called to make sure the HCDP serial + * console will be available for use. IA-64 kernel calls this function + * from setup_arch() after the EFI and ACPI tables have been parsed. + */ +void __init setup_serial_hcdp(void *tablep) +{ + hcdp_t hcdp; + hcdp_dev_t *hcdp_dev; + struct serial_struct serial_req; + unsigned long iobase; + int global_sys_irq; + int i, nr; + int shift_once = 1; + +#ifdef SERIAL_DEBUG_HCDP + printk("Entering setup_serial_hcdp()\n"); +#endif + + /* Verify we have a valid table pointer */ + if (tablep == NULL) { + return; + } + + /* + * We do not trust firmware to give us a table starting at an + * aligned address. Make a local copy of the HCDP table with + * aligned structures. + */ + memcpy(&hcdp, tablep, sizeof(hcdp)); + + /* + * Perform a sanity check on the table. Table should have a + * signature of "HCDP" and it should be atleast 82 bytes + * long to have any useful information. + */ + if ((strncmp(hcdp.signature, HCDP_SIGNATURE, + HCDP_SIG_LEN) != 0)) { + return; + } + if (hcdp.len < 82) { + return; + } + +#ifdef SERIAL_DEBUG_HCDP + printk("setup_serial_hcdp(): table pointer = 0x%p\n", tablep); + printk(" sig = '%c%c%c%c'\n", + hcdp.signature[0], + hcdp.signature[1], + hcdp.signature[2], + hcdp.signature[3]); + printk(" length = %d\n", hcdp.len); + printk(" Rev = %d\n", hcdp.rev); + printk(" OEM ID = %c%c%c%c%c%c\n", + hcdp.oemid[0], hcdp.oemid[1], hcdp.oemid[2], + hcdp.oemid[3], hcdp.oemid[4], hcdp.oemid[5]); + printk(" Number of entries = %d\n", hcdp.num_entries); +#endif + + /* + * Parse each device entry + */ + for (nr=0; nrtype != HCDP_DEV_CONSOLE) + continue; + + iobase = (u64)(hcdp_dev->base_addr.addrhi)<<32 | hcdp_dev->base_addr.addrlo; + global_sys_irq = hcdp_dev->global_int; +#ifdef SERIAL_DEBUG_HCDP + printk(" type = %s\n", + ((hcdp_dev->type == HCDP_DEV_CONSOLE)?"Headless Console":((hcdp_dev->type == HCDP_DEV_DEBUG)?"Debug port":"Huh????"))); + printk(" Base address space = %s\n", ((hcdp_dev->base_addr.space_id == ACPI_MEM_SPACE)?"Memory Space":((hcdp_dev->base_addr.space_id == ACPI_IO_SPACE)?"I/O space":"PCI space"))); + printk(" Base address = 0x%p\n", iobase); + printk(" Global System Int = %d\n", global_sys_irq); + printk(" Baud rate = %d\n", hcdp_dev->baud); + printk(" Bits = %d\n", hcdp_dev->bits); + printk(" Clock rate = %d\n", hcdp_dev->clock_rate); + if (hcdp_dev->base_addr.space_id == ACPI_PCICONF_SPACE) { + printk(" PCI serial port:\n"); + printk(" Bus %d, Device %d, Vendor ID 0x%x, Dev ID 0x%x\n", + hcdp_dev->pci_bus, hcdp_dev->pci_dev, + hcdp_dev->pci_vendor_id, hcdp_dev->pci_dev_id); + } +#endif + + + /* + * Now build a serial_req structure to update the entry in + * rs_table for the headless console port. + */ + if (hcdp_dev->clock_rate) + serial_req.baud_base = hcdp_dev->clock_rate; + else + serial_req.baud_base = DEFAULT_BAUD_BASE; + /* + * Check if this is an I/O mapped address or a memory mapped address + */ + if (hcdp_dev->base_addr.space_id == ACPI_MEM_SPACE) { + serial_req.port = 0; + serial_req.port_high = 0; + serial_req.iomem_base = (void *)ioremap(iobase, 64); + serial_req.io_type = SERIAL_IO_MEM; + } + else if (hcdp_dev->base_addr.space_id == ACPI_IO_SPACE) { + serial_req.port = (unsigned long) iobase & 0xffffffff; + serial_req.port_high = (unsigned long)(((u64)iobase) >> 32); + serial_req.iomem_base = NULL; + serial_req.io_type = SERIAL_IO_PORT; + } + else if (hcdp_dev->base_addr.space_id == ACPI_PCICONF_SPACE) { + printk("WARNING: No support for PCI serial console\n"); + return; + } + + /* + * Check if HCDP defines a port already in rs_table + */ + for (i = 0; i < serial_nr_ports; i++) { + if ((rs_table[i].port == serial_req.port) && + (rs_table[i].iomem_base==serial_req.iomem_base)) + break; + } + if (i == serial_nr_ports) { + /* + * We have reserved a slot for HCDP defined console + * port at HCDP_SERIAL_CONSOLE_PORT in rs_table + * which is not 0. This means using this slot would + * put the console at a device other than ttyS0. + * Users expect to see the console at ttyS0. Now + * that we have determined HCDP does describe a + * serial console and it is not one of the compiled + * in ports, let us move the entries in rs_table + * up by a slot towards HCDP_SERIAL_CONSOLE_PORT to + * make room for the HCDP console at ttyS0. We may go + * through this loop more than once if + * early_serial_setup() fails. Make sure we shift the + * entries in rs_table only once. + */ + if (shift_once) { + int j; + + for (j=HCDP_SERIAL_CONSOLE_PORT; j>0; j--) + memcpy(rs_table+j, rs_table+j-1, + sizeof(struct serial_state)); + shift_once = 0; + } + serial_req.line = 0; + } + else + serial_req.line = i; + + /* + * If the table does not have IRQ information, use 0 for IRQ. + * This will force rs_init() to probe for IRQ. + */ + serial_req.irq = global_sys_irq; + if (global_sys_irq == 0) { + serial_req.flags = ASYNC_SKIP_TEST|ASYNC_BOOT_AUTOCONF; + } + else { + serial_req.flags = ASYNC_SKIP_TEST|ASYNC_BOOT_AUTOCONF| + ASYNC_AUTO_IRQ; + } + + serial_req.xmit_fifo_size = serial_req.custom_divisor = 0; + serial_req.close_delay = serial_req.hub6 = serial_req.closing_wait = 0; + serial_req.iomem_reg_shift = 0; + if (early_serial_setup(&serial_req) < 0) { + printk("setup_serial_hcdp(): early_serial_setup() for HCDP serial console port failed. Will try any additional consoles in HCDP.\n"); + continue; + } + else + if (hcdp_dev->type == HCDP_DEV_CONSOLE) + break; +#ifdef SERIAL_DEBUG_HCDP + printk("\n"); +#endif + } + +#ifdef SERIAL_DEBUG_HCDP + printk("Leaving setup_serial_hcdp()\n"); +#endif +} diff -urN linux-2.4.19-pre6/drivers/char/i810-tco.c linux-2.4.19-pre7/drivers/char/i810-tco.c --- linux-2.4.19-pre6/drivers/char/i810-tco.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-pre7/drivers/char/i810-tco.c Mon Apr 15 21:54:27 2002 @@ -1,5 +1,5 @@ /* - * i810-tco 0.02: TCO timer driver for i810 chipsets + * i810-tco 0.03: TCO timer driver for i8xx chipsets * * (c) Copyright 2000 kernel concepts , All Rights Reserved. * http://www.kernelconcepts.de @@ -17,17 +17,22 @@ * developed for * Jentro AG, Haar/Munich (Germany) * - * TCO timer driver for i810/i815 chipsets + * TCO timer driver for i8xx chipsets * based on softdog.c by Alan Cox * - * The TCO timer is implemented in the 82801AA (82801AB) chip, - * see intel documentation from http://developer.intel.com, - * order number 290655-003 + * The TCO timer is implemented in the following I/O controller hubs: + * (See the intel documentation on http://developer.intel.com.) + * 82801AA & 82801AB chip : document number 290655-003, 290677-004, + * 82801BA & 82801BAM chip : document number 290687-002, 298242-005, + * 82801CA & 82801CAM chip : document number 290716-001, 290718-001 * * 20000710 Nils Faerber * Initial Version 0.01 * 20000728 Nils Faerber * 0.02 Fix for SMI_EN->TCO_EN bit, some cleanups + * 20020224 Joel Becker, Wim Van Sebroeck + * 0.03 Support for 82801CA(M) chipset, timer margin needs to be > 3, + * add support for WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT. */ #include @@ -46,13 +51,13 @@ #include "i810-tco.h" -/* Just in case that the PCI vendor and device IDs are not yet defined */ -#ifndef PCI_DEVICE_ID_INTEL_82801AA_0 -#define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410 -#endif - /* Default expire timeout */ -#define TIMER_MARGIN 50 /* steps of 0.6sec, 2 0x3f || tmrval < 0x03) + if (tmrval > 0x3f || tmrval < 0x04) return -1; spin_lock(&tco_lock); @@ -235,7 +240,7 @@ if (get_user(u_margin, (int *) arg)) return -EFAULT; new_margin = (u_margin * 10 + 5) / 6; - if ((new_margin < 3) || (new_margin > 63)) + if ((new_margin < 4) || (new_margin > 63)) return -EINVAL; if (tco_timer_settimer((unsigned char)new_margin)) return -EINVAL; @@ -260,6 +265,8 @@ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, }; MODULE_DEVICE_TABLE (pci, i810tco_pci_tbl); @@ -294,7 +301,7 @@ ACPIBASE = badr; /* Something's wrong here, ACPIBASE has to be set */ if (badr == 0x0001 || badr == 0x0000) { - printk (KERN_ERR "i810tco init: failed to get TCOBASE address\n"); + printk (KERN_ERR TCO_MODULE_NAME " init: failed to get TCOBASE address\n"); return 0; } /* @@ -306,7 +313,7 @@ pci_write_config_byte (i810tco_pci, 0xd4, val1); pci_read_config_byte (i810tco_pci, 0xd4, &val1); if (val1 & 0x02) { - printk (KERN_ERR "i810tco init: failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); + printk (KERN_ERR TCO_MODULE_NAME " init: failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); return 0; /* Cannot reset NO_REBOOT bit */ } } @@ -343,21 +350,21 @@ if (!i810tco_getdevice () || i810tco_pci == NULL) return -ENODEV; if (!request_region (TCOBASE, 0x10, "i810 TCO")) { - printk (KERN_ERR - "i810 TCO timer: I/O address 0x%04x already in use\n", + printk (KERN_ERR TCO_MODULE_NAME + ": I/O address 0x%04x already in use\n", TCOBASE); return -EIO; } if (misc_register (&i810tco_miscdev) != 0) { release_region (TCOBASE, 0x10); - printk (KERN_ERR "i810 TCO timer: cannot register miscdev\n"); + printk (KERN_ERR TCO_MODULE_NAME ": cannot register miscdev\n"); return -EIO; } tco_timer_settimer ((unsigned char) i810_margin); tco_timer_reload (); - printk (KERN_INFO - "i810 TCO timer: V0.02, timer margin: %d sec (0x%04x)\n", + printk (KERN_INFO TCO_MODULE_NAME + ": timer margin: %d sec (0x%04x)\n", (int) (i810_margin * 6 / 10), TCOBASE); return 0; } diff -urN linux-2.4.19-pre6/drivers/char/i810-tco.h linux-2.4.19-pre7/drivers/char/i810-tco.h --- linux-2.4.19-pre6/drivers/char/i810-tco.h Fri Aug 11 15:57:57 2000 +++ linux-2.4.19-pre7/drivers/char/i810-tco.h Mon Apr 15 21:54:27 2002 @@ -1,5 +1,5 @@ /* - * i810-tco 0.02: TCO timer driver for i810 chipsets + * i810-tco 0.03: TCO timer driver for i8xx chipsets * * (c) Copyright 2000 kernel concepts , All Rights Reserved. * http://www.kernelconcepts.de @@ -17,12 +17,14 @@ * developed for * Jentro AG, Haar/Munich (Germany) * - * TCO timer driver for i810 chipsets + * TCO timer driver for i8xx chipsets * based on softdog.c by Alan Cox * - * The TCO timer is implemented in the 82801AA (82801AB) chip, - * see intel documentation from http://developer.intel.com, - * order number 290655-003 + * The TCO timer is implemented in the following I/O controller hubs: + * (See the intel documentation on http://developer.intel.com.) + * 82801AA & 82801AB chip : document number 290655-003, 290677-004, + * 82801BA & 82801BAM chip : document number 290687-002, 298242-005, + * 82801CA & 82801CAM chip : document number 290716-001, 290718-001 * * For history see i810-tco.c */ diff -urN linux-2.4.19-pre6/drivers/char/i810_rng.c linux-2.4.19-pre7/drivers/char/i810_rng.c --- linux-2.4.19-pre6/drivers/char/i810_rng.c Thu Oct 11 09:14:32 2001 +++ linux-2.4.19-pre7/drivers/char/i810_rng.c Mon Apr 15 21:54:27 2002 @@ -35,7 +35,7 @@ /* * core module and version information */ -#define RNG_VERSION "0.9.6" +#define RNG_VERSION "0.9.7" #define RNG_MODULE_NAME "i810_rng" #define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION #define PFX RNG_MODULE_NAME ": " @@ -334,7 +334,8 @@ static struct pci_device_id rng_pci_tbl[] __initdata = { { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, }, { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, }, - { 0x8086, 0x1130, PCI_ANY_ID, PCI_ANY_ID, }, + { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, }, + { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, }; MODULE_DEVICE_TABLE (pci, rng_pci_tbl); diff -urN linux-2.4.19-pre6/drivers/char/raw.c linux-2.4.19-pre7/drivers/char/raw.c --- linux-2.4.19-pre6/drivers/char/raw.c Sat Sep 22 20:35:43 2001 +++ linux-2.4.19-pre7/drivers/char/raw.c Mon Apr 15 21:54:27 2002 @@ -34,6 +34,7 @@ int raw_open(struct inode *, struct file *); int raw_release(struct inode *, struct file *); int raw_ctl_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +int raw_ioctl(struct inode *, struct file *, unsigned int, unsigned long); static struct file_operations raw_fops = { @@ -41,6 +42,7 @@ write: raw_write, open: raw_open, release: raw_release, + ioctl: raw_ioctl, }; static struct file_operations raw_ctl_fops = { @@ -160,6 +162,25 @@ +/* Forward ioctls to the underlying block device. */ +int raw_ioctl(struct inode *inode, + struct file *flip, + unsigned int command, + unsigned long arg) +{ + int minor = minor(inode->i_rdev), err; + struct block_device *b; + if (minor < 1 && minor > 255) + return -ENODEV; + + b = raw_devices[minor].binding; + err = -EINVAL; + if (b && b->bd_inode && b->bd_op && b->bd_op->ioctl) { + err = b->bd_op->ioctl(b->bd_inode, NULL, command, arg); + } + return err; +} + /* * Deal with ioctls against the raw-device control interface, to bind * and unbind other raw devices. diff -urN linux-2.4.19-pre6/drivers/char/serial.c linux-2.4.19-pre7/drivers/char/serial.c --- linux-2.4.19-pre6/drivers/char/serial.c Mon Apr 15 21:53:54 2002 +++ linux-2.4.19-pre7/drivers/char/serial.c Mon Apr 15 21:54:28 2002 @@ -326,11 +326,12 @@ MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA"); #endif /* CONFIG_SERIAL_RSA */ -static struct serial_state rs_table[RS_TABLE_SIZE] = { +struct serial_state rs_table[RS_TABLE_SIZE] = { SERIAL_PORT_DFNS /* Defined in serial.h */ }; #define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) +int serial_nr_ports = NR_PORTS; #if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)) #define NR_PCI_BOARDS 8 @@ -3258,14 +3259,17 @@ int ret; unsigned long flags; + /* + * Return zero characters for ports not claimed by driver. + */ + if (state->type == PORT_UNKNOWN) { + return 0; /* ignore unused ports */ + } + ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d", state->line, uart_config[state->type].name, - state->port, state->irq); - - if (!state->port || (state->type == PORT_UNKNOWN)) { - ret += sprintf(buf+ret, "\n"); - return ret; - } + (state->port ? state->port : (long)state->iomem_base), + state->irq); /* * Figure out the current RS-232 lines diff -urN linux-2.4.19-pre6/drivers/ide/ide-cd.c linux-2.4.19-pre7/drivers/ide/ide-cd.c --- linux-2.4.19-pre6/drivers/ide/ide-cd.c Mon Apr 15 21:53:55 2002 +++ linux-2.4.19-pre7/drivers/ide/ide-cd.c Mon Apr 15 21:54:31 2002 @@ -2644,7 +2644,9 @@ * but they do support reading TOC & audio datas */ if (strcmp (drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 || - strcmp (drive->id->model, "MATSHITADVD-ROM SR-8186") == 0) + strcmp (drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 || + strcmp (drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 || + strcmp (drive->id->model, "MATSHITADVD-ROM SR-8174") == 0) CDROM_CONFIG_FLAGS (drive)->audio_play = 1; #if ! STANDARD_ATAPI diff -urN linux-2.4.19-pre6/drivers/ide/ide-pci.c linux-2.4.19-pre7/drivers/ide/ide-pci.c --- linux-2.4.19-pre6/drivers/ide/ide-pci.c Mon Apr 15 21:53:55 2002 +++ linux-2.4.19-pre7/drivers/ide/ide-pci.c Mon Apr 15 21:54:31 2002 @@ -45,6 +45,7 @@ #define DEVID_PIIX4U3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9}) #define DEVID_PIIX4U4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8}) #define DEVID_PIIX4U5 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10}) +#define DEVID_PIIX4U6 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11}) #define DEVID_VIA_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561}) #define DEVID_MR_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1}) #define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1}) @@ -400,6 +401,7 @@ {DEVID_PIIX4U3, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX4U4, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX4U5, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4U6, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_MR_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, {DEVID_VP_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, diff -urN linux-2.4.19-pre6/drivers/ide/ide-pmac.c linux-2.4.19-pre7/drivers/ide/ide-pmac.c --- linux-2.4.19-pre6/drivers/ide/ide-pmac.c Mon Feb 25 11:37:57 2002 +++ linux-2.4.19-pre7/drivers/ide/ide-pmac.c Mon Apr 15 21:54:31 2002 @@ -26,11 +26,14 @@ #include #include #include +#include + #include #include #include #include #include +#include #include #include #include @@ -55,11 +58,18 @@ int aapl_bus_id; struct device_node* node; u32 timings[2]; - struct resource* reg_resource; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC + /* Those fields are duplicating what is in hwif. We currently + * can't use the hwif ones because of some assumptions that are + * beeing done by the generic code about the kind of dma controller + * and format of the dma table. This will have to be fixed though. + */ volatile struct dbdma_regs* dma_regs; - struct dbdma_cmd* dma_table; - struct resource* dma_resource; + struct dbdma_cmd* dma_table_cpu; + dma_addr_t dma_table_dma; + struct scatterlist* sg_table; + int sg_nents; + int sg_dma_direction; #endif } pmac_ide[MAX_HWIFS] __pmacdata; @@ -308,7 +318,7 @@ ide_hwifs[ix].tuneproc = pmac_ide_tuneproc; ide_hwifs[ix].selectproc = pmac_ide_selectproc; ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset; - if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table) { + if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table_cpu) { ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO if (!noautodma) @@ -823,6 +833,8 @@ struct pmac_ide_hwif* pmhw; int *bidp; int in_bay = 0; + u8 pbus, pid; + struct pci_dev *pdev = NULL; /* * If this node is not under a mac-io or dbdma node, @@ -841,6 +853,15 @@ continue; } + /* We need to find the pci_dev of the mac-io holding the + * IDE interface + */ + if (pci_device_from_OF_node(tp, &pbus, &pid) == 0) + pdev = pci_find_slot(pbus, pid); + if (pdev == NULL) + printk(KERN_WARNING "ide: no PCI host for device %s, DMA disabled\n", + np->full_name); + /* * If this slot is taken (e.g. by ide-pci.c) try the next one. */ @@ -860,8 +881,7 @@ if (np->n_addrs > 1 && np->addrs[1].size > 0x100) np->addrs[1].size = 0x100; - pmhw->reg_resource = request_OF_resource(np, 0, " (mac-io IDE IO)"); - if (!pmhw->reg_resource) { + if (request_OF_resource(np, 0, " (mac-io IDE IO)") == NULL) { printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name); continue; } @@ -935,6 +955,7 @@ hwif->chipset = ide_pmac; hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay; hwif->udma_four = (pmhw->kind == controller_kl_ata4_80); + hwif->pci_dev = pdev; #ifdef CONFIG_PMAC_PBOOK if (in_bay && check_media_bay_by_base(base, MB_CD) == 0) hwif->noprobe = 0; @@ -964,13 +985,14 @@ static void __init pmac_ide_setup_dma(struct device_node *np, int ix) { - pmac_ide[ix].dma_resource = request_OF_resource(np, 1, " (mac-io IDE DMA)"); - if (!pmac_ide[ix].dma_resource) { + struct pmac_ide_hwif *pmif = &pmac_ide[ix]; + + if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) { printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name); return; } - pmac_ide[ix].dma_regs = + pmif->dma_regs = (volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200); /* @@ -978,14 +1000,24 @@ * The +2 is +1 for the stop command and +1 to allow for * aligning the start address to a multiple of 16 bytes. */ - pmac_ide[ix].dma_table = (struct dbdma_cmd*) - kmalloc((MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), GFP_KERNEL); - if (pmac_ide[ix].dma_table == 0) { + pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent( + ide_hwifs[ix].pci_dev, + (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), + &pmif->dma_table_dma); + if (pmif->dma_table_cpu == NULL) { printk(KERN_ERR "%s: unable to allocate DMA command list\n", ide_hwifs[ix].name); return; } + pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS, + GFP_KERNEL); + if (pmif->sg_table == NULL) { + pci_free_consistent( ide_hwifs[ix].pci_dev, + (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), + pmif->dma_table_cpu, pmif->dma_table_dma); + return; + } ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO if (!noautodma) @@ -993,65 +1025,118 @@ #endif } +static int +pmac_ide_build_sglist (int ix, struct request *rq) +{ + ide_hwif_t *hwif = &ide_hwifs[ix]; + struct pmac_ide_hwif *pmif = &pmac_ide[ix]; + struct buffer_head *bh; + struct scatterlist *sg = pmif->sg_table; + int nents = 0; + + if (hwif->sg_dma_active) + BUG(); + + if (rq->cmd == READ) + pmif->sg_dma_direction = PCI_DMA_FROMDEVICE; + else + pmif->sg_dma_direction = PCI_DMA_TODEVICE; + bh = rq->bh; + do { + unsigned char *virt_addr = bh->b_data; + unsigned int size = bh->b_size; + + if (nents >= MAX_DCMDS) + return 0; + + while ((bh = bh->b_reqnext) != NULL) { + if ((virt_addr + size) != (unsigned char *) bh->b_data) + break; + size += bh->b_size; + } + memset(&sg[nents], 0, sizeof(*sg)); + sg[nents].address = virt_addr; + sg[nents].length = size; + nents++; + } while (bh != NULL); + + return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction); +} + +static int +pmac_ide_raw_build_sglist (int ix, struct request *rq) +{ + ide_hwif_t *hwif = &ide_hwifs[ix]; + struct pmac_ide_hwif *pmif = &pmac_ide[ix]; + struct scatterlist *sg = hwif->sg_table; + int nents = 0; + ide_task_t *args = rq->special; + unsigned char *virt_addr = rq->buffer; + int sector_count = rq->nr_sectors; + +// if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA) || +// (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA_EXT)) + if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE) + pmif->sg_dma_direction = PCI_DMA_TODEVICE; + else + pmif->sg_dma_direction = PCI_DMA_FROMDEVICE; + + if (sector_count > 128) { + memset(&sg[nents], 0, sizeof(*sg)); + sg[nents].address = virt_addr; + sg[nents].length = 128 * SECTOR_SIZE; + nents++; + virt_addr = virt_addr + (128 * SECTOR_SIZE); + sector_count -= 128; + } + memset(&sg[nents], 0, sizeof(*sg)); + sg[nents].address = virt_addr; + sg[nents].length = sector_count * SECTOR_SIZE; + nents++; + + return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction); +} + /* * pmac_ide_build_dmatable builds the DBDMA command list * for a transfer and sets the DBDMA channel to point to it. */ -static int __pmac +static int pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr) { - struct dbdma_cmd *table, *tstart; - int count = 0; + struct dbdma_cmd *table; + int i, count = 0; struct request *rq = HWGROUP(drive)->rq; - struct buffer_head *bh = rq->bh; - unsigned int size, addr; volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs; + struct scatterlist *sg; - table = tstart = (struct dbdma_cmd *) DBDMA_ALIGN(pmac_ide[ix].dma_table); + /* DMA table is already aligned */ + table = (struct dbdma_cmd *) pmac_ide[ix].dma_table_cpu; -#ifdef IDE_PMAC_DEBUG - if (in_le32(&dma->status) & (RUN|ACTIVE)) - printk("ide-pmac: channel status not stopped ! (%x)\n", - in_le32(&dma->status)); -#endif - /* Make sure channel is stopped and all error conditions are clear */ + /* Make sure DMA controller is stopped (necessary ?) */ out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16); while (in_le32(&dma->status) & RUN) udelay(1); - do { - /* - * Determine addr and size of next buffer area. We assume that - * individual virtual buffers are always composed linearly in - * physical memory. For example, we assume that any 8kB buffer - * is always composed of two adjacent physical 4kB pages rather - * than two possibly non-adjacent physical 4kB pages. - */ - if (bh == NULL) { /* paging requests have (rq->bh == NULL) */ - addr = virt_to_bus(rq->buffer); - size = rq->nr_sectors << 9; - } else { - /* group sequential buffers into one large buffer */ - addr = virt_to_bus(bh->b_data); - size = bh->b_size; - while ((bh = bh->b_reqnext) != NULL) { - if ((addr + size) != virt_to_bus(bh->b_data)) - break; - size += bh->b_size; - } - } + /* Build sglist */ + if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) + pmac_ide[ix].sg_nents = i = pmac_ide_raw_build_sglist(ix, rq); + else + pmac_ide[ix].sg_nents = i = pmac_ide_build_sglist(ix, rq); + if (!i) + return 0; - /* - * Fill in the next DBDMA command block. - * Note that one DBDMA command can transfer - * at most 65535 bytes. - */ -#ifdef IDE_PMAC_DEBUG - if (size & 0x01) - printk("ide-pmac: odd size transfer ! (%d)\n", size); -#endif - while (size) { - unsigned int tc = (size < 0xfe00)? size: 0xfe00; + /* Build DBDMA commands list */ + sg = pmac_ide[ix].sg_table; + while (i) { + u32 cur_addr; + u32 cur_len; + + cur_addr = sg_dma_address(sg); + cur_len = sg_dma_len(sg); + + while (cur_len) { + unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00; if (++count >= MAX_DCMDS) { printk(KERN_WARNING "%s: DMA table too small\n", @@ -1060,15 +1145,17 @@ } st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE); st_le16(&table->req_count, tc); - st_le32(&table->phy_addr, addr); + st_le32(&table->phy_addr, cur_addr); table->cmd_dep = 0; table->xfer_status = 0; table->res_count = 0; - addr += tc; - size -= tc; + cur_addr += tc; + cur_len -= tc; ++table; } - } while (bh != NULL); + sg++; + i--; + } /* convert the last command to an input/output last command */ if (count) @@ -1080,10 +1167,23 @@ memset(table, 0, sizeof(struct dbdma_cmd)); out_le16(&table->command, DBDMA_STOP); - out_le32(&dma->cmdptr, virt_to_bus(tstart)); + out_le32(&dma->cmdptr, pmac_ide[ix].dma_table_dma); return 1; } +/* Teardown mappings after DMA has completed. */ +static void +pmac_ide_destroy_dmatable (ide_drive_t *drive, int ix) +{ + struct pci_dev *dev = HWIF(drive)->pci_dev; + struct scatterlist *sg = pmac_ide[ix].sg_table; + int nents = pmac_ide[ix].sg_nents; + + if (nents) { + pci_unmap_sg(dev, sg, nents, pmac_ide[ix].sg_dma_direction); + pmac_ide[ix].sg_nents = 0; + } +} static __inline__ unsigned char dma_bits_to_command(unsigned char bits) @@ -1237,6 +1337,7 @@ volatile struct dbdma_regs *dma; byte unit = (drive->select.b.unit & 0x01); byte ata4; + int reading = 0; /* Can we stuff a pointer to our intf structure in config_data * or select_data in hwif ? @@ -1259,22 +1360,31 @@ pmac_ide_check_dma(drive); break; case ide_dma_read: + reading = 1; case ide_dma_write: - if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write)) + SELECT_READ_WRITE(HWIF(drive),drive,func); + if (!pmac_ide_build_dmatable(drive, ix, !reading)) return 1; /* Apple adds 60ns to wrDataSetup on reads */ if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) { out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE), pmac_ide[ix].timings[unit] + - ((func == ide_dma_read) ? 0x00800000UL : 0)); + (reading ? 0x00800000UL : 0)); (void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE)); } drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); - OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA, - IDE_COMMAND_REG); + if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) && + (drive->addressing == 1)) { + ide_task_t *args = HWGROUP(drive)->rq->special; + OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); + } else if (drive->addressing) { + OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG); + } else { + OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); + } case ide_dma_begin: out_le32(&dma->control, (RUN << 16) | RUN); /* Make sure it gets to the controller right now */ @@ -1284,6 +1394,7 @@ drive->waiting_for_dma = 0; dstat = in_le32(&dma->status); out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16)); + pmac_ide_destroy_dmatable(drive, ix); /* verify good dma status */ return (dstat & (RUN|DEAD|ACTIVE)) != RUN; case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ diff -urN linux-2.4.19-pre6/drivers/ide/ide-proc.c linux-2.4.19-pre7/drivers/ide/ide-proc.c --- linux-2.4.19-pre6/drivers/ide/ide-proc.c Mon Apr 15 21:53:55 2002 +++ linux-2.4.19-pre7/drivers/ide/ide-proc.c Mon Apr 15 21:54:31 2002 @@ -597,7 +597,8 @@ if (!driver) len = sprintf(page, "(none)\n"); else - len = sprintf(page,"%llu\n", (__u64) ((ide_driver_t *)drive->driver)->capacity(drive)); + len = sprintf(page,"%llu\n", + (unsigned long long) ((ide_driver_t *)drive->driver)->capacity(drive)); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } diff -urN linux-2.4.19-pre6/drivers/ide/ide.c linux-2.4.19-pre7/drivers/ide/ide.c --- linux-2.4.19-pre6/drivers/ide/ide.c Mon Apr 15 21:53:55 2002 +++ linux-2.4.19-pre7/drivers/ide/ide.c Mon Apr 15 21:54:32 2002 @@ -990,7 +990,9 @@ high = read_24(drive); sectors = ((__u64)high << 24) | low; - printk(", LBAsect=%lld, high=%d, low=%d", sectors, high, low); + printk(", LBAsect=%llu, high=%d, low=%d", + (unsigned long long) sectors, + high, low); } else { byte cur = IN_BYTE(IDE_SELECT_REG); if (cur & 0x40) { /* using LBA? */ diff -urN linux-2.4.19-pre6/drivers/ide/piix.c linux-2.4.19-pre7/drivers/ide/piix.c --- linux-2.4.19-pre6/drivers/ide/piix.c Mon Apr 15 21:53:55 2002 +++ linux-2.4.19-pre7/drivers/ide/piix.c Mon Apr 15 21:54:32 2002 @@ -92,6 +92,7 @@ case PCI_DEVICE_ID_INTEL_82801BA_8: case PCI_DEVICE_ID_INTEL_82801BA_9: case PCI_DEVICE_ID_INTEL_82801CA_10: + case PCI_DEVICE_ID_INTEL_82801CA_11: p += sprintf(p, "\n Intel PIIX4 Ultra 100 Chipset.\n"); break; case PCI_DEVICE_ID_INTEL_82372FB_1: @@ -366,7 +367,8 @@ byte udma_66 = eighty_ninty_three(drive); int ultra100 = ((dev->device == PCI_DEVICE_ID_INTEL_82801BA_8) || (dev->device == PCI_DEVICE_ID_INTEL_82801BA_9) || - (dev->device == PCI_DEVICE_ID_INTEL_82801CA_10)) ? 1 : 0; + (dev->device == PCI_DEVICE_ID_INTEL_82801CA_10) || + (dev->device == PCI_DEVICE_ID_INTEL_82801CA_11)) ? 1 : 0; int ultra66 = ((ultra100) || (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) || (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0; diff -urN linux-2.4.19-pre6/drivers/ieee1394/ohci1394.h linux-2.4.19-pre7/drivers/ieee1394/ohci1394.h --- linux-2.4.19-pre6/drivers/ieee1394/ohci1394.h Mon Apr 15 21:53:56 2002 +++ linux-2.4.19-pre7/drivers/ieee1394/ohci1394.h Mon Apr 15 21:54:32 2002 @@ -21,6 +21,8 @@ #ifndef _OHCI1394_H #define _OHCI1394_H +#include + #include "ieee1394_types.h" #define OHCI1394_DRIVER_NAME "ohci1394" diff -urN linux-2.4.19-pre6/drivers/isdn/hisax/hfc_pci.c linux-2.4.19-pre7/drivers/isdn/hisax/hfc_pci.c --- linux-2.4.19-pre6/drivers/isdn/hisax/hfc_pci.c Fri Dec 21 09:41:54 2001 +++ linux-2.4.19-pre7/drivers/isdn/hisax/hfc_pci.c Mon Apr 15 21:54:32 2002 @@ -76,6 +76,8 @@ { unsigned long flags; + printk(KERN_INFO "HiSax: release hfcpci at %p\n", + cs->hw.hfcpci.pci_io); save_flags(flags); cli(); cs->hw.hfcpci.int_m2 = 0; /* interrupt output off ! */ @@ -86,13 +88,11 @@ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */ -#if CONFIG_PCI pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0); /* disable memory mapped ports + busmaster */ -#endif /* CONFIG_PCI */ del_timer(&cs->hw.hfcpci.timer); kfree(cs->hw.hfcpci.share_start); cs->hw.hfcpci.share_start = NULL; - vfree(cs->hw.hfcpci.pci_io); + iounmap((void *)cs->hw.hfcpci.pci_io); } /********************************************************************************/ diff -urN linux-2.4.19-pre6/drivers/isdn/hisax/w6692.c linux-2.4.19-pre7/drivers/isdn/hisax/w6692.c --- linux-2.4.19-pre6/drivers/isdn/hisax/w6692.c Fri Dec 21 09:41:54 2001 +++ linux-2.4.19-pre7/drivers/isdn/hisax/w6692.c Mon Apr 15 21:54:32 2002 @@ -29,11 +29,17 @@ static const PCI_ENTRY id_list[] = { - {PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"}, {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, "Winbond", "W6692"}, - {0, 0, NULL, NULL} + {PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"}, + {0, 0, "U.S.Robotics", "ISDN PCI Card TA"} }; +#define W6692_SV_USR 0x16ec +#define W6692_SD_USR 0x3409 +#define W6692_WINBOND 0 +#define W6692_DYNALINK 1 +#define W6692_USR 2 + extern const char *CardType[]; const char *w6692_revision = "$Revision: 1.1.4.1 $"; @@ -859,6 +865,28 @@ return (0); } +void resetW6692(struct IsdnCardState *cs) +{ + cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST); + schedule_timeout((10*HZ)/1000); + cs->writeW6692(cs, W_D_CTL, 0x00); + schedule_timeout((10*HZ)/1000); + cs->writeW6692(cs, W_IMASK, 0xff); + cs->writeW6692(cs, W_D_SAM, 0xff); + cs->writeW6692(cs, W_D_TAM, 0xff); + cs->writeW6692(cs, W_D_EXIM, 0x00); + cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT); + cs->writeW6692(cs, W_IMASK, 0x18); + if (cs->subtyp == W6692_USR) { + /* seems that USR implemented some power control features + * Pin 79 is connected to the oscilator circuit so we + * have to handle it here + */ + cs->writeW6692(cs, W_PCTL, 0x80); + cs->writeW6692(cs, W_XDATA, 0x00); + } +} + void __init initW6692(struct IsdnCardState *cs, int part) { if (part & 1) { @@ -868,15 +896,7 @@ cs->dbusytimer.function = (void *) dbusy_timer_handler; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); - - cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST); - cs->writeW6692(cs, W_D_CTL, 0x00); - cs->writeW6692(cs, W_IMASK, 0xff); - cs->writeW6692(cs, W_D_SAM, 0xff); - cs->writeW6692(cs, W_D_TAM, 0xff); - cs->writeW6692(cs, W_D_EXIM, 0x00); - cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT); - cs->writeW6692(cs, W_IMASK, 0x18); + resetW6692(cs); ph_command(cs, W_L1CMD_RST); cs->dc.w6692.ph_state = W_L1CMD_RST; W6692_new_ph(cs); @@ -943,9 +963,14 @@ { switch (mt) { case CARD_RESET: + resetW6692(cs); return (0); case CARD_RELEASE: + cs->writeW6692(cs, W_IMASK, 0xff); release_region(cs->hw.w6692.iobase, 256); + if (cs->subtyp == W6692_USR) { + cs->writeW6692(cs, W_XDATA, 0x04); + } return (0); case CARD_INIT: initW6692(cs, 3); @@ -988,6 +1013,7 @@ if (dev_w6692) { if (pci_enable_device(dev_w6692)) continue; + cs->subtyp = id_idx; break; } id_idx++; @@ -998,6 +1024,13 @@ /* I think address 0 is allways the configuration area */ /* and address 1 is the real IO space KKe 03.09.99 */ pci_ioaddr = pci_resource_start(dev_w6692, 1); + /* USR ISDN PCI card TA need some special handling */ + if (cs->subtyp == W6692_WINBOND) { + if ((W6692_SV_USR == dev_w6692->subsystem_vendor) && + (W6692_SD_USR == dev_w6692->subsystem_device)) { + cs->subtyp = W6692_USR; + } + } } if (!found) { printk(KERN_WARNING "W6692: No PCI card found\n"); @@ -1014,18 +1047,18 @@ } cs->hw.w6692.iobase = pci_ioaddr; printk(KERN_INFO "Found: %s %s, I/O base: 0x%x, irq: %d\n", - id_list[id_idx].vendor_name, id_list[id_idx].card_name, - pci_ioaddr, dev_w6692->irq); + id_list[cs->subtyp].vendor_name, id_list[cs->subtyp].card_name, + pci_ioaddr, pci_irq); if (check_region((cs->hw.w6692.iobase), 256)) { printk(KERN_WARNING "HiSax: %s I/O ports %x-%x already in use\n", - id_list[id_idx].card_name, + id_list[cs->subtyp].card_name, cs->hw.w6692.iobase, cs->hw.w6692.iobase + 255); return (0); } else { request_region(cs->hw.w6692.iobase, 256, - id_list[id_idx].card_name); + id_list[cs->subtyp].card_name); } #else printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n"); @@ -1035,7 +1068,7 @@ printk(KERN_INFO "HiSax: %s config irq:%d I/O:%x\n", - id_list[id_idx].card_name, cs->irq, + id_list[cs->subtyp].card_name, cs->irq, cs->hw.w6692.iobase); cs->readW6692 = &ReadW6692; diff -urN linux-2.4.19-pre6/drivers/macintosh/adb.c linux-2.4.19-pre7/drivers/macintosh/adb.c --- linux-2.4.19-pre6/drivers/macintosh/adb.c Mon Feb 25 11:37:58 2002 +++ linux-2.4.19-pre7/drivers/macintosh/adb.c Mon Apr 15 21:54:32 2002 @@ -78,7 +78,7 @@ static int adb_got_sleep = 0; static int adb_inited = 0; static pid_t adb_probe_task_pid; -static int adb_probe_task_flag; +static DECLARE_MUTEX(adb_probe_mutex); static struct completion adb_probe_task_comp; static int sleepy_trackpad; int __adb_probe_sync; @@ -242,7 +242,8 @@ printk(KERN_INFO "adb: finished probe task...\n"); adb_probe_task_pid = 0; - clear_bit(0, &adb_probe_task_flag); + up(&adb_probe_mutex); + return 0; } @@ -264,14 +265,8 @@ do_adb_reset_bus(); return 0; } - - /* We need to get a lock on the probe thread */ - while (test_and_set_bit(0, &adb_probe_task_flag)) - schedule(); - /* Just wait for PID to be 0 just in case (possible race) */ - while (adb_probe_task_pid != 0) - schedule(); + down(&adb_probe_mutex); /* Create probe thread as a child of keventd */ if (current_is_keventd()) @@ -341,21 +336,20 @@ case PBOOK_SLEEP_REQUEST: adb_got_sleep = 1; /* We need to get a lock on the probe thread */ - while (test_and_set_bit(0, &adb_probe_task_flag)) - schedule(); - /* Just wait for PID to be 0 just in case (possible race) */ - while (adb_probe_task_pid != 0) - schedule(); + down(&adb_probe_mutex); + /* Stop autopoll */ if (adb_controller->autopoll) adb_controller->autopoll(0); ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL); - if (ret & NOTIFY_STOP_MASK) + if (ret & NOTIFY_STOP_MASK) { + up(&adb_probe_mutex); return PBOOK_SLEEP_REFUSE; + } break; case PBOOK_SLEEP_REJECT: if (adb_got_sleep) { adb_got_sleep = 0; - clear_bit(0, &adb_probe_task_flag); + up(&adb_probe_mutex); adb_reset_bus(); } break; @@ -364,7 +358,7 @@ break; case PBOOK_WAKE: adb_got_sleep = 0; - clear_bit(0, &adb_probe_task_flag); + up(&adb_probe_mutex); adb_reset_bus(); break; } @@ -773,9 +767,9 @@ atomic_inc(&state->n_pending); - /* If a probe is in progress, wait for it to complete */ - while (adb_probe_task_pid != 0 || test_bit(0, &adb_probe_task_flag)) - schedule(); + /* If a probe is in progress or we are sleeping, wait for it to complete */ + down(&adb_probe_mutex); + up(&adb_probe_mutex); /* Special case for ADB_BUSRESET request, all others are sent to the controller */ diff -urN linux-2.4.19-pre6/drivers/macintosh/adbhid.c linux-2.4.19-pre7/drivers/macintosh/adbhid.c --- linux-2.4.19-pre6/drivers/macintosh/adbhid.c Mon Feb 25 11:37:58 2002 +++ linux-2.4.19-pre7/drivers/macintosh/adbhid.c Mon Apr 15 21:54:32 2002 @@ -96,6 +96,11 @@ static struct adb_ids mouse_ids; static struct adb_ids buttons_ids; +#ifdef CONFIG_PMAC_BACKLIGHT +/* Exported to via-pmu.c */ +int disable_kernel_backlight = 0; +#endif /* CONFIG_PMAC_BACKLIGHT */ + /* Kind of keyboard, see Apple technote 1152 */ #define ADB_KEYBOARD_UNKNOWN 0 #define ADB_KEYBOARD_ANSI 0x0100 @@ -284,44 +289,48 @@ switch (data[1] & 0x0f) { case 0x8: /* mute */ - input_report_key(&adbhid[id]->input, KEY_MUTE, - data[1] == (data[1] & 0xf)); + input_report_key(&adbhid[id]->input, KEY_MUTE, down); break; case 0x7: /* volume decrease */ - input_report_key(&adbhid[id]->input, KEY_VOLUMEDOWN, - data[1] == (data[1] & 0xf)); + input_report_key(&adbhid[id]->input, KEY_VOLUMEDOWN, down); break; case 0x6: /* volume increase */ - input_report_key(&adbhid[id]->input, KEY_VOLUMEUP, - data[1] == (data[1] & 0xf)); + input_report_key(&adbhid[id]->input, KEY_VOLUMEUP, down); break; case 0xb: /* eject */ - input_report_key(&adbhid[id]->input, KEY_EJECTCD, - data[1] == (data[1] & 0xf)); + input_report_key(&adbhid[id]->input, KEY_EJECTCD, down); break; - -#ifdef CONFIG_PMAC_BACKLIGHT case 0xa: /* brightness decrease */ - if (!down || backlight < 0) +#ifdef CONFIG_PMAC_BACKLIGHT + if (!disable_kernel_backlight) { + if (!down || backlight < 0) + break; + if (backlight > BACKLIGHT_OFF) + set_backlight_level(backlight-1); + else + set_backlight_level(BACKLIGHT_OFF); break; - if (backlight > BACKLIGHT_OFF) - set_backlight_level(backlight-1); - else - set_backlight_level(BACKLIGHT_OFF); + } +#endif /* CONFIG_PMAC_BACKLIGHT */ + input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSDOWN, down); break; - case 0x9: /* brightness increase */ - if (!down || backlight < 0) +#ifdef CONFIG_PMAC_BACKLIGHT + if (!disable_kernel_backlight) { + if (!down || backlight < 0) + break; + if (backlight < BACKLIGHT_MAX) + set_backlight_level(backlight+1); + else + set_backlight_level(BACKLIGHT_MAX); break; - if (backlight < BACKLIGHT_MAX) - set_backlight_level(backlight+1); - else - set_backlight_level(BACKLIGHT_MAX); - break; + } #endif /* CONFIG_PMAC_BACKLIGHT */ + input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSUP, down); + break; } } break; @@ -521,6 +530,8 @@ set_bit(KEY_MUTE, adbhid[id]->input.keybit); set_bit(KEY_VOLUMEUP, adbhid[id]->input.keybit); set_bit(KEY_VOLUMEDOWN, adbhid[id]->input.keybit); + set_bit(KEY_BRIGHTNESSUP, adbhid[id]->input.keybit); + set_bit(KEY_BRIGHTNESSDOWN, adbhid[id]->input.keybit); set_bit(KEY_EJECTCD, adbhid[id]->input.keybit); break; } diff -urN linux-2.4.19-pre6/drivers/macintosh/apm_emu.c linux-2.4.19-pre7/drivers/macintosh/apm_emu.c --- linux-2.4.19-pre6/drivers/macintosh/apm_emu.c Mon Feb 25 11:37:58 2002 +++ linux-2.4.19-pre7/drivers/macintosh/apm_emu.c Mon Apr 15 21:54:32 2002 @@ -436,15 +436,18 @@ int percentage = -1; int time_units = -1; int real_count = 0; + int charge = -1; + int current = 0; int i; char * p = buf; + char charging = 0; ac_line_status = ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0); for (i=0; ireply[0] & 0x01) + pmu_power_flags |= PMU_PWR_AC_PRESENT; + else + pmu_power_flags &= ~PMU_PWR_AC_PRESENT; + + if (req->reply[0] & 0x04) { + int vb, i, j, k, charge, pcharge; + bat_flags |= PMU_BATT_PRESENT; + vb = (req->reply[1] << 8) | req->reply[2]; + voltage = ((vb * 2650) + 726650)/100; + vb *= 100; + current = req->reply[5]; + if ((req->reply[0] & 0x01) == 0 && (current > 200)) + vb += (current - 200) * 15; + else if (req->reply[0] & 0x02) + vb = (vb - 2000); + i = (33000 - vb) / 10; + j = i - (i % 100); + k = j/100; + if (k <= 0) + charge = 0; + else if (k >= 21) + charge = 650000; + else + charge = (lrange[k + 1] - lrange[k]) * (i - j) + (lrange[k] * 100); + charge = (1000 - charge / 650) / 10; + if (req->reply[0] & 0x40) { + pcharge = (req->reply[6] << 8) + req->reply[7]; + if (pcharge > 6500) + pcharge = 6500; + pcharge *= 100; + pcharge = (1000 - pcharge / 650) / 10; + if (pcharge < charge) + charge = pcharge; + } + capa = charge; + max = 100; + time = (charge * 16440) / current; + current = -current; + + } else + capa = max = current = voltage = time = 0; + + if (req->reply[0] & 0x02) + bat_flags |= PMU_BATT_CHARGING; + + pmu_batteries[pmu_cur_battery].flags = bat_flags; + pmu_batteries[pmu_cur_battery].charge = capa; + pmu_batteries[pmu_cur_battery].max_charge = max; + pmu_batteries[pmu_cur_battery].current = current; + pmu_batteries[pmu_cur_battery].voltage = voltage; + pmu_batteries[pmu_cur_battery].time_remaining = time; +} +#else /* NEW_OHARE_CODE */ static void __pmac done_battery_state_ohare(struct adb_request* req) { @@ -610,6 +684,88 @@ pmu_batteries[pmu_cur_battery].voltage = voltage; pmu_batteries[pmu_cur_battery].time_remaining = time; } +#endif /* NEW_OHARE_CODE */ + + static void __pmac +done_battery_state_comet(struct adb_request* req) +{ + /* format: + * [0] : flags + * 0x01 : AC indicator + * 0x02 : charging + * 0x04 : battery exist + * 0x08 : + * 0x10 : + * 0x20 : full charged + * 0x40 : pcharge reset + * 0x80 : battery exist + * + * [1][2] : battery voltage + * [3] : CPU temperature + * [4] : battery temperature + * [5] : current + * [6][7] : pcharge + * --tkoba + */ + + unsigned int bat_flags = 0; + int current = 0; + unsigned int max = 100; + unsigned int charge, voltage, time; + int lrange[] = { 0, 600, 750, 900, 1000, 1080, + 1180, 1250, 1300, 1340, 1360, + 1390, 1420, 1440, 1470, 1490, + 1520, 1550, 1580, 1610, 1650, + 1700 + }; + + if (req->reply[0] & 0x01) + pmu_power_flags |= PMU_PWR_AC_PRESENT; + else + pmu_power_flags &= ~PMU_PWR_AC_PRESENT; + + if (req->reply[0] & 0x04) { /* battery exist */ + int vb, i; + bat_flags |= PMU_BATT_PRESENT; + vb = (req->reply[1] << 8) | req->reply[2]; + voltage = ((vb * 2650) + 726650)/100; + vb *= 10; + current = req->reply[5]; + if ((req->reply[0] & 0x01) == 0 && (current > 200)) + vb += ((current - 200) * 3); /* vb = 500<->1800 */ + else if (req->reply[0] & 0x02) + vb = ((vb - 800) * 1700/13)/100; /* in charging vb = 1300<->2130 */ + + if (req->reply[0] & 0x20) { /* full charged */ + charge = max; + } else { + if (lrange[21] < vb) + charge = max; + else { + if (vb < lrange[1]) + charge = 0; + else { + for (i=21; vb < lrange[i]; --i); + charge = (i * 100)/21; + } + } + if (charge > max) charge = max; + } + time = (charge * 72); + current = -current; + } else + max = current = voltage = time = 0; + + if (req->reply[0] & 0x02) + bat_flags |= PMU_BATT_CHARGING; + + pmu_batteries[pmu_cur_battery].flags = bat_flags; + pmu_batteries[pmu_cur_battery].charge = charge; + pmu_batteries[pmu_cur_battery].max_charge = max; + pmu_batteries[pmu_cur_battery].current = current; + pmu_batteries[pmu_cur_battery].voltage = voltage; + pmu_batteries[pmu_cur_battery].time_remaining = time; +} static void __pmac done_battery_state_smart(struct adb_request* req) @@ -691,10 +847,17 @@ { if (!batt_req.complete) return; - if (pmu_kind == PMU_OHARE_BASED) - pmu_request(&batt_req, done_battery_state_ohare, - 1, PMU_BATTERY_STATE); - else + if (pmu_kind == PMU_OHARE_BASED) { + int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO, + NULL, PMAC_MB_INFO_MODEL, 0); + + if (mb == PMAC_TYPE_COMET) + pmu_request(&batt_req, done_battery_state_comet, + 1, PMU_BATTERY_STATE); + else + pmu_request(&batt_req, done_battery_state_ohare, + 1, PMU_BATTERY_STATE); + } else pmu_request(&batt_req, done_battery_state_smart, 2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1); } @@ -1372,8 +1535,11 @@ /* Sound/brightness button pressed */ if ((data[0] & PMU_INT_SNDBRT) && len == 3) { #ifdef CONFIG_PMAC_BACKLIGHT - set_backlight_level(data[1] >> 4); -#endif +#ifdef CONFIG_INPUT_ADBHID + if (!disable_kernel_backlight) +#endif /* CONFIG_INPUT_ADBHID */ + set_backlight_level(data[1] >> 4); +#endif /* CONFIG_PMAC_BACKLIGHT */ } #ifdef CONFIG_PMAC_PBOOK /* Environement or tick interrupt, query batteries */ @@ -1588,7 +1754,15 @@ for (list = sleep_notifiers.next; list != &sleep_notifiers; list = list->next) { notifier = list_entry(list, struct pmu_sleep_notifier, list); +#ifdef VERBOSE_WAKEUP + if (notifier->priority < SLEEP_LEVEL_VIDEO) + xmon_printf("wake, before notifier %x\n", notifier); +#endif notifier->notifier_call(notifier, PBOOK_WAKE); +#ifdef VERBOSE_WAKEUP + if (notifier->priority <= SLEEP_LEVEL_VIDEO) + xmon_printf("wake, after notifier %x\n", notifier); +#endif } return ret; } @@ -1607,28 +1781,48 @@ u32 config[16]; #endif } *pbook_pci_saves; -static int n_pbook_pci_saves; +static int pbook_npci_saves; static void __openfirmware -pbook_pci_save(void) +pbook_alloc_pci_save(void) { int npci; struct pci_dev *pd; - struct pci_save *ps; npci = 0; pci_for_each_dev(pd) { ++npci; } - n_pbook_pci_saves = npci; if (npci == 0) return; - ps = (struct pci_save *) kmalloc(npci * sizeof(*ps), GFP_KERNEL); - pbook_pci_saves = ps; + pbook_pci_saves = (struct pci_save *) + kmalloc(npci * sizeof(struct pci_save), GFP_KERNEL); + pbook_npci_saves = npci; +} + +static void __openfirmware +pbook_free_pci_save(void) +{ + if (pbook_pci_saves == NULL) + return; + kfree(pbook_pci_saves); + pbook_pci_saves = NULL; + pbook_npci_saves = 0; +} + +static void __openfirmware +pbook_pci_save(void) +{ + struct pci_save *ps = pbook_pci_saves; + struct pci_dev *pd; + int npci = pbook_npci_saves; + if (ps == NULL) return; pci_for_each_dev(pd) { + if (npci-- == 0) + return; #ifndef HACKED_PCI_SAVE pci_read_config_word(pd, PCI_COMMAND, &ps->command); pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat); @@ -1653,16 +1847,22 @@ u16 cmd; struct pci_save *ps = pbook_pci_saves - 1; struct pci_dev *pd; + int npci = pbook_npci_saves; int j; pci_for_each_dev(pd) { #ifdef HACKED_PCI_SAVE int i; + if (npci-- == 0) + return; ps++; for (i=2;i<16;i++) pci_write_config_dword(pd, i<<4, ps->config[i]); pci_write_config_dword(pd, 4, ps->config[1]); #else + if (npci-- == 0) + return; + ps++; if (ps->command == 0) continue; pci_read_config_word(pd, PCI_COMMAND, &cmd); @@ -2115,9 +2315,13 @@ } mem_ctrl_sleep = (unsigned int *) (mem_ctrl + PB3400_MEM_CTRL_SLEEP); + /* Allocate room for PCI save */ + pbook_alloc_pci_save(); + /* Notify device drivers */ ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); if (ret != PBOOK_SLEEP_OK) { + pbook_free_pci_save(); printk("pmu: sleep rejected\n"); return -EBUSY; } @@ -2138,6 +2342,7 @@ ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); if (ret != PBOOK_SLEEP_OK) { printk("pmu: sleep failed\n"); + pbook_free_pci_save(); return -EBUSY; } @@ -2211,6 +2416,7 @@ /* Notify drivers */ broadcast_wake(); + pbook_free_pci_save(); iounmap(mem_ctrl); return 0; } @@ -2229,6 +2435,9 @@ } rb_buf[RB_SIZE]; wait_queue_head_t wait; spinlock_t lock; +#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) + int backlight_locker; +#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */ }; static LIST_HEAD(all_pmu_pvt); @@ -2274,9 +2483,13 @@ spin_lock_init(&pp->lock); init_waitqueue_head(&pp->wait); spin_lock_irqsave(&all_pvt_lock, flags); +#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) + pp->backlight_locker = 0; +#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */ list_add(&pp->list, &all_pmu_pvt); spin_unlock_irqrestore(&all_pvt_lock, flags); file->private_data = pp; + return 0; } @@ -2365,6 +2578,13 @@ spin_lock_irqsave(&all_pvt_lock, flags); list_del(&pp->list); spin_unlock_irqrestore(&all_pvt_lock, flags); +#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) + if (pp->backlight_locker) { + spin_lock_irqsave(&pmu_lock, flags); + disable_kernel_backlight--; + spin_unlock_irqrestore(&pmu_lock, flags); + } +#endif defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) kfree(pp); } unlock_kernel(); @@ -2375,6 +2595,7 @@ static int pmu_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) { + struct pmu_private *pp = filp->private_data; int error; switch (cmd) { @@ -2424,6 +2645,18 @@ error = set_backlight_level(value); return error; } +#ifdef CONFIG_INPUT_ADBHID + case PMU_IOC_GRAB_BACKLIGHT: { + unsigned long flags; + if (pp->backlight_locker) + return 0; + pp->backlight_locker = 1; + spin_lock_irqsave(&pmu_lock, flags); + disable_kernel_backlight++; + spin_unlock_irqrestore(&pmu_lock, flags); + return 0; + } +#endif /* CONFIG_INPUT_ADBHID */ #endif /* CONFIG_PMAC_BACKLIGHT */ case PMU_IOC_GET_MODEL: return put_user(pmu_kind, (__u32 *)arg); diff -urN linux-2.4.19-pre6/drivers/net/Config.in linux-2.4.19-pre7/drivers/net/Config.in --- linux-2.4.19-pre6/drivers/net/Config.in Mon Apr 15 21:53:59 2002 +++ linux-2.4.19-pre7/drivers/net/Config.in Mon Apr 15 21:54:38 2002 @@ -3,7 +3,6 @@ # source drivers/net/arcnet/Config.in -source drivers/net/appletalk/Config.in tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'Bonding driver support' CONFIG_BONDING diff -urN linux-2.4.19-pre6/drivers/net/Makefile linux-2.4.19-pre7/drivers/net/Makefile --- linux-2.4.19-pre6/drivers/net/Makefile Mon Apr 15 21:53:59 2002 +++ linux-2.4.19-pre7/drivers/net/Makefile Mon Apr 15 21:54:38 2002 @@ -37,7 +37,7 @@ subdir-$(CONFIG_WAN) += wan subdir-$(CONFIG_NET_FC) += fc subdir-$(CONFIG_ARCNET) += arcnet -subdir-$(CONFIG_APPLETALK) += appletalk +subdir-$(CONFIG_DEV_APPLETALK) += appletalk subdir-$(CONFIG_SK98LIN) += sk98lin subdir-$(CONFIG_SKFP) += skfp diff -urN linux-2.4.19-pre6/drivers/net/appletalk/Config.in linux-2.4.19-pre7/drivers/net/appletalk/Config.in --- linux-2.4.19-pre6/drivers/net/appletalk/Config.in Fri Nov 9 14:01:22 2001 +++ linux-2.4.19-pre7/drivers/net/appletalk/Config.in Mon Apr 15 21:54:38 2002 @@ -2,22 +2,20 @@ # Appletalk driver configuration # -if [ "$CONFIG_ATALK" != "n" ]; then - mainmenu_option next_comment - comment 'Appletalk devices' - bool 'Appletalk interfaces support' CONFIG_APPLETALK - if [ "$CONFIG_ATALK" != "n" ]; then - dep_tristate ' Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_DEV_APPLETALK - dep_tristate ' COPS LocalTalk PC support' CONFIG_COPS $CONFIG_DEV_APPLETALK - if [ "$CONFIG_COPS" != "n" ]; then - bool ' Dayna firmware support' CONFIG_COPS_DAYNA - bool ' Tangent firmware support' CONFIG_COPS_TANGENT - fi - dep_tristate ' Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_DEV_APPLETALK - if [ "$CONFIG_IPDDP" != "n" ]; then - bool ' IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP - bool ' Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP - fi +mainmenu_option next_comment +comment 'Appletalk devices' +dep_mbool 'Appletalk interfaces support' CONFIG_DEV_APPLETALK $CONFIG_ATALK +if [ "$CONFIG_DEV_APPLETALK" = "y" ]; then + tristate ' Apple/Farallon LocalTalk PC support' CONFIG_LTPC + tristate ' COPS LocalTalk PC support' CONFIG_COPS + if [ "$CONFIG_COPS" != "n" ]; then + bool ' Dayna firmware support' CONFIG_COPS_DAYNA $CONFIG_COPS + bool ' Tangent firmware support' CONFIG_COPS_TANGENT $CONFIG_COPS + fi + dep_tristate ' Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK + if [ "$CONFIG_IPDDP" != "n" ]; then + bool ' IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP + bool ' Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP fi - endmenu fi +endmenu diff -urN linux-2.4.19-pre6/drivers/net/bmac.c linux-2.4.19-pre7/drivers/net/bmac.c --- linux-2.4.19-pre6/drivers/net/bmac.c Mon Apr 15 21:53:59 2002 +++ linux-2.4.19-pre7/drivers/net/bmac.c Mon Apr 15 21:54:39 2002 @@ -25,11 +25,11 @@ #include #include #include +#include #ifdef CONFIG_PMAC_PBOOK #include #include -#include -#endif +#endif /* CONFIG_PMAC_PBOOK */ #include "bmac.h" #define trunc_page(x) ((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1)))) diff -urN linux-2.4.19-pre6/drivers/net/sunhme.c linux-2.4.19-pre7/drivers/net/sunhme.c --- linux-2.4.19-pre6/drivers/net/sunhme.c Mon Apr 15 21:53:59 2002 +++ linux-2.4.19-pre7/drivers/net/sunhme.c Mon Apr 15 21:54:43 2002 @@ -14,7 +14,7 @@ */ static char version[] = - "sunhme.c:v2.00 20/Mar/2002 David S. Miller (davem@redhat.com)\n"; + "sunhme.c:v2.01 26/Mar/2002 David S. Miller (davem@redhat.com)\n"; #include @@ -697,7 +697,7 @@ return 1; } -static int happy_meal_init(struct happy_meal *hp, int from_irq); +static int happy_meal_init(struct happy_meal *hp); static int is_lucent_phy(struct happy_meal *hp) { @@ -708,12 +708,8 @@ mr2 = happy_meal_tcvr_read(hp, tregs, 2); mr3 = happy_meal_tcvr_read(hp, tregs, 3); if ((mr2 & 0xffff) == 0x0180 && - ((mr3 & 0xffff) >> 10) == 0x1d) { -#if 0 - printk("HMEDEBUG: Lucent PHY detected.\n"); -#endif + ((mr3 & 0xffff) >> 10) == 0x1d) ret = 1; - } return ret; } @@ -724,6 +720,8 @@ unsigned long tregs = hp->tcvregs; int restart_timer = 0; + spin_lock_irq(&hp->happy_lock); + hp->timer_ticks++; switch(hp->timer_state) { case arbwait: @@ -853,13 +851,13 @@ printk(KERN_NOTICE "%s: Link down, cable problem?\n", hp->dev->name); - ret = happy_meal_init(hp, 0); + ret = happy_meal_init(hp); if (ret) { /* ho hum... */ printk(KERN_ERR "%s: Error, cannot re-init the " "Happy Meal.\n", hp->dev->name); } - return; + goto out; } if (!is_lucent_phy(hp)) { hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, @@ -891,11 +889,15 @@ hp->happy_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2 sec. */ add_timer(&hp->happy_timer); } + +out: + spin_unlock_irq(&hp->happy_lock); } #define TX_RESET_TRIES 32 #define RX_RESET_TRIES 32 +/* hp->happy_lock must be held */ static void happy_meal_tx_reset(struct happy_meal *hp, unsigned long bregs) { int tries = TX_RESET_TRIES; @@ -915,6 +917,7 @@ HMD(("done\n")); } +/* hp->happy_lock must be held */ static void happy_meal_rx_reset(struct happy_meal *hp, unsigned long bregs) { int tries = RX_RESET_TRIES; @@ -936,6 +939,7 @@ #define STOP_TRIES 16 +/* hp->happy_lock must be held */ static void happy_meal_stop(struct happy_meal *hp, unsigned long gregs) { int tries = STOP_TRIES; @@ -955,6 +959,7 @@ HMD(("done\n")); } +/* hp->happy_lock must be held */ static void happy_meal_get_counters(struct happy_meal *hp, unsigned long bregs) { struct net_device_stats *stats = &hp->net_stats; @@ -977,53 +982,7 @@ hme_write32(hp, bregs + BMAC_LTCTR, 0); } -#if 0 -static void happy_meal_poll_start(struct happy_meal *hp, unsigned long tregs) -{ - u32 tmp; - int speed; - - ASD(("happy_meal_poll_start: ")); - if (!(hp->happy_flags & HFLAG_POLLENABLE)) { - HMD(("polling disabled, return\n")); - return; - } - - /* Start the MIF polling on the external transceiver. */ - ASD(("polling on, ")); - tmp = hme_read32(hp, tregs + TCVR_CFG); - tmp &= ~(TCV_CFG_PDADDR | TCV_CFG_PREGADDR); - tmp |= ((hp->paddr & 0x1f) << 10); - tmp |= (TCV_PADDR_ETX << 3); - tmp |= TCV_CFG_PENABLE; - hme_write32(hp, tregs + TCVR_CFG, tmp); - - /* Let the bits set. */ - udelay(200); - - /* We are polling now. */ - ASD(("now polling, ")); - hp->happy_flags |= HFLAG_POLL; - - /* Clear the poll flags, get the basic status as of now. */ - hp->poll_flag = 0; - hp->poll_data = hme_read32(hp, tregs + TCVR_STATUS) >> 16; - - if (hp->happy_flags & HFLAG_AUTO) - speed = hp->auto_speed; - else - speed = hp->forced_speed; - - /* Listen only for the MIF interrupts we want to hear. */ - ASD(("mif ints on, ")); - if (speed == 100) - hme_write32(hp, tregs + TCVR_IMASK, 0xfffb); - else - hme_write32(hp, tregs + TCVR_IMASK, 0xfff9); - ASD(("done\n")); -} -#endif - +/* hp->happy_lock must be held */ static void happy_meal_poll_stop(struct happy_meal *hp, unsigned long tregs) { ASD(("happy_meal_poll_stop: ")); @@ -1058,6 +1017,7 @@ #define TCVR_RESET_TRIES 16 /* It should reset quickly */ #define TCVR_UNISOLATE_TRIES 32 /* Dis-isolation can take longer. */ +/* hp->happy_lock must be held */ static int happy_meal_tcvr_reset(struct happy_meal *hp, unsigned long tregs) { u32 tconfig; @@ -1152,7 +1112,10 @@ return 0; } -/* Figure out whether we have an internal or external transceiver. */ +/* Figure out whether we have an internal or external transceiver. + * + * hp->happy_lock must be held + */ static void happy_meal_transceiver_check(struct happy_meal *hp, unsigned long tregs) { unsigned long tconfig = hme_read32(hp, tregs + TCVR_CFG); @@ -1304,14 +1267,12 @@ } } -static void happy_meal_init_rings(struct happy_meal *hp, int from_irq) +/* hp->happy_lock must be held */ +static void happy_meal_init_rings(struct happy_meal *hp) { struct hmeal_init_block *hb = hp->happy_block; struct net_device *dev = hp->dev; - int i, gfp_flags = GFP_KERNEL; - - if (from_irq || in_interrupt()) - gfp_flags = GFP_ATOMIC; + int i; HMD(("happy_meal_init_rings: counters to zero, ")); hp->rx_new = hp->rx_old = hp->tx_new = hp->tx_old = 0; @@ -1325,7 +1286,7 @@ for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; - skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags); + skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); if (!skb) { hme_write_rxd(hp, &hb->happy_meal_rxd[i], 0, 0); continue; @@ -1348,6 +1309,7 @@ HMD(("done\n")); } +/* hp->happy_lock must be held */ static void happy_meal_begin_auto_negotiation(struct happy_meal *hp, unsigned long tregs, struct ethtool_cmd *ep) @@ -1471,7 +1433,8 @@ add_timer(&hp->happy_timer); } -static int happy_meal_init(struct happy_meal *hp, int from_irq) +/* hp->happy_lock must be held */ +static int happy_meal_init(struct happy_meal *hp) { unsigned long gregs = hp->gregs; unsigned long etxregs = hp->etxregs; @@ -1502,7 +1465,7 @@ /* Alloc and reset the tx/rx descriptor chains. */ HMD(("happy_meal_init: to happy_meal_init_rings\n")); - happy_meal_init_rings(hp, from_irq); + happy_meal_init_rings(hp); /* Shut up the MIF. */ HMD(("happy_meal_init: Disable all MIF irqs (old[%08x]), ", @@ -1619,6 +1582,17 @@ hme_write32(hp, etxregs + ETX_RING, ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0))); + /* Parity issues in the ERX unit of some HME revisions can cause some + * registers to not be written unless their parity is even. Detect such + * lost writes and simply rewrite with a low bit set (which will be ignored + * since the rxring needs to be 2K aligned). + */ + if (hme_read32(hp, erxregs + ERX_RING) != + ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))) + hme_write32(hp, erxregs + ERX_RING, + ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)) + | 0x4); + /* Set the supported burst sizes. */ HMD(("happy_meal_init: old[%08x] bursts<", hme_read32(hp, gregs + GREG_CFG))); @@ -1699,7 +1673,7 @@ /* Enable Big Mac hash table filter. */ HMD(("happy_meal_init: enable hash rx_cfg_old[%08x], ", hme_read32(hp, bregs + BMAC_RXCFG))); - rxcfg = BIGMAC_RXCFG_HENABLE; + rxcfg = BIGMAC_RXCFG_HENABLE | BIGMAC_RXCFG_REJME; if (hp->dev->flags & IFF_PROMISC) rxcfg |= BIGMAC_RXCFG_PMISC; hme_write32(hp, bregs + BMAC_RXCFG, rxcfg); @@ -1712,7 +1686,14 @@ regtmp = 0; if (hp->happy_flags & HFLAG_FULL) regtmp |= BIGMAC_TXCFG_FULLDPLX; - hme_write32(hp, bregs + BMAC_TXCFG, regtmp | BIGMAC_TXCFG_DGIVEUP); + + /* Don't turn on the "don't give up" bit for now. It could cause hme + * to deadlock with the PHY if a Jabber occurs. + */ + hme_write32(hp, bregs + BMAC_TXCFG, regtmp /*| BIGMAC_TXCFG_DGIVEUP*/); + + /* Give up after 16 TX attempts. */ + hme_write32(hp, bregs + BMAC_ALIMIT, 16); /* Enable the output drivers no matter what. */ regtmp = BIGMAC_XCFG_ODENABLE; @@ -1745,6 +1726,7 @@ return 0; } +/* hp->happy_lock must be held */ static void happy_meal_set_initial_advertisement(struct happy_meal *hp) { unsigned long tregs = hp->tcvregs; @@ -1802,6 +1784,8 @@ /* Once status is latched (by happy_meal_interrupt) it is cleared by * the hardware, so we cannot re-read it and get a correct value. + * + * hp->happy_lock must be held */ static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status) { @@ -1910,12 +1894,13 @@ if (reset) { printk(KERN_NOTICE "%s: Resetting...\n", hp->dev->name); - happy_meal_init(hp, 1); + happy_meal_init(hp); return 1; } return 0; } +/* hp->happy_lock must be held */ static void happy_meal_mif_interrupt(struct happy_meal *hp) { unsigned long tregs = hp->tcvregs; @@ -1949,6 +1934,7 @@ #define TXD(x) #endif +/* hp->happy_lock must be held */ static void happy_meal_tx(struct happy_meal *hp) { struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0]; @@ -1956,8 +1942,6 @@ struct net_device *dev = hp->dev; int elem; - spin_lock(&hp->happy_lock); - elem = hp->tx_old; TXD(("TX<")); while (elem != hp->tx_new) { @@ -2001,10 +1985,8 @@ TXD((">")); if (netif_queue_stopped(dev) && - TX_BUFFS_AVAIL(hp) > 0) + TX_BUFFS_AVAIL(hp) > (MAX_SKB_FRAGS + 1)) netif_wake_queue(dev); - - spin_unlock(&hp->happy_lock); } #ifdef RXDEBUG @@ -2019,6 +2001,8 @@ * with all of the packets it has DMA'd in. So now I just drop the entire * ring when we cannot get a new skb and give them all back to the happy meal, * maybe things will be "happier" now. + * + * hp->happy_lock must be held */ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) { @@ -2128,10 +2112,12 @@ HMD(("happy_meal_interrupt: status=%08x ", happy_status)); + spin_lock(&hp->happy_lock); + if (happy_status & GREG_STAT_ERRORS) { HMD(("ERRORS ")); if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status)) - return; + goto out; } if (happy_status & GREG_STAT_MIFIRQ) { @@ -2150,6 +2136,8 @@ } HMD(("done\n")); +out: + spin_unlock(&hp->happy_lock); } #ifdef CONFIG_SBUS @@ -2171,10 +2159,12 @@ GREG_STAT_RXTOHOST))) continue; + spin_lock(&hp->happy_lock); + if (happy_status & GREG_STAT_ERRORS) { HMD(("ERRORS ")); if (happy_meal_is_not_so_happy(hp, happy_status)) - break; + goto next; } if (happy_status & GREG_STAT_MIFIRQ) { @@ -2191,6 +2181,9 @@ HMD(("RXTOHOST ")); happy_meal_rx(hp, dev); } + + next: + spin_unlock(&hp->happy_lock); } HMD(("done\n")); } @@ -2223,7 +2216,11 @@ } HMD(("to happy_meal_init\n")); - res = happy_meal_init(hp, 0); + + spin_lock_irq(&hp->happy_lock); + res = happy_meal_init(hp); + spin_unlock_irq(&hp->happy_lock); + if (res && ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO)) free_irq(dev->irq, dev); return res; @@ -2233,12 +2230,15 @@ { struct happy_meal *hp = dev->priv; + spin_lock_irq(&hp->happy_lock); happy_meal_stop(hp, hp->gregs); happy_meal_clean_rings(hp); /* If auto-negotiation timer is running, kill it. */ del_timer(&hp->happy_timer); + spin_unlock_irq(&hp->happy_lock); + /* On Quattro QFE cards, all hme interrupts are concentrated * into a single source which we register handling at probe * time and never unregister. @@ -2255,7 +2255,6 @@ #define SXD(x) #endif -#ifdef CONFIG_SBUS static void happy_meal_tx_timeout(struct net_device *dev) { struct happy_meal *hp = dev->priv; @@ -2266,10 +2265,13 @@ hme_read32(hp, hp->gregs + GREG_STAT), hme_read32(hp, hp->etxregs + ETX_CFG), hme_read32(hp, hp->bigmacregs + BMAC_TXCFG)); - happy_meal_init(hp, 0); + + spin_lock_irq(&hp->happy_lock); + happy_meal_init(hp); + spin_unlock_irq(&hp->happy_lock); + netif_wake_queue(dev); } -#endif static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -2294,6 +2296,8 @@ if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) { netif_stop_queue(dev); spin_unlock_irq(&hp->happy_lock); + printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n", + dev->name); return 1; } @@ -2346,7 +2350,7 @@ hp->tx_new = entry; - if (TX_BUFFS_AVAIL(hp) <= 0) + if (TX_BUFFS_AVAIL(hp) <= (MAX_SKB_FRAGS + 1)) netif_stop_queue(dev); /* Get it going. */ @@ -2364,7 +2368,10 @@ { struct happy_meal *hp = dev->priv; + spin_lock_irq(&hp->happy_lock); happy_meal_get_counters(hp, hp->bigmacregs); + spin_unlock_irq(&hp->happy_lock); + return &hp->net_stats; } @@ -2377,7 +2384,8 @@ int i; u32 crc; - /* Lock out others. */ + spin_lock_irq(&hp->happy_lock); + netif_stop_queue(dev); if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { @@ -2411,8 +2419,9 @@ hme_write32(hp, bregs + BMAC_HTABLE3, hash_table[3]); } - /* Let us get going again. */ netif_wake_queue(dev); + + spin_unlock_irq(&hp->happy_lock); } /* Ethtool support... */ @@ -2440,8 +2449,11 @@ ecmd.phy_address = 0; /* XXX fixed PHYAD */ /* Record PHY settings. */ + spin_lock_irq(&hp->happy_lock); hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR); hp->sw_lpa = happy_meal_tcvr_read(hp, hp->tcvregs, MII_LPA); + spin_unlock_irq(&hp->happy_lock); + if (hp->sw_bmcr & BMCR_ANENABLE) { ecmd.autoneg = AUTONEG_ENABLE; ecmd.speed = @@ -2483,10 +2495,12 @@ return -EINVAL; /* Ok, do it to it. */ + spin_lock_irq(&hp->happy_lock); del_timer(&hp->happy_timer); happy_meal_begin_auto_negotiation(hp, hp->tcvregs, &ecmd); + spin_unlock_irq(&hp->happy_lock); return 0; } else @@ -2808,7 +2822,9 @@ /* Grrr, Happy Meal comes up by default not advertising * full duplex 100baseT capabilities, fix this. */ + spin_lock_irq(&hp->happy_lock); happy_meal_set_initial_advertisement(hp); + spin_unlock_irq(&hp->happy_lock); if (register_netdev(hp->dev)) { printk(KERN_ERR "happymeal: Cannot register net device, " @@ -3121,6 +3137,8 @@ dev->hard_start_xmit = &happy_meal_start_xmit; dev->get_stats = &happy_meal_get_stats; dev->set_multicast_list = &happy_meal_set_multicast; + dev->tx_timeout = &happy_meal_tx_timeout; + dev->watchdog_timeo = 5*HZ; dev->do_ioctl = &happy_meal_ioctl; dev->irq = pdev->irq; dev->dma = 0; @@ -3143,7 +3161,9 @@ /* Grrr, Happy Meal comes up by default not advertising * full duplex 100baseT capabilities, fix this. */ + spin_lock_irq(&hp->happy_lock); happy_meal_set_initial_advertisement(hp); + spin_unlock_irq(&hp->happy_lock); if (register_netdev(hp->dev)) { printk(KERN_ERR "happymeal(PCI): Cannot register net device, " diff -urN linux-2.4.19-pre6/drivers/net/sunhme.h linux-2.4.19-pre7/drivers/net/sunhme.h --- linux-2.4.19-pre6/drivers/net/sunhme.h Mon Apr 15 21:53:59 2002 +++ linux-2.4.19-pre7/drivers/net/sunhme.h Mon Apr 15 21:54:43 2002 @@ -227,7 +227,7 @@ #define BIGMAC_RXCFG_PMISC 0x00000040 /* Enable promiscous mode */ #define BIGMAC_RXCFG_DERR 0x00000080 /* Disable error checking */ #define BIGMAC_RXCFG_DCRCS 0x00000100 /* Disable CRC stripping */ -#define BIGMAC_RXCFG_ME 0x00000200 /* Receive packets addressed to me */ +#define BIGMAC_RXCFG_REJME 0x00000200 /* Reject packets addressed to me */ #define BIGMAC_RXCFG_PGRP 0x00000400 /* Enable promisc group mode */ #define BIGMAC_RXCFG_HENABLE 0x00000800 /* Enable the hash filter */ #define BIGMAC_RXCFG_AENABLE 0x00001000 /* Enable the address filter */ diff -urN linux-2.4.19-pre6/drivers/net/tg3.c linux-2.4.19-pre7/drivers/net/tg3.c --- linux-2.4.19-pre6/drivers/net/tg3.c Mon Apr 15 21:53:59 2002 +++ linux-2.4.19-pre7/drivers/net/tg3.c Mon Apr 15 21:54:44 2002 @@ -52,8 +52,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "0.97" -#define DRV_MODULE_RELDATE "Mar 13, 2002" +#define DRV_MODULE_VERSION "0.98" +#define DRV_MODULE_RELDATE "Mar 28, 2002" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -1509,7 +1509,8 @@ if (unlikely(skb == NULL)) BUG(); - pci_unmap_single(tp->pdev, ri->mapping, + pci_unmap_single(tp->pdev, + pci_unmap_addr(ri, mapping), (skb->len - skb->data_len), PCI_DMA_TODEVICE); @@ -1526,7 +1527,7 @@ BUG(); pci_unmap_page(tp->pdev, - ri->mapping, + pci_unmap_addr(ri, mapping), skb_shinfo(skb)->frags[i].size, PCI_DMA_TODEVICE); @@ -1614,7 +1615,7 @@ PCI_DMA_FROMDEVICE); map->skb = skb; - map->mapping = mapping; + pci_unmap_addr_set(map, mapping, mapping); if (src_map != NULL) src_map->skb = NULL; @@ -1666,7 +1667,8 @@ }; dest_map->skb = src_map->skb; - dest_map->mapping = src_map->mapping; + pci_unmap_addr_set(dest_map, mapping, + pci_unmap_addr(src_map, mapping)); dest_desc->addr_hi = src_desc->addr_hi; dest_desc->addr_lo = src_desc->addr_lo; @@ -1723,17 +1725,20 @@ desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; if (opaque_key == RXD_OPAQUE_RING_STD) { - dma_addr = tp->rx_std_buffers[desc_idx].mapping; + dma_addr = pci_unmap_addr(&tp->rx_std_buffers[desc_idx], + mapping); skb = tp->rx_std_buffers[desc_idx].skb; post_ptr = &tp->rx_std_ptr; } else if (opaque_key == RXD_OPAQUE_RING_JUMBO) { - dma_addr = tp->rx_jumbo_buffers[desc_idx].mapping; + dma_addr = pci_unmap_addr(&tp->rx_jumbo_buffers[desc_idx], + mapping); skb = tp->rx_jumbo_buffers[desc_idx].skb; post_ptr = &tp->rx_jumbo_ptr; } #if TG3_MINI_RING_WORKS else if (opaque_key == RXD_OPAQUE_RING_MINI) { - dma_addr = tp->rx_mini_buffers[desc_idx].mapping; + dma_addr = pci_unmap_addr(&tp->rx_mini_buffers[desc_idx], + mapping); skb = tp->rx_mini_buffers[desc_idx].skb; post_ptr = &tp->rx_mini_ptr; } @@ -2072,8 +2077,9 @@ NIC_SRAM_TX_BUFFER_DESC); txd += (entry * TXD_SIZE); - writel(((u64) mapping >> 32), - txd + TXD_ADDR + TG3_64BIT_REG_HIGH); + if (sizeof(dma_addr_t) != sizeof(u32)) + writel(((u64) mapping >> 32), + txd + TXD_ADDR + TG3_64BIT_REG_HIGH); writel(((u64) mapping & 0xffffffff), txd + TXD_ADDR + TG3_64BIT_REG_LOW); @@ -2111,10 +2117,12 @@ frag->page, frag->page_offset, guilty_len, PCI_DMA_TODEVICE); } - pci_unmap_single(tp->pdev, tp->tx_buffers[guilty_entry].mapping, + pci_unmap_single(tp->pdev, pci_unmap_addr(&tp->tx_buffers[guilty_entry], + mapping), guilty_len, PCI_DMA_TODEVICE); tg3_set_txd_addr(tp, guilty_entry, new_addr); - tp->tx_buffers[guilty_entry].mapping = new_addr; + pci_unmap_addr_set(&tp->tx_buffers[guilty_entry], mapping, + new_addr); *start = last_plus_one; #else /* Oh well, no IOMMU, have to allocate a whole new SKB. */ @@ -2148,11 +2156,12 @@ len = skb->len - skb->data_len; else len = skb_shinfo(skb)->frags[i-1].size; - pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping, + pci_unmap_single(tp->pdev, + pci_unmap_addr(&tp->tx_buffers[entry], mapping), len, PCI_DMA_TODEVICE); if (i == 0) { tp->tx_buffers[entry].skb = new_skb; - tp->tx_buffers[entry].mapping = new_addr; + pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, new_addr); } else { tp->tx_buffers[entry].skb = NULL; } @@ -2199,8 +2208,7 @@ txd += (entry * TXD_SIZE); /* Save some PIOs */ - if (((u64) tp->tx_buffers[entry].mapping >> 32) != - ((u64) mapping >> 32)) + if (sizeof(dma_addr_t) != sizeof(u32)) writel(((u64) mapping >> 32), txd + TXD_ADDR + TG3_64BIT_REG_HIGH); @@ -2257,9 +2265,12 @@ mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE); tp->tx_buffers[entry].skb = skb; - tp->tx_buffers[entry].mapping = mapping; + pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); + + would_hit_hwbug = 0; - would_hit_hwbug = tg3_4g_overflow_test(mapping, len); + if (tg3_4g_overflow_test(mapping, len)) + would_hit_hwbug = entry + 1; tg3_set_txd(tp, entry, mapping, len, base_flags, (skb_shinfo(skb)->nr_frags == 0)); @@ -2281,10 +2292,14 @@ len, PCI_DMA_TODEVICE); tp->tx_buffers[entry].skb = NULL; - tp->tx_buffers[entry].mapping = mapping; + pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); - would_hit_hwbug |= - tg3_4g_overflow_test(mapping, len); + if (tg3_4g_overflow_test(mapping, len)) { + /* Only one should match. */ + if (would_hit_hwbug) + BUG(); + would_hit_hwbug = entry + 1; + } tg3_set_txd(tp, entry, mapping, len, base_flags, (i == last)); @@ -2298,19 +2313,18 @@ u32 start; unsigned int len = 0; + would_hit_hwbug -= 1; entry = entry - 1 - skb_shinfo(skb)->nr_frags; entry &= (TG3_TX_RING_SIZE - 1); start = entry; i = 0; while (entry != last_plus_one) { - dma_addr_t mapping = tp->tx_buffers[entry].mapping; - if (i == 0) len = skb->len - skb->data_len; else len = skb_shinfo(skb)->frags[i-1].size; - if (tg3_4g_overflow_test(mapping, len)) + if (entry == would_hit_hwbug) break; i++; @@ -2390,7 +2404,7 @@ mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE); tp->tx_buffers[entry].skb = skb; - tp->tx_buffers[entry].mapping = mapping; + pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); tg3_set_txd(tp, entry, mapping, len, base_flags, (skb_shinfo(skb)->nr_frags == 0)); @@ -2413,7 +2427,7 @@ len, PCI_DMA_TODEVICE); tp->tx_buffers[entry].skb = NULL; - tp->tx_buffers[entry].mapping = mapping; + pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); tg3_set_txd(tp, entry, mapping, len, base_flags, (i == last)); @@ -2497,7 +2511,8 @@ if (rxp->skb == NULL) continue; - pci_unmap_single(tp->pdev, rxp->mapping, + pci_unmap_single(tp->pdev, + pci_unmap_addr(rxp, mapping), RX_PKT_BUF_SZ - tp->rx_offset, PCI_DMA_FROMDEVICE); dev_kfree_skb(rxp->skb); @@ -2509,7 +2524,8 @@ if (rxp->skb == NULL) continue; - pci_unmap_single(tp->pdev, rxp->mapping, + pci_unmap_single(tp->pdev, + pci_unmap_addr(rxp, mapping), RX_MINI_PKT_BUF_SZ - tp->rx_offset, PCI_DMA_FROMDEVICE); dev_kfree_skb(rxp->skb); @@ -2521,7 +2537,8 @@ if (rxp->skb == NULL) continue; - pci_unmap_single(tp->pdev, rxp->mapping, + pci_unmap_single(tp->pdev, + pci_unmap_addr(rxp, mapping), RX_JUMBO_PKT_BUF_SZ - tp->rx_offset, PCI_DMA_FROMDEVICE); dev_kfree_skb(rxp->skb); @@ -2541,7 +2558,8 @@ continue; } - pci_unmap_single(tp->pdev, txp->mapping, + pci_unmap_single(tp->pdev, + pci_unmap_addr(txp, mapping), (skb->len - skb->data_len), PCI_DMA_TODEVICE); txp->skb = NULL; @@ -2550,7 +2568,8 @@ for (j = 0; j < skb_shinfo(skb)->nr_frags; j++) { txp = &tp->tx_buffers[i & (TG3_TX_RING_SIZE - 1)]; - pci_unmap_page(tp->pdev, txp->mapping, + pci_unmap_page(tp->pdev, + pci_unmap_addr(txp, mapping), skb_shinfo(skb)->frags[j].size, PCI_DMA_TODEVICE); i++; @@ -4770,6 +4789,7 @@ edata.data = netif_carrier_ok(tp->dev) ? 1 : 0; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; + return 0; } case ETHTOOL_GCOALESCE: { struct ethtool_coalesce ecoal = { ETHTOOL_GCOALESCE }; @@ -5441,10 +5461,23 @@ pci_read_config_dword(tp->pdev, TG3PCI_CACHELINESZ, &cacheline_sz_reg); - tp->pci_cacheline_sz = (cacheline_sz_reg >> 24) & 0xff; - tp->pci_lat_timer = (cacheline_sz_reg >> 16) & 0xff; - tp->pci_hdr_type = (cacheline_sz_reg >> 8) & 0xff; - tp->pci_bist = (cacheline_sz_reg >> 0) & 0xff; + tp->pci_cacheline_sz = (cacheline_sz_reg >> 0) & 0xff; + tp->pci_lat_timer = (cacheline_sz_reg >> 8) & 0xff; + tp->pci_hdr_type = (cacheline_sz_reg >> 16) & 0xff; + tp->pci_bist = (cacheline_sz_reg >> 24) & 0xff; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 && + tp->pci_lat_timer < 64) { + tp->pci_lat_timer = 64; + + cacheline_sz_reg = ((tp->pci_cacheline_sz & 0xff) << 0); + cacheline_sz_reg |= ((tp->pci_lat_timer & 0xff) << 8); + cacheline_sz_reg |= ((tp->pci_hdr_type & 0xff) << 16); + cacheline_sz_reg |= ((tp->pci_bist & 0xff) << 24); + + pci_write_config_dword(tp->pdev, TG3PCI_CACHELINESZ, + cacheline_sz_reg); + } pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &pci_state_reg); @@ -5924,6 +5957,10 @@ tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl); + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) + return 0; + ret = 0; while (1) { u32 *p, i; diff -urN linux-2.4.19-pre6/drivers/net/tg3.h linux-2.4.19-pre7/drivers/net/tg3.h --- linux-2.4.19-pre6/drivers/net/tg3.h Mon Apr 15 21:53:59 2002 +++ linux-2.4.19-pre7/drivers/net/tg3.h Mon Apr 15 21:54:44 2002 @@ -99,6 +99,7 @@ #define CHIPREV_ID_5700_A1 0x7001 #define CHIPREV_ID_5700_B0 0x7100 #define CHIPREV_ID_5700_B1 0x7101 +#define CHIPREV_ID_5700_B3 0x7102 #define CHIPREV_ID_5700_C0 0x7200 #define CHIPREV_ID_5701_A0 0x0000 #define CHIPREV_ID_5701_B0 0x0100 @@ -1654,7 +1655,7 @@ */ struct ring_info { struct sk_buff *skb; - dma_addr_t mapping; + DECLARE_PCI_UNMAP_ADDR(mapping) }; struct tg3_config_info { diff -urN linux-2.4.19-pre6/drivers/pci/pci.ids linux-2.4.19-pre7/drivers/pci/pci.ids --- linux-2.4.19-pre6/drivers/pci/pci.ids Mon Apr 15 21:53:59 2002 +++ linux-2.4.19-pre7/drivers/pci/pci.ids Mon Apr 15 21:54:44 2002 @@ -1120,6 +1120,9 @@ 121a NetServer SMIC Controller 121b NetServer Legacy COM Port Decoder 121c NetServer PCI COM Port Decoder + 1229 zx1 System Bus Adapter + 122a zx1 I/O Controller + 122e zx1 Local Bus Adapter 2910 E2910A PCIBus Exerciser 2925 E2925A 32 Bit, 33 MHzPCI Exerciser & Analyzer 103e Solliday Engineering diff -urN linux-2.4.19-pre6/drivers/pcmcia/Config.in linux-2.4.19-pre7/drivers/pcmcia/Config.in --- linux-2.4.19-pre6/drivers/pcmcia/Config.in Mon Apr 15 21:53:59 2002 +++ linux-2.4.19-pre7/drivers/pcmcia/Config.in Mon Apr 15 21:54:44 2002 @@ -24,6 +24,8 @@ dep_tristate ' HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA fi fi -dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA +if [ "$CONFIG_ARM" = "y" ]; then + dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA +fi endmenu diff -urN linux-2.4.19-pre6/drivers/s390/ccwcache.c linux-2.4.19-pre7/drivers/s390/ccwcache.c --- linux-2.4.19-pre6/drivers/s390/ccwcache.c Wed Jul 25 14:12:02 2001 +++ linux-2.4.19-pre7/drivers/s390/ccwcache.c Mon Apr 15 21:54:45 2002 @@ -291,9 +291,11 @@ /* Shrink the caches, if available */ for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) { if ( ccw_cache[cachind] ) { +#if 0 /* this is useless and could cause an OOPS in the worst case */ if ( kmem_cache_shrink(ccw_cache[cachind]) == 0 ) { ccw_cache[cachind] = NULL; } +#endif kmem_cache_destroy(ccw_cache[cachind]); } } diff -urN linux-2.4.19-pre6/drivers/sbus/sbus.c linux-2.4.19-pre7/drivers/sbus/sbus.c --- linux-2.4.19-pre6/drivers/sbus/sbus.c Mon Feb 25 11:38:04 2002 +++ linux-2.4.19-pre7/drivers/sbus/sbus.c Mon Apr 15 21:54:45 2002 @@ -391,6 +391,10 @@ sbus_bus_ranges_init(iommund, sbus); sbus_devs = prom_getchild(this_sbus); + if (!sbus_devs) { + sbus->devices = NULL; + goto next_bus; + } sbus->devices = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC); @@ -454,7 +458,7 @@ sbus_fixup_all_regs(sbus->devices); dvma_init(sbus); - + next_bus: num_sbus++; if(sparc_cpu_model == sun4u) { this_sbus = prom_getsibling(this_sbus); diff -urN linux-2.4.19-pre6/drivers/scsi/Makefile linux-2.4.19-pre7/drivers/scsi/Makefile --- linux-2.4.19-pre6/drivers/scsi/Makefile Mon Feb 25 11:38:04 2002 +++ linux-2.4.19-pre7/drivers/scsi/Makefile Mon Apr 15 21:54:45 2002 @@ -69,7 +69,7 @@ obj-$(CONFIG_SCSI_AACRAID) += aacraid/aacraid.o endif ifeq ($(CONFIG_SCSI_AIC7XXX),y) -obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/aic7xxx_drv.o + obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/aic7xxx.o endif obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o obj-$(CONFIG_SCSI_IPS) += ips.o diff -urN linux-2.4.19-pre6/drivers/scsi/aacraid/Makefile linux-2.4.19-pre7/drivers/scsi/aacraid/Makefile --- linux-2.4.19-pre6/drivers/scsi/aacraid/Makefile Fri Dec 21 09:41:55 2001 +++ linux-2.4.19-pre7/drivers/scsi/aacraid/Makefile Mon Apr 15 21:54:46 2002 @@ -1,16 +1,10 @@ EXTRA_CFLAGS += -I$(TOPDIR)/drivers/scsi +O_TARGET := aacraid.o +obj-m := $(O_TARGET) -O_TARGET := dummy.o - -list-multi := aacraid.o -aacraid-objs := linit.o aachba.o commctrl.o comminit.o commsup.o \ +obj-y := linit.o aachba.o commctrl.o comminit.o commsup.o \ dpcsup.o rx.o sap1sup.o -obj-$(CONFIG_SCSI_AACRAID) += aacraid.o - include $(TOPDIR)/Rules.make - -aacraid.o: $(aacraid-objs) - $(LD) -r -o $@ $(aacraid-objs) diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/Makefile linux-2.4.19-pre7/drivers/scsi/aic7xxx/Makefile --- linux-2.4.19-pre6/drivers/scsi/aic7xxx/Makefile Mon Apr 15 21:54:00 2002 +++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/Makefile Mon Apr 15 21:54:46 2002 @@ -6,26 +6,23 @@ O_TARGET := aic7xxx_drv.o -list-multi := aic7xxx_mod.o aic79xx_mod.o +list-multi := aic7xxx.o -ifeq (aic7xxx_core.c, $(wildcard aic7xxx_core.c)) obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx.o -endif #EXTRA_CFLAGS += -g # Platform Specific Files -AIC7XXX_OBJS = aic7xxx_osm.o -AIC7XXX_OBJS += aic7xxx_proc.o aic7770_osm.o +obj-aic7xxx = aic7xxx_osm.o aic7xxx_proc.o aic7770_osm.o #PCI Specific Platform Files ifeq ($(CONFIG_PCI),y) -AIC7XXX_OBJS += aic7xxx_osm_pci.o +obj-aic7xxx += aic7xxx_osm_pci.o endif # Core Files -AIC7XXX_OBJS += aic7xxx_core.o aic7xxx_93cx6.o aic7770.o +obj-aic7xxx += aic7xxx_core.o aic7xxx_93cx6.o aic7770.o #PCI Specific Core Files ifeq ($(CONFIG_PCI),y) -AIC7XXX_OBJS += aic7xxx_pci.o +obj-aic7xxx += aic7xxx_pci.o endif # Override our module desitnation @@ -33,12 +30,14 @@ include $(TOPDIR)/Rules.make -.NOPARALLEL: - -aic7xxx.o: aic7xxx_seq.h aic7xxx_reg.h $(AIC7XXX_OBJS) - $(LD) $(LD_RFLAG) -r -o $@ $(AIC7XXX_OBJS) +aic7xxx.o: $(obj-aic7xxx) + $(LD) $(LD_RFLAG) -r -o $@ $(obj-aic7xxx) ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y) +aic7xxx_core.o: aic7xxx_seq.h + +$(obj-aic7xxx): aic7xxx_reg.h + aic7xxx_seq.h aic7xxx_reg.h: aic7xxx.seq aic7xxx.reg aicasm/aicasm aicasm/aicasm -I. -r aic7xxx_reg.h -o aic7xxx_seq.h aic7xxx.seq endif diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx.h linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx.h --- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx.h Mon Apr 15 21:54:00 2002 +++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx.h Mon Apr 15 21:54:46 2002 @@ -51,6 +51,7 @@ /************************* Forward Declarations *******************************/ struct ahc_platform_data; struct scb_platform_data; +struct seeprom_descriptor; /****************************** Useful Macros *********************************/ #ifndef MAX @@ -1117,6 +1118,7 @@ int ahc_suspend(struct ahc_softc *ahc); int ahc_resume(struct ahc_softc *ahc); void ahc_softc_insert(struct ahc_softc *); +struct ahc_softc *ahc_find_softc(struct ahc_softc *ahc); void ahc_set_unit(struct ahc_softc *, int); void ahc_set_name(struct ahc_softc *, char *); void ahc_alloc_scbs(struct ahc_softc *ahc); @@ -1228,4 +1230,8 @@ #endif void ahc_print_scb(struct scb *scb); void ahc_dump_card_state(struct ahc_softc *ahc); +/******************************* SEEPROM *************************************/ +int ahc_acquire_seeprom(struct ahc_softc *ahc, + struct seeprom_descriptor *sd); +void ahc_release_seeprom(struct seeprom_descriptor *sd); #endif /* _AIC7XXX_H_ */ diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx.reg linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx.reg --- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx.reg Mon Apr 15 21:54:00 2002 +++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx.reg Mon Apr 15 21:54:46 2002 @@ -1319,7 +1319,7 @@ bit SDMAENACK 0x10 bit HDMAEN 0x08 bit HDMAENACK 0x08 - bit DIRECTION 0x04 + bit DIRECTION 0x04 /* Set indicates PCI->SCSI */ bit FIFOFLUSH 0x02 bit FIFORESET 0x01 } diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_93cx6.c linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_93cx6.c --- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_93cx6.c Mon Apr 15 21:54:00 2002 +++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_93cx6.c Mon Apr 15 21:54:46 2002 @@ -83,9 +83,13 @@ */ static struct seeprom_cmd { uint8_t len; - uint8_t bits[3]; + uint8_t bits[9]; } seeprom_read = {3, {1, 1, 0}}; +static struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}}; +static struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}}; +static struct seeprom_cmd seeprom_write = {3, {1, 0, 1}}; + /* * Wait for the SEERDY to go high; about 800 ns. */ @@ -96,6 +100,49 @@ (void)SEEPROM_INB(sd); /* Clear clock */ /* + * Send a START condition and the given command + */ +static void +send_seeprom_cmd(struct seeprom_descriptor *sd, struct seeprom_cmd *cmd) +{ + uint8_t temp; + int i = 0; + + /* Send chip select for one clock cycle. */ + temp = sd->sd_MS ^ sd->sd_CS; + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + + for (i = 0; i < cmd->len; i++) { + if (cmd->bits[i] != 0) + temp ^= sd->sd_DO; + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + if (cmd->bits[i] != 0) + temp ^= sd->sd_DO; + } +} + +/* + * Clear CS put the chip in the reset state, where it can wait for new commands. + */ +static void +reset_seeprom(struct seeprom_descriptor *sd) +{ + uint8_t temp; + + temp = sd->sd_MS; + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); +} + +/* * Read the serial EEPROM and returns 1 if successful and 0 if * not successful. */ @@ -113,26 +160,14 @@ * will range from 0 to count-1. */ for (k = start_addr; k < count + start_addr; k++) { - /* Send chip select for one clock cycle. */ - temp = sd->sd_MS ^ sd->sd_CS; - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - /* * Now we're ready to send the read command followed by the * address of the 16-bit register we want to read. */ - for (i = 0; i < seeprom_read.len; i++) { - if (seeprom_read.bits[i] != 0) - temp ^= sd->sd_DO; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - if (seeprom_read.bits[i] != 0) - temp ^= sd->sd_DO; - } + send_seeprom_cmd(sd, &seeprom_read); + /* Send the 6 or 8 bit address (MSB first, LSB last). */ + temp = sd->sd_MS ^ sd->sd_CS; for (i = (sd->sd_chip - 1); i >= 0; i--) { if ((k & (1 << i)) != 0) temp ^= sd->sd_DO; @@ -164,13 +199,7 @@ buf[k - start_addr] = v; /* Reset the chip select for the next command cycle. */ - temp = sd->sd_MS; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); + reset_seeprom(sd); } #ifdef AHC_DUMP_EEPROM printf("\nSerial EEPROM:\n\t"); @@ -185,6 +214,75 @@ return (1); } +/* + * Write the serial EEPROM and return 1 if successful and 0 if + * not successful. + */ +int +ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, + u_int start_addr, u_int count) +{ + uint16_t v; + uint8_t temp; + int i, k; + + /* Place the chip into write-enable mode */ + send_seeprom_cmd(sd, &seeprom_ewen); + reset_seeprom(sd); + + /* Write all requested data out to the seeprom. */ + temp = sd->sd_MS ^ sd->sd_CS; + for (k = start_addr; k < count + start_addr; k++) { + /* Send the write command */ + send_seeprom_cmd(sd, &seeprom_write); + + /* Send the 6 or 8 bit address (MSB first). */ + for (i = (sd->sd_chip - 1); i >= 0; i--) { + if ((k & (1 << i)) != 0) + temp ^= sd->sd_DO; + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + if ((k & (1 << i)) != 0) + temp ^= sd->sd_DO; + } + + /* Write the 16 bit value, MSB first */ + v = buf[k - start_addr]; + for (i = 15; i >= 0; i--) { + if ((v & (1 << i)) != 0) + temp ^= sd->sd_DO; + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + if ((v & (1 << i)) != 0) + temp ^= sd->sd_DO; + } + + /* Wait for the chip to complete the write */ + temp = sd->sd_MS; + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + temp = sd->sd_MS ^ sd->sd_CS; + do { + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + } while ((SEEPROM_DATA_INB(sd) & sd->sd_DI) == 0); + + reset_seeprom(sd); + } + + /* Put the chip back into write-protect mode */ + send_seeprom_cmd(sd, &seeprom_ewds); + reset_seeprom(sd); + + return (1); +} + int ahc_verify_cksum(struct seeprom_config *sc) { diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_93cx6.h linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_93cx6.h --- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_93cx6.h Mon Apr 15 21:54:00 2002 +++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_93cx6.h Mon Apr 15 21:54:46 2002 @@ -95,6 +95,8 @@ int ahc_read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, u_int start_addr, u_int count); +int ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, + u_int start_addr, u_int count); int ahc_verify_cksum(struct seeprom_config *sc); #endif /* _AIC7XXX_93CX6_H_ */ diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_core.c linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_core.c --- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_core.c Mon Apr 15 21:54:00 2002 +++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_core.c Mon Apr 15 21:54:46 2002 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_core.c#1 $ + * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_core.c#2 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.61 2000/11/13 03:35:43 gibbs Exp $ */ @@ -821,7 +821,12 @@ * target does a command complete. */ ahc_freeze_devq(ahc, scb); - ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); + if ((scb->flags & SCB_SENSE) == 0) { + ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); + } else { + scb->flags &= ~SCB_SENSE; + ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); + } ahc_freeze_scb(scb); if ((ahc->features & AHC_ULTRA2) != 0) { @@ -1495,7 +1500,7 @@ memcpy(tstate, master_tstate, sizeof(*tstate)); memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns)); tstate->ultraenb = 0; - for (i = 0; i < 16; i++) { + for (i = 0; i < AHC_NUM_TARGETS; i++) { memset(&tstate->transinfo[i].curr, 0, sizeof(tstate->transinfo[i].curr)); memset(&tstate->transinfo[i].goal, 0, @@ -2598,7 +2603,7 @@ /* * Read the latched byte, but turn off SPIOEN first - * so that we don't inadvertantly cause a REQ for the + * so that we don't inadvertently cause a REQ for the * next byte. */ ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN); @@ -3541,7 +3546,7 @@ ahc->bugs = AHC_BUGNONE; ahc->flags = AHC_FNONE; - for (i = 0; i < 16; i++) + for (i = 0; i < AHC_NUM_TARGETS; i++) TAILQ_INIT(&ahc->untagged_queues[i]); if (ahc_platform_alloc(ahc, platform_arg) != 0) { ahc_free(ahc); @@ -3628,6 +3633,22 @@ ahc->init_level++; } +/* + * Verify that the passed in softc pointer is for a + * controller that is still configured. + */ +struct ahc_softc * +ahc_find_softc(struct ahc_softc *ahc) +{ + struct ahc_softc *list_ahc; + + TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { + if (list_ahc == ahc) + return (ahc); + } + return (NULL); +} + void ahc_set_unit(struct ahc_softc *ahc, int unit) { diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_host.h linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_host.h --- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_host.h Mon Apr 15 21:54:00 2002 +++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_host.h Mon Apr 15 21:54:46 2002 @@ -36,7 +36,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_host.h#1 $ + * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_host.h#3 $ */ #ifndef _AIC7XXX_HOST_H_ @@ -82,12 +82,12 @@ reset: NULL, \ slave_attach: NULL, \ bios_param: AIC7XXX_BIOSPARAM, \ - can_queue: 253, /* max simultaneous cmds */\ - this_id: -1, /* scsi id of host adapter */\ - sg_tablesize: 0, /* max scatter-gather cmds */\ - cmd_per_lun: 2, /* cmds per lun */\ - present: 0, /* number of 7xxx's present */\ - unchecked_isa_dma: 0, /* no memory DMA restrictions */\ + can_queue: AHC_MAX_QUEUE,/* max simultaneous cmds */\ + this_id: -1, /* scsi id of host adapter */\ + sg_tablesize: AHC_NSEG, /* max scatter-gather cmds */\ + cmd_per_lun: 2, /* cmds per lun */\ + present: 0, /* number of 7xxx's present */\ + unchecked_isa_dma: 0, /* no memory DMA restrictions*/\ use_clustering: ENABLE_CLUSTERING, \ use_new_eh_code: 1 \ } diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_osm.c linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_osm.c --- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_osm.c Mon Apr 15 21:54:00 2002 +++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_osm.c Mon Apr 15 21:54:46 2002 @@ -1,7 +1,7 @@ /* * Adaptec AIC7xxx device driver for Linux. * - * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_osm.c#1 $ + * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_osm.c#4 $ * * Copyright (c) 1994 John Aycock * The University of Calgary Department of Computer Science. @@ -1134,7 +1134,15 @@ #else template->proc_dir = &proc_scsi_aic7xxx; #endif - template->sg_tablesize = AHC_NSEG; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) + /* + * We can only map 16MB per-SG + * so create a sector limit of + * "16MB" in 2K sectors. + */ + template->max_sectors = 8192; +#endif #ifdef CONFIG_PCI ahc_linux_pci_probe(template); @@ -1370,6 +1378,14 @@ #endif free(ahc->platform_data, M_DEVBUF); } + if (TAILQ_EMPTY(&ahc_tailq)) { + unregister_reboot_notifier(&ahc_linux_notifier); +#ifdef CONFIG_PCI +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pci_unregister_driver(&aic7xxx_pci_driver); +#endif +#endif + } } void @@ -2871,16 +2887,14 @@ if (host != NULL) { - ahc = *(struct ahc_softc **)host->hostdata; - ahc_free(ahc); - } - if (TAILQ_EMPTY(&ahc_tailq)) { - unregister_reboot_notifier(&ahc_linux_notifier); -#ifdef CONFIG_PCI -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - pci_unregister_driver(&aic7xxx_pci_driver); -#endif -#endif + /* + * We should be able to just perform + * the free directly, but check our + * list for extra sanity. + */ + ahc = ahc_find_softc(*(struct ahc_softc **)host->hostdata); + if (ahc != NULL) + ahc_free(ahc); } return (0); } diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_osm.h linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_osm.h --- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_osm.h Mon Apr 15 21:54:00 2002 +++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_osm.h Mon Apr 15 21:54:46 2002 @@ -409,7 +409,7 @@ #include #endif -#define AIC7XXX_DRIVER_VERSION "6.2.5" +#define AIC7XXX_DRIVER_VERSION "6.2.6" /**************************** Front End Queues ********************************/ /* diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c --- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c Mon Apr 15 21:54:00 2002 +++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c Mon Apr 15 21:54:46 2002 @@ -36,7 +36,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#1 $ + * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#2 $ */ #include "aic7xxx_osm.h" @@ -85,20 +85,15 @@ ahc_linux_pci_dev_remove(struct pci_dev *pdev) { struct ahc_softc *ahc; - struct ahc_softc *list_ahc; /* * We should be able to just perform * the free directly, but check our * list for extra sanity. */ - ahc = (struct ahc_softc *)pdev->driver_data; - TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { - if (list_ahc == ahc) { - ahc_free(ahc); - break; - } - } + ahc = ahc_find_softc((struct ahc_softc *)pdev->driver_data); + if (ahc != NULL) + ahc_free(ahc); } #endif /* !LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) */ diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_pci.c linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_pci.c --- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_pci.c Mon Apr 15 21:54:00 2002 +++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_pci.c Mon Apr 15 21:54:46 2002 @@ -685,9 +685,6 @@ static void aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present, int *externalcable_present, int *eeprom_present); -static int acquire_seeprom(struct ahc_softc *ahc, - struct seeprom_descriptor *sd); -static void release_seeprom(struct seeprom_descriptor *sd); static void write_brdctl(struct ahc_softc *ahc, uint8_t value); static uint8_t read_brdctl(struct ahc_softc *ahc); @@ -1013,6 +1010,14 @@ if ((ahc->features & AHC_ULTRA2) != 0) ramps = (ahc_inb(ahc, DSCOMMAND0) & RAMPS) != 0; + else if (chip == AHC_AIC7895 || chip == AHC_AIC7895C) + /* + * External SCBRAM arbitration is flakey + * on these chips. Unfortunately this means + * we don't use the extra SCB ram space on the + * 3940AUW. + */ + ramps = 0; else if (chip >= AHC_AIC7870) ramps = (devconfig & RAMPSM) != 0; else @@ -1215,7 +1220,7 @@ sd.sd_DO = SEEDO; sd.sd_DI = SEEDI; - have_seeprom = acquire_seeprom(ahc, &sd); + have_seeprom = ahc_acquire_seeprom(ahc, &sd); if (have_seeprom) { if (bootverbose) @@ -1244,7 +1249,7 @@ } sd.sd_chip = C56_66; } - release_seeprom(&sd); + ahc_release_seeprom(&sd); } if (!have_seeprom) { @@ -1428,9 +1433,9 @@ } if (have_autoterm) { - acquire_seeprom(ahc, &sd); + ahc_acquire_seeprom(ahc, &sd); configure_termination(ahc, &sd, adapter_control, sxfrctl1); - release_seeprom(&sd); + ahc_release_seeprom(&sd); } } @@ -1736,8 +1741,8 @@ *eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0; } -static int -acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd) +int +ahc_acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd) { int wait; @@ -1764,8 +1769,8 @@ return(1); } -static void -release_seeprom(struct seeprom_descriptor *sd) +void +ahc_release_seeprom(struct seeprom_descriptor *sd) { /* Release access to the memory port and the serial EEPROM. */ SEEPROM_OUTB(sd, 0); diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_proc.c linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_proc.c --- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_proc.c Mon Apr 15 21:54:01 2002 +++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_proc.c Mon Apr 15 21:54:46 2002 @@ -41,6 +41,7 @@ */ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" +#include "aic7xxx_93cx6.h" static void copy_mem_info(struct info_str *info, char *data, int len); static int copy_info(struct info_str *info, char *fmt, ...); @@ -225,6 +226,55 @@ copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen); } +static int +ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length) +{ + struct seeprom_descriptor sd; + int have_seeprom; + + if (length != sizeof(struct seeprom_config)) { + printf("ahc_proc_write_seeprom: incorrect buffer size\n"); + return (-EINVAL); + } + + have_seeprom = ahc_verify_cksum((struct seeprom_config*)buffer); + if (have_seeprom == 0) { + printf("ahc_proc_write_seeprom: checksum verification failuire\n"); + return (-EINVAL); + } + + sd.sd_ahc = ahc; + sd.sd_control_offset = SEECTL; + sd.sd_status_offset = SEECTL; + sd.sd_dataout_offset = SEECTL; + if (ahc->flags & AHC_LARGE_SEEPROM) + sd.sd_chip = C56_66; + else + sd.sd_chip = C46; + sd.sd_MS = SEEMS; + sd.sd_RDY = SEERDY; + sd.sd_CS = SEECS; + sd.sd_CK = SEECK; + sd.sd_DO = SEEDO; + sd.sd_DI = SEEDI; + + have_seeprom = ahc_acquire_seeprom(ahc, &sd); + if (!have_seeprom) { + printf("ahc_proc_write_seeprom: No Serial EEPROM\n"); + return (-EINVAL); + } else { + u_int start_addr; + + printf("aic7xxx: Writing Serial EEPROM\n"); + start_addr = 32 * (ahc->channel - 'A'); + ahc_write_seeprom(&sd, (u_int16_t *)buffer, start_addr, + sizeof(struct seeprom_config)); + ahc_release_seeprom(&sd); + } + + return (length); +} + /* * Return information to handle /proc support for the driver. */ @@ -234,9 +284,12 @@ { struct ahc_softc *ahc; struct info_str info; + struct seeprom_descriptor sd; char ahc_info[256]; + u_int16_t buf[32]; u_int max_targ; u_int i; + int have_seeprom; TAILQ_FOREACH(ahc, &ahc_tailq, links) { if (ahc->platform_data->host->host_no == hostno) @@ -248,7 +301,7 @@ /* Has data been written to the file? */ if (inout == TRUE) - return (-ENOSYS); + return (ahc_proc_write_seeprom(ahc, buffer, length)); if (start) *start = buffer; @@ -261,7 +314,51 @@ copy_info(&info, "Adaptec AIC7xxx driver version: %s\n", AIC7XXX_DRIVER_VERSION); ahc_controller_info(ahc, ahc_info); - copy_info(&info, "%s\n", ahc_info); + copy_info(&info, "%s\n\n", ahc_info); + + sd.sd_ahc = ahc; + sd.sd_control_offset = SEECTL; + sd.sd_status_offset = SEECTL; + sd.sd_dataout_offset = SEECTL; + if (ahc->flags & AHC_LARGE_SEEPROM) + sd.sd_chip = C56_66; + else + sd.sd_chip = C46; + sd.sd_MS = SEEMS; + sd.sd_RDY = SEERDY; + sd.sd_CS = SEECS; + sd.sd_CK = SEECK; + sd.sd_DO = SEEDO; + sd.sd_DI = SEEDI; + + have_seeprom = ahc_acquire_seeprom(ahc, &sd); + if (!have_seeprom) + copy_info(&info, "No Serial EEPROM\n"); + else { + u_int start_addr; + + start_addr = 32 * (ahc->channel - 'A'); + have_seeprom = ahc_read_seeprom(&sd, (u_int16_t *)&buf, + start_addr, sizeof(buf)/2); + if (have_seeprom) + have_seeprom = + ahc_verify_cksum((struct seeprom_config*)&buf); + if (have_seeprom == 0) + copy_info(&info, "Corrupted Serial EEPROM\n"); + else { + copy_info(&info, "Serial EEPROM:\n"); + for (i = 0; i < sizeof(buf)/2; i++) { + if (((i % 8) == 0) && (i != 0)) { + copy_info(&info, "\n"); + } + copy_info(&info, "0x%.4x ", buf[i]); + } + copy_info(&info, "\n"); + } + ahc_release_seeprom(&sd); + } + + copy_info(&info, "\n"); max_targ = 15; if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0) diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_reg.h linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_reg.h --- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_reg.h Mon Apr 15 21:54:01 2002 +++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_reg.h Mon Apr 15 21:54:46 2002 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id$ - * $Id$ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#39 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#27 $ */ #define SCSISEQ 0x00 diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_seq.h linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_seq.h --- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_seq.h Mon Apr 15 21:54:01 2002 +++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_seq.h Mon Apr 15 21:54:46 2002 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id$ - * $Id$ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#39 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#27 $ */ static uint8_t seqprog[] = { 0xb2, 0x00, 0x00, 0x08, diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aicasm/Makefile linux-2.4.19-pre7/drivers/scsi/aic7xxx/aicasm/Makefile --- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aicasm/Makefile Mon Apr 15 21:54:01 2002 +++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aicasm/Makefile Mon Apr 15 21:54:46 2002 @@ -29,8 +29,6 @@ LFLAGS= -d endif -.NOTPARALLEL: - $(PROG): ${GENHDRS} $(SRCS) $(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) @@ -61,7 +59,7 @@ mv $(<:.y=).tab.h $(<:.y=.h) aicasm_scan.c: aicasm_scan.l - $(LEX) $(LFLAGS) -t $< > $@ + $(LEX) $(LFLAGS) -o$@ $< aicasm_macro_scan.c: aicasm_macro_scan.l - $(LEX) $(LFLAGS) -t -Pmm $< > $@ + $(LEX) $(LFLAGS) -Pmm -o$@ $< diff -urN linux-2.4.19-pre6/drivers/scsi/sd.c linux-2.4.19-pre7/drivers/scsi/sd.c --- linux-2.4.19-pre6/drivers/scsi/sd.c Mon Apr 15 21:54:01 2002 +++ linux-2.4.19-pre7/drivers/scsi/sd.c Mon Apr 15 21:54:49 2002 @@ -65,8 +65,13 @@ * static const char RCSid[] = "$Header:"; */ +/* system major --> sd_gendisks index */ +#define SD_MAJOR_IDX(i) (MAJOR(i) & SD_MAJOR_MASK) +/* sd_gendisks index --> system major */ #define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i)) +#define SD_PARTITION(dev) ((SD_MAJOR_IDX(dev) << 8) | (MINOR(dev) & 255)) + #define SCSI_DISKS_PER_MAJOR 16 #define SD_MAJOR_NUMBER(i) SD_MAJOR((i) >> 8) #define SD_MINOR_NUMBER(i) ((i) & 255) @@ -84,9 +89,8 @@ #define SD_TIMEOUT (30 * HZ) #define SD_MOD_TIMEOUT (75 * HZ) -struct hd_struct *sd; - static Scsi_Disk *rscsi_disks; +static struct gendisk *sd_gendisks; static int *sd_sizes; static int *sd_blocksizes; static int *sd_hardsizes; /* Hardware sector size */ @@ -195,7 +199,9 @@ if (put_user(diskinfo[0], &loc->heads) || put_user(diskinfo[1], &loc->sectors) || put_user(diskinfo[2], &loc->cylinders) || - put_user(sd[SD_PARTITION(inode->i_rdev)].start_sect, &loc->start)) + put_user(sd_gendisks[SD_MAJOR_IDX( + inode->i_rdev)].part[MINOR( + inode->i_rdev)].start_sect, &loc->start)) return -EFAULT; return 0; } @@ -226,7 +232,9 @@ if (put_user(diskinfo[0], &loc->heads) || put_user(diskinfo[1], &loc->sectors) || put_user(diskinfo[2], (unsigned int *) &loc->cylinders) || - put_user(sd[SD_PARTITION(inode->i_rdev)].start_sect, &loc->start)) + put_user(sd_gendisks[SD_MAJOR_IDX( + inode->i_rdev)].part[MINOR( + inode->i_rdev)].start_sect, &loc->start)) return -EFAULT; return 0; } @@ -286,30 +294,32 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) { - int dev, devm, block, this_count; + int dev, block, this_count; + struct hd_struct *ppnt; Scsi_Disk *dpnt; #if CONFIG_SCSI_LOGGING char nbuff[6]; #endif - devm = SD_PARTITION(SCpnt->request.rq_dev); + ppnt = &sd_gendisks[SD_MAJOR_IDX(SCpnt->request.rq_dev)].part[MINOR(SCpnt->request.rq_dev)]; dev = DEVICE_NR(SCpnt->request.rq_dev); block = SCpnt->request.sector; this_count = SCpnt->request_bufflen >> 9; - SCSI_LOG_HLQUEUE(1, printk("Doing sd request, dev = %d, block = %d\n", devm, block)); + SCSI_LOG_HLQUEUE(1, printk("Doing sd request, dev = 0x%x, block = %d\n", + SCpnt->request.rq_dev, block)); dpnt = &rscsi_disks[dev]; - if (devm >= (sd_template.dev_max << 4) || + if (dev >= sd_template.dev_max || !dpnt->device || !dpnt->device->online || - block + SCpnt->request.nr_sectors > sd[devm].nr_sects) { + block + SCpnt->request.nr_sectors > ppnt->nr_sects) { SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors)); SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt)); return 0; } - block += sd[devm].start_sect; + block += ppnt->start_sect; if (dpnt->device->changed) { /* * quietly refuse to do anything to a changed disc until the changed @@ -318,7 +328,7 @@ /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */ return 0; } - SCSI_LOG_HLQUEUE(2, sd_devname(devm, nbuff)); + SCSI_LOG_HLQUEUE(2, sd_devname(dev, nbuff)); SCSI_LOG_HLQUEUE(2, printk("%s : real dev = /dev/%d, block = %d\n", nbuff, dev, block)); @@ -576,8 +586,6 @@ fops: &sd_fops, }; -static struct gendisk *sd_gendisks = &sd_gendisk; - #define SD_GENDISK(i) sd_gendisks[(i) / SCSI_DISKS_PER_MAJOR] /* @@ -613,7 +621,7 @@ /* An error occurred */ if (driver_byte(result) != 0 && /* An error occured */ - SCpnt->sense_buffer[0] != 0xF0) { /* Sense data is valid */ + SCpnt->sense_buffer[0] == 0xF0) { /* Sense data is valid */ switch (SCpnt->sense_buffer[2]) { case MEDIUM_ERROR: error_sector = (SCpnt->sense_buffer[3] << 24) | @@ -644,7 +652,9 @@ default: break; } - error_sector -= sd[SD_PARTITION(SCpnt->request.rq_dev)].start_sect; + error_sector -= sd_gendisks[SD_MAJOR_IDX( + SCpnt->request.rq_dev)].part[MINOR( + SCpnt->request.rq_dev)].start_sect; error_sector &= ~(block_sectors - 1); good_sectors = error_sector - SCpnt->request.sector; if (good_sectors < 0 || good_sectors >= this_count) @@ -1146,23 +1156,12 @@ hardsect_size[SD_MAJOR(i)] = sd_hardsizes + i * (SCSI_DISKS_PER_MAJOR << 4); max_sectors[SD_MAJOR(i)] = sd_max_sectors + i * (SCSI_DISKS_PER_MAJOR << 4); } - /* - * FIXME: should unregister blksize_size, hardsect_size and max_sectors when - * the module is unloaded. - */ - sd = kmalloc((sd_template.dev_max << 4) * - sizeof(struct hd_struct), - GFP_ATOMIC); - if (!sd) - goto cleanup_sd; - memset(sd, 0, (sd_template.dev_max << 4) * sizeof(struct hd_struct)); - - if (N_USED_SD_MAJORS > 1) - sd_gendisks = kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC); - if (!sd_gendisks) - goto cleanup_sd_gendisks; + + sd_gendisks = kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC); + if (!sd_gendisks) + goto cleanup_sd_gendisks; for (i = 0; i < N_USED_SD_MAJORS; i++) { - sd_gendisks[i] = sd_gendisk; + sd_gendisks[i] = sd_gendisk; /* memcpy */ sd_gendisks[i].de_arr = kmalloc (SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].de_arr, GFP_ATOMIC); if (!sd_gendisks[i].de_arr) @@ -1179,7 +1178,11 @@ sd_gendisks[i].major_name = "sd"; sd_gendisks[i].minor_shift = 4; sd_gendisks[i].max_p = 1 << 4; - sd_gendisks[i].part = sd + (i * SCSI_DISKS_PER_MAJOR << 4); + sd_gendisks[i].part = kmalloc((SCSI_DISKS_PER_MAJOR << 4) * sizeof(struct hd_struct), + GFP_ATOMIC); + if (!sd_gendisks[i].part) + goto cleanup_gendisks_part; + memset(sd_gendisks[i].part, 0, (SCSI_DISKS_PER_MAJOR << 4) * sizeof(struct hd_struct)); sd_gendisks[i].sizes = sd_sizes + (i * SCSI_DISKS_PER_MAJOR << 4); sd_gendisks[i].nr_real = 0; sd_gendisks[i].real_devices = @@ -1188,18 +1191,19 @@ return 0; +cleanup_gendisks_part: + kfree(sd_gendisks[i].flags); cleanup_gendisks_flags: kfree(sd_gendisks[i].de_arr); cleanup_gendisks_de_arr: while (--i >= 0 ) { kfree(sd_gendisks[i].de_arr); kfree(sd_gendisks[i].flags); + kfree(sd_gendisks[i].part); } - if (sd_gendisks != &sd_gendisk) - kfree(sd_gendisks); + kfree(sd_gendisks); + sd_gendisks = NULL; cleanup_sd_gendisks: - kfree(sd); -cleanup_sd: kfree(sd_max_sectors); cleanup_max_sectors: kfree(sd_hardsizes); @@ -1320,6 +1324,7 @@ */ int revalidate_scsidisk(kdev_t dev, int maxusage) { + struct gendisk *sdgd; int target; int max_p; int start; @@ -1333,14 +1338,15 @@ } DEVICE_BUSY = 1; - max_p = sd_gendisks->max_p; - start = target << sd_gendisks->minor_shift; + sdgd = &SD_GENDISK(target); + max_p = sd_gendisk.max_p; + start = target << sd_gendisk.minor_shift; for (i = max_p - 1; i >= 0; i--) { int index = start + i; invalidate_device(MKDEV_SD_PARTITION(index), 1); - sd_gendisks->part[index].start_sect = 0; - sd_gendisks->part[index].nr_sects = 0; + sdgd->part[SD_MINOR_NUMBER(index)].start_sect = 0; + sdgd->part[SD_MINOR_NUMBER(index)].nr_sects = 0; /* * Reset the blocksize for everything so that we can read * the partition table. Technically we will determine the @@ -1372,6 +1378,7 @@ static void sd_detach(Scsi_Device * SDp) { Scsi_Disk *dpnt; + struct gendisk *sdgd; int i, j; int max_p; int start; @@ -1384,17 +1391,18 @@ /* If we are disconnecting a disk driver, sync and invalidate * everything */ + sdgd = &SD_GENDISK(i); max_p = sd_gendisk.max_p; start = i << sd_gendisk.minor_shift; for (j = max_p - 1; j >= 0; j--) { int index = start + j; invalidate_device(MKDEV_SD_PARTITION(index), 1); - sd_gendisks->part[index].start_sect = 0; - sd_gendisks->part[index].nr_sects = 0; + sdgd->part[SD_MINOR_NUMBER(index)].start_sect = 0; + sdgd->part[SD_MINOR_NUMBER(index)].nr_sects = 0; sd_sizes[index] = 0; } - devfs_register_partitions (&SD_GENDISK (i), + devfs_register_partitions (sdgd, SD_MINOR_NUMBER (start), 1); /* unregister_disk() */ dpnt->has_part_table = 0; @@ -1430,16 +1438,22 @@ kfree(sd_sizes); kfree(sd_blocksizes); kfree(sd_hardsizes); - kfree((char *) sd); + for (i = 0; i < N_USED_SD_MAJORS; i++) { +#if 0 /* XXX aren't we forgetting to deallocate something? */ + kfree(sd_gendisks[i].de_arr); + kfree(sd_gendisks[i].flags); +#endif + kfree(sd_gendisks[i].part); + } } for (i = 0; i < N_USED_SD_MAJORS; i++) { del_gendisk(&sd_gendisks[i]); - blk_size[SD_MAJOR(i)] = NULL; + blk_size[SD_MAJOR(i)] = NULL; /* XXX blksize_size actually? */ hardsect_size[SD_MAJOR(i)] = NULL; read_ahead[SD_MAJOR(i)] = 0; } sd_template.dev_max = 0; - if (sd_gendisks != &sd_gendisk) + if (sd_gendisks != NULL) /* kfree tests for 0, but leave explicit */ kfree(sd_gendisks); } diff -urN linux-2.4.19-pre6/drivers/scsi/sd.h linux-2.4.19-pre7/drivers/scsi/sd.h --- linux-2.4.19-pre6/drivers/scsi/sd.h Thu Nov 22 11:49:15 2001 +++ linux-2.4.19-pre7/drivers/scsi/sd.h Mon Apr 15 21:54:49 2002 @@ -23,8 +23,6 @@ #include #endif -extern struct hd_struct *sd; - typedef struct scsi_disk { unsigned capacity; /* size in blocks */ Scsi_Device *device; @@ -45,7 +43,6 @@ #define N_SD_MAJORS 8 #define SD_MAJOR_MASK (N_SD_MAJORS - 1) -#define SD_PARTITION(i) (((MAJOR(i) & SD_MAJOR_MASK) << 8) | (MINOR(i) & 255)) #endif diff -urN linux-2.4.19-pre6/drivers/sound/dmasound/dmasound_awacs.c linux-2.4.19-pre7/drivers/sound/dmasound/dmasound_awacs.c --- linux-2.4.19-pre6/drivers/sound/dmasound/dmasound_awacs.c Mon Feb 25 11:38:05 2002 +++ linux-2.4.19-pre7/drivers/sound/dmasound/dmasound_awacs.c Mon Apr 15 21:54:51 2002 @@ -963,7 +963,9 @@ st_le16(&cp->res_count, 0); st_le16(&cp->xfer_status, 0); st_le32(&cp->phy_addr, phy); - st_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS); + st_le32(&cp->cmd_dep, virt_to_bus(&awacs_tx_cmds[(i+1)%write_sq.max_count])); + st_le16(&cp->command, OUTPUT_MORE | BR_ALWAYS | INTR_ALWAYS); + /* point at our patched up command block */ out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp)); /* we must re-start the controller */ diff -urN linux-2.4.19-pre6/drivers/usb/hid-core.c linux-2.4.19-pre7/drivers/usb/hid-core.c --- linux-2.4.19-pre6/drivers/usb/hid-core.c Mon Apr 15 21:54:10 2002 +++ linux-2.4.19-pre7/drivers/usb/hid-core.c Mon Apr 15 21:54:51 2002 @@ -53,7 +53,7 @@ * Version Information */ -#define DRIVER_VERSION "v1.8" +#define DRIVER_VERSION "v1.8.1" #define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik " #define DRIVER_DESC "USB HID support drivers" @@ -1074,8 +1074,11 @@ } #define USB_VENDOR_ID_WACOM 0x056a +#define USB_DEVICE_ID_WACOM_PENPARTNER 0x0000 #define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010 #define USB_DEVICE_ID_WACOM_INTUOS 0x0020 +#define USB_DEVICE_ID_WACOM_PL 0x0030 +#define USB_DEVICE_ID_WACOM_INTUOS2 0x0041 #define USB_VENDOR_ID_ATEN 0x0557 #define USB_DEVICE_ID_ATEN_UC100KM 0x2004 @@ -1087,12 +1090,26 @@ __u16 idProduct; unsigned quirks; } hid_blacklist[] = { + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 2, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 1, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 2, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 3, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 4, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 5, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 1, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 2, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 3, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, diff -urN linux-2.4.19-pre6/drivers/usb/rtl8150.c linux-2.4.19-pre7/drivers/usb/rtl8150.c --- linux-2.4.19-pre6/drivers/usb/rtl8150.c Mon Apr 15 21:54:11 2002 +++ linux-2.4.19-pre7/drivers/usb/rtl8150.c Mon Apr 15 21:54:52 2002 @@ -19,6 +19,7 @@ #include #include #include +#include #include diff -urN linux-2.4.19-pre6/drivers/usb/serial/visor.c linux-2.4.19-pre7/drivers/usb/serial/visor.c --- linux-2.4.19-pre6/drivers/usb/serial/visor.c Mon Apr 15 21:54:11 2002 +++ linux-2.4.19-pre7/drivers/usb/serial/visor.c Mon Apr 15 21:54:55 2002 @@ -12,6 +12,10 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (04/03/2002) gkh + * Added support for the Sony OS 4.1 devices. Thanks to Hiroyuki ARAKI + * for the information. + * * (03/23/2002) gkh * Added support for the Palm i705 device, thanks to Thomas Riemer * for the information. @@ -189,6 +193,7 @@ static __devinitdata struct usb_device_id clie_id_4_0_table [] = { { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) }, + { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) }, { } /* Terminating entry */ }; @@ -203,6 +208,7 @@ { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) }, + { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) }, { } /* Terminating entry */ }; @@ -290,7 +296,7 @@ /* device info for the Sony Clie OS version 4.0 */ static struct usb_serial_device_type clie_4_0_device = { - name: "Sony Clié 4.0", + name: "Sony Clié 4.x", id_table: clie_id_4_0_table, needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ @@ -698,7 +704,8 @@ } if ((serial->dev->descriptor.idVendor == PALM_VENDOR_ID) || - (serial->dev->descriptor.idVendor == SONY_VENDOR_ID)) { + ((serial->dev->descriptor.idVendor == SONY_VENDOR_ID) && + (serial->dev->descriptor.idProduct != SONY_CLIE_4_1_ID))) { /* Palm OS 4.0 Hack */ response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), PALM_GET_SOME_UNKNOWN_INFORMATION, diff -urN linux-2.4.19-pre6/drivers/usb/serial/visor.h linux-2.4.19-pre7/drivers/usb/serial/visor.h --- linux-2.4.19-pre6/drivers/usb/serial/visor.h Mon Apr 15 21:54:11 2002 +++ linux-2.4.19-pre7/drivers/usb/serial/visor.h Mon Apr 15 21:54:55 2002 @@ -32,6 +32,7 @@ #define SONY_CLIE_3_5_ID 0x0038 #define SONY_CLIE_4_0_ID 0x0066 #define SONY_CLIE_S360_ID 0x0095 +#define SONY_CLIE_4_1_ID 0x009A /**************************************************************************** * Handspring Visor Vendor specific request codes (bRequest values) diff -urN linux-2.4.19-pre6/drivers/usb/uhci.c linux-2.4.19-pre7/drivers/usb/uhci.c --- linux-2.4.19-pre6/drivers/usb/uhci.c Mon Apr 15 21:54:11 2002 +++ linux-2.4.19-pre7/drivers/usb/uhci.c Mon Apr 15 21:54:55 2002 @@ -748,7 +748,7 @@ if ((!(urb->transfer_flags & USB_NO_FSBR)) && !urbp->fsbr) { urbp->fsbr = 1; - if (!uhci->fsbr++) + if (!uhci->fsbr++ && !uhci->fsbrtimeout) uhci->skel_term_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH; } @@ -1622,8 +1622,7 @@ if (urb->status != -EINPROGRESS) { info("uhci_transfer_result: called for URB %p not in flight?", urb); - spin_unlock_irqrestore(&urb->lock, flags); - return; + goto out; } switch (usb_pipetype(urb->pipe)) { @@ -1643,10 +1642,8 @@ urbp->status = ret; - if (ret == -EINPROGRESS) { - spin_unlock_irqrestore(&urb->lock, flags); - return; - } + if (ret == -EINPROGRESS) + goto out; switch (usb_pipetype(urb->pipe)) { case PIPE_CONTROL: @@ -1660,11 +1657,8 @@ break; case PIPE_INTERRUPT: /* Interrupts are an exception */ - if (urb->interval) { - uhci_add_complete(urb); - spin_unlock_irqrestore(&urb->lock, flags); - return; /* <-- note return */ - } + if (urb->interval) + goto out_complete; /* Release bandwidth for Interrupt or Isoc. transfers */ /* Spinlock needed ? */ @@ -1680,8 +1674,10 @@ /* Remove it from uhci->urb_list */ list_del_init(&urb->urb_list); +out_complete: uhci_add_complete(urb); +out: spin_unlock_irqrestore(&urb->lock, flags); } @@ -1811,6 +1807,9 @@ } else { urb->status = -ENOENT; + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + if (in_interrupt()) { /* wait at least 1 frame */ static int errorcount = 10; @@ -1820,9 +1819,6 @@ } else schedule_timeout(1+1*HZ/1000); - spin_unlock(&urb->lock); - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); - uhci_call_completion(urb); } } @@ -1837,10 +1833,6 @@ uhci_dec_fsbr(uhci, urb); - /* There is a race with updating IOC in here, but it's not worth */ - /* trying to fix since this is merely an optimization. The only */ - /* time we'd lose is if the status of the packet got updated */ - /* and we'd be turning on FSBR next frame anyway, so it's a wash */ urbp->fsbr_timeout = 1; head = &urbp->td_list; @@ -2004,23 +1996,23 @@ tmp = head->next; while (tmp != head) { struct urb *u = list_entry(tmp, struct urb, urb_list); - struct urb_priv *urbp = (struct urb_priv *)u->hcpriv; + struct urb_priv *up = (struct urb_priv *)u->hcpriv; tmp = tmp->next; - spin_lock(&urb->lock); + spin_lock(&u->lock); /* Check if the FSBR timed out */ - if (urbp->fsbr && !urbp->fsbr_timeout && time_after_eq(jiffies, urbp->fsbrtime + IDLE_TIMEOUT)) + if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT)) uhci_fsbr_timeout(uhci, u); /* Check if the URB timed out */ - if (u->timeout && time_after_eq(jiffies, urbp->inserttime + u->timeout)) { + if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout)) { list_del(&u->urb_list); list_add_tail(&u->urb_list, &list); } - spin_unlock(&urb->lock); + spin_unlock(&u->lock); } spin_unlock_irqrestore(&uhci->urb_list_lock, flags); @@ -2193,12 +2185,12 @@ OK(0); case RH_PORT_RESET: SET_RH_PORTSTAT(USBPORTSC_PR); - wait_ms(50); /* USB v1.1 7.1.7.3 */ + mdelay(50); /* USB v1.1 7.1.7.3 */ uhci->rh.c_p_r[wIndex - 1] = 1; CLR_RH_PORTSTAT(USBPORTSC_PR); udelay(10); SET_RH_PORTSTAT(USBPORTSC_PE); - wait_ms(10); + mdelay(10); SET_RH_PORTSTAT(0xa); OK(0); case RH_PORT_POWER: @@ -2714,6 +2706,7 @@ } uhci->dev = dev; + uhci->irq = dev->irq; uhci->io_addr = io_addr; uhci->io_size = io_size; pci_set_drvdata(dev, uhci); @@ -2740,6 +2733,11 @@ /* or broken setup */ reset_hc(uhci); + uhci->fsbr = 0; + uhci->fsbrtimeout = 0; + + uhci->is_suspended = 0; + spin_lock_init(&uhci->qh_remove_list_lock); INIT_LIST_HEAD(&uhci->qh_remove_list); @@ -2922,8 +2920,6 @@ if (request_irq(dev->irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci)) goto err_request_irq; - uhci->irq = dev->irq; - /* disable legacy emulation */ pci_write_config_word(uhci->dev, USBLEGSUP, USBLEGSUP_DEFAULT); diff -urN linux-2.4.19-pre6/drivers/usb/uhci.h linux-2.4.19-pre7/drivers/usb/uhci.h --- linux-2.4.19-pre6/drivers/usb/uhci.h Mon Apr 15 21:54:11 2002 +++ linux-2.4.19-pre7/drivers/usb/uhci.h Mon Apr 15 21:54:55 2002 @@ -287,17 +287,17 @@ struct uhci { struct pci_dev *dev; +#ifdef CONFIG_PROC_FS /* procfs */ int num; struct proc_dir_entry *proc_entry; +#endif /* Grabbed from PCI */ int irq; unsigned int io_addr; unsigned int io_size; - struct list_head uhci_list; - struct pci_pool *qh_pool; struct pci_pool *td_pool; diff -urN linux-2.4.19-pre6/drivers/usb/usb-uhci.h linux-2.4.19-pre7/drivers/usb/usb-uhci.h --- linux-2.4.19-pre6/drivers/usb/usb-uhci.h Tue Aug 28 11:21:02 2001 +++ linux-2.4.19-pre7/drivers/usb/usb-uhci.h Mon Apr 15 21:54:55 2002 @@ -11,7 +11,7 @@ { if(!in_interrupt()) { - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1 + ms * HZ / 1000); } else diff -urN linux-2.4.19-pre6/drivers/usb/usbmouse.c linux-2.4.19-pre7/drivers/usb/usbmouse.c --- linux-2.4.19-pre6/drivers/usb/usbmouse.c Fri Sep 14 14:04:07 2001 +++ linux-2.4.19-pre7/drivers/usb/usbmouse.c Mon Apr 15 21:54:55 2002 @@ -114,7 +114,9 @@ endpoint = interface->endpoint + 0; if (!(endpoint->bEndpointAddress & 0x80)) return NULL; if ((endpoint->bmAttributes & 3) != 3) return NULL; - + /* wacom tablets match... */ + if (dev->descriptor.idVendor == 0x056a) return NULL; + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); diff -urN linux-2.4.19-pre6/drivers/usb/wacom.c linux-2.4.19-pre7/drivers/usb/wacom.c --- linux-2.4.19-pre6/drivers/usb/wacom.c Mon Sep 17 22:52:35 2001 +++ linux-2.4.19-pre7/drivers/usb/wacom.c Mon Apr 15 21:54:56 2002 @@ -1,5 +1,5 @@ /* - * $Id: wacom.c,v 1.22 2001/04/26 11:26:09 vojtech Exp $ + * $Id: wacom.c,v 1.23 2001/05/29 12:57:18 vojtech Exp $ * * Copyright (c) 2000-2001 Vojtech Pavlik * Copyright (c) 2000 Andreas Bach Aaen @@ -39,6 +39,13 @@ * v1.21 (vp) - Removed protocol descriptions * - Added MISC_SERIAL for tool serial numbers * (gb) - Identify version on module load. + * v1.21.1 (fl) - added Graphire2 support + * v1.21.2 (fl) - added Intuos2 support + * - added all the PL ids + * v1.21.3 (fl) - added another eraser id from Neil Okamoto + * - added smooth filter for Graphire from Peri Hankey + * - added PenPartner support from Olaf van Es + * - new tool ids from Ole Martin Bjoerndalen */ /* @@ -71,7 +78,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.21" +#define DRIVER_VERSION "v1.21.3" #define DRIVER_AUTHOR "Vojtech Pavlik " #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver" @@ -117,9 +124,11 @@ if (urb->status) return; - if (data[0] != 2) - dbg("received unknown report #%d", data[0]); - + if (data[0] != 2) { + printk(KERN_ERR "wacom_pl_irq: received unknown report #%d\n", data[0]); + return; + } + prox = data[1] & 0x20; input_report_key(dev, BTN_TOOL_PEN, prox); @@ -138,6 +147,33 @@ input_event(dev, EV_MSC, MSC_SERIAL, 0); } +static void wacom_penpartner_irq(struct urb *urb) +{ + struct wacom *wacom = urb->context; + unsigned char *data = wacom->data; + struct input_dev *dev = &wacom->dev; + int x, y; + char pressure; + int leftmb; + + if (urb->status) return; + + x = data[2] << 8 | data[1]; + y = data[4] << 8 | data[3]; + pressure = data[6]; + leftmb = ((pressure > -80) && !(data[5] &20)); + + input_report_key(dev, BTN_TOOL_PEN, 1); + + input_report_abs(dev, ABS_X, x); + input_report_abs(dev, ABS_Y, y); + input_report_abs(dev, ABS_PRESSURE, pressure+127); + input_report_key(dev, BTN_LEFT, leftmb); + input_report_key(dev, BTN_RIGHT, (data[5] & 0x40)); + + input_event(dev, EV_MSC, MSC_SERIAL, leftmb); +} + static void wacom_graphire_irq(struct urb *urb) { struct wacom *wacom = urb->context; @@ -147,12 +183,18 @@ if (urb->status) return; - if (data[0] != 2) - dbg("received unknown report #%d", data[0]); - + if (data[0] != 2) { + printk(KERN_ERR "wacom_graphire_irq: received unknown report #%d\n", data[0]); + return; + } + x = data[2] | ((__u32)data[3] << 8); y = data[4] | ((__u32)data[5] << 8); + /* exponential smoothing to eliminate jitter */ + x = (wacom->x * 2 + x) / 3; + y = (wacom->y * 2 + y) / 3; + switch ((data[1] >> 5) & 3) { case 0: /* Pen */ @@ -171,8 +213,8 @@ input_report_abs(dev, ABS_DISTANCE, data[7]); input_report_rel(dev, REL_WHEEL, (signed char) data[6]); - input_report_abs(dev, ABS_X, x); - input_report_abs(dev, ABS_Y, y); + input_report_abs(dev, ABS_X, wacom->x = x); + input_report_abs(dev, ABS_Y, wacom->y = y); input_event(dev, EV_MSC, MSC_SERIAL, data[1] & 0x01); return; @@ -198,12 +240,15 @@ struct input_dev *dev = &wacom->dev; unsigned int t; int idx; + int x, y; if (urb->status) return; - if (data[0] != 2) - dbg("received unknown report #%d", data[0]); - + if (data[0] != 2) { + printk(KERN_ERR "wacom_intuos_irq: received unknown report #%d\n", data[0]); + return; + } + /* tool number */ idx = data[1] & 0x01; @@ -217,18 +262,21 @@ case 0x832: case 0x012: wacom->tool[idx] = BTN_TOOL_PENCIL; break; /* Inking pen */ case 0x822: + case 0x852: case 0x022: wacom->tool[idx] = BTN_TOOL_PEN; break; /* Pen */ case 0x812: case 0x032: wacom->tool[idx] = BTN_TOOL_BRUSH; break; /* Stroke pen */ case 0x09c: + case 0x007: case 0x094: wacom->tool[idx] = BTN_TOOL_MOUSE; break; /* Mouse 4D */ case 0x096: wacom->tool[idx] = BTN_TOOL_LENS; break; /* Lens cursor */ case 0x82a: + case 0x85a: case 0x91a: case 0x0fa: wacom->tool[idx] = BTN_TOOL_RUBBER; break; /* Eraser */ case 0x112: wacom->tool[idx] = BTN_TOOL_AIRBRUSH; break; /* Airbrush */ default: wacom->tool[idx] = BTN_TOOL_PEN; break; /* Unknown tool */ - } + } input_report_key(dev, wacom->tool[idx], 1); input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); @@ -241,10 +289,17 @@ return; } - input_report_abs(dev, ABS_X, ((__u32)data[2] << 8) | data[3]); - input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]); - input_report_abs(dev, ABS_DISTANCE, data[9] >> 4); + x = ((__u32)data[2] << 8) | data[3]; + y = ((__u32)data[4] << 8) | data[5]; + + /* exponential smoothing to eliminate jitter */ + wacom->x = (wacom->x * 2 + x) / 3; + wacom->y = (wacom->y * 2 + y) / 3; + input_report_abs(dev, ABS_X, wacom->x); + input_report_abs(dev, ABS_Y, wacom->y); + input_report_abs(dev, ABS_DISTANCE, data[9] >> 4); + if ((data[1] & 0xb8) == 0xa0) { /* general pen packet */ input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3)); input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7)); @@ -298,8 +353,14 @@ #define WACOM_INTUOS_ABS (BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_RZ) | BIT(ABS_THROTTLE)) struct wacom_features wacom_features[] = { + { "Wacom Penpartner", 7, 5040, 3780, 255, 32, wacom_penpartner_irq, + 0, 0, 0, 0 }, { "Wacom Graphire", 8, 10206, 7422, 511, 32, wacom_graphire_irq, BIT(EV_REL), 0, BIT(REL_WHEEL), 0 }, + { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, wacom_graphire_irq, + BIT(EV_REL), 0, BIT(REL_WHEEL), 0 }, + { "Wacom Graphire2 5x7", 8, 10206, 7422, 511, 32, wacom_graphire_irq, + BIT(EV_REL), 0, BIT(REL_WHEEL), 0 }, { "Wacom Intuos 4x5", 10, 12700, 10360, 1023, 15, wacom_intuos_irq, 0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS }, { "Wacom Intuos 6x8", 10, 20320, 15040, 1023, 15, wacom_intuos_irq, @@ -310,19 +371,52 @@ 0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS }, { "Wacom Intuos 12x18", 10, 47720, 30480, 1023, 15, wacom_intuos_irq, 0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS }, + { "Wacom PL400", 8, 12328, 9256, 511, 32, wacom_pl_irq, + 0, 0, 0, 0 }, { "Wacom PL500", 8, 12328, 9256, 511, 32, wacom_pl_irq, 0, 0, 0, 0 }, + { "Wacom PL600", 8, 12328, 9256, 511, 32, wacom_pl_irq, + 0, 0, 0, 0 }, + { "Wacom PL600SX", 8, 12328, 9256, 511, 32, wacom_pl_irq, + 0, 0, 0, 0 }, + { "Wacom PL550", 8, 12328, 9256, 511, 32, wacom_pl_irq, + 0, 0, 0, 0 }, + { "Wacom PL800", 8, 12328, 9256, 511, 32, wacom_pl_irq, + 0, 0, 0, 0 }, + { "Wacom Intuos2 4x5", 10, 12700, 10360, 1023, 15, wacom_intuos_irq, + 0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS }, + { "Wacom Intuos2 6x8", 10, 20320, 15040, 1023, 15, wacom_intuos_irq, + 0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS }, + { "Wacom Intuos2 9x12", 10, 30480, 23060, 1023, 15, wacom_intuos_irq, + 0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS }, + { "Wacom Intuos2 12x12", 10, 30480, 30480, 1023, 15, wacom_intuos_irq, + 0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS }, + { "Wacom Intuos2 12x18", 10, 47720, 30480, 1023, 15, wacom_intuos_irq, + 0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS }, { NULL , 0 } }; struct usb_device_id wacom_ids[] = { - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10), driver_info: 0 }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20), driver_info: 1 }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21), driver_info: 2 }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22), driver_info: 3 }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23), driver_info: 4 }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24), driver_info: 5 }, - { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31), driver_info: 6 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00), driver_info: 0 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10), driver_info: 1 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11), driver_info: 2 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12), driver_info: 3 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20), driver_info: 4 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21), driver_info: 5 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22), driver_info: 6 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23), driver_info: 7 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24), driver_info: 8 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30), driver_info: 9 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31), driver_info: 10 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32), driver_info: 11 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33), driver_info: 12 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34), driver_info: 13 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35), driver_info: 14 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41), driver_info: 15 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42), driver_info: 16 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43), driver_info: 17 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44), driver_info: 18 }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45), driver_info: 19 }, { } }; @@ -331,7 +425,7 @@ static int wacom_open(struct input_dev *dev) { struct wacom *wacom = dev->private; - + if (wacom->open++) return 0; @@ -354,7 +448,8 @@ { struct usb_endpoint_descriptor *endpoint; struct wacom *wacom; - + char rep_data[2] = {0x02, 0x02}; + if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) return NULL; memset(wacom, 0, sizeof(struct wacom)); @@ -397,13 +492,20 @@ endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; + usb_set_idle(dev, dev->config[0].interface[ifnum].altsetting[0].bInterfaceNumber, 0, 0); + FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), wacom->data, wacom->features->pktlen, wacom->features->irq, wacom, endpoint->bInterval); input_register_device(&wacom->dev); + /* ask the tablet to report tablet data */ + usb_set_report(dev, ifnum, 3, 2, rep_data, 2); + usb_set_report(dev, ifnum, 3, 5, rep_data, 0); + usb_set_report(dev, ifnum, 3, 6, rep_data, 0); + printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", - wacom->dev.number, wacom->features->name, dev->bus->busnum, dev->devnum, ifnum); + wacom->dev.number, wacom->features->name, dev->bus->busnum, dev->devnum, ifnum); return wacom; } @@ -426,7 +528,8 @@ static int __init wacom_init(void) { usb_register(&wacom_driver); - info(DRIVER_VERSION ":" DRIVER_DESC); + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); return 0; } diff -urN linux-2.4.19-pre6/drivers/video/radeonfb.c linux-2.4.19-pre7/drivers/video/radeonfb.c --- linux-2.4.19-pre6/drivers/video/radeonfb.c Mon Feb 25 11:38:07 2002 +++ linux-2.4.19-pre7/drivers/video/radeonfb.c Mon Apr 15 21:54:57 2002 @@ -1855,7 +1855,7 @@ if (noaccel) fix->accel = FB_ACCEL_NONE; else - fix->accel = 40; /* XXX */ + fix->accel = FB_ACCEL_ATI_RADEON; return 0; } diff -urN linux-2.4.19-pre6/fs/buffer.c linux-2.4.19-pre7/fs/buffer.c --- linux-2.4.19-pre6/fs/buffer.c Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/fs/buffer.c Mon Apr 15 21:54:58 2002 @@ -2222,8 +2222,8 @@ mark_buffer_uptodate(bh, uptodate); kiobuf = bh->b_private; - unlock_buffer(bh); end_kio_request(kiobuf, uptodate); + unlock_buffer(bh); } /* diff -urN linux-2.4.19-pre6/fs/dcache.c linux-2.4.19-pre7/fs/dcache.c --- linux-2.4.19-pre6/fs/dcache.c Mon Feb 25 11:38:08 2002 +++ linux-2.4.19-pre7/fs/dcache.c Mon Apr 15 21:54:58 2002 @@ -568,8 +568,7 @@ count = dentry_stat.nr_unused / priority; prune_dcache(count); - kmem_cache_shrink(dentry_cache); - return 0; + return kmem_cache_shrink(dentry_cache); } #define NAME_ALLOC_LEN(len) ((len+16) & ~15) diff -urN linux-2.4.19-pre6/fs/devfs/util.c linux-2.4.19-pre7/fs/devfs/util.c --- linux-2.4.19-pre6/fs/devfs/util.c Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/fs/devfs/util.c Mon Apr 15 21:54:58 2002 @@ -272,7 +272,7 @@ if (minor >= 256) continue; __set_bit (minor, entry->bits); up (semaphore); - return MKDEV (entry->major, minor); + return mk_kdev (entry->major, minor); } /* Need to allocate a new major */ if ( ( entry = kmalloc (sizeof *entry, GFP_KERNEL) ) == NULL ) @@ -294,7 +294,7 @@ else list->last->next = entry; list->last = entry; up (semaphore); - return MKDEV (entry->major, 0); + return mk_kdev (entry->major, 0); } /* End Function devfs_alloc_devnum */ EXPORT_SYMBOL(devfs_alloc_devnum); @@ -314,7 +314,7 @@ struct device_list *list; struct minor_list *entry; - if (devnum == NODEV) return; + if ( kdev_none (devnum) ) return; if (type == DEVFS_SPECIAL_CHR) { semaphore = &char_semaphore; @@ -325,8 +325,8 @@ semaphore = &block_semaphore; list = &block_list; } - major = MAJOR (devnum); - minor = MINOR (devnum); + major = major (devnum); + minor = minor (devnum); down (semaphore); for (entry = list->first; entry != NULL; entry = entry->next) { diff -urN linux-2.4.19-pre6/fs/dquot.c linux-2.4.19-pre7/fs/dquot.c --- linux-2.4.19-pre6/fs/dquot.c Thu Nov 22 10:38:31 2001 +++ linux-2.4.19-pre7/fs/dquot.c Mon Apr 15 21:54:58 2002 @@ -413,8 +413,7 @@ lock_kernel(); prune_dqcache(nr_free_dquots / (priority + 1)); unlock_kernel(); - kmem_cache_shrink(dquot_cachep); - return 0; + return kmem_cache_shrink(dquot_cachep); } /* NOTE: If you change this function please check whether dqput_blocks() works right... */ diff -urN linux-2.4.19-pre6/fs/ext3/balloc.c linux-2.4.19-pre7/fs/ext3/balloc.c --- linux-2.4.19-pre6/fs/ext3/balloc.c Mon Feb 25 11:38:08 2002 +++ linux-2.4.19-pre7/fs/ext3/balloc.c Mon Apr 15 21:54:58 2002 @@ -542,6 +542,7 @@ int i, j, k, tmp, alloctmp; int bitmap_nr; int fatal = 0, err; + int performed_allocation = 0; struct super_block * sb; struct ext3_group_desc * gdp; struct ext3_super_block * es; @@ -644,8 +645,7 @@ } /* No space left on the device */ - unlock_super (sb); - return 0; + goto out; search_back: /* @@ -694,6 +694,7 @@ J_ASSERT_BH(bh, !ext3_test_bit(j, bh->b_data)); BUFFER_TRACE(bh, "setting bitmap bit"); ext3_set_bit(j, bh->b_data); + performed_allocation = 1; #ifdef CONFIG_JBD_DEBUG { @@ -815,6 +816,11 @@ ext3_std_error(sb, fatal); } unlock_super (sb); + /* + * Undo the block allocation + */ + if (!performed_allocation) + DQUOT_FREE_BLOCK(inode, 1); return 0; } diff -urN linux-2.4.19-pre6/fs/inode.c linux-2.4.19-pre7/fs/inode.c --- linux-2.4.19-pre6/fs/inode.c Fri Dec 21 09:41:55 2001 +++ linux-2.4.19-pre7/fs/inode.c Mon Apr 15 21:54:58 2002 @@ -247,15 +247,15 @@ static inline void sync_one(struct inode *inode, int sync) { - if (inode->i_state & I_LOCK) { + while (inode->i_state & I_LOCK) { __iget(inode); spin_unlock(&inode_lock); __wait_on_inode(inode); iput(inode); spin_lock(&inode_lock); - } else { - __sync_one(inode, sync); } + + __sync_one(inode, sync); } static inline void sync_list(struct list_head *head) @@ -725,8 +725,7 @@ count = inodes_stat.nr_unused / priority; prune_icache(count); - kmem_cache_shrink(inode_cachep); - return 0; + return kmem_cache_shrink(inode_cachep); } /* diff -urN linux-2.4.19-pre6/fs/nfsd/nfsctl.c linux-2.4.19-pre7/fs/nfsd/nfsctl.c --- linux-2.4.19-pre6/fs/nfsd/nfsctl.c Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/fs/nfsd/nfsctl.c Mon Apr 15 21:54:58 2002 @@ -32,6 +32,7 @@ #include #include #include +#include static int nfsctl_svc(struct nfsctl_svc *data); static int nfsctl_addclient(struct nfsctl_client *data); diff -urN linux-2.4.19-pre6/fs/partitions/Makefile linux-2.4.19-pre7/fs/partitions/Makefile --- linux-2.4.19-pre6/fs/partitions/Makefile Thu Jul 26 16:30:04 2001 +++ linux-2.4.19-pre7/fs/partitions/Makefile Mon Apr 15 21:54:58 2002 @@ -9,7 +9,7 @@ O_TARGET := partitions.o -export-objs := check.o ibm.o +export-objs := check.o ibm.o msdos.o obj-y := check.o diff -urN linux-2.4.19-pre6/fs/partitions/msdos.c linux-2.4.19-pre7/fs/partitions/msdos.c --- linux-2.4.19-pre6/fs/partitions/msdos.c Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/fs/partitions/msdos.c Mon Apr 15 21:54:58 2002 @@ -29,7 +29,13 @@ #ifdef CONFIG_BLK_DEV_IDE #include /* IDE xlate */ -#endif /* CONFIG_BLK_DEV_IDE */ +#elif defined(CONFIG_BLK_DEV_IDE_MODULE) +#include + +int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *); +EXPORT_SYMBOL(ide_xlate_1024_hook); +#define ide_xlate_1024 ide_xlate_1024_hook +#endif #include @@ -467,7 +473,7 @@ */ static int handle_ide_mess(struct block_device *bdev) { -#ifdef CONFIG_BLK_DEV_IDE +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) Sector sect; unsigned char *data; kdev_t dev = to_kdev_t(bdev->bd_dev); @@ -475,6 +481,10 @@ int heads = 0; struct partition *p; int i; +#ifdef CONFIG_BLK_DEV_IDE_MODULE + if (!ide_xlate_1024) + return 1; +#endif /* * The i386 partition handling programs very often * make partitions end on cylinder boundaries. @@ -536,7 +546,7 @@ /* Flush the cache */ invalidate_bdev(bdev, 1); truncate_inode_pages(bdev->bd_inode->i_mapping, 0); -#endif /* CONFIG_BLK_DEV_IDE */ +#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */ return 1; } diff -urN linux-2.4.19-pre6/fs/super.c linux-2.4.19-pre7/fs/super.c --- linux-2.4.19-pre6/fs/super.c Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/fs/super.c Mon Apr 15 21:54:58 2002 @@ -613,16 +613,6 @@ if (!s) return ERR_PTR(-ENOMEM); - spin_lock(&unnamed_dev_lock); - dev = find_first_zero_bit(unnamed_dev_in_use, Max_anon); - if (dev == Max_anon) { - spin_unlock(&unnamed_dev_lock); - destroy_super(s); - return ERR_PTR(-EMFILE); - } - set_bit(dev, unnamed_dev_in_use); - spin_unlock(&unnamed_dev_lock); - retry: spin_lock(&sb_lock); if (compare) list_for_each(p, &type->fs_supers) { @@ -636,6 +626,17 @@ return old; } + spin_lock(&unnamed_dev_lock); + dev = find_first_zero_bit(unnamed_dev_in_use, Max_anon); + if (dev == Max_anon) { + spin_unlock(&unnamed_dev_lock); + spin_unlock(&sb_lock); + destroy_super(s); + return ERR_PTR(-EMFILE); + } + set_bit(dev, unnamed_dev_in_use); + spin_unlock(&unnamed_dev_lock); + s->s_dev = dev; insert_super(s, type); return s; diff -urN linux-2.4.19-pre6/include/asm-i386/serial.h linux-2.4.19-pre7/include/asm-i386/serial.h --- linux-2.4.19-pre6/include/asm-i386/serial.h Thu Nov 22 11:47:23 2001 +++ linux-2.4.19-pre7/include/asm-i386/serial.h Mon Apr 15 21:54:58 2002 @@ -57,6 +57,20 @@ { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \ { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */ +/* + * HCDP_SERIAL_PORT_DEFNS should be placed in exactly the same slot + * in rs_table as defined by HCDP_SERIAL_CONSOLE_PORT in + * include/linux/serial.h + */ +#define HCDP_SERIAL_PORT_DEFNS \ + { 0, BASE_BAUD, -1, 0, STD_COM_FLAGS}, /* ttySx device + in comments sucks. + You add an entry + and you get to edit + boatloads of these + comments. Not worth + it */ + #ifdef CONFIG_SERIAL_MANY_PORTS #define EXTRA_SERIAL_PORT_DEFNS \ @@ -126,6 +140,7 @@ #endif #define SERIAL_PORT_DFNS \ + HCDP_SERIAL_PORT_DEFNS \ STD_SERIAL_PORT_DEFNS \ EXTRA_SERIAL_PORT_DEFNS \ HUB6_SERIAL_PORT_DFNS \ diff -urN linux-2.4.19-pre6/include/asm-i386/unistd.h linux-2.4.19-pre7/include/asm-i386/unistd.h --- linux-2.4.19-pre6/include/asm-i386/unistd.h Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/include/asm-i386/unistd.h Mon Apr 15 21:54:58 2002 @@ -242,8 +242,11 @@ #define __NR_removexattr 235 #define __NR_lremovexattr 236 #define __NR_fremovexattr 237 - #define __NR_tkill 238 +#define __NR_sendfile64 239 +#define __NR_futex 240 +#define __NR_sched_setaffinity 241 +#define __NR_sched_getaffinity 242 /* user-visible error numbers are in the range -1 - -124: see */ diff -urN linux-2.4.19-pre6/include/asm-ia64/efi.h linux-2.4.19-pre7/include/asm-ia64/efi.h --- linux-2.4.19-pre6/include/asm-ia64/efi.h Tue Jul 31 10:30:09 2001 +++ linux-2.4.19-pre7/include/asm-ia64/efi.h Mon Apr 15 21:54:58 2002 @@ -181,6 +181,9 @@ #define SAL_SYSTEM_TABLE_GUID \ ((efi_guid_t) { 0xeb9d2d32, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}) +#define HCDP_TABLE_GUID \ + ((efi_guid_t) { 0xf951938d, 0x620b, 0x42ef, {0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98}}) + typedef struct { efi_guid_t guid; u64 table; @@ -215,6 +218,7 @@ void *acpi20; /* ACPI table (ACPI 2.0) */ void *smbios; /* SM BIOS table */ void *sal_systab; /* SAL system table */ + void *hcdp; /* HCDP table */ void *boot_info; /* boot info table */ efi_get_time_t *get_time; efi_set_time_t *set_time; diff -urN linux-2.4.19-pre6/include/asm-ia64/serial.h linux-2.4.19-pre7/include/asm-ia64/serial.h --- linux-2.4.19-pre6/include/asm-ia64/serial.h Sun Feb 6 18:42:40 2000 +++ linux-2.4.19-pre7/include/asm-ia64/serial.h Mon Apr 15 21:54:58 2002 @@ -59,6 +59,20 @@ { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \ { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */ +/* + * HCDP_SERIAL_PORT_DEFNS should be placed in exactly the same slot + * in rs_table as defined by HCDP_SERIAL_CONSOLE_PORT in + * include/linux/serial.h + */ +#define HCDP_SERIAL_PORT_DEFNS \ + { 0, BASE_BAUD, -1, 0, STD_COM_FLAGS}, /* ttySx device + in comments sucks. + You add an entry + and you get to edit + boatloads of these + comments. Not worth + it */ + #ifdef CONFIG_SERIAL_MANY_PORTS #define EXTRA_SERIAL_PORT_DEFNS \ @@ -129,6 +143,7 @@ #define SERIAL_PORT_DFNS \ STD_SERIAL_PORT_DEFNS \ + HCDP_SERIAL_PORT_DEFNS \ EXTRA_SERIAL_PORT_DEFNS \ HUB6_SERIAL_PORT_DFNS \ MCA_SERIAL_PORT_DFNS diff -urN linux-2.4.19-pre6/include/asm-ppc/btext.h linux-2.4.19-pre7/include/asm-ppc/btext.h --- linux-2.4.19-pre6/include/asm-ppc/btext.h Tue Aug 28 06:58:33 2001 +++ linux-2.4.19-pre7/include/asm-ppc/btext.h Mon Apr 15 21:54:58 2002 @@ -17,11 +17,11 @@ extern unsigned long disp_BAT[2]; -extern boot_infos_t *disp_bi; +extern boot_infos_t disp_bi; extern int boot_text_mapped; void btext_init(boot_infos_t *bi); -void btext_welcome(boot_infos_t* bi); +void btext_welcome(void); void btext_prepare_BAT(void); void btext_setup_display(int width, int height, int depth, int pitch, unsigned long address); diff -urN linux-2.4.19-pre6/include/asm-ppc/cputable.h linux-2.4.19-pre7/include/asm-ppc/cputable.h --- linux-2.4.19-pre6/include/asm-ppc/cputable.h Tue Aug 28 06:58:33 2001 +++ linux-2.4.19-pre7/include/asm-ppc/cputable.h Mon Apr 15 21:54:58 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.cputable.h 1.3 08/19/01 22:31:46 paulus + * BK Id: SCCS/s.cputable.h 1.4 03/19/02 15:04:39 benh */ /* * include/asm-ppc/cputable.h @@ -67,6 +67,8 @@ #define CPU_FTR_604_PERF_MON 0x00000080 #define CPU_FTR_601 0x00000100 #define CPU_FTR_HPTE_TABLE 0x00000200 +#define CPU_FTR_CAN_NAP 0x00000400 +#define CPU_FTR_L3CR 0x00000800 #ifdef __ASSEMBLY__ diff -urN linux-2.4.19-pre6/include/asm-ppc/heathrow.h linux-2.4.19-pre7/include/asm-ppc/heathrow.h --- linux-2.4.19-pre6/include/asm-ppc/heathrow.h Mon Feb 25 11:38:12 2002 +++ linux-2.4.19-pre7/include/asm-ppc/heathrow.h Mon Apr 15 21:54:58 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.heathrow.h 1.10 12/01/01 20:09:11 benh + * BK Id: SCCS/s.heathrow.h 1.12 03/19/02 15:53:56 benh */ /* * heathrow.h: definitions for using the "Heathrow" I/O controller chip. @@ -25,7 +25,7 @@ * Bits in feature control register. * Bits postfixed with a _N are in inverse logic */ -#define HRW_RESET_SCC 0x00000001 /* actually controls transceiver... */ +#define HRW_SCC_TRANS_EN_N 0x00000001 /* Also controls modem power */ #define HRW_BAY_POWER_N 0x00000002 #define HRW_BAY_PCI_ENABLE 0x00000004 #define HRW_BAY_IDE_ENABLE 0x00000008 @@ -51,7 +51,7 @@ #define HRW_ARB_BYPASS 0x00400000 /* Disable internal PCI arbitrer */ #define HRW_IDE1_RESET_N 0x00800000 /* Media bay */ #define HRW_SLOW_SCC_PCLK 0x01000000 /* ??? (0) */ -#define HRW_MODEM_POWER_N 0x02000000 /* Used by internal modem on wallstreet */ +#define HRW_RESET_SCC 0x02000000 #define HRW_MFDC_CELL_ENABLE 0x04000000 /* ??? (0) */ #define HRW_USE_MFDC 0x08000000 /* ??? (0) */ #define HRW_BMAC_IO_ENABLE 0x60000000 /* two bits, not documented in OF */ @@ -60,10 +60,6 @@ /* We OR those features at boot on desktop G3s */ #define HRW_DEFAULTS (HRW_SCCA_IO | HRW_SCCB_IO | HRW_SCC_ENABLE) -/* Those seem to be different on paddington */ -#define PADD_MODEM_POWER_N 0x00000001 /* modem power on paddington */ -#define PADD_RESET_SCC 0x02000000 /* check this please */ - /* Looks like Heathrow has some sort of GPIOs as well... */ #define HRW_GPIO_MODEM_RESET 0x6d diff -urN linux-2.4.19-pre6/include/asm-ppc/pgtable.h linux-2.4.19-pre7/include/asm-ppc/pgtable.h --- linux-2.4.19-pre6/include/asm-ppc/pgtable.h Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/include/asm-ppc/pgtable.h Mon Apr 15 21:54:58 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pgtable.h 1.15 09/22/01 11:26:52 trini + * BK Id: SCCS/s.pgtable.h 1.21 03/12/02 11:49:48 paulus */ #ifdef __KERNEL__ #ifndef _PPC_PGTABLE_H @@ -264,15 +264,6 @@ #define _PAGE_HWWRITE 0 #endif -/* We can't use _PAGE_HWWRITE on any SMP due to the lack of ability - * to atomically manage _PAGE_HWWRITE and it's coordination flags, - * _PAGE_DIRTY or _PAGE_RW. The SMP systems must manage HWWRITE - * or its logical equivalent in the MMU management software. - */ -#if CONFIG_SMP && _PAGE_HWWRITE -#error "You can't configure SMP and HWWRITE" -#endif - #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) /* @@ -282,7 +273,7 @@ * another purpose. -- paulus. */ #define _PAGE_BASE _PAGE_PRESENT | _PAGE_ACCESSED -#define _PAGE_WRENABLE _PAGE_RW | _PAGE_DIRTY +#define _PAGE_WRENABLE _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE #define _PAGE_KERNEL _PAGE_BASE | _PAGE_WRENABLE | _PAGE_SHARED #define _PAGE_IO _PAGE_KERNEL | _PAGE_NO_CACHE | _PAGE_GUARDED diff -urN linux-2.4.19-pre6/include/asm-ppc/pmac_feature.h linux-2.4.19-pre7/include/asm-ppc/pmac_feature.h --- linux-2.4.19-pre6/include/asm-ppc/pmac_feature.h Mon Feb 25 11:38:12 2002 +++ linux-2.4.19-pre7/include/asm-ppc/pmac_feature.h Mon Apr 15 21:54:58 2002 @@ -38,9 +38,11 @@ */ /* PowerSurge are the first generation of PCI Pmacs. This include - * all of the Grand-Central based machines + * all of the Grand-Central based machines. We currently don't + * differenciate most of them. */ #define PMAC_TYPE_PSURGE 0x10 /* PowerSurge */ +#define PMAC_TYPE_ANS 0x11 /* Apple Network Server */ /* Here is the infamous serie of OHare based machines */ @@ -90,6 +92,7 @@ */ #define PMAC_TYPE_PANGEA_IMAC 0x100 /* Flower Power iMac */ #define PMAC_TYPE_IBOOK2 0x101 /* iBook2 (polycarbonate) */ +#define PMAC_TYPE_FLAT_PANEL_IMAC 0x102 /* Flat panel iMac */ #define PMAC_TYPE_UNKNOWN_PANGEA 0x10f /* diff -urN linux-2.4.19-pre6/include/asm-ppc/processor.h linux-2.4.19-pre7/include/asm-ppc/processor.h --- linux-2.4.19-pre6/include/asm-ppc/processor.h Mon Feb 25 11:38:13 2002 +++ linux-2.4.19-pre7/include/asm-ppc/processor.h Mon Apr 15 21:54:58 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.processor.h 1.33 12/01/01 20:09:11 benh + * BK Id: SCCS/s.processor.h 1.35 03/19/02 15:04:39 benh */ #ifdef __KERNEL__ #ifndef __ASM_PPC_PROCESSOR_H @@ -267,6 +267,24 @@ #define SPRN_L2CR2 0x3f8 #define SPRN_L3CR 0x3FA /* Level 3 Cache Control Regsiter (7450) */ #define L3CR_L3E 0x80000000 /* L3 enable */ +#define L3CR_L3PE 0x40000000 /* L3 data parity enable */ +#define L3CR_L3APE 0x20000000 /* L3 addr parity enable */ +#define L3CR_L3SIZ 0x10000000 /* L3 size */ +#define L3CR_L3CLKEN 0x08000000 /* L3 clock enable */ +#define L3CR_L3RES 0x04000000 /* L3 special reserved bit */ +#define L3CR_L3CLKDIV 0x03800000 /* L3 clock divisor */ +#define L3CR_L3IO 0x00400000 /* L3 instruction only */ +#define L3CR_L3SPO 0x00040000 /* L3 sample point override */ +#define L3CR_L3CKSP 0x00030000 /* L3 clock sample point */ +#define L3CR_L3PSP 0x0000e000 /* L3 P-clock sample point */ +#define L3CR_L3REP 0x00001000 /* L3 replacement algorithm */ +#define L3CR_L3HWF 0x00000800 /* L3 hardware flush */ +#define L3CR_L3I 0x00000400 /* L3 global invalidate */ +#define L3CR_L3RT 0x00000300 /* L3 SRAM type */ +#define L3CR_L3NIRCA 0x00000080 /* L3 non-integer ratio clock adj. */ +#define L3CR_L3DO 0x00000040 /* L3 data only mode */ +#define L3CR_PMEN 0x00000004 /* L3 private memory enable */ +#define L3CR_PMSIZ 0x00000001 /* L3 private memory size */ #define SPRN_MSSCR0 0x3f6 /* Memory Subsystem Control Register 0 */ #define SPRN_MSSSR0 0x3f7 /* Memory Subsystem Status Register 1 */ #define SPRN_ICTRL 0x3f3 /* Instruction Cache & Interrupt control reg */ diff -urN linux-2.4.19-pre6/include/asm-ppc/prom.h linux-2.4.19-pre7/include/asm-ppc/prom.h --- linux-2.4.19-pre6/include/asm-ppc/prom.h Mon Feb 25 11:38:13 2002 +++ linux-2.4.19-pre7/include/asm-ppc/prom.h Mon Apr 15 21:54:58 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.prom.h 1.21 12/01/01 20:09:11 benh + * BK Id: SCCS/s.prom.h 1.24 04/09/02 21:01:58 paulus */ /* * Definitions for talking to the Open Firmware PROM on @@ -107,10 +107,11 @@ * pointer values. See arch/ppc/kernel/prom.c for how these are used. */ extern unsigned long reloc_offset(void); +extern unsigned long add_reloc_offset(unsigned long); +extern unsigned long sub_reloc_offset(unsigned long); -#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset)) -#define PTRUNRELOC(x) ((typeof(x))((unsigned long)(x) - offset)) -#define RELOC(x) (*PTRRELOC(&(x))) +#define PTRRELOC(x) ((typeof(x))add_reloc_offset((unsigned long)(x))) +#define PTRUNRELOC(x) ((typeof(x))sub_reloc_offset((unsigned long)(x))) #endif /* _PPC_PROM_H */ #endif /* __KERNEL__ */ diff -urN linux-2.4.19-pre6/include/asm-ppc/ptrace.h linux-2.4.19-pre7/include/asm-ppc/ptrace.h --- linux-2.4.19-pre6/include/asm-ppc/ptrace.h Mon May 21 15:02:06 2001 +++ linux-2.4.19-pre7/include/asm-ppc/ptrace.h Mon Apr 15 21:54:58 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ptrace.h 1.5 05/17/01 18:14:25 cort + * BK Id: SCCS/s.ptrace.h 1.8 01/17/02 23:05:50 paulus */ #ifndef _PPC_PTRACE_H #define _PPC_PTRACE_H @@ -103,5 +103,8 @@ #define PT_FPR31 (PT_FPR0 + 2*31) #define PT_FPSCR (PT_FPR0 + 2*32 + 1) -#endif +/* Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go */ +#define PTRACE_GETVRREGS 18 +#define PTRACE_SETVRREGS 19 +#endif diff -urN linux-2.4.19-pre6/include/asm-ppc/smp.h linux-2.4.19-pre7/include/asm-ppc/smp.h --- linux-2.4.19-pre6/include/asm-ppc/smp.h Tue Aug 28 06:58:33 2001 +++ linux-2.4.19-pre7/include/asm-ppc/smp.h Mon Apr 15 21:54:58 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.smp.h 1.12 08/16/01 07:49:31 paulus + * BK Id: SCCS/s.smp.h 1.14 03/28/02 16:54:23 hozer */ /* smp.h: PPC specific SMP stuff. * @@ -62,6 +62,12 @@ #define KLOCK_HELD 0xffffffff #define KLOCK_CLEAR 0x0 +#ifdef CONFIG_750_SMP +#define smp_send_tlb_invalidate(x) smp_ppc750_send_tlb_invalidate(x) +#else +#define smp_send_tlb_invalidate(x) do {} while(0) +#endif + #endif /* __ASSEMBLY__ */ #else /* !(CONFIG_SMP) */ diff -urN linux-2.4.19-pre6/include/asm-ppc/system.h linux-2.4.19-pre7/include/asm-ppc/system.h --- linux-2.4.19-pre6/include/asm-ppc/system.h Tue Aug 28 06:58:33 2001 +++ linux-2.4.19-pre7/include/asm-ppc/system.h Mon Apr 15 21:54:58 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.system.h 1.14 08/20/01 14:34:41 paulus + * BK Id: SCCS/s.system.h 1.20 03/19/02 15:04:39 benh */ /* * Copyright (C) 1999 Cort Dougan @@ -58,9 +58,13 @@ #ifdef CONFIG_6xx extern long _get_L2CR(void); extern void _set_L2CR(unsigned long); +extern long _get_L3CR(void); +extern void _set_L3CR(unsigned long); #else -#define _get_L2CR() 0 +#define _get_L2CR() 0L #define _set_L2CR(val) do { } while(0) +#define _get_L3CR() 0L +#define _set_L3CR(val) do { } while(0) #endif extern void via_cuda_init(void); extern void pmac_nvram_init(void); @@ -120,10 +124,6 @@ #define local_irq_save(flags) __save_and_cli(flags) #define local_irq_restore(flags) __restore_flags(flags) -#endif /* __KERNEL__ */ - -#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) - static __inline__ unsigned long xchg_u32(volatile void *p, unsigned long val) { @@ -222,4 +222,5 @@ (unsigned long)_n_, sizeof(*(ptr))); \ }) +#endif /* __KERNEL__ */ #endif /* __PPC_SYSTEM_H */ diff -urN linux-2.4.19-pre6/include/asm-sparc/pgtable.h linux-2.4.19-pre7/include/asm-sparc/pgtable.h --- linux-2.4.19-pre6/include/asm-sparc/pgtable.h Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/include/asm-sparc/pgtable.h Mon Apr 15 21:54:58 2002 @@ -293,9 +293,6 @@ #define page_pte_prot(page, prot) mk_pte(page, prot) #define page_pte(page) page_pte_prot(page, __pgprot(0)) -/* Permanent address of a page. */ -#define page_address(page) ((page)->virtual) - BTFIXUPDEF_CALL(struct page *, pte_page, pte_t) #define pte_page(pte) BTFIXUP_CALL(pte_page)(pte) diff -urN linux-2.4.19-pre6/include/asm-sparc/sbus.h linux-2.4.19-pre7/include/asm-sparc/sbus.h --- linux-2.4.19-pre6/include/asm-sparc/sbus.h Fri Feb 18 15:07:20 2000 +++ linux-2.4.19-pre7/include/asm-sparc/sbus.h Mon Apr 15 21:54:58 2002 @@ -94,7 +94,8 @@ for((device) = (bus)->devices; (device); (device)=(device)->next) #define for_all_sbusdev(device, bus) \ - for((bus) = sbus_root, ((device) = (bus) ? (bus)->devices : 0); (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0))) + for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \ + for ((device) = (bus)->devices; (device); (device) = (device)->next) /* Driver DVMA interfaces. */ #define sbus_can_dma_64bit(sdev) (0) /* actually, sparc_cpu_model==sun4d */ diff -urN linux-2.4.19-pre6/include/asm-sparc64/elf.h linux-2.4.19-pre7/include/asm-sparc64/elf.h --- linux-2.4.19-pre6/include/asm-sparc64/elf.h Mon Feb 25 11:38:13 2002 +++ linux-2.4.19-pre7/include/asm-sparc64/elf.h Mon Apr 15 21:54:58 2002 @@ -21,8 +21,39 @@ typedef unsigned long elf_greg_t; -#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t)) +#define ELF_NGREG 36 typedef elf_greg_t elf_gregset_t[ELF_NGREG]; +/* Format of 64-bit elf_gregset_t is: + * G0 --> G7 + * O0 --> O7 + * L0 --> L7 + * I0 --> I7 + * TSTATE + * TPC + * TNPC + * Y + */ +#include +#define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs) \ +do { unsigned long *dest = &(__elf_regs[0]); \ + struct pt_regs *src = (__pt_regs); \ + unsigned long *sp; \ + int i; \ + for(i = 0; i < 16; i++) \ + dest[i] = src->u_regs[i]; \ + /* Don't try this at home kids... */ \ + set_fs(USER_DS); \ + sp = (unsigned long *) \ + ((src->u_regs[14] + STACK_BIAS) \ + & 0xfffffffffffffff8UL); \ + for(i = 0; i < 16; i++) \ + __get_user(dest[i+16], &sp[i]); \ + set_fs(KERNEL_DS); \ + dest[32] = src->tstate; \ + dest[33] = src->tpc; \ + dest[34] = src->tnpc; \ + dest[35] = src->y; \ +} while (0); typedef struct { unsigned long pr_regs[32]; diff -urN linux-2.4.19-pre6/include/asm-sparc64/sbus.h linux-2.4.19-pre7/include/asm-sparc64/sbus.h --- linux-2.4.19-pre6/include/asm-sparc64/sbus.h Fri Feb 18 15:07:20 2000 +++ linux-2.4.19-pre7/include/asm-sparc64/sbus.h Mon Apr 15 21:54:58 2002 @@ -87,7 +87,8 @@ for((device) = (bus)->devices; (device); (device)=(device)->next) #define for_all_sbusdev(device, bus) \ - for((bus) = sbus_root, ((device) = (bus) ? (bus)->devices : 0); (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0))) + for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \ + for ((device) = (bus)->devices; (device); (device) = (device)->next) /* Driver DVMA interfaces. */ #define sbus_can_dma_64bit(sdev) (1) diff -urN linux-2.4.19-pre6/include/asm-sparc64/timex.h linux-2.4.19-pre7/include/asm-sparc64/timex.h --- linux-2.4.19-pre6/include/asm-sparc64/timex.h Thu Sep 20 14:11:58 2001 +++ linux-2.4.19-pre7/include/asm-sparc64/timex.h Mon Apr 15 21:54:58 2002 @@ -16,7 +16,7 @@ typedef unsigned long cycles_t; #define get_cycles() \ ({ cycles_t ret; \ - __asm__("rd %%tick, %0" : "=r" (ret)); \ + __asm__ __volatile__("rd %%tick, %0" : "=r" (ret)); \ ret; \ }) diff -urN linux-2.4.19-pre6/include/linux/acpi_serial.h linux-2.4.19-pre7/include/linux/acpi_serial.h --- linux-2.4.19-pre6/include/linux/acpi_serial.h Fri Nov 9 14:11:15 2001 +++ linux-2.4.19-pre7/include/linux/acpi_serial.h Wed Dec 31 16:00:00 1969 @@ -1,103 +0,0 @@ -/* - * linux/include/linux/acpi_serial.h - * - * Copyright (C) 2000 Hewlett-Packard Co. - * Copyright (C) 2000 Khalid Aziz - * - * Definitions for ACPI defined serial ports (headless console and - * debug ports) - * - */ - -extern void setup_serial_acpi(void *); - -/* ACPI table signatures */ -#define ACPI_SPCRT_SIGNATURE "SPCR" -#define ACPI_DBGPT_SIGNATURE "DBGP" - -/* Interface type as defined in ACPI serial port tables */ -#define ACPI_SERIAL_INTFC_16550 0 -#define ACPI_SERIAL_INTFC_16450 1 - -/* Interrupt types for ACPI serial port tables */ -#define ACPI_SERIAL_INT_PCAT 0x01 -#define ACPI_SERIAL_INT_APIC 0x02 -#define ACPI_SERIAL_INT_SAPIC 0x04 - -/* Baud rates as defined in ACPI serial port tables */ -#define ACPI_SERIAL_BAUD_9600 3 -#define ACPI_SERIAL_BAUD_19200 4 -#define ACPI_SERIAL_BAUD_57600 6 -#define ACPI_SERIAL_BAUD_115200 7 - -/* Parity as defined in ACPI serial port tables */ -#define ACPI_SERIAL_PARITY_NONE 0 - -/* Flow control methods as defined in ACPI serial port tables */ -#define ACPI_SERIAL_FLOW_DCD 0x01 -#define ACPI_SERIAL_FLOW_RTS 0x02 -#define ACPI_SERIAL_FLOW_XON 0x04 - -/* Terminal types as defined in ACPI serial port tables */ -#define ACPI_SERIAL_TERM_VT100 0 -#define ACPI_SERIAL_TERM_VT100X 1 - -/* PCI Flags as defined by SPCR table */ -#define ACPI_SERIAL_PCIFLAG_PNP 0x00000001 - -/* Space ID as defined in base address structure in ACPI serial port tables */ -#define ACPI_SERIAL_MEM_SPACE 0 -#define ACPI_SERIAL_IO_SPACE 1 -#define ACPI_SERIAL_PCICONF_SPACE 2 - -/* - * Generic Register Address Structure - as defined by Microsoft - * in http://www.microsoft.com/hwdev/onnow/download/LFreeACPI.doc - * -*/ -typedef struct { - u8 space_id; - u8 bit_width; - u8 bit_offset; - u8 resv; - u32 addrl; - u32 addrh; -} gen_regaddr; - -/* Space ID for generic register address structure */ -#define REGADDR_SPACE_SYSMEM 0 -#define REGADDR_SPACE_SYSIO 1 -#define REGADDR_SPACE_PCICONFIG 2 - -/* Serial Port Console Redirection and Debug Port Table formats */ -typedef struct { - u8 signature[4]; - u32 length; - u8 rev; - u8 chksum; - u8 oemid[6]; - u8 oem_tabid[8]; - u32 oem_rev; - u8 creator_id[4]; - u32 creator_rev; - u8 intfc_type; - u8 resv1[3]; - gen_regaddr base_addr; - u8 int_type; - u8 irq; - u8 global_int[4]; - u8 baud; - u8 parity; - u8 stop_bits; - u8 flow_ctrl; - u8 termtype; - u8 language; - u16 pci_dev_id; - u16 pci_vendor_id; - u8 pci_bus; - u8 pci_dev; - u8 pci_func; - u8 pci_flags[4]; - u8 pci_seg; - u32 resv2; -} acpi_ser_t; diff -urN linux-2.4.19-pre6/include/linux/agp_backend.h linux-2.4.19-pre7/include/linux/agp_backend.h --- linux-2.4.19-pre6/include/linux/agp_backend.h Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/include/linux/agp_backend.h Mon Apr 15 21:54:58 2002 @@ -75,7 +75,8 @@ ALI_GENERIC, SVWRKS_HE, SVWRKS_LE, - SVWRKS_GENERIC + SVWRKS_GENERIC, + HP_ZX1, }; typedef struct _agp_version { diff -urN linux-2.4.19-pre6/include/linux/dcache.h linux-2.4.19-pre7/include/linux/dcache.h --- linux-2.4.19-pre6/include/linux/dcache.h Thu Nov 22 11:46:18 2001 +++ linux-2.4.19-pre7/include/linux/dcache.h Mon Apr 15 21:54:58 2002 @@ -244,7 +244,7 @@ { if (dentry) { if (!atomic_read(&dentry->d_count)) - BUG(); + out_of_line_bug(); atomic_inc(&dentry->d_count); } return dentry; diff -urN linux-2.4.19-pre6/include/linux/devfs_fs_kernel.h linux-2.4.19-pre7/include/linux/devfs_fs_kernel.h --- linux-2.4.19-pre6/include/linux/devfs_fs_kernel.h Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/include/linux/devfs_fs_kernel.h Mon Apr 15 21:54:58 2002 @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff -urN linux-2.4.19-pre6/include/linux/fb.h linux-2.4.19-pre7/include/linux/fb.h --- linux-2.4.19-pre6/include/linux/fb.h Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/include/linux/fb.h Mon Apr 15 21:54:58 2002 @@ -94,6 +94,7 @@ #define FB_ACCEL_IGS_CYBER5000 35 /* CyberPro 5000 */ #define FB_ACCEL_SIS_GLAMOUR 36 /* SiS 300/630/540 */ #define FB_ACCEL_3DLABS_PERMEDIA3 37 /* 3Dlabs Permedia 3 */ +#define FB_ACCEL_ATI_RADEON 38 /* ATI Radeon family */ #define FB_ACCEL_NEOMAGIC_NM2070 90 /* NeoMagic NM2070 */ diff -urN linux-2.4.19-pre6/include/linux/hcdp_serial.h linux-2.4.19-pre7/include/linux/hcdp_serial.h --- linux-2.4.19-pre6/include/linux/hcdp_serial.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/include/linux/hcdp_serial.h Mon Apr 15 21:54:58 2002 @@ -0,0 +1,84 @@ +/* + * linux/include/asm-ia64/hcdp_serial.h + * + * Copyright (C) 2002 Hewlett-Packard Co. + * Copyright (C) 2002 Khalid Aziz + * + * Definitions for HCDP defined serial ports (Serial console and + * debug ports) + * + */ +#ifndef _ASM_IA64_HCDP_SERIAL_H +#define _ASM_IA64_HCDP_SERIAL_H + +/* ACPI table signatures */ +#define HCDP_SIG_LEN 4 +#define HCDP_SIGNATURE "HCDP" + +/* Space ID as defined in ACPI generic address structure */ +#define ACPI_MEM_SPACE 0 +#define ACPI_IO_SPACE 1 +#define ACPI_PCICONF_SPACE 2 + +/* + * Maximum number of HCDP devices we want to read in + */ +#define MAX_HCDP_DEVICES 6 + +/* + * Default base baud rate if clock rate is 0 in HCDP table. + */ +#define DEFAULT_BAUD_BASE 115200 + +/* + * ACPI Generic Address Structure + */ +typedef struct { + u8 space_id; + u8 bit_width; + u8 bit_offset; + u8 resv; + u32 addrlo; + u32 addrhi; +} acpi_gen_addr; + +/* HCDP Device descriptor entry types */ +#define HCDP_DEV_CONSOLE 0 +#define HCDP_DEV_DEBUG 1 + +/* HCDP Device descriptor type */ +typedef struct { + u8 type; + u8 bits; + u8 parity; + u8 stop_bits; + u8 pci_seg; + u8 pci_bus; + u8 pci_dev; + u8 pci_func; + u64 baud; + acpi_gen_addr base_addr; + u16 pci_dev_id; + u16 pci_vendor_id; + u32 global_int; + u32 clock_rate; + u8 pci_prog_intfc; + u8 resv; +} hcdp_dev_t; + +/* HCDP Table format */ +typedef struct { + u8 signature[4]; + u32 len; + u8 rev; + u8 chksum; + u8 oemid[6]; + u8 oem_tabid[8]; + u32 oem_rev; + u8 creator_id[4]; + u32 creator_rev; + u32 num_entries; + hcdp_dev_t hcdp_dev[MAX_HCDP_DEVICES]; +} hcdp_t; + +#endif /* _ASM_IA64_HCDP_SERIAL_H */ diff -urN linux-2.4.19-pre6/include/linux/highmem.h linux-2.4.19-pre7/include/linux/highmem.h --- linux-2.4.19-pre6/include/linux/highmem.h Mon Feb 25 11:38:13 2002 +++ linux-2.4.19-pre7/include/linux/highmem.h Mon Apr 15 21:54:58 2002 @@ -64,7 +64,7 @@ char *kaddr; if (offset + size > PAGE_SIZE) - BUG(); + out_of_line_bug(); kaddr = kmap(page); memset(kaddr + offset, 0, size); flush_dcache_page(page); diff -urN linux-2.4.19-pre6/include/linux/input.h linux-2.4.19-pre7/include/linux/input.h --- linux-2.4.19-pre6/include/linux/input.h Wed Sep 12 15:34:06 2001 +++ linux-2.4.19-pre7/include/linux/input.h Mon Apr 15 21:54:58 2002 @@ -307,6 +307,9 @@ #define KEY_UNKNOWN 220 +#define KEY_BRIGHTNESSDOWN 224 +#define KEY_BRIGHTNESSUP 225 + #define BTN_MISC 0x100 #define BTN_0 0x100 #define BTN_1 0x101 diff -urN linux-2.4.19-pre6/include/linux/kernel_stat.h linux-2.4.19-pre7/include/linux/kernel_stat.h --- linux-2.4.19-pre6/include/linux/kernel_stat.h Thu Nov 22 11:46:19 2001 +++ linux-2.4.19-pre7/include/linux/kernel_stat.h Mon Apr 15 21:54:58 2002 @@ -29,9 +29,6 @@ #if !defined(CONFIG_ARCH_S390) unsigned int irqs[NR_CPUS][NR_IRQS]; #endif - unsigned int ipackets, opackets; - unsigned int ierrors, oerrors; - unsigned int collisions; unsigned int context_swtch; }; diff -urN linux-2.4.19-pre6/include/linux/pci_ids.h linux-2.4.19-pre7/include/linux/pci_ids.h --- linux-2.4.19-pre6/include/linux/pci_ids.h Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/include/linux/pci_ids.h Mon Apr 15 21:54:58 2002 @@ -506,6 +506,9 @@ #define PCI_DEVICE_ID_HP_DIVA1 0x1049 #define PCI_DEVICE_ID_HP_DIVA2 0x104A #define PCI_DEVICE_ID_HP_SP2_0 0x104B +#define PCI_DEVICE_ID_HP_ZX1_SBA 0x1229 +#define PCI_DEVICE_ID_HP_ZX1_IOC 0x122a +#define PCI_DEVICE_ID_HP_ZX1_LBA 0x122e #define PCI_VENDOR_ID_PCTECH 0x1042 #define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000 diff -urN linux-2.4.19-pre6/include/linux/pmu.h linux-2.4.19-pre7/include/linux/pmu.h --- linux-2.4.19-pre6/include/linux/pmu.h Mon Feb 25 11:38:13 2002 +++ linux-2.4.19-pre7/include/linux/pmu.h Mon Apr 15 21:54:58 2002 @@ -113,6 +113,8 @@ #define PMU_IOC_HAS_ADB _IOR('B', 4, sizeof(__u32*)) /* out param: u32* can_sleep: 0 or 1 */ #define PMU_IOC_CAN_SLEEP _IOR('B', 5, sizeof(__u32*)) +/* no param */ +#define PMU_IOC_GRAB_BACKLIGHT _IOR('B', 6, 0) #ifdef __KERNEL__ diff -urN linux-2.4.19-pre6/include/linux/quotaops.h linux-2.4.19-pre7/include/linux/quotaops.h --- linux-2.4.19-pre6/include/linux/quotaops.h Thu Nov 22 11:46:52 2001 +++ linux-2.4.19-pre7/include/linux/quotaops.h Mon Apr 15 21:54:58 2002 @@ -41,7 +41,7 @@ static __inline__ void DQUOT_INIT(struct inode *inode) { if (!inode->i_sb) - BUG(); + out_of_line_bug(); lock_kernel(); if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) inode->i_sb->dq_op->initialize(inode, -1); @@ -53,7 +53,7 @@ lock_kernel(); if (IS_QUOTAINIT(inode)) { if (!inode->i_sb) - BUG(); + out_of_line_bug(); inode->i_sb->dq_op->drop(inode); /* Ops must be set when there's any quota... */ } unlock_kernel(); diff -urN linux-2.4.19-pre6/include/linux/sched.h linux-2.4.19-pre7/include/linux/sched.h --- linux-2.4.19-pre6/include/linux/sched.h Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/include/linux/sched.h Mon Apr 15 21:54:58 2002 @@ -900,7 +900,8 @@ static inline void unhash_process(struct task_struct *p) { - if (task_on_runqueue(p)) BUG(); + if (task_on_runqueue(p)) + out_of_line_bug(); write_lock_irq(&tasklist_lock); nr_threads--; unhash_pid(p); diff -urN linux-2.4.19-pre6/include/linux/serial.h linux-2.4.19-pre7/include/linux/serial.h --- linux-2.4.19-pre6/include/linux/serial.h Thu Nov 22 11:46:19 2001 +++ linux-2.4.19-pre7/include/linux/serial.h Mon Apr 15 21:54:58 2002 @@ -182,11 +182,8 @@ /* Allow complicated architectures to specify rs_table[] at run time */ extern int early_serial_setup(struct serial_struct *req); -#ifdef CONFIG_ACPI -/* tty ports reserved for the ACPI serial console port and debug port */ -#define ACPI_SERIAL_CONSOLE_PORT 4 -#define ACPI_SERIAL_DEBUG_PORT 5 -#endif +/* tty port reserved for the HCDP serial console port */ +#define HCDP_SERIAL_CONSOLE_PORT 4 #endif /* __KERNEL__ */ #endif /* _LINUX_SERIAL_H */ diff -urN linux-2.4.19-pre6/include/linux/skbuff.h linux-2.4.19-pre7/include/linux/skbuff.h --- linux-2.4.19-pre6/include/linux/skbuff.h Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/include/linux/skbuff.h Mon Apr 15 21:54:58 2002 @@ -826,7 +826,7 @@ { skb->len-=len; if (skb->len < skb->data_len) - BUG(); + out_of_line_bug(); return skb->data+=len; } diff -urN linux-2.4.19-pre6/include/math-emu/op-common.h linux-2.4.19-pre7/include/math-emu/op-common.h --- linux-2.4.19-pre6/include/math-emu/op-common.h Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/include/math-emu/op-common.h Mon Apr 15 21:54:58 2002 @@ -780,11 +780,12 @@ X##_e -= (_FP_W_TYPE_SIZE - rsize); \ X##_e = rsize - X##_e - 1; \ \ - if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e) \ - __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs), rsize); \ r &= ~((rtype)1 << X##_e); \ + if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e) \ + __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs + 1), rsize); \ _FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize); \ - _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1)); \ + if ((_FP_WFRACBITS_##fs - X##_e - 1) > 0) \ + _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1)); \ } \ else \ { \ diff -urN linux-2.4.19-pre6/include/math-emu/soft-fp.h linux-2.4.19-pre7/include/math-emu/soft-fp.h --- linux-2.4.19-pre6/include/math-emu/soft-fp.h Mon Feb 25 11:38:13 2002 +++ linux-2.4.19-pre7/include/math-emu/soft-fp.h Mon Apr 15 21:54:58 2002 @@ -154,11 +154,11 @@ #define _FP_CLS_COMBINE(x,y) (((x) << 2) | (y)) -#include "op-1.h" -#include "op-2.h" -#include "op-4.h" -#include "op-8.h" -#include "op-common.h" +#include +#include +#include +#include +#include /* Sigh. Silly things longlong.h needs. */ #define UWtype _FP_W_TYPE diff -urN linux-2.4.19-pre6/include/net/bluetooth/bluetooth.h linux-2.4.19-pre7/include/net/bluetooth/bluetooth.h --- linux-2.4.19-pre6/include/net/bluetooth/bluetooth.h Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/include/net/bluetooth/bluetooth.h Mon Apr 15 21:54:58 2002 @@ -23,7 +23,7 @@ */ /* - * $Id: bluetooth.h,v 1.6 2001/08/03 04:19:49 maxk Exp $ + * $Id: bluetooth.h,v 1.6 2002/04/01 01:57:14 maxk Exp $ */ #ifndef __BLUETOOTH_H @@ -31,17 +31,57 @@ #include #include +#include +#include #ifndef AF_BLUETOOTH #define AF_BLUETOOTH 31 #define PF_BLUETOOTH AF_BLUETOOTH #endif +/* Reserv for core and drivers use */ +#define BLUEZ_SKB_RESERVE 8 + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + #define BTPROTO_L2CAP 0 #define BTPROTO_HCI 1 +#define BTPROTO_SCO 2 +#define BTPROTO_RFCOMM 3 #define SOL_HCI 0 #define SOL_L2CAP 6 +#define SOL_SCO 17 +#define SOL_RFCOMM 18 + +/* Debugging */ +#ifdef CONFIG_BLUEZ_DEBUG + +#define HCI_CORE_DEBUG 1 +#define HCI_SOCK_DEBUG 1 +#define HCI_UART_DEBUG 1 +#define HCI_USB_DEBUG 1 +//#define HCI_DATA_DUMP 1 + +#define L2CAP_DEBUG 1 +#define SCO_DEBUG 1 +#define AF_BLUETOOTH_DEBUG 1 + +#endif /* CONFIG_BLUEZ_DEBUG */ + +extern void bluez_dump(char *pref, __u8 *buf, int count); + +#define INF(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg) +#define DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" ,__func__, ## arg) +#define ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" ,__func__, ## arg) + +#ifdef HCI_DATA_DUMP +#define DMP(buf, len) bluez_dump(__func__, buf, len) +#else +#define DMP(D...) +#endif /* Connection and socket states */ enum { @@ -50,6 +90,7 @@ BT_BOUND, BT_LISTEN, BT_CONNECT, + BT_CONNECT2, BT_CONFIG, BT_DISCONN, BT_CLOSED @@ -66,7 +107,8 @@ __u8 b[6]; } __attribute__((packed)) bdaddr_t; -#define BDADDR_ANY ((bdaddr_t *)"\000\000\000\000\000") +#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}}) +#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}}) /* Copy, swap, convert BD Address */ static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2) @@ -82,6 +124,91 @@ char *batostr(bdaddr_t *ba); bdaddr_t *strtoba(char *str); +/* Common socket structures and functions */ + +#define bluez_pi(sk) ((struct bluez_pinfo *) &sk->protinfo) +#define bluez_sk(pi) ((struct sock *) \ + ((void *)pi - (unsigned long)(&((struct sock *)0)->protinfo))) + +struct bluez_pinfo { + bdaddr_t src; + bdaddr_t dst; + + struct list_head accept_q; + struct sock *parent; +}; + +struct bluez_sock_list { + struct sock *head; + rwlock_t lock; +}; + +int bluez_sock_register(int proto, struct net_proto_family *ops); +int bluez_sock_unregister(int proto); +void bluez_sock_init(struct socket *sock, struct sock *sk); +void bluez_sock_link(struct bluez_sock_list *l, struct sock *s); +void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s); +int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm); +uint bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait); +int bluez_sock_w4_connect(struct sock *sk, int flags); + +void bluez_accept_enqueue(struct sock *parent, struct sock *sk); +struct sock * bluez_accept_dequeue(struct sock *parent, struct socket *newsock); + +/* Skb helpers */ +struct bluez_skb_cb { + int incomming; +}; +#define bluez_cb(skb) ((struct bluez_skb_cb *)(skb->cb)) + +static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how) +{ + struct sk_buff *skb; + + if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) { + skb_reserve(skb, BLUEZ_SKB_RESERVE); + bluez_cb(skb)->incomming = 0; + } + return skb; +} + +static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len, + int nb, int *err) +{ + struct sk_buff *skb; + + if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) { + skb_reserve(skb, BLUEZ_SKB_RESERVE); + bluez_cb(skb)->incomming = 0; + } + + return skb; +} + +static inline int skb_frags_no(struct sk_buff *skb) +{ + register struct sk_buff *frag = skb_shinfo(skb)->frag_list; + register int n = 1; + + for (; frag; frag=frag->next, n++); + return n; +} + +int hci_core_init(void); +int hci_core_cleanup(void); +int hci_sock_init(void); +int hci_sock_cleanup(void); + int bterr(__u16 code); +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(x) +#endif + +#ifndef list_for_each_safe +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) +#endif + #endif /* __BLUETOOTH_H */ diff -urN linux-2.4.19-pre6/include/net/bluetooth/bluez.h linux-2.4.19-pre7/include/net/bluetooth/bluez.h --- linux-2.4.19-pre6/include/net/bluetooth/bluez.h Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/include/net/bluetooth/bluez.h Wed Dec 31 16:00:00 1969 @@ -1,124 +0,0 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * $Id: bluez.h,v 1.4 2001/08/03 04:19:49 maxk Exp $ - */ - -#ifndef __IF_BLUEZ_H -#define __IF_BLUEZ_H - -#include - -#define BLUEZ_MAX_PROTO 2 - -/* Reserv for core and drivers use */ -#define BLUEZ_SKB_RESERVE 8 - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -/* Debugging */ -#ifdef BLUEZ_DEBUG - -#define HCI_CORE_DEBUG 1 -#define HCI_SOCK_DEBUG 1 -#define HCI_UART_DEBUG 1 -#define HCI_USB_DEBUG 1 -//#define HCI_DATA_DUMP 1 - -#define L2CAP_DEBUG 1 - -#endif /* BLUEZ_DEBUG */ - -extern void bluez_dump(char *pref, __u8 *buf, int count); - -#define INF(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg) -#define DBG(fmt, arg...) printk(KERN_INFO __FUNCTION__ ": " fmt "\n" , ## arg) -#define ERR(fmt, arg...) printk(KERN_ERR __FUNCTION__ ": " fmt "\n" , ## arg) - -#ifdef HCI_DATA_DUMP -#define DMP(buf, len) bluez_dump(__FUNCTION__, buf, len) -#else -#define DMP(D...) -#endif - -/* ----- Sockets ------ */ -struct bluez_sock_list { - struct sock *head; - rwlock_t lock; -}; - -extern int bluez_sock_register(int proto, struct net_proto_family *ops); -extern int bluez_sock_unregister(int proto); - -extern void bluez_sock_link(struct bluez_sock_list *l, struct sock *s); -extern void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s); - -/* ----- SKB helpers ----- */ -struct bluez_skb_cb { - int incomming; -}; -#define bluez_cb(skb) ((struct bluez_skb_cb *)(skb->cb)) - -static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how) -{ - struct sk_buff *skb; - - if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) { - skb_reserve(skb, BLUEZ_SKB_RESERVE); - bluez_cb(skb)->incomming = 0; - } - return skb; -} - -static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len, - int nb, int *err) -{ - struct sk_buff *skb; - - if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) { - skb_reserve(skb, BLUEZ_SKB_RESERVE); - bluez_cb(skb)->incomming = 0; - } - - return skb; -} - -static inline int skb_frags_no(struct sk_buff *skb) -{ - register struct sk_buff *frag = skb_shinfo(skb)->frag_list; - register int n = 1; - - for (; frag; frag=frag->next, n++); - return n; -} - -extern int hci_core_init(void); -extern int hci_core_cleanup(void); -extern int hci_sock_init(void); -extern int hci_sock_cleanup(void); - -#endif /* __IF_BLUEZ_H */ diff -urN linux-2.4.19-pre6/include/net/bluetooth/hci.h linux-2.4.19-pre7/include/net/bluetooth/hci.h --- linux-2.4.19-pre6/include/net/bluetooth/hci.h Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/include/net/bluetooth/hci.h Mon Apr 15 21:54:58 2002 @@ -23,16 +23,16 @@ */ /* - * $Id: hci.h,v 1.15 2001/08/05 06:02:15 maxk Exp $ + * $Id: hci.h,v 1.3 2002/03/26 17:54:57 maxk Exp $ */ #ifndef __HCI_H #define __HCI_H -#include - -#define HCI_MAX_DEV 8 -#define HCI_MAX_FRAME_SIZE 2048 +#define HCI_MAX_ACL_SIZE 1024 +#define HCI_MAX_SCO_SIZE 255 +#define HCI_MAX_EVENT_SIZE 260 +#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4) /* HCI dev events */ #define HCI_DEV_REG 1 @@ -41,41 +41,54 @@ #define HCI_DEV_DOWN 4 /* HCI device types */ -#define HCI_UART 0 +#define HCI_VHCI 0 #define HCI_USB 1 -#define HCI_VHCI 2 - -/* HCI device modes */ -#define HCI_NORMAL 0x0001 -#define HCI_RAW 0x0002 -#define HCI_MODE_MASK (HCI_NORMAL | HCI_RAW) -#define HCI_SOCK 0x1000 - -/* HCI device states */ -#define HCI_INIT 0x0010 -#define HCI_UP 0x0020 -#define HCI_RUNNING 0x0040 +#define HCI_PCCARD 2 +#define HCI_UART 3 +#define HCI_RS232 4 /* HCI device flags */ -#define HCI_PSCAN 0x0100 -#define HCI_ISCAN 0x0200 -#define HCI_AUTH 0x0400 +enum { + HCI_UP, + HCI_INIT, + HCI_RUNNING, + + HCI_PSCAN, + HCI_ISCAN, + HCI_AUTH, + HCI_ENCRYPT, + HCI_INQUIRY, -/* HCI Ioctl defines */ + HCI_RAW +}; + +/* HCI ioctl defines */ #define HCIDEVUP _IOW('H', 201, int) #define HCIDEVDOWN _IOW('H', 202, int) #define HCIDEVRESET _IOW('H', 203, int) -#define HCIRESETSTAT _IOW('H', 204, int) -#define HCIGETINFO _IOR('H', 205, int) -#define HCIGETDEVLIST _IOR('H', 206, int) -#define HCISETRAW _IOW('H', 207, int) -#define HCISETSCAN _IOW('H', 208, int) -#define HCISETAUTH _IOW('H', 209, int) -#define HCIINQUIRY _IOR('H', 210, int) -#define HCISETPTYPE _IOW('H', 211, int) +#define HCIDEVRESTAT _IOW('H', 204, int) + +#define HCIGETDEVLIST _IOR('H', 210, int) +#define HCIGETDEVINFO _IOR('H', 211, int) #define HCIGETCONNLIST _IOR('H', 212, int) +#define HCIGETCONNINFO _IOR('H', 213, int) -#ifndef __NO_HCI_DEFS +#define HCISETRAW _IOW('H', 220, int) +#define HCISETSCAN _IOW('H', 221, int) +#define HCISETAUTH _IOW('H', 222, int) +#define HCISETENCRYPT _IOW('H', 223, int) +#define HCISETPTYPE _IOW('H', 224, int) +#define HCISETLINKPOL _IOW('H', 225, int) +#define HCISETLINKMODE _IOW('H', 226, int) +#define HCISETACLMTU _IOW('H', 227, int) +#define HCISETSCOMTU _IOW('H', 228, int) + +#define HCIINQUIRY _IOR('H', 240, int) + +/* HCI timeouts */ +#define HCI_CONN_TIMEOUT (HZ * 40) +#define HCI_DISCONN_TIMEOUT (HZ * 2) +#define HCI_CONN_IDLE_TIMEOUT (HZ * 60) /* HCI Packet types */ #define HCI_COMMAND_PKT 0x01 @@ -92,6 +105,13 @@ #define HCI_DH3 0x0800 #define HCI_DH5 0x8000 +#define HCI_HV1 0x0020 +#define HCI_HV2 0x0040 +#define HCI_HV3 0x0080 + +#define SCO_PTYPE_MASK (HCI_HV1 | HCI_HV2 | HCI_HV3) +#define ACL_PTYPE_MASK (~SCO_PTYPE_MASK) + /* ACL flags */ #define ACL_CONT 0x0001 #define ACL_START 0x0002 @@ -125,6 +145,19 @@ #define LMP_PSCHEME 0x02 #define LMP_PCONTROL 0x04 +/* Link policies */ +#define HCI_LP_RSWITCH 0x0001 +#define HCI_LP_HOLD 0x0002 +#define HCI_LP_SNIFF 0x0004 +#define HCI_LP_PARK 0x0008 + +/* Link mode */ +#define HCI_LM_ACCEPT 0x8000 +#define HCI_LM_MASTER 0x0001 +#define HCI_LM_AUTH 0x0002 +#define HCI_LM_ENCRYPT 0x0004 +#define HCI_LM_TRUSTED 0x0008 + /* ----- HCI Commands ----- */ /* OGF & OCF values */ @@ -137,9 +170,10 @@ __u8 hci_ver; __u16 hci_rev; __u8 lmp_ver; - __u16 man_name; - __u16 lmp_sub; + __u16 manufacturer; + __u16 lmp_subver; } __attribute__ ((packed)) read_local_version_rp; +#define READ_LOCAL_VERSION_RP_SIZE 9 #define OCF_READ_LOCAL_FEATURES 0x0003 typedef struct { @@ -165,18 +199,24 @@ /* Host Controller and Baseband */ #define OGF_HOST_CTL 0x03 #define OCF_RESET 0x0003 +#define OCF_READ_AUTH_ENABLE 0x001F #define OCF_WRITE_AUTH_ENABLE 0x0020 - #define AUTH_DISABLED 0x00 - #define AUTH_ENABLED 0x01 + #define AUTH_DISABLED 0x00 + #define AUTH_ENABLED 0x01 + +#define OCF_READ_ENCRYPT_MODE 0x0021 +#define OCF_WRITE_ENCRYPT_MODE 0x0022 + #define ENCRYPT_DISABLED 0x00 + #define ENCRYPT_P2P 0x01 + #define ENCRYPT_BOTH 0x02 #define OCF_WRITE_CA_TIMEOUT 0x0016 #define OCF_WRITE_PG_TIMEOUT 0x0018 #define OCF_WRITE_SCAN_ENABLE 0x001A - #define SCANS_DISABLED 0x00 - #define IS_ENA_PS_DIS 0x01 - #define IS_DIS_PS_ENA 0x02 - #define IS_ENA_PS_ENA 0x03 + #define SCAN_DISABLED 0x00 + #define SCAN_INQUIRY 0x01 + #define SCAN_PAGE 0x02 #define OCF_SET_EVENT_FLT 0x0005 typedef struct { @@ -226,9 +266,18 @@ } __attribute__ ((packed)) write_class_of_dev_cp; #define WRITE_CLASS_OF_DEV_CP_SIZE 3 +#define OCF_HOST_BUFFER_SIZE 0x0033 +typedef struct { + __u16 acl_mtu; + __u8 sco_mtu; + __u16 acl_max_pkt; + __u16 sco_max_pkt; +} __attribute__ ((packed)) host_buffer_size_cp; +#define HOST_BUFFER_SIZE_CP_SIZE 7 + /* Link Control */ #define OGF_LINK_CTL 0x01 -#define OCF_CREATE_CONN 0x0005 +#define OCF_CREATE_CONN 0x0005 typedef struct { bdaddr_t bdaddr; __u16 pkt_type; @@ -246,6 +295,13 @@ } __attribute__ ((packed)) accept_conn_req_cp; #define ACCEPT_CONN_REQ_CP_SIZE 7 +#define OCF_REJECT_CONN_REQ 0x000a +typedef struct { + bdaddr_t bdaddr; + __u8 reason; +} __attribute__ ((packed)) reject_conn_req_cp; +#define REJECT_CONN_REQ_CP_SIZE 7 + #define OCF_DISCONNECT 0x0006 typedef struct { __u16 handle; @@ -253,17 +309,134 @@ } __attribute__ ((packed)) disconnect_cp; #define DISCONNECT_CP_SIZE 3 +#define OCF_ADD_SCO 0x0007 +typedef struct { + __u16 handle; + __u16 pkt_type; +} __attribute__ ((packed)) add_sco_cp; +#define ADD_SCO_CP_SIZE 4 + #define OCF_INQUIRY 0x0001 typedef struct { __u8 lap[3]; - __u8 lenght; + __u8 length; __u8 num_rsp; } __attribute__ ((packed)) inquiry_cp; #define INQUIRY_CP_SIZE 5 -#define OGF_LINK_POLICY 0x02 /* Link Policy */ +typedef struct { + __u8 status; + bdaddr_t bdaddr; +} __attribute__ ((packed)) status_bdaddr_rp; +#define STATUS_BDADDR_RP_SIZE 7 + +#define OCF_LINK_KEY_REPLY 0x000B +#define OCF_LINK_KEY_NEG_REPLY 0x000C +typedef struct { + bdaddr_t bdaddr; + __u8 link_key[16]; +} __attribute__ ((packed)) link_key_reply_cp; +#define LINK_KEY_REPLY_CP_SIZE 22 + +#define OCF_PIN_CODE_REPLY 0x000D +#define OCF_PIN_CODE_NEG_REPLY 0x000E +typedef struct { + bdaddr_t bdaddr; + __u8 pin_len; + __u8 pin_code[16]; +} __attribute__ ((packed)) pin_code_reply_cp; +#define PIN_CODE_REPLY_CP_SIZE 23 + +#define OCF_CHANGE_CONN_PTYPE 0x000F +typedef struct { + __u16 handle; + __u16 pkt_type; +} __attribute__ ((packed)) change_conn_ptype_cp; +#define CHANGE_CONN_PTYPE_CP_SIZE 4 -/* --------- HCI Events --------- */ +#define OCF_AUTH_REQUESTED 0x0011 +typedef struct { + __u16 handle; +} __attribute__ ((packed)) auth_requested_cp; +#define AUTH_REQUESTED_CP_SIZE 2 + +#define OCF_SET_CONN_ENCRYPT 0x0013 +typedef struct { + __u16 handle; + __u8 encrypt; +} __attribute__ ((packed)) set_conn_encrypt_cp; +#define SET_CONN_ENCRYPT_CP_SIZE 3 + +#define OCF_REMOTE_NAME_REQ 0x0019 +typedef struct { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; + __u8 pscan_mode; + __u16 clock_offset; +} __attribute__ ((packed)) remote_name_req_cp; +#define REMOTE_NAME_REQ_CP_SIZE 10 + +#define OCF_READ_REMOTE_FEATURES 0x001B +typedef struct { + __u16 handle; +} __attribute__ ((packed)) read_remote_features_cp; +#define READ_REMOTE_FEATURES_CP_SIZE 2 + +#define OCF_READ_REMOTE_VERSION 0x001D +typedef struct { + __u16 handle; +} __attribute__ ((packed)) read_remote_version_cp; +#define READ_REMOTE_VERSION_CP_SIZE 2 + +/* Link Policy */ +#define OGF_LINK_POLICY 0x02 +#define OCF_ROLE_DISCOVERY 0x0009 +typedef struct { + __u16 handle; +} __attribute__ ((packed)) role_discovery_cp; +#define ROLE_DISCOVERY_CP_SIZE 2 +typedef struct { + __u8 status; + __u16 handle; + __u8 role; +} __attribute__ ((packed)) role_discovery_rp; +#define ROLE_DISCOVERY_RP_SIZE 4 + +#define OCF_READ_LINK_POLICY 0x000C +typedef struct { + __u16 handle; +} __attribute__ ((packed)) read_link_policy_cp; +#define READ_LINK_POLICY_CP_SIZE 2 +typedef struct { + __u8 status; + __u16 handle; + __u16 policy; +} __attribute__ ((packed)) read_link_policy_rp; +#define READ_LINK_POLICY_RP_SIZE 5 + +#define OCF_SWITCH_ROLE 0x000B +typedef struct { + bdaddr_t bdaddr; + __u8 role; +} __attribute__ ((packed)) switch_role_cp; +#define SWITCH_ROLE_CP_SIZE 7 + +#define OCF_WRITE_LINK_POLICY 0x000D +typedef struct { + __u16 handle; + __u16 policy; +} __attribute__ ((packed)) write_link_policy_cp; +#define WRITE_LINK_POLICY_CP_SIZE 4 +typedef struct { + __u8 status; + __u16 handle; +} __attribute__ ((packed)) write_link_policy_rp; +#define WRITE_LINK_POLICY_RP_SIZE 3 + +/* Status params */ +#define OGF_STATUS_PARAM 0x05 + +/* ---- HCI Events ---- */ #define EVT_INQUIRY_COMPLETE 0x01 #define EVT_INQUIRY_RESULT 0x02 @@ -272,7 +445,7 @@ __u8 pscan_rep_mode; __u8 pscan_period_mode; __u8 pscan_mode; - __u8 class[3]; + __u8 dev_class[3]; __u16 clock_offset; } __attribute__ ((packed)) inquiry_info; #define INQUIRY_INFO_SIZE 14 @@ -303,6 +476,44 @@ } __attribute__ ((packed)) evt_disconn_complete; #define EVT_DISCONN_COMPLETE_SIZE 4 +#define EVT_AUTH_COMPLETE 0x06 +typedef struct { + __u8 status; + __u16 handle; +} __attribute__ ((packed)) evt_auth_complete; +#define EVT_AUTH_COMPLETE_SIZE 3 + +#define EVT_REMOTE_NAME_REQ_COMPLETE 0x07 +typedef struct { + __u8 status; + bdaddr_t bdaddr; + __u8 name[248]; +} __attribute__ ((packed)) evt_remote_name_req_complete; +#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255 + +#define EVT_ENCRYPT_CHANGE 0x08 +typedef struct { + __u8 status; + __u16 handle; + __u8 encrypt; +} __attribute__ ((packed)) evt_encrypt_change; +#define EVT_ENCRYPT_CHANGE_SIZE 5 + +#define EVT_QOS_SETUP_COMPLETE 0x0D +typedef struct { + __u8 service_type; + __u32 token_rate; + __u32 peak_bandwidth; + __u32 latency; + __u32 delay_variation; +} __attribute__ ((packed)) hci_qos; +typedef struct { + __u8 status; + __u16 handle; + hci_qos qos; +} __attribute__ ((packed)) evt_qos_setup_complete; +#define EVT_QOS_SETUP_COMPLETE_SIZE 20 + #define EVT_CMD_COMPLETE 0x0e typedef struct { __u8 ncmd; @@ -321,16 +532,78 @@ #define EVT_NUM_COMP_PKTS 0x13 typedef struct { __u8 num_hndl; - /* variable lenght part */ + /* variable length part */ } __attribute__ ((packed)) evt_num_comp_pkts; #define EVT_NUM_COMP_PKTS_SIZE 1 -#define EVT_HCI_DEV_EVENT 0xfd +#define EVT_ROLE_CHANGE 0x12 +typedef struct { + __u8 status; + bdaddr_t bdaddr; + __u8 role; +} __attribute__ ((packed)) evt_role_change; +#define EVT_ROLE_CHANGE_SIZE 1 + +#define EVT_PIN_CODE_REQ 0x16 +typedef struct { + bdaddr_t bdaddr; +} __attribute__ ((packed)) evt_pin_code_req; +#define EVT_PIN_CODE_REQ_SIZE 6 + +#define EVT_LINK_KEY_REQ 0x17 +typedef struct { + bdaddr_t bdaddr; +} __attribute__ ((packed)) evt_link_key_req; +#define EVT_LINK_KEY_REQ_SIZE 6 + +#define EVT_LINK_KEY_NOTIFY 0x18 +typedef struct { + bdaddr_t bdaddr; + __u8 link_key[16]; + __u8 key_type; +} __attribute__ ((packed)) evt_link_key_notify; +#define EVT_LINK_KEY_NOTIFY_SIZE 23 + +#define EVT_READ_REMOTE_FEATURES_COMPLETE 0x0B +typedef struct { + __u8 status; + __u16 handle; + __u8 features[8]; +} __attribute__ ((packed)) evt_read_remote_features_complete; +#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11 + +#define EVT_READ_REMOTE_VERSION_COMPLETE 0x0C +typedef struct { + __u8 status; + __u16 handle; + __u8 lmp_ver; + __u16 manufacturer; + __u16 lmp_subver; +} __attribute__ ((packed)) evt_read_remote_version_complete; +#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8 + +/* Internal events generated by BlueZ stack */ +#define EVT_STACK_INTERNAL 0xfd +typedef struct { + __u16 type; + __u8 data[0]; +} __attribute__ ((packed)) evt_stack_internal; +#define EVT_STACK_INTERNAL_SIZE 2 + +#define EVT_SI_DEVICE 0x01 +typedef struct { + __u16 event; + __u16 dev_id; +} __attribute__ ((packed)) evt_si_device; +#define EVT_SI_DEVICE_SIZE 4 + +#define EVT_SI_SECURITY 0x02 typedef struct { __u16 event; - __u16 param; -} __attribute__ ((packed)) evt_hci_dev_event; -#define EVT_HCI_DEV_EVENT_SIZE 4 + __u16 proto; + __u16 subproto; + __u8 incomming; +} __attribute__ ((packed)) evt_si_security; /* -------- HCI Packet structures -------- */ #define HCI_TYPE_LEN 1 @@ -369,14 +642,14 @@ #define acl_handle(h) (h & 0x0fff) #define acl_flags(h) (h >> 12) -#endif /* _NO_HCI_DEFS */ - /* HCI Socket options */ -#define HCI_DATA_DIR 0x0001 -#define HCI_FILTER 0x0002 +#define HCI_DATA_DIR 1 +#define HCI_FILTER 2 +#define HCI_TIME_STAMP 3 /* HCI CMSG flags */ #define HCI_CMSG_DIR 0x0001 +#define HCI_CMSG_TSTAMP 0x0002 struct sockaddr_hci { sa_family_t hci_family; @@ -387,27 +660,15 @@ struct hci_filter { __u32 type_mask; __u32 event_mask[2]; + __u16 opcode; }; -struct hci_dev_req { - __u16 dev_id; - __u32 dev_opt; -}; - -struct hci_dev_list_req { - __u16 dev_num; - struct hci_dev_req dev_req[0]; /* hci_dev_req structures */ -}; - -struct hci_inquiry_req { - __u16 dev_id; - __u16 flags; - __u8 lap[3]; - __u8 length; - __u8 num_rsp; -}; -#define IREQ_CACHE_FLUSH 0x0001 +#define HCI_FLT_TYPE_BITS 31 +#define HCI_FLT_EVENT_BITS 63 +#define HCI_FLT_OGF_BITS 63 +#define HCI_FLT_OCF_BITS 127 +/* Ioctl requests structures */ struct hci_dev_stats { __u32 err_rx; __u32 err_tx; @@ -433,11 +694,13 @@ __u8 features[8]; __u32 pkt_type; + __u32 link_policy; + __u32 link_mode; __u16 acl_mtu; - __u16 acl_max; + __u16 acl_pkts; __u16 sco_mtu; - __u16 sco_max; + __u16 sco_pkts; struct hci_dev_stats stat; }; @@ -445,6 +708,20 @@ struct hci_conn_info { __u16 handle; bdaddr_t bdaddr; + __u8 type; + __u8 out; + __u16 state; + __u32 link_mode; +}; + +struct hci_dev_req { + __u16 dev_id; + __u32 dev_opt; +}; + +struct hci_dev_list_req { + __u16 dev_num; + struct hci_dev_req dev_req[0]; /* hci_dev_req structures */ }; struct hci_conn_list_req { @@ -453,4 +730,26 @@ struct hci_conn_info conn_info[0]; }; +struct hci_conn_info_req { + bdaddr_t bdaddr; + __u8 type; + struct hci_conn_info conn_info[0]; +}; + +struct hci_inquiry_req { + __u16 dev_id; + __u16 flags; + __u8 lap[3]; + __u8 length; + __u8 num_rsp; +}; +#define IREQ_CACHE_FLUSH 0x0001 + +struct hci_remotename_req { + __u16 dev_id; + __u16 flags; + bdaddr_t bdaddr; + __u8 name[248]; +}; + #endif /* __HCI_H */ diff -urN linux-2.4.19-pre6/include/net/bluetooth/hci_core.h linux-2.4.19-pre7/include/net/bluetooth/hci_core.h --- linux-2.4.19-pre6/include/net/bluetooth/hci_core.h Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/include/net/bluetooth/hci_core.h Mon Apr 15 21:54:58 2002 @@ -23,7 +23,7 @@ */ /* - * $Id: hci_core.h,v 1.11 2001/08/05 06:02:15 maxk Exp $ + * $Id: hci_core.h,v 1.2 2002/03/26 17:54:57 maxk Exp $ */ #ifndef __HCI_CORE_H @@ -32,14 +32,12 @@ #include /* HCI upper protocols */ -#define HCI_MAX_PROTO 1 #define HCI_PROTO_L2CAP 0 +#define HCI_PROTO_SCO 1 #define HCI_INIT_TIMEOUT (HZ * 10) -/* ----- Inquiry cache ----- */ -#define INQUIRY_CACHE_AGE_MAX (HZ*5) // 5 seconds -#define INQUIRY_ENTRY_AGE_MAX (HZ*60) // 60 seconds +/* HCI Core structures */ struct inquiry_entry { struct inquiry_entry *next; @@ -53,111 +51,180 @@ struct inquiry_entry *list; }; -static inline void inquiry_cache_init(struct inquiry_cache *cache) -{ - spin_lock_init(&cache->lock); - cache->list = NULL; -} +struct conn_hash { + struct list_head list; + spinlock_t lock; + unsigned int num; +}; -static inline void inquiry_cache_lock(struct inquiry_cache *cache) -{ - spin_lock(&cache->lock); -} +struct hci_dev { + struct list_head list; + spinlock_t lock; + atomic_t refcnt; -static inline void inquiry_cache_unlock(struct inquiry_cache *cache) -{ - spin_unlock(&cache->lock); -} + char name[8]; + __u32 flags; + __u16 id; + __u8 type; + bdaddr_t bdaddr; + __u8 features[8]; -static inline void inquiry_cache_lock_bh(struct inquiry_cache *cache) -{ - spin_lock_bh(&cache->lock); -} + __u16 pkt_type; + __u16 link_policy; + __u16 link_mode; + + atomic_t cmd_cnt; + unsigned int acl_cnt; + unsigned int sco_cnt; -static inline void inquiry_cache_unlock_bh(struct inquiry_cache *cache) -{ - spin_unlock_bh(&cache->lock); -} + unsigned int acl_mtu; + unsigned int sco_mtu; + unsigned int acl_pkts; + unsigned int sco_pkts; -static inline long inquiry_cache_age(struct inquiry_cache *cache) -{ - return jiffies - cache->timestamp; -} + unsigned long cmd_last_tx; + unsigned long acl_last_tx; + unsigned long sco_last_tx; + + struct tasklet_struct cmd_task; + struct tasklet_struct rx_task; + struct tasklet_struct tx_task; -static inline long inquiry_entry_age(struct inquiry_entry *e) -{ - return jiffies - e->timestamp; -} -extern void inquiry_cache_flush(struct inquiry_cache *cache); + struct sk_buff_head rx_q; + struct sk_buff_head raw_q; + struct sk_buff_head cmd_q; -struct hci_dev; + struct sk_buff *sent_cmd; + + struct semaphore req_lock; + wait_queue_head_t req_wait_q; + __u32 req_status; + __u32 req_result; + + struct inquiry_cache inq_cache; + struct conn_hash conn_hash; + + struct hci_dev_stats stat; + + void *driver_data; + void *core_data; + + atomic_t promisc; + + int (*open)(struct hci_dev *hdev); + int (*close)(struct hci_dev *hdev); + int (*flush)(struct hci_dev *hdev); + int (*send)(struct sk_buff *skb); + void (*destruct)(struct hci_dev *hdev); + int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg); +}; -/* ----- HCI Connections ----- */ struct hci_conn { struct list_head list; + + atomic_t refcnt; + spinlock_t lock; + bdaddr_t dst; __u16 handle; + __u16 state; __u8 type; - unsigned int sent; + __u8 out; + __u32 link_mode; + __u32 pend; + + unsigned int sent; + + struct sk_buff_head data_q; + struct timer_list timer; + struct hci_dev *hdev; void *l2cap_data; + void *sco_data; void *priv; - struct sk_buff_head data_q; + struct hci_conn *link; }; -struct conn_hash { - struct list_head list; - spinlock_t lock; - unsigned int num; -}; +extern struct hci_proto *hci_proto[]; +extern struct list_head hdev_list; +extern spinlock_t hdev_list_lock; + +/* ----- Inquiry cache ----- */ +#define INQUIRY_CACHE_AGE_MAX (HZ*30) // 30 seconds +#define INQUIRY_ENTRY_AGE_MAX (HZ*60) // 60 seconds + +#define inquiry_cache_lock(c) spin_lock(&c->lock) +#define inquiry_cache_unlock(c) spin_unlock(&c->lock) +#define inquiry_cache_lock_bh(c) spin_lock_bh(&c->lock) +#define inquiry_cache_unlock_bh(c) spin_unlock_bh(&c->lock) -static inline void conn_hash_init(struct conn_hash *h) +static inline void inquiry_cache_init(struct hci_dev *hdev) { - INIT_LIST_HEAD(&h->list); - spin_lock_init(&h->lock); - h->num = 0; + struct inquiry_cache *c = &hdev->inq_cache; + spin_lock_init(&c->lock); + c->list = NULL; } -static inline void conn_hash_lock(struct conn_hash *h) +static inline long inquiry_cache_age(struct hci_dev *hdev) { - spin_lock(&h->lock); + struct inquiry_cache *c = &hdev->inq_cache; + return jiffies - c->timestamp; } -static inline void conn_hash_unlock(struct conn_hash *h) +static inline long inquiry_entry_age(struct inquiry_entry *e) { - spin_unlock(&h->lock); + return jiffies - e->timestamp; } -static inline void __conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c) +struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); +void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info); +void inquiry_cache_flush(struct hci_dev *hdev); +int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf); + +/* ----- HCI Connections ----- */ +enum { + HCI_CONN_AUTH_PEND, + HCI_CONN_ENCRYPT_PEND +}; + +#define hci_conn_lock(c) spin_lock(&c->lock) +#define hci_conn_unlock(c) spin_unlock(&c->lock) +#define hci_conn_lock_bh(c) spin_lock_bh(&c->lock) +#define hci_conn_unlock_bh(c) spin_unlock_bh(&c->lock) + +#define conn_hash_lock(d) spin_lock(&d->conn_hash->lock) +#define conn_hash_unlock(d) spin_unlock(&d->conn_hash->lock) +#define conn_hash_lock_bh(d) spin_lock_bh(&d->conn_hash->lock) +#define conn_hash_unlock_bh(d) spin_unlock_bh(&d->conn_hash->lock) + +static inline void conn_hash_init(struct hci_dev *hdev) { - list_add(&c->list, &h->list); - h->num++; + struct conn_hash *h = &hdev->conn_hash; + INIT_LIST_HEAD(&h->list); + spin_lock_init(&h->lock); + h->num = 0; } -static inline void conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c) +static inline void conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) { - conn_hash_lock(h); - __conn_hash_add(h, handle, c); - conn_hash_unlock(h); + struct conn_hash *h = &hdev->conn_hash; + list_add(&c->list, &h->list); + h->num++; } -static inline void __conn_hash_del(struct conn_hash *h, struct hci_conn *c) +static inline void conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) { + struct conn_hash *h = &hdev->conn_hash; list_del(&c->list); h->num--; } -static inline void conn_hash_del(struct conn_hash *h, struct hci_conn *c) -{ - conn_hash_lock(h); - __conn_hash_del(h, c); - conn_hash_unlock(h); -} - -static inline struct hci_conn *__conn_hash_lookup(struct conn_hash *h, __u16 handle) +static inline struct hci_conn *conn_hash_lookup_handle(struct hci_dev *hdev, + __u16 handle) { + register struct conn_hash *h = &hdev->conn_hash; register struct list_head *p; register struct hci_conn *c; @@ -169,101 +236,89 @@ return NULL; } -static inline struct hci_conn *conn_hash_lookup(struct conn_hash *h, __u16 handle) +static inline struct hci_conn *conn_hash_lookup_ba(struct hci_dev *hdev, + __u8 type, bdaddr_t *ba) { - struct hci_conn *conn; + register struct conn_hash *h = &hdev->conn_hash; + register struct list_head *p; + register struct hci_conn *c; - conn_hash_lock(h); - conn = __conn_hash_lookup(h, handle); - conn_hash_unlock(h); - return conn; + list_for_each(p, &h->list) { + c = list_entry(p, struct hci_conn, list); + if (c->type == type && !bacmp(&c->dst, ba)) + return c; + } + return NULL; } -/* ----- HCI Devices ----- */ -struct hci_dev { - atomic_t refcnt; - - char name[8]; - __u32 flags; - __u16 id; - __u8 type; - bdaddr_t bdaddr; - __u8 features[8]; - - __u16 pkt_type; - - atomic_t cmd_cnt; - unsigned int acl_cnt; - unsigned int sco_cnt; - - unsigned int acl_mtu; - unsigned int sco_mtu; - unsigned int acl_max; - unsigned int sco_max; - - void *driver_data; - void *l2cap_data; - void *priv; - - struct tasklet_struct cmd_task; - struct tasklet_struct rx_task; - struct tasklet_struct tx_task; - - struct sk_buff_head rx_q; - struct sk_buff_head raw_q; - struct sk_buff_head cmd_q; - - struct sk_buff *sent_cmd; - - struct semaphore req_lock; - wait_queue_head_t req_wait_q; - __u32 req_status; - __u32 req_result; - - struct inquiry_cache inq_cache; +void hci_acl_connect(struct hci_conn *conn); +void hci_acl_disconn(struct hci_conn *conn, __u8 reason); +void hci_add_sco(struct hci_conn *conn, __u16 handle); - struct conn_hash conn_hash; +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); +int hci_conn_del(struct hci_conn *conn); +void hci_conn_hash_flush(struct hci_dev *hdev); - struct hci_dev_stats stat; +struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src); +int hci_conn_auth(struct hci_conn *conn); +int hci_conn_encrypt(struct hci_conn *conn); - int (*open)(struct hci_dev *hdev); - int (*close)(struct hci_dev *hdev); - int (*flush)(struct hci_dev *hdev); - int (*send)(struct sk_buff *skb); -}; +static inline void hci_conn_set_timer(struct hci_conn *conn, long timeout) +{ + mod_timer(&conn->timer, jiffies + timeout); +} -static inline void hci_dev_hold(struct hci_dev *hdev) +static inline void hci_conn_del_timer(struct hci_conn *conn) { - atomic_inc(&hdev->refcnt); + del_timer(&conn->timer); } -static inline void hci_dev_put(struct hci_dev *hdev) +static inline void hci_conn_hold(struct hci_conn *conn) { - atomic_dec(&hdev->refcnt); + atomic_inc(&conn->refcnt); + hci_conn_del_timer(conn); } -extern struct hci_dev *hci_dev_get(int index); -extern int hci_register_dev(struct hci_dev *hdev); -extern int hci_unregister_dev(struct hci_dev *hdev); -extern int hci_dev_open(__u16 dev); -extern int hci_dev_close(__u16 dev); -extern int hci_dev_reset(__u16 dev); -extern int hci_dev_reset_stat(__u16 dev); -extern int hci_dev_info(unsigned long arg); -extern int hci_dev_list(unsigned long arg); -extern int hci_dev_setscan(unsigned long arg); -extern int hci_dev_setauth(unsigned long arg); -extern int hci_dev_setptype(unsigned long arg); -extern int hci_conn_list(unsigned long arg); -extern int hci_inquiry(unsigned long arg); +static inline void hci_conn_put(struct hci_conn *conn) +{ + if (atomic_dec_and_test(&conn->refcnt) && conn->out) + hci_conn_set_timer(conn, HCI_DISCONN_TIMEOUT); +} -extern __u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode); -extern __u32 hci_dev_getmode(struct hci_dev *hdev); +/* ----- HCI Devices ----- */ +static inline void hci_dev_put(struct hci_dev *d) +{ + if (atomic_dec_and_test(&d->refcnt)) + d->destruct(d); +} +#define hci_dev_hold(d) atomic_inc(&d->refcnt) + +#define hci_dev_lock(d) spin_lock(&d->lock) +#define hci_dev_unlock(d) spin_unlock(&d->lock) +#define hci_dev_lock_bh(d) spin_lock_bh(&d->lock) +#define hci_dev_unlock_bh(d) spin_unlock_bh(&d->lock) + +struct hci_dev *hci_dev_get(int index); +struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst); +int hci_register_dev(struct hci_dev *hdev); +int hci_unregister_dev(struct hci_dev *hdev); +int hci_dev_open(__u16 dev); +int hci_dev_close(__u16 dev); +int hci_dev_reset(__u16 dev); +int hci_dev_reset_stat(__u16 dev); +int hci_dev_cmd(unsigned int cmd, unsigned long arg); +int hci_get_dev_list(unsigned long arg); +int hci_get_dev_info(unsigned long arg); +int hci_get_conn_list(unsigned long arg); +int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg); +int hci_inquiry(unsigned long arg); -extern int hci_recv_frame(struct sk_buff *skb); +int hci_recv_frame(struct sk_buff *skb); +void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); /* ----- LMP capabilities ----- */ #define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH) +#define lmp_encrypt_capable(dev) (dev->features[0] & LMP_ENCRYPT) /* ----- HCI tasks ----- */ static inline void hci_sched_cmd(struct hci_dev *hdev) @@ -289,38 +344,127 @@ void *priv; - int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr); - int (*connect_cfm) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *conn); + int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type); + int (*connect_cfm) (struct hci_conn *conn, __u8 status); int (*disconn_ind) (struct hci_conn *conn, __u8 reason); - int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb , __u16 flags); + int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags); int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb); + int (*auth_cfm) (struct hci_conn *conn, __u8 status); + int (*encrypt_cfm) (struct hci_conn *conn, __u8 status); }; -extern int hci_register_proto(struct hci_proto *hproto); -extern int hci_unregister_proto(struct hci_proto *hproto); -extern int hci_register_notifier(struct notifier_block *nb); -extern int hci_unregister_notifier(struct notifier_block *nb); -extern int hci_connect(struct hci_dev * hdev, bdaddr_t * bdaddr); -extern int hci_disconnect(struct hci_conn *conn, __u8 reason); -extern int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void * param); -extern int hci_send_raw(struct sk_buff *skb); -extern int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags); -extern int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); +static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) +{ + register struct hci_proto *hp; + int mask = 0; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->connect_ind) + mask |= hp->connect_ind(hdev, bdaddr, type); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->connect_ind) + mask |= hp->connect_ind(hdev, bdaddr, type); + + return mask; +} + +static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status) +{ + register struct hci_proto *hp; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->connect_cfm) + hp->connect_cfm(conn, status); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->connect_cfm) + hp->connect_cfm(conn, status); +} + +static inline void hci_proto_disconn_ind(struct hci_conn *conn, __u8 reason) +{ + register struct hci_proto *hp; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->disconn_ind) + hp->disconn_ind(conn, reason); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->disconn_ind) + hp->disconn_ind(conn, reason); +} + +static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) +{ + register struct hci_proto *hp; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->auth_cfm) + hp->auth_cfm(conn, status); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->auth_cfm) + hp->auth_cfm(conn, status); +} + +static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status) +{ + register struct hci_proto *hp; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->encrypt_cfm) + hp->encrypt_cfm(conn, status); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->encrypt_cfm) + hp->encrypt_cfm(conn, status); +} + +int hci_register_proto(struct hci_proto *hproto); +int hci_unregister_proto(struct hci_proto *hproto); +int hci_register_notifier(struct notifier_block *nb); +int hci_unregister_notifier(struct notifier_block *nb); + +int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param); +int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags); +int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); +int hci_send_raw(struct sk_buff *skb); + +void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf); + +void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); /* ----- HCI Sockets ----- */ -extern void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); +void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); /* HCI info for socket */ -#define hci_pi(sk) ((struct hci_pinfo *) &sk->protinfo) +#define hci_pi(sk) ((struct hci_pinfo *) &sk->tp_pinfo) struct hci_pinfo { struct hci_dev *hdev; struct hci_filter filter; __u32 cmsg_mask; }; +/* HCI security filter */ +#define HCI_SFLT_MAX_OGF 4 + +struct hci_sec_filter { + __u32 type_mask; + __u32 event_mask[2]; + __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4]; +}; + + /* ----- HCI requests ----- */ #define HCI_REQ_DONE 0 #define HCI_REQ_PEND 1 #define HCI_REQ_CANCELED 2 +#define hci_req_lock(d) down(&d->req_lock) +#define hci_req_unlock(d) up(&d->req_lock) + +void hci_req_complete(struct hci_dev *hdev, int result); +void hci_req_cancel(struct hci_dev *hdev, int err); + #endif /* __HCI_CORE_H */ diff -urN linux-2.4.19-pre6/include/net/bluetooth/hci_uart.h linux-2.4.19-pre7/include/net/bluetooth/hci_uart.h --- linux-2.4.19-pre6/include/net/bluetooth/hci_uart.h Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/include/net/bluetooth/hci_uart.h Wed Dec 31 16:00:00 1969 @@ -1,62 +0,0 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * $Id: hci_uart.h,v 1.2 2001/06/02 01:40:08 maxk Exp $ - */ - -#ifndef N_HCI -#define N_HCI 15 -#endif - -#ifdef __KERNEL__ - -#define tty2n_hci(tty) ((struct n_hci *)((tty)->disc_data)) -#define n_hci2tty(n_hci) ((n_hci)->tty) - -struct n_hci { - struct tty_struct *tty; - struct hci_dev hdev; - - struct sk_buff_head txq; - unsigned long tx_state; - - spinlock_t rx_lock; - unsigned long rx_state; - unsigned long rx_count; - struct sk_buff *rx_skb; -}; - -/* Transmit states */ -#define TRANS_SENDING 1 -#define TRANS_WAKEUP 2 - -/* Receiver States */ -#define WAIT_PACKET_TYPE 0 -#define WAIT_EVENT_HDR 1 -#define WAIT_ACL_HDR 2 -#define WAIT_SCO_HDR 3 -#define WAIT_DATA 4 - -#endif /* __KERNEL__ */ diff -urN linux-2.4.19-pre6/include/net/bluetooth/hci_usb.h linux-2.4.19-pre7/include/net/bluetooth/hci_usb.h --- linux-2.4.19-pre6/include/net/bluetooth/hci_usb.h Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/include/net/bluetooth/hci_usb.h Wed Dec 31 16:00:00 1969 @@ -1,68 +0,0 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * $Id: hci_usb.h,v 1.3 2001/06/02 01:40:08 maxk Exp $ - */ - -#ifdef __KERNEL__ - -/* Class, SubClass, and Protocol codes that describe a Bluetooth device */ -#define HCI_DEV_CLASS 0xe0 /* Wireless class */ -#define HCI_DEV_SUBCLASS 0x01 /* RF subclass */ -#define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */ - -#define HCI_CTRL_REQ 0x20 - -struct hci_usb { - struct usb_device *udev; - - devrequest dev_req; - struct urb *ctrl_urb; - struct urb *intr_urb; - struct urb *read_urb; - struct urb *write_urb; - - __u8 *read_buf; - __u8 *intr_buf; - struct sk_buff *intr_skb; - int intr_count; - - __u8 bulk_out_ep_addr; - __u8 bulk_in_ep_addr; - __u8 intr_in_ep_addr; - __u8 intr_in_interval; - - struct hci_dev hdev; - - unsigned long tx_state; - struct sk_buff_head tx_ctrl_q; - struct sk_buff_head tx_write_q; -}; - -/* Transmit states */ -#define HCI_TX_CTRL 1 -#define HCI_TX_WRITE 2 - -#endif /* __KERNEL__ */ diff -urN linux-2.4.19-pre6/include/net/bluetooth/hci_vhci.h linux-2.4.19-pre7/include/net/bluetooth/hci_vhci.h --- linux-2.4.19-pre6/include/net/bluetooth/hci_vhci.h Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/include/net/bluetooth/hci_vhci.h Wed Dec 31 16:00:00 1969 @@ -1,50 +0,0 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * $Id: hci_vhci.h,v 1.2 2001/08/01 01:02:20 maxk Exp $ - */ - -#ifndef __HCI_VHCI_H -#define __HCI_VHCI_H - -#ifdef __KERNEL__ - -struct hci_vhci_struct { - struct hci_dev hdev; - __u32 flags; - wait_queue_head_t read_wait; - struct sk_buff_head readq; - struct fasync_struct *fasync; -}; - -/* VHCI device flags */ -#define VHCI_FASYNC 0x0010 - -#endif /* __KERNEL__ */ - -#define VHCI_DEV "/dev/vhci" -#define VHCI_MINOR 250 - -#endif /* __HCI_VHCI_H */ diff -urN linux-2.4.19-pre6/include/net/bluetooth/l2cap.h linux-2.4.19-pre7/include/net/bluetooth/l2cap.h --- linux-2.4.19-pre6/include/net/bluetooth/l2cap.h Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/include/net/bluetooth/l2cap.h Mon Apr 15 21:54:58 2002 @@ -23,22 +23,17 @@ */ /* - * $Id: l2cap.h,v 1.5 2001/06/14 21:28:26 maxk Exp $ + * $Id: l2cap.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ */ #ifndef __L2CAP_H #define __L2CAP_H -#include -#include - /* L2CAP defaults */ #define L2CAP_DEFAULT_MTU 672 #define L2CAP_DEFAULT_FLUSH_TO 0xFFFF #define L2CAP_CONN_TIMEOUT (HZ * 40) -#define L2CAP_DISCONN_TIMEOUT (HZ * 2) -#define L2CAP_CONN_IDLE_TIMEOUT (HZ * 60) /* L2CAP socket address */ struct sockaddr_l2 { @@ -47,17 +42,12 @@ bdaddr_t l2_bdaddr; }; -/* set/get sockopt defines */ -#define L2CAP_OPTIONS 0x01 +/* Socket options */ +#define L2CAP_OPTIONS 0x01 struct l2cap_options { __u16 omtu; __u16 imtu; __u16 flush_to; - __u32 token_rate; - __u32 bucket_size; - __u32 pick_band; - __u32 latency; - __u32 delay_var; }; #define L2CAP_CONNINFO 0x02 @@ -65,6 +55,26 @@ __u16 hci_handle; }; +#define L2CAP_LM 0x03 +#define L2CAP_LM_MASTER 0x0001 +#define L2CAP_LM_AUTH 0x0002 +#define L2CAP_LM_ENCRYPT 0x0004 +#define L2CAP_LM_TRUSTED 0x0008 + +#define L2CAP_QOS 0x04 +struct l2cap_qos { + __u16 service_type; + __u32 token_rate; + __u32 token_bucket_size; + __u32 peak_bandwidth; + __u32 latency; + __u32 delay_variation; +}; + +#define L2CAP_SERV_NO_TRAFFIC 0x00 +#define L2CAP_SERV_BEST_EFFORT 0x01 +#define L2CAP_SERV_GUARANTEED 0x02 + /* L2CAP command codes */ #define L2CAP_COMMAND_REJ 0x01 #define L2CAP_CONN_REQ 0x02 @@ -79,7 +89,6 @@ #define L2CAP_INFO_RSP 0x0b /* L2CAP structures */ - typedef struct { __u16 len; __u16 cid; @@ -112,11 +121,17 @@ } __attribute__ ((packed)) l2cap_conn_rsp; #define L2CAP_CONN_RSP_SIZE 8 -#define L2CAP_CONN_SUCCESS 0x0000 -#define L2CAP_CONN_PEND 0x0001 -#define L2CAP_CONN_BAD_PSM 0x0002 -#define L2CAP_CONN_SEC_BLOCK 0x0003 -#define L2CAP_CONN_NO_MEM 0x0004 +/* connect result */ +#define L2CAP_CR_SUCCESS 0x0000 +#define L2CAP_CR_PEND 0x0001 +#define L2CAP_CR_BAD_PSM 0x0002 +#define L2CAP_CR_SEC_BLOCK 0x0003 +#define L2CAP_CR_NO_MEM 0x0004 + +/* connect status */ +#define L2CAP_CS_NO_INFO 0x0000 +#define L2CAP_CS_AUTHEN_PEND 0x0001 +#define L2CAP_CS_AUTHOR_PEND 0x0002 typedef struct { __u16 dcid; @@ -147,6 +162,8 @@ #define L2CAP_CONF_FLUSH_TO 0x02 #define L2CAP_CONF_QOS 0x03 +#define L2CAP_CONF_MAX_SIZE 22 + typedef struct { __u16 dcid; __u16 scid; @@ -159,4 +176,70 @@ } __attribute__ ((packed)) l2cap_disconn_rsp; #define L2CAP_DISCONN_RSP_SIZE 4 +typedef struct { + __u16 type; + __u8 data[0]; +} __attribute__ ((packed)) l2cap_info_req; +#define L2CAP_INFO_REQ_SIZE 2 + +typedef struct { + __u16 type; + __u16 result; + __u8 data[0]; +} __attribute__ ((packed)) l2cap_info_rsp; +#define L2CAP_INFO_RSP_SIZE 4 + +/* ----- L2CAP connections ----- */ +struct l2cap_chan_list { + struct sock *head; + rwlock_t lock; + long num; +}; + +struct l2cap_conn { + struct hci_conn *hcon; + + bdaddr_t *dst; + bdaddr_t *src; + + unsigned int mtu; + + spinlock_t lock; + + struct sk_buff *rx_skb; + __u32 rx_len; + __u8 rx_ident; + __u8 tx_ident; + + struct l2cap_chan_list chan_list; +}; + +/* ----- L2CAP channel and socket info ----- */ +#define l2cap_pi(sk) ((struct l2cap_pinfo *) &sk->tp_pinfo) + +struct l2cap_pinfo { + __u16 psm; + __u16 dcid; + __u16 scid; + + __u16 imtu; + __u16 omtu; + __u16 flush_to; + + __u32 link_mode; + + __u8 conf_state; + __u16 conf_mtu; + + __u8 ident; + + struct l2cap_conn *conn; + struct sock *next_c; + struct sock *prev_c; +}; + +#define CONF_REQ_SENT 0x01 +#define CONF_INPUT_DONE 0x02 +#define CONF_OUTPUT_DONE 0x04 + #endif /* __L2CAP_H */ diff -urN linux-2.4.19-pre6/include/net/bluetooth/l2cap_core.h linux-2.4.19-pre7/include/net/bluetooth/l2cap_core.h --- linux-2.4.19-pre6/include/net/bluetooth/l2cap_core.h Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/include/net/bluetooth/l2cap_core.h Wed Dec 31 16:00:00 1969 @@ -1,144 +0,0 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * $Id: l2cap_core.h,v 1.6 2001/08/03 04:19:49 maxk Exp $ - */ - -#ifndef __L2CAP_CORE_H -#define __L2CAP_CORE_H - -#ifdef __KERNEL__ - -/* ----- L2CAP interface ----- */ -struct l2cap_iff { - struct list_head list; - struct hci_dev *hdev; - bdaddr_t *bdaddr; - __u16 mtu; - spinlock_t lock; - struct list_head conn_list; -}; - -static inline void l2cap_iff_lock(struct l2cap_iff *iff) -{ - spin_lock(&iff->lock); -} - -static inline void l2cap_iff_unlock(struct l2cap_iff *iff) -{ - spin_unlock(&iff->lock); -} - -/* ----- L2CAP connections ----- */ -struct l2cap_chan_list { - struct sock *head; - rwlock_t lock; - long num; -}; - -struct l2cap_conn { - struct l2cap_iff *iff; - struct list_head list; - - struct hci_conn *hconn; - - __u16 state; - __u8 out; - bdaddr_t src; - bdaddr_t dst; - - spinlock_t lock; - atomic_t refcnt; - - struct sk_buff *rx_skb; - __u32 rx_len; - __u8 rx_ident; - __u8 tx_ident; - - struct l2cap_chan_list chan_list; - - struct timer_list timer; -}; - -static inline void __l2cap_conn_link(struct l2cap_iff *iff, struct l2cap_conn *c) -{ - list_add(&c->list, &iff->conn_list); -} - -static inline void __l2cap_conn_unlink(struct l2cap_iff *iff, struct l2cap_conn *c) -{ - list_del(&c->list); -} - -/* ----- L2CAP channel and socket info ----- */ -#define l2cap_pi(sk) ((struct l2cap_pinfo *) &sk->protinfo) - -struct l2cap_accept_q { - struct sock *head; - struct sock *tail; -}; - -struct l2cap_pinfo { - bdaddr_t src; - bdaddr_t dst; - __u16 psm; - __u16 dcid; - __u16 scid; - __u32 flags; - - __u16 imtu; - __u16 omtu; - __u16 flush_to; - - __u8 conf_state; - __u16 conf_mtu; - - __u8 ident; - - struct l2cap_conn *conn; - struct sock *next_c; - struct sock *prev_c; - - struct sock *parent; - struct sock *next_q; - struct sock *prev_q; - - struct l2cap_accept_q accept_q; -}; - -#define CONF_REQ_SENT 0x01 -#define CONF_INPUT_DONE 0x02 -#define CONF_OUTPUT_DONE 0x04 - -extern struct bluez_sock_list l2cap_sk_list; -extern struct list_head l2cap_iff_list; -extern rwlock_t l2cap_rt_lock; - -extern void l2cap_register_proc(void); -extern void l2cap_unregister_proc(void); - -#endif /* __KERNEL__ */ - -#endif /* __L2CAP_CORE_H */ diff -urN linux-2.4.19-pre6/include/net/bluetooth/sco.h linux-2.4.19-pre7/include/net/bluetooth/sco.h --- linux-2.4.19-pre6/include/net/bluetooth/sco.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/include/net/bluetooth/sco.h Mon Apr 15 21:54:58 2002 @@ -0,0 +1,81 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * $Id: sco.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ + */ + +#ifndef __SCO_H +#define __SCO_H + +/* SCO defaults */ +#define SCO_DEFAULT_MTU 500 +#define SCO_DEFAULT_FLUSH_TO 0xFFFF + +#define SCO_CONN_TIMEOUT (HZ * 40) +#define SCO_DISCONN_TIMEOUT (HZ * 2) +#define SCO_CONN_IDLE_TIMEOUT (HZ * 60) + +/* SCO socket address */ +struct sockaddr_sco { + sa_family_t sco_family; + bdaddr_t sco_bdaddr; +}; + +/* set/get sockopt defines */ +#define SCO_OPTIONS 0x01 +struct sco_options { + __u16 mtu; +}; + +#define SCO_CONNINFO 0x02 +struct sco_conninfo { + __u16 hci_handle; +}; + +/* ---- SCO connections ---- */ +struct sco_conn { + struct hci_conn *hcon; + + bdaddr_t *dst; + bdaddr_t *src; + + spinlock_t lock; + struct sock *sk; + + unsigned int mtu; +}; + +#define sco_conn_lock(c) spin_lock(&c->lock); +#define sco_conn_unlock(c) spin_unlock(&c->lock); + +/* ----- SCO socket info ----- */ +#define sco_pi(sk) ((struct sco_pinfo *) &sk->tp_pinfo) + +struct sco_pinfo { + __u32 flags; + struct sco_conn *conn; +}; + +#endif /* __SCO_H */ diff -urN linux-2.4.19-pre6/include/net/sock.h linux-2.4.19-pre7/include/net/sock.h --- linux-2.4.19-pre6/include/net/sock.h Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/include/net/sock.h Mon Apr 15 21:54:58 2002 @@ -283,9 +283,9 @@ /* Data for direct copy to user */ struct { struct sk_buff_head prequeue; - int memory; struct task_struct *task; struct iovec *iov; + int memory; int len; } ucopy; diff -urN linux-2.4.19-pre6/include/net/tcp.h linux-2.4.19-pre7/include/net/tcp.h --- linux-2.4.19-pre6/include/net/tcp.h Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/include/net/tcp.h Mon Apr 15 21:54:58 2002 @@ -819,6 +819,11 @@ extern const char timer_bug_msg[]; +/* Read 'sendfile()'-style from a TCP socket */ +typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *, + unsigned int, size_t); +extern int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, + sk_read_actor_t recv_actor); static inline void tcp_clear_xmit_timer(struct sock *sk, int what) { @@ -1327,7 +1332,8 @@ if (tp->ucopy.memory > sk->rcvbuf) { struct sk_buff *skb1; - if (sk->lock.users) BUG(); + if (sk->lock.users) + out_of_line_bug(); while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) { sk->backlog_rcv(sk, skb1); diff -urN linux-2.4.19-pre6/init/do_mounts.c linux-2.4.19-pre7/init/do_mounts.c --- linux-2.4.19-pre6/init/do_mounts.c Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/init/do_mounts.c Mon Apr 15 21:54:58 2002 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -198,6 +199,22 @@ { "cciss/c0d14p",0x68E0 }, { "cciss/c0d15p",0x68F0 }, #endif + { "ataraid/d0p",0x7200 }, + { "ataraid/d1p",0x7210 }, + { "ataraid/d2p",0x7220 }, + { "ataraid/d3p",0x7230 }, + { "ataraid/d4p",0x7240 }, + { "ataraid/d5p",0x7250 }, + { "ataraid/d6p",0x7260 }, + { "ataraid/d7p",0x7270 }, + { "ataraid/d8p",0x7280 }, + { "ataraid/d9p",0x7290 }, + { "ataraid/d10p",0x72A0 }, + { "ataraid/d11p",0x72B0 }, + { "ataraid/d12p",0x72C0 }, + { "ataraid/d13p",0x72D0 }, + { "ataraid/d14p",0x72E0 }, + { "ataraid/d15p",0x72F0 }, { "nftla", 0x5d00 }, { "nftlb", 0x5d10 }, { "nftlc", 0x5d20 }, diff -urN linux-2.4.19-pre6/init/main.c linux-2.4.19-pre7/init/main.c --- linux-2.4.19-pre6/init/main.c Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/init/main.c Mon Apr 15 21:54:58 2002 @@ -293,9 +293,11 @@ #ifndef CONFIG_SMP #ifdef CONFIG_X86_LOCAL_APIC +extern int skip_ioapic_setup; static void __init smp_init(void) { - APIC_init_uniprocessor(); + if (!skip_ioapic_setup) + APIC_init_uniprocessor(); } #else #define smp_init() do { } while (0) diff -urN linux-2.4.19-pre6/kernel/time.c linux-2.4.19-pre7/kernel/time.c --- linux-2.4.19-pre6/kernel/time.c Mon Feb 25 11:38:13 2002 +++ linux-2.4.19-pre7/kernel/time.c Mon Apr 15 21:54:58 2002 @@ -216,6 +216,11 @@ /* Now we validate the data before disabling interrupts */ + if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) + /* singleshot must not be used with any other mode bits */ + if (txc->modes != ADJ_OFFSET_SINGLESHOT) + return -EINVAL; + if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET)) /* adjustment Offset limited to +- .512 seconds */ if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE ) diff -urN linux-2.4.19-pre6/mm/filemap.c linux-2.4.19-pre7/mm/filemap.c --- linux-2.4.19-pre6/mm/filemap.c Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/mm/filemap.c Mon Apr 15 21:54:58 2002 @@ -2957,7 +2957,7 @@ */ err = -EFBIG; - if (limit != RLIM_INFINITY) { + if (!S_ISBLK(inode->i_mode) && limit != RLIM_INFINITY) { if (pos >= limit) { send_sig(SIGXFSZ, current, 0); goto out; diff -urN linux-2.4.19-pre6/mm/mmap.c linux-2.4.19-pre7/mm/mmap.c --- linux-2.4.19-pre6/mm/mmap.c Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/mm/mmap.c Mon Apr 15 21:54:58 2002 @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff -urN linux-2.4.19-pre6/mm/oom_kill.c linux-2.4.19-pre7/mm/oom_kill.c --- linux-2.4.19-pre6/mm/oom_kill.c Sat Nov 3 17:05:25 2001 +++ linux-2.4.19-pre7/mm/oom_kill.c Mon Apr 15 21:54:58 2002 @@ -110,8 +110,7 @@ /* * Simple selection loop. We chose the process with the highest - * number of 'points'. We need the locks to make sure that the - * list of task structs doesn't change while we look the other way. + * number of 'points'. We expect the caller will lock the tasklist. * * (not docbooked, we don't want this one cluttering up the manual) */ @@ -121,7 +120,6 @@ struct task_struct *p = NULL; struct task_struct *chosen = NULL; - read_lock(&tasklist_lock); for_each_task(p) { if (p->pid) { int points = badness(p); @@ -131,7 +129,6 @@ } } } - read_unlock(&tasklist_lock); return chosen; } @@ -170,16 +167,19 @@ */ static void oom_kill(void) { - struct task_struct *p = select_bad_process(), *q; + struct task_struct *p, *q; + + read_lock(&tasklist_lock); + p = select_bad_process(); /* Found nothing?!?! Either we hang forever, or we panic. */ if (p == NULL) panic("Out of memory and no killable processes...\n"); /* kill all processes that share the ->mm (i.e. all threads) */ - read_lock(&tasklist_lock); for_each_task(q) { - if(q->mm == p->mm) oom_kill_task(q); + if (q->mm == p->mm) + oom_kill_task(q); } read_unlock(&tasklist_lock); @@ -198,7 +198,7 @@ */ void out_of_memory(void) { - static unsigned long first, last, count; + static unsigned long first, last, count, lastkill; unsigned long now, since; /* @@ -235,8 +235,18 @@ return; /* + * If we just killed a process, wait a while + * to give that task a chance to exit. This + * avoids killing multiple processes needlessly. + */ + since = now - lastkill; + if (since < HZ*5) + return; + + /* * Ok, really out of memory. Kill something. */ + lastkill = now; oom_kill(); reset: diff -urN linux-2.4.19-pre6/mm/slab.c linux-2.4.19-pre7/mm/slab.c --- linux-2.4.19-pre6/mm/slab.c Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/mm/slab.c Mon Apr 15 21:54:58 2002 @@ -909,14 +909,13 @@ #define drain_cpu_caches(cachep) do { } while (0) #endif -static int __kmem_cache_shrink(kmem_cache_t *cachep) +/* + * Called with the &cachep->spinlock held, returns number of slabs released + */ +static int __kmem_cache_shrink_locked(kmem_cache_t *cachep) { slab_t *slabp; - int ret; - - drain_cpu_caches(cachep); - - spin_lock_irq(&cachep->spinlock); + int ret = 0; /* If the cache is growing, stop shrinking. */ while (!cachep->growing) { @@ -935,9 +934,22 @@ spin_unlock_irq(&cachep->spinlock); kmem_slab_destroy(cachep, slabp); + ret++; spin_lock_irq(&cachep->spinlock); } - ret = !list_empty(&cachep->slabs_full) || !list_empty(&cachep->slabs_partial); + return ret; +} + +static int __kmem_cache_shrink(kmem_cache_t *cachep) +{ + int ret; + + drain_cpu_caches(cachep); + + spin_lock_irq(&cachep->spinlock); + __kmem_cache_shrink_locked(cachep); + ret = !list_empty(&cachep->slabs_full) || + !list_empty(&cachep->slabs_partial); spin_unlock_irq(&cachep->spinlock); return ret; } @@ -947,14 +959,22 @@ * @cachep: The cache to shrink. * * Releases as many slabs as possible for a cache. - * To help debugging, a zero exit status indicates all slabs were released. + * Returns number of pages released. */ int kmem_cache_shrink(kmem_cache_t *cachep) { + int ret; + if (!cachep || in_interrupt() || !is_chained_kmem_cache(cachep)) BUG(); - return __kmem_cache_shrink(cachep); + drain_cpu_caches(cachep); + + spin_lock_irq(&cachep->spinlock); + ret = __kmem_cache_shrink_locked(cachep); + spin_unlock_irq(&cachep->spinlock); + + return ret << cachep->gfporder; } /** diff -urN linux-2.4.19-pre6/net/Config.in linux-2.4.19-pre7/net/Config.in --- linux-2.4.19-pre6/net/Config.in Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/net/Config.in Mon Apr 15 21:54:59 2002 @@ -52,7 +52,10 @@ if [ "$CONFIG_IPX" != "n" ]; then source net/ipx/Config.in fi + tristate 'Appletalk protocol support' CONFIG_ATALK +source drivers/net/appletalk/Config.in + tristate 'DECnet Support' CONFIG_DECNET if [ "$CONFIG_DECNET" != "n" ]; then source net/decnet/Config.in diff -urN linux-2.4.19-pre6/net/bluetooth/Config.in linux-2.4.19-pre7/net/bluetooth/Config.in --- linux-2.4.19-pre6/net/bluetooth/Config.in Mon Jun 11 19:15:27 2001 +++ linux-2.4.19-pre7/net/bluetooth/Config.in Mon Apr 15 21:54:59 2002 @@ -9,6 +9,7 @@ if [ "$CONFIG_BLUEZ" != "n" ]; then dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ + dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ source drivers/bluetooth/Config.in fi endmenu diff -urN linux-2.4.19-pre6/net/bluetooth/Makefile linux-2.4.19-pre7/net/bluetooth/Makefile --- linux-2.4.19-pre6/net/bluetooth/Makefile Mon Jun 11 19:15:27 2001 +++ linux-2.4.19-pre7/net/bluetooth/Makefile Mon Apr 15 21:54:59 2002 @@ -3,18 +3,15 @@ # O_TARGET := bluetooth.o -list-multi := hci.o l2cap.o +list-multi := bluez.o export-objs := syms.o -hci-objs := af_bluetooth.o hci_core.o hci_sock.o lib.o syms.o -l2cap-objs := l2cap_core.o l2cap_proc.o +bluez-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o -obj-$(CONFIG_BLUEZ) += hci.o +obj-$(CONFIG_BLUEZ) += bluez.o obj-$(CONFIG_BLUEZ_L2CAP) += l2cap.o +obj-$(CONFIG_BLUEZ_SCO) += sco.o include $(TOPDIR)/Rules.make -hci.o: $(hci-objs) - $(LD) -r -o $@ $(hci-objs) - -l2cap.o: $(l2cap-objs) - $(LD) -r -o $@ $(l2cap-objs) +bluez.o: $(bluez-objs) + $(LD) -r -o $@ $(bluez-objs) diff -urN linux-2.4.19-pre6/net/bluetooth/af_bluetooth.c linux-2.4.19-pre7/net/bluetooth/af_bluetooth.c --- linux-2.4.19-pre6/net/bluetooth/af_bluetooth.c Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/net/bluetooth/af_bluetooth.c Mon Apr 15 21:54:59 2002 @@ -25,14 +25,15 @@ /* * BlueZ Bluetooth address family and sockets. * - * $Id: af_bluetooth.c,v 1.4 2001/07/05 18:42:44 maxk Exp $ + * $Id: af_bluetooth.c,v 1.2 2002/03/18 19:16:40 maxk Exp $ */ -#define VERSION "1.1" +#define VERSION "2.0" #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include #include #include @@ -48,32 +50,37 @@ #endif #include -#include + +#ifndef AF_BLUETOOTH_DEBUG +#undef DBG +#define DBG( A... ) +#endif /* Bluetooth sockets */ -static struct net_proto_family *bluez_sock[BLUEZ_MAX_PROTO]; +#define BLUEZ_MAX_PROTO 4 +static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO]; int bluez_sock_register(int proto, struct net_proto_family *ops) { - if (proto > BLUEZ_MAX_PROTO) + if (proto >= BLUEZ_MAX_PROTO) return -EINVAL; - if (bluez_sock[proto]) + if (bluez_proto[proto]) return -EEXIST; - bluez_sock[proto] = ops; + bluez_proto[proto] = ops; return 0; } int bluez_sock_unregister(int proto) { - if (proto > BLUEZ_MAX_PROTO) + if (proto >= BLUEZ_MAX_PROTO) return -EINVAL; - if (!bluez_sock[proto]) + if (!bluez_proto[proto]) return -ENOENT; - bluez_sock[proto] = NULL; + bluez_proto[proto] = NULL; return 0; } @@ -83,27 +90,31 @@ return -EINVAL; #if defined(CONFIG_KMOD) - if (!bluez_sock[proto]) { + if (!bluez_proto[proto]) { char module_name[30]; sprintf(module_name, "bt-proto-%d", proto); request_module(module_name); } #endif - if (!bluez_sock[proto]) + if (!bluez_proto[proto]) return -ENOENT; - return bluez_sock[proto]->create(sock, proto); + return bluez_proto[proto]->create(sock, proto); +} + +void bluez_sock_init(struct socket *sock, struct sock *sk) +{ + sock_init_data(sock, sk); + INIT_LIST_HEAD(&bluez_pi(sk)->accept_q); } void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk) { write_lock(&l->lock); - sk->next = l->head; l->head = sk; sock_hold(sk); - write_unlock(&l->lock); } @@ -122,6 +133,162 @@ write_unlock(&l->lock); } +void bluez_accept_enqueue(struct sock *parent, struct sock *sk) +{ + DBG("parent %p, sk %p", parent, sk); + + sock_hold(sk); + list_add_tail(&bluez_pi(sk)->accept_q, &bluez_pi(parent)->accept_q); + bluez_pi(sk)->parent = parent; + parent->ack_backlog++; +} + +static void bluez_accept_unlink(struct sock *sk) +{ + DBG("sk %p state %d", sk, sk->state); + + list_del_init(&bluez_pi(sk)->accept_q); + bluez_pi(sk)->parent->ack_backlog--; + bluez_pi(sk)->parent = NULL; + sock_put(sk); +} + +struct sock *bluez_accept_dequeue(struct sock *parent, struct socket *newsock) +{ + struct list_head *p, *n; + struct bluez_pinfo *pi; + struct sock *sk; + + DBG("parent %p", parent); + + list_for_each_safe(p, n, &bluez_pi(parent)->accept_q) { + pi = list_entry(p, struct bluez_pinfo, accept_q); + sk = bluez_sk(pi); + + lock_sock(sk); + if (sk->state == BT_CLOSED) { + release_sock(sk); + bluez_accept_unlink(sk); + continue; + } + + if (sk->state == BT_CONNECTED || !newsock) { + bluez_accept_unlink(sk); + if (newsock) + sock_graft(sk, newsock); + release_sock(sk); + return sk; + } + release_sock(sk); + } + return NULL; +} + +int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm) +{ + int noblock = flags & MSG_DONTWAIT; + struct sock *sk = sock->sk; + struct sk_buff *skb; + int copied, err; + + DBG("sock %p sk %p len %d", sock, sk, len); + + if (flags & (MSG_OOB)) + return -EOPNOTSUPP; + + if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) { + if (sk->shutdown & RCV_SHUTDOWN) + return 0; + return err; + } + + msg->msg_namelen = 0; + + copied = skb->len; + if (len < copied) { + msg->msg_flags |= MSG_TRUNC; + copied = len; + } + + skb->h.raw = skb->data; + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + + skb_free_datagram(sk, skb); + + return err ? : copied; +} + +unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait) +{ + struct sock *sk = sock->sk; + unsigned int mask; + + DBG("sock %p, sk %p", sock, sk); + + poll_wait(file, sk->sleep, wait); + mask = 0; + + if (sk->err || !skb_queue_empty(&sk->error_queue)) + mask |= POLLERR; + + if (sk->shutdown == SHUTDOWN_MASK) + mask |= POLLHUP; + + if (!skb_queue_empty(&sk->receive_queue) || + !list_empty(&bluez_pi(sk)->accept_q) || + (sk->shutdown & RCV_SHUTDOWN)) + mask |= POLLIN | POLLRDNORM; + + if (sk->state == BT_CLOSED) + mask |= POLLHUP; + + if (sock_writeable(sk)) + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + else + set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + + return mask; +} + +int bluez_sock_w4_connect(struct sock *sk, int flags) +{ + DECLARE_WAITQUEUE(wait, current); + long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); + int err = 0; + + DBG("sk %p", sk); + + add_wait_queue(sk->sleep, &wait); + while (sk->state != BT_CONNECTED) { + set_current_state(TASK_INTERRUPTIBLE); + if (!timeo) { + err = -EAGAIN; + break; + } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); + + err = 0; + if (sk->state == BT_CONNECTED) + break; + + if (sk->err) { + err = sock_error(sk); + break; + } + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + break; + } + } + set_current_state(TASK_RUNNING); + remove_wait_queue(sk->sleep, &wait); + return err; +} + struct net_proto_family bluez_sock_family_ops = { PF_BLUETOOTH, bluez_sock_create @@ -129,7 +296,7 @@ int bluez_init(void) { - INF("BlueZ HCI Core ver %s Copyright (C) 2000,2001 Qualcomm Inc", + INF("BlueZ Core ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); INF("Written 2000,2001 by Maxim Krasnyansky "); @@ -164,5 +331,6 @@ module_exit(bluez_cleanup); MODULE_AUTHOR("Maxim Krasnyansky "); -MODULE_DESCRIPTION("BlueZ HCI Core ver " VERSION); +MODULE_DESCRIPTION("BlueZ Core ver " VERSION); +MODULE_LICENSE("GPL"); #endif diff -urN linux-2.4.19-pre6/net/bluetooth/hci_conn.c linux-2.4.19-pre7/net/bluetooth/hci_conn.c --- linux-2.4.19-pre6/net/bluetooth/hci_conn.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/net/bluetooth/hci_conn.c Mon Apr 15 21:54:59 2002 @@ -0,0 +1,437 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * HCI Connection handling. + * + * $Id: hci_conn.c,v 1.1 2002/03/08 21:06:59 maxk Exp $ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#ifndef HCI_CORE_DEBUG +#undef DBG +#define DBG( A... ) +#endif + +void hci_acl_connect(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + struct inquiry_entry *ie; + create_conn_cp cp; + + DBG("%p", conn); + + conn->state = BT_CONNECT; + conn->out = 1; + conn->link_mode = HCI_LM_MASTER; + + memset(&cp, 0, sizeof(cp)); + bacpy(&cp.bdaddr, &conn->dst); + + if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) && + inquiry_entry_age(ie) > INQUIRY_ENTRY_AGE_MAX) { + cp.pscan_rep_mode = ie->info.pscan_rep_mode; + cp.pscan_mode = ie->info.pscan_mode; + cp.clock_offset = ie->info.clock_offset | __cpu_to_le16(0x8000); + } + + cp.pkt_type = __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK); + if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)) + cp.role_switch = 0x01; + else + cp.role_switch = 0x00; + + hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, + CREATE_CONN_CP_SIZE, &cp); +} + +void hci_acl_disconn(struct hci_conn *conn, __u8 reason) +{ + disconnect_cp cp; + + DBG("%p", conn); + + conn->state = BT_DISCONN; + + cp.handle = __cpu_to_le16(conn->handle); + cp.reason = reason; + hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, + DISCONNECT_CP_SIZE, &cp); +} + +void hci_add_sco(struct hci_conn *conn, __u16 handle) +{ + struct hci_dev *hdev = conn->hdev; + add_sco_cp cp; + + DBG("%p", conn); + + conn->state = BT_CONNECT; + conn->out = 1; + + cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); + cp.handle = __cpu_to_le16(handle); + + hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, ADD_SCO_CP_SIZE, &cp); +} + +static void hci_conn_timeout(unsigned long arg) +{ + struct hci_conn *conn = (void *)arg; + struct hci_dev *hdev = conn->hdev; + + DBG("conn %p state %d", conn, conn->state); + + if (atomic_read(&conn->refcnt)) + return; + + hci_dev_lock(hdev); + if (conn->state == BT_CONNECTED) + hci_acl_disconn(conn, 0x13); + else + conn->state = BT_CLOSED; + hci_dev_unlock(hdev); + return; +} + +static void hci_conn_init_timer(struct hci_conn *conn) +{ + init_timer(&conn->timer); + conn->timer.function = hci_conn_timeout; + conn->timer.data = (unsigned long)conn; +} + +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) +{ + struct hci_conn *conn; + + DBG("%s dst %s", hdev->name, batostr(dst)); + + if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC))) + return NULL; + memset(conn, 0, sizeof(struct hci_conn)); + + bacpy(&conn->dst, dst); + conn->type = type; + conn->hdev = hdev; + conn->state = BT_OPEN; + + skb_queue_head_init(&conn->data_q); + hci_conn_init_timer(conn); + + atomic_set(&conn->refcnt, 0); + + hci_dev_hold(hdev); + + tasklet_disable(&hdev->tx_task); + conn_hash_add(hdev, conn); + tasklet_enable(&hdev->tx_task); + + return conn; +} + +int hci_conn_del(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + + DBG("%s conn %p handle %d", hdev->name, conn, conn->handle); + + hci_conn_del_timer(conn); + + if (conn->type == SCO_LINK) { + struct hci_conn *acl = conn->link; + if (acl) { + acl->link = NULL; + hci_conn_put(acl); + } + + /* Unacked frames */ + hdev->sco_cnt += conn->sent; + } else { + struct hci_conn *sco = conn->link; + if (sco) + sco->link = NULL; + + /* Unacked frames */ + hdev->acl_cnt += conn->sent; + } + + tasklet_disable(&hdev->tx_task); + conn_hash_del(hdev, conn); + tasklet_enable(&hdev->tx_task); + + skb_queue_purge(&conn->data_q); + + hci_dev_put(hdev); + + kfree(conn); + return 0; +} + +struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) +{ + int use_src = bacmp(src, BDADDR_ANY); + struct hci_dev *hdev = NULL; + struct list_head *p; + + DBG("%s -> %s", batostr(src), batostr(dst)); + + spin_lock_bh(&hdev_list_lock); + + list_for_each(p, &hdev_list) { + struct hci_dev *d; + d = list_entry(p, struct hci_dev, list); + + if (!test_bit(HCI_UP, &d->flags)) + continue; + + /* Simple routing: + * No source address - find interface with bdaddr != dst + * Source address - find interface with bdaddr == src + */ + + if (use_src) { + if (!bacmp(&d->bdaddr, src)) { + hdev = d; break; + } + } else { + if (bacmp(&d->bdaddr, dst)) { + hdev = d; break; + } + } + } + + if (hdev) + hci_dev_hold(hdev); + + spin_unlock_bh(&hdev_list_lock); + return hdev; +} + +/* Create SCO or ACL connection. + * Device _must_ be locked */ +struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst) +{ + struct hci_conn *acl; + + DBG("%s dst %s", hdev->name, batostr(dst)); + + if (!(acl = conn_hash_lookup_ba(hdev, ACL_LINK, dst))) { + if (!(acl = hci_conn_add(hdev, ACL_LINK, dst))) + return NULL; + } + + hci_conn_hold(acl); + + if (acl->state == BT_OPEN || acl->state == BT_CLOSED) + hci_acl_connect(acl); + + if (type == SCO_LINK) { + struct hci_conn *sco; + + if (!(sco = conn_hash_lookup_ba(hdev, SCO_LINK, dst))) { + if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) { + hci_conn_put(acl); + return NULL; + } + } + acl->link = sco; + sco->link = acl; + + hci_conn_hold(sco); + + if (acl->state == BT_CONNECTED && + (sco->state == BT_OPEN || sco->state == BT_CLOSED)) + hci_add_sco(sco, acl->handle); + + return sco; + } else { + return acl; + } +} + +/* Authenticate remote device */ +int hci_conn_auth(struct hci_conn *conn) +{ + DBG("conn %p", conn); + + if (conn->link_mode & HCI_LM_AUTH) + return 1; + + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + auth_requested_cp ar; + ar.handle = __cpu_to_le16(conn->handle); + hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED, + AUTH_REQUESTED_CP_SIZE, &ar); + } + return 0; +} + +/* Enable encryption */ +int hci_conn_encrypt(struct hci_conn *conn) +{ + DBG("conn %p", conn); + + if (conn->link_mode & HCI_LM_ENCRYPT) + return 1; + + if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + return 0; + + if (hci_conn_auth(conn)) { + set_conn_encrypt_cp ce; + ce.handle = __cpu_to_le16(conn->handle); + ce.encrypt = 1; + hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT, + SET_CONN_ENCRYPT_CP_SIZE, &ce); + } + return 0; +} + +/* Drop all connection on the device */ +void hci_conn_hash_flush(struct hci_dev *hdev) +{ + struct conn_hash *h = &hdev->conn_hash; + struct list_head *p; + + DBG("hdev %s", hdev->name); + + p = h->list.next; + while (p != &h->list) { + struct hci_conn *c; + + c = list_entry(p, struct hci_conn, list); + p = p->next; + + c->state = BT_CLOSED; + + hci_proto_disconn_ind(c, 0x16); + hci_conn_del(c); + } +} + +int hci_get_conn_list(unsigned long arg) +{ + struct hci_conn_list_req req, *cl; + struct hci_conn_info *ci; + struct hci_dev *hdev; + struct list_head *p; + int n = 0, size; + + if (copy_from_user(&req, (void *) arg, sizeof(req))) + return -EFAULT; + + if (!(hdev = hci_dev_get(req.dev_id))) + return -ENODEV; + + size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req); + + if (verify_area(VERIFY_WRITE, (void *)arg, size)) + return -EFAULT; + + if (!(cl = (void *) kmalloc(size, GFP_KERNEL))) + return -ENOMEM; + ci = cl->conn_info; + + hci_dev_lock_bh(hdev); + list_for_each(p, &hdev->conn_hash.list) { + register struct hci_conn *c; + c = list_entry(p, struct hci_conn, list); + + bacpy(&(ci + n)->bdaddr, &c->dst); + (ci + n)->handle = c->handle; + (ci + n)->type = c->type; + (ci + n)->out = c->out; + (ci + n)->state = c->state; + (ci + n)->link_mode = c->link_mode; + n++; + } + hci_dev_unlock_bh(hdev); + + cl->dev_id = hdev->id; + cl->conn_num = n; + size = n * sizeof(struct hci_conn_info) + sizeof(req); + + hci_dev_put(hdev); + + copy_to_user((void *) arg, cl, size); + kfree(cl); + + return 0; +} + +int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg) +{ + struct hci_conn_info_req req; + struct hci_conn_info ci; + struct hci_conn *conn; + char *ptr = (void *) arg + sizeof(req); + + if (copy_from_user(&req, (void *) arg, sizeof(req))) + return -EFAULT; + + if (verify_area(VERIFY_WRITE, ptr, sizeof(ci))) + return -EFAULT; + + hci_dev_lock_bh(hdev); + conn = conn_hash_lookup_ba(hdev, req.type, &req.bdaddr); + if (conn) { + bacpy(&ci.bdaddr, &conn->dst); + ci.handle = conn->handle; + ci.type = conn->type; + ci.out = conn->out; + ci.state = conn->state; + ci.link_mode = conn->link_mode; + } + hci_dev_unlock_bh(hdev); + + if (!conn) + return -ENOENT; + + copy_to_user(ptr, &ci, sizeof(ci)); + return 0; +} diff -urN linux-2.4.19-pre6/net/bluetooth/hci_core.c linux-2.4.19-pre7/net/bluetooth/hci_core.c --- linux-2.4.19-pre6/net/bluetooth/hci_core.c Fri Nov 9 14:21:21 2001 +++ linux-2.4.19-pre7/net/bluetooth/hci_core.c Mon Apr 15 21:55:00 2002 @@ -25,7 +25,7 @@ /* * BlueZ HCI Core. * - * $Id: hci_core.c,v 1.22 2001/08/03 04:19:50 maxk Exp $ + * $Id: hci_core.c,v 1.5 2002/03/26 17:56:44 maxk Exp $ */ #include @@ -50,7 +50,6 @@ #include #include -#include #include #ifndef HCI_CORE_DEBUG @@ -63,277 +62,41 @@ static void hci_tx_task(unsigned long arg); static void hci_notify(struct hci_dev *hdev, int event); -static rwlock_t hci_task_lock = RW_LOCK_UNLOCKED; +rwlock_t hci_task_lock = RW_LOCK_UNLOCKED; /* HCI device list */ -struct hci_dev *hdev_list[HCI_MAX_DEV]; +LIST_HEAD(hdev_list); spinlock_t hdev_list_lock; -#define GET_HDEV(a) (hdev_list[a]) -/* HCI protocol list */ -struct hci_proto *hproto_list[HCI_MAX_PROTO]; -#define GET_HPROTO(a) (hproto_list[a]) +/* HCI protocols */ +#define HCI_MAX_PROTO 2 +struct hci_proto *hci_proto[HCI_MAX_PROTO]; /* HCI notifiers list */ -struct notifier_block *hci_dev_notifier; +static struct notifier_block *hci_notifier; -/* HCI device notifications */ -int hci_register_notifier(struct notifier_block *nb) -{ - int err, i; - struct hci_dev *hdev; - - if ((err = notifier_chain_register(&hci_dev_notifier, nb))) - return err; - - /* Notify about already registered devices */ - spin_lock(&hdev_list_lock); - for (i = 0; i < HCI_MAX_DEV; i++) { - if (!(hdev = GET_HDEV(i))) - continue; - if (hdev->flags & HCI_UP) - (*nb->notifier_call)(nb, HCI_DEV_UP, hdev); - } - spin_unlock(&hdev_list_lock); - - return 0; -} - -int hci_unregister_notifier(struct notifier_block *nb) -{ - return notifier_chain_unregister(&hci_dev_notifier, nb); -} - -static inline void hci_notify(struct hci_dev *hdev, int event) -{ - notifier_call_chain(&hci_dev_notifier, event, hdev); -} - -/* Get HCI device by index (device is locked on return)*/ -struct hci_dev *hci_dev_get(int index) -{ - struct hci_dev *hdev; - DBG("%d", index); - - if (index < 0 || index >= HCI_MAX_DEV) - return NULL; - - spin_lock(&hdev_list_lock); - if ((hdev = GET_HDEV(index))) - hci_dev_hold(hdev); - spin_unlock(&hdev_list_lock); - - return hdev; -} - -/* Flush inquiry cache */ -void inquiry_cache_flush(struct inquiry_cache *cache) -{ - struct inquiry_entry *next = cache->list, *e; - - DBG("cache %p", cache); - - cache->list = NULL; - while ((e = next)) { - next = e->next; - kfree(e); - } -} - -/* Lookup by bdaddr. - * Cache must be locked. */ -static struct inquiry_entry * __inquiry_cache_lookup(struct inquiry_cache *cache, bdaddr_t *bdaddr) -{ - struct inquiry_entry *e; - - DBG("cache %p, %s", cache, batostr(bdaddr)); - - for (e = cache->list; e; e = e->next) - if (!bacmp(&e->info.bdaddr, bdaddr)) - break; - - return e; -} - -static void inquiry_cache_update(struct inquiry_cache *cache, inquiry_info *info) -{ - struct inquiry_entry *e; - - DBG("cache %p, %s", cache, batostr(&info->bdaddr)); - - inquiry_cache_lock(cache); - - if (!(e = __inquiry_cache_lookup(cache, &info->bdaddr))) { - /* Entry not in the cache. Add new one. */ - if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC))) - goto unlock; - memset(e, 0, sizeof(struct inquiry_entry)); - e->next = cache->list; - cache->list = e; - } - - memcpy(&e->info, info, sizeof(inquiry_info)); - e->timestamp = jiffies; - cache->timestamp = jiffies; -unlock: - inquiry_cache_unlock(cache); -} - -static int inquiry_cache_dump(struct inquiry_cache *cache, int num, __u8 *buf) -{ - inquiry_info *info = (inquiry_info *) buf; - struct inquiry_entry *e; - int copied = 0; - - inquiry_cache_lock(cache); - - for (e = cache->list; e && copied < num; e = e->next, copied++) - memcpy(info++, &e->info, sizeof(inquiry_info)); - - inquiry_cache_unlock(cache); - - DBG("cache %p, copied %d", cache, copied); - return copied; -} - -/* --------- BaseBand connections --------- */ -static struct hci_conn *hci_conn_add(struct hci_dev *hdev, __u16 handle, __u8 type, bdaddr_t *dst) -{ - struct hci_conn *conn; - - DBG("%s handle %d dst %s", hdev->name, handle, batostr(dst)); - - if ( conn_hash_lookup(&hdev->conn_hash, handle)) { - ERR("%s handle 0x%x already exists", hdev->name, handle); - return NULL; - } - - if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC))) - return NULL; - memset(conn, 0, sizeof(struct hci_conn)); - bacpy(&conn->dst, dst); - conn->handle = handle; - conn->type = type; - conn->hdev = hdev; +/* ---- HCI notifications ---- */ - skb_queue_head_init(&conn->data_q); - - hci_dev_hold(hdev); - conn_hash_add(&hdev->conn_hash, handle, conn); - - return conn; -} - -static int hci_conn_del(struct hci_dev *hdev, struct hci_conn *conn) -{ - DBG("%s conn %p handle %d", hdev->name, conn, conn->handle); - - conn_hash_del(&hdev->conn_hash, conn); - hci_dev_put(hdev); - - /* Unacked frames */ - hdev->acl_cnt += conn->sent; - - skb_queue_purge(&conn->data_q); - - kfree(conn); - return 0; -} - -/* Drop all connection on the device */ -static void hci_conn_hash_flush(struct hci_dev *hdev) +int hci_register_notifier(struct notifier_block *nb) { - struct conn_hash *h = &hdev->conn_hash; - struct hci_proto *hp; - struct list_head *p; - - DBG("hdev %s", hdev->name); - - p = h->list.next; - while (p != &h->list) { - struct hci_conn *c; - - c = list_entry(p, struct hci_conn, list); - p = p->next; - - if (c->type == ACL_LINK) { - /* ACL link notify L2CAP layer */ - if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind) - hp->disconn_ind(c, 0x16); - } else { - /* SCO link (no notification) */ - } - - hci_conn_del(hdev, c); - } + return notifier_chain_register(&hci_notifier, nb); } -int hci_connect(struct hci_dev *hdev, bdaddr_t *bdaddr) +int hci_unregister_notifier(struct notifier_block *nb) { - struct inquiry_cache *cache = &hdev->inq_cache; - struct inquiry_entry *e; - create_conn_cp cc; - __u16 clock_offset; - - DBG("%s bdaddr %s", hdev->name, batostr(bdaddr)); - - if (!(hdev->flags & HCI_UP)) - return -ENODEV; - - inquiry_cache_lock_bh(cache); - - if (!(e = __inquiry_cache_lookup(cache, bdaddr)) || inquiry_entry_age(e) > INQUIRY_ENTRY_AGE_MAX) { - cc.pscan_rep_mode = 0; - cc.pscan_mode = 0; - clock_offset = 0; - } else { - cc.pscan_rep_mode = e->info.pscan_rep_mode; - cc.pscan_mode = e->info.pscan_mode; - clock_offset = __le16_to_cpu(e->info.clock_offset) & 0x8000; - } - - inquiry_cache_unlock_bh(cache); - - bacpy(&cc.bdaddr, bdaddr); - cc.pkt_type = __cpu_to_le16(hdev->pkt_type); - cc.clock_offset = __cpu_to_le16(clock_offset); - - if (lmp_rswitch_capable(hdev)) - cc.role_switch = 0x01; - else - cc.role_switch = 0x00; - - hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, CREATE_CONN_CP_SIZE, &cc); - - return 0; + return notifier_chain_unregister(&hci_notifier, nb); } -int hci_disconnect(struct hci_conn *conn, __u8 reason) +void hci_notify(struct hci_dev *hdev, int event) { - disconnect_cp dc; - - DBG("conn %p handle %d", conn, conn->handle); - - dc.handle = __cpu_to_le16(conn->handle); - dc.reason = reason; - hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, DISCONNECT_CP_SIZE, &dc); - - return 0; + notifier_call_chain(&hci_notifier, event, hdev); } -/* --------- HCI request handling ------------ */ -static inline void hci_req_lock(struct hci_dev *hdev) -{ - down(&hdev->req_lock); -} -static inline void hci_req_unlock(struct hci_dev *hdev) -{ - up(&hdev->req_lock); -} +/* ---- HCI requests ---- */ -static inline void hci_req_complete(struct hci_dev *hdev, int result) +void hci_req_complete(struct hci_dev *hdev, int result) { DBG("%s result 0x%2.2x", hdev->name, result); @@ -344,7 +107,7 @@ } } -static inline void hci_req_cancel(struct hci_dev *hdev, int err) +void hci_req_cancel(struct hci_dev *hdev, int err) { DBG("%s err 0x%2.2x", hdev->name, err); @@ -356,8 +119,7 @@ } /* Execute request and wait for completion. */ -static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), - unsigned long opt, __u32 timeout) +static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), unsigned long opt, __u32 timeout) { DECLARE_WAITQUEUE(wait, current); int err = 0; @@ -367,12 +129,12 @@ hdev->req_status = HCI_REQ_PEND; add_wait_queue(&hdev->req_wait_q, &wait); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); req(hdev, opt); schedule_timeout(timeout); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&hdev->req_wait_q, &wait); if (signal_pending(current)) @@ -412,7 +174,6 @@ return ret; } -/* --------- HCI requests ---------- */ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt) { DBG("%s %ld", hdev->name, opt); @@ -423,7 +184,7 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) { - set_event_flt_cp ec; + set_event_flt_cp ef; __u16 param; DBG("%s %ld", hdev->name, opt); @@ -436,14 +197,27 @@ /* Read Buffer Size (ACL mtu, max pkt, etc.) */ hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL); +#if 0 + /* Host buffer size */ + { + host_buffer_size_cp bs; + bs.acl_mtu = __cpu_to_le16(HCI_MAX_ACL_SIZE); + bs.sco_mtu = HCI_MAX_SCO_SIZE; + bs.acl_max_pkt = __cpu_to_le16(0xffff); + bs.sco_max_pkt = __cpu_to_le16(0xffff); + hci_send_cmd(hdev, OGF_HOST_CTL, OCF_HOST_BUFFER_SIZE, + HOST_BUFFER_SIZE_CP_SIZE, &bs); + } +#endif + /* Read BD Address */ hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL); /* Optional initialization */ /* Clear Event Filters */ - ec.flt_type = FLT_CLEAR_ALL; - hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ec); + ef.flt_type = FLT_CLEAR_ALL; + hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ef); /* Page timeout ~20 secs */ param = __cpu_to_le16(0x8000); @@ -474,110 +248,263 @@ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE, 1, &auth); } -static void hci_inq_req(struct hci_dev *hdev, unsigned long opt) +static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt) { - struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt; - inquiry_cp ic; + __u8 encrypt = opt; - DBG("%s", hdev->name); + DBG("%s %x", hdev->name, encrypt); - /* Start Inquiry */ - memcpy(&ic.lap, &ir->lap, 3); - ic.lenght = ir->length; - ic.num_rsp = ir->num_rsp; - hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic); + /* Authentication */ + hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE, 1, &encrypt); } -/* HCI ioctl helpers */ -int hci_dev_open(__u16 dev) +/* Get HCI device by index. + * Device is locked on return. */ +struct hci_dev *hci_dev_get(int index) { struct hci_dev *hdev; - int ret = 0; - - if (!(hdev = hci_dev_get(dev))) - return -ENODEV; + struct list_head *p; - DBG("%s %p", hdev->name, hdev); + DBG("%d", index); - hci_req_lock(hdev); + if (index < 0) + return NULL; - if (hdev->flags & HCI_UP) { - ret = -EALREADY; - goto done; + spin_lock(&hdev_list_lock); + list_for_each(p, &hdev_list) { + hdev = list_entry(p, struct hci_dev, list); + if (hdev->id == index) { + hci_dev_hold(hdev); + goto done; + } } + hdev = NULL; +done: + spin_unlock(&hdev_list_lock); + return hdev; +} - if (hdev->open(hdev)) { - ret = -EIO; - goto done; - } +/* ---- Inquiry support ---- */ +void inquiry_cache_flush(struct hci_dev *hdev) +{ + struct inquiry_cache *cache = &hdev->inq_cache; + struct inquiry_entry *next = cache->list, *e; - if (hdev->flags & HCI_NORMAL) { - atomic_set(&hdev->cmd_cnt, 1); - hdev->flags |= HCI_INIT; + DBG("cache %p", cache); - //__hci_request(hdev, hci_reset_req, 0, HZ); - ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT); - - hdev->flags &= ~HCI_INIT; + cache->list = NULL; + while ((e = next)) { + next = e->next; + kfree(e); } +} - if (!ret) { - hdev->flags |= HCI_UP; - hci_notify(hdev, HCI_DEV_UP); - } else { - /* Init failed, cleanup */ - tasklet_kill(&hdev->rx_task); - tasklet_kill(&hdev->tx_task); - tasklet_kill(&hdev->cmd_task); +struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) +{ + struct inquiry_cache *cache = &hdev->inq_cache; + struct inquiry_entry *e; - skb_queue_purge(&hdev->cmd_q); - skb_queue_purge(&hdev->rx_q); + DBG("cache %p, %s", cache, batostr(bdaddr)); - if (hdev->flush) - hdev->flush(hdev); + for (e = cache->list; e; e = e->next) + if (!bacmp(&e->info.bdaddr, bdaddr)) + break; + return e; +} - if (hdev->sent_cmd) { - kfree_skb(hdev->sent_cmd); - hdev->sent_cmd = NULL; - } +void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info) +{ + struct inquiry_cache *cache = &hdev->inq_cache; + struct inquiry_entry *e; - hdev->close(hdev); - } + DBG("cache %p, %s", cache, batostr(&info->bdaddr)); -done: - hci_req_unlock(hdev); - hci_dev_put(hdev); + if (!(e = inquiry_cache_lookup(hdev, &info->bdaddr))) { + /* Entry not in the cache. Add new one. */ + if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC))) + return; + memset(e, 0, sizeof(struct inquiry_entry)); + e->next = cache->list; + cache->list = e; + } - return ret; + memcpy(&e->info, info, sizeof(inquiry_info)); + e->timestamp = jiffies; + cache->timestamp = jiffies; } -int hci_dev_close(__u16 dev) +int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) { - struct hci_dev *hdev; - - if (!(hdev = hci_dev_get(dev))) - return -ENODEV; + struct inquiry_cache *cache = &hdev->inq_cache; + inquiry_info *info = (inquiry_info *) buf; + struct inquiry_entry *e; + int copied = 0; - DBG("%s %p", hdev->name, hdev); + for (e = cache->list; e && copied < num; e = e->next, copied++) + memcpy(info++, &e->info, sizeof(inquiry_info)); - hci_req_cancel(hdev, ENODEV); - hci_req_lock(hdev); + DBG("cache %p, copied %d", cache, copied); + return copied; +} - if (!(hdev->flags & HCI_UP)) +static void hci_inq_req(struct hci_dev *hdev, unsigned long opt) +{ + struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt; + inquiry_cp ic; + + DBG("%s", hdev->name); + + if (test_bit(HCI_INQUIRY, &hdev->flags)) + return; + + /* Start Inquiry */ + memcpy(&ic.lap, &ir->lap, 3); + ic.length = ir->length; + ic.num_rsp = ir->num_rsp; + hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic); +} + +int hci_inquiry(unsigned long arg) +{ + struct hci_inquiry_req ir; + struct hci_dev *hdev; + int err = 0, do_inquiry = 0; + long timeo; + __u8 *buf, *ptr; + + ptr = (void *) arg; + if (copy_from_user(&ir, ptr, sizeof(ir))) + return -EFAULT; + + if (!(hdev = hci_dev_get(ir.dev_id))) + return -ENODEV; + + hci_dev_lock_bh(hdev); + if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || + ir.flags & IREQ_CACHE_FLUSH) { + inquiry_cache_flush(hdev); + do_inquiry = 1; + } + hci_dev_unlock_bh(hdev); + + timeo = ir.length * 2 * HZ; + if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0) + goto done; + + /* cache_dump can't sleep. Therefore we allocate temp buffer and then + * copy it to the user space. + */ + if (!(buf = kmalloc(sizeof(inquiry_info) * ir.num_rsp, GFP_KERNEL))) { + err = -ENOMEM; + goto done; + } + + hci_dev_lock_bh(hdev); + ir.num_rsp = inquiry_cache_dump(hdev, ir.num_rsp, buf); + hci_dev_unlock_bh(hdev); + + DBG("num_rsp %d", ir.num_rsp); + + if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + + (sizeof(inquiry_info) * ir.num_rsp))) { + copy_to_user(ptr, &ir, sizeof(ir)); + ptr += sizeof(ir); + copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp); + } else + err = -EFAULT; + + kfree(buf); + +done: + hci_dev_put(hdev); + return err; +} + +/* ---- HCI ioctl helpers ---- */ + +int hci_dev_open(__u16 dev) +{ + struct hci_dev *hdev; + int ret = 0; + + if (!(hdev = hci_dev_get(dev))) + return -ENODEV; + + DBG("%s %p", hdev->name, hdev); + + hci_req_lock(hdev); + + if (test_bit(HCI_UP, &hdev->flags)) { + ret = -EALREADY; + goto done; + } + + if (hdev->open(hdev)) { + ret = -EIO; goto done; + } + + if (!test_bit(HCI_RAW, &hdev->flags)) { + atomic_set(&hdev->cmd_cnt, 1); + set_bit(HCI_INIT, &hdev->flags); + + //__hci_request(hdev, hci_reset_req, 0, HZ); + ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT); + + clear_bit(HCI_INIT, &hdev->flags); + } + + if (!ret) { + set_bit(HCI_UP, &hdev->flags); + hci_notify(hdev, HCI_DEV_UP); + } else { + /* Init failed, cleanup */ + tasklet_kill(&hdev->rx_task); + tasklet_kill(&hdev->tx_task); + tasklet_kill(&hdev->cmd_task); + + skb_queue_purge(&hdev->cmd_q); + skb_queue_purge(&hdev->rx_q); + + if (hdev->flush) + hdev->flush(hdev); + + if (hdev->sent_cmd) { + kfree_skb(hdev->sent_cmd); + hdev->sent_cmd = NULL; + } + + hdev->close(hdev); + hdev->flags = 0; + } + +done: + hci_req_unlock(hdev); + hci_dev_put(hdev); + return ret; +} + +static int hci_dev_do_close(struct hci_dev *hdev) +{ + DBG("%s %p", hdev->name, hdev); + + hci_req_cancel(hdev, ENODEV); + hci_req_lock(hdev); + + if (!test_and_clear_bit(HCI_UP, &hdev->flags)) { + hci_req_unlock(hdev); + return 0; + } /* Kill RX and TX tasks */ tasklet_kill(&hdev->rx_task); tasklet_kill(&hdev->tx_task); - inquiry_cache_flush(&hdev->inq_cache); - + hci_dev_lock_bh(hdev); + inquiry_cache_flush(hdev); hci_conn_hash_flush(hdev); - - /* Clear flags */ - hdev->flags &= HCI_SOCK; - hdev->flags |= HCI_NORMAL; - + hci_dev_unlock_bh(hdev); + hci_notify(hdev, HCI_DEV_DOWN); if (hdev->flush) @@ -586,9 +513,9 @@ /* Reset device */ skb_queue_purge(&hdev->cmd_q); atomic_set(&hdev->cmd_cnt, 1); - hdev->flags |= HCI_INIT; - __hci_request(hdev, hci_reset_req, 0, HZ); - hdev->flags &= ~HCI_INIT; + set_bit(HCI_INIT, &hdev->flags); + __hci_request(hdev, hci_reset_req, 0, HZ/4); + clear_bit(HCI_INIT, &hdev->flags); /* Kill cmd task */ tasklet_kill(&hdev->cmd_task); @@ -605,17 +532,28 @@ } /* After this point our queues are empty - * and no tasks are scheduled. - */ + * and no tasks are scheduled. */ hdev->close(hdev); -done: - hci_req_unlock(hdev); - hci_dev_put(hdev); + /* Clear flags */ + hdev->flags = 0; + hci_req_unlock(hdev); return 0; } +int hci_dev_close(__u16 dev) +{ + struct hci_dev *hdev; + int err; + + if (!(hdev = hci_dev_get(dev))) + return -ENODEV; + err = hci_dev_do_close(hdev); + hci_dev_put(hdev); + return err; +} + int hci_dev_reset(__u16 dev) { struct hci_dev *hdev; @@ -627,16 +565,17 @@ hci_req_lock(hdev); tasklet_disable(&hdev->tx_task); - if (!(hdev->flags & HCI_UP)) + if (!test_bit(HCI_UP, &hdev->flags)) goto done; /* Drop queues */ skb_queue_purge(&hdev->rx_q); skb_queue_purge(&hdev->cmd_q); - inquiry_cache_flush(&hdev->inq_cache); - + hci_dev_lock_bh(hdev); + inquiry_cache_flush(hdev); hci_conn_hash_flush(hdev); + hci_dev_unlock_bh(hdev); if (hdev->flush) hdev->flush(hdev); @@ -650,7 +589,6 @@ tasklet_enable(&hdev->tx_task); hci_req_unlock(hdev); hci_dev_put(hdev); - return ret; } @@ -669,30 +607,11 @@ return ret; } -int hci_dev_setauth(unsigned long arg) -{ - struct hci_dev *hdev; - struct hci_dev_req dr; - int ret = 0; - - if (copy_from_user(&dr, (void *) arg, sizeof(dr))) - return -EFAULT; - - if (!(hdev = hci_dev_get(dr.dev_id))) - return -ENODEV; - - ret = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT); - - hci_dev_put(hdev); - - return ret; -} - -int hci_dev_setscan(unsigned long arg) +int hci_dev_cmd(unsigned int cmd, unsigned long arg) { struct hci_dev *hdev; struct hci_dev_req dr; - int ret = 0; + int err = 0; if (copy_from_user(&dr, (void *) arg, sizeof(dr))) return -EFAULT; @@ -700,45 +619,75 @@ if (!(hdev = hci_dev_get(dr.dev_id))) return -ENODEV; - ret = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT); - - hci_dev_put(hdev); + switch (cmd) { + case HCISETAUTH: + err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT); + break; - return ret; -} + case HCISETENCRYPT: + if (!lmp_encrypt_capable(hdev)) { + err = -EOPNOTSUPP; + break; + } -int hci_dev_setptype(unsigned long arg) -{ - struct hci_dev *hdev; - struct hci_dev_req dr; - int ret = 0; + if (!test_bit(HCI_AUTH, &hdev->flags)) { + /* Auth must be enabled first */ + err = hci_request(hdev, hci_auth_req, + dr.dev_opt, HCI_INIT_TIMEOUT); + if (err) + break; + } + + err = hci_request(hdev, hci_encrypt_req, + dr.dev_opt, HCI_INIT_TIMEOUT); + break; + + case HCISETSCAN: + err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT); + break; + + case HCISETPTYPE: + hdev->pkt_type = (__u16) dr.dev_opt; + break; + + case HCISETLINKPOL: + hdev->link_policy = (__u16) dr.dev_opt; + break; - if (copy_from_user(&dr, (void *) arg, sizeof(dr))) - return -EFAULT; + case HCISETLINKMODE: + hdev->link_mode = ((__u16) dr.dev_opt) & (HCI_LM_MASTER | HCI_LM_ACCEPT); + break; - if (!(hdev = hci_dev_get(dr.dev_id))) - return -ENODEV; + case HCISETACLMTU: + hdev->acl_mtu = *((__u16 *)&dr.dev_opt + 1); + hdev->acl_pkts = *((__u16 *)&dr.dev_opt + 0); + break; - hdev->pkt_type = (__u16) dr.dev_opt; + case HCISETSCOMTU: + hdev->sco_mtu = *((__u16 *)&dr.dev_opt + 1); + hdev->sco_pkts = *((__u16 *)&dr.dev_opt + 0); + break; + default: + err = -EINVAL; + break; + } hci_dev_put(hdev); - - return ret; + return err; } -int hci_dev_list(unsigned long arg) +int hci_get_dev_list(unsigned long arg) { struct hci_dev_list_req *dl; struct hci_dev_req *dr; - struct hci_dev *hdev; - int i, n, size; + struct list_head *p; + int n = 0, size; __u16 dev_num; if (get_user(dev_num, (__u16 *) arg)) return -EFAULT; - /* Avoid long loop, overflow */ - if (dev_num > 2048) + if (!dev_num) return -EINVAL; size = dev_num * sizeof(struct hci_dev_req) + sizeof(__u16); @@ -751,12 +700,13 @@ dr = dl->dev_req; spin_lock_bh(&hdev_list_lock); - for (i = 0, n = 0; i < HCI_MAX_DEV && n < dev_num; i++) { - if ((hdev = hdev_list[i])) { - (dr + n)->dev_id = hdev->id; - (dr + n)->dev_opt = hdev->flags; - n++; - } + list_for_each(p, &hdev_list) { + struct hci_dev *hdev; + hdev = list_entry(p, struct hci_dev, list); + (dr + n)->dev_id = hdev->id; + (dr + n)->dev_opt = hdev->flags; + if (++n >= dev_num) + break; } spin_unlock_bh(&hdev_list_lock); @@ -764,11 +714,12 @@ size = n * sizeof(struct hci_dev_req) + sizeof(__u16); copy_to_user((void *) arg, dl, size); + kfree(dl); return 0; } -int hci_dev_info(unsigned long arg) +int hci_get_dev_info(unsigned long arg) { struct hci_dev *hdev; struct hci_dev_info di; @@ -786,9 +737,11 @@ di.flags = hdev->flags; di.pkt_type = hdev->pkt_type; di.acl_mtu = hdev->acl_mtu; - di.acl_max = hdev->acl_max; + di.acl_pkts = hdev->acl_pkts; di.sco_mtu = hdev->sco_mtu; - di.sco_max = hdev->sco_max; + di.sco_pkts = hdev->sco_pkts; + di.link_policy = hdev->link_policy; + di.link_mode = hdev->link_mode; memcpy(&di.stat, &hdev->stat, sizeof(di.stat)); memcpy(&di.features, &hdev->features, sizeof(di.features)); @@ -801,258 +754,149 @@ return err; } -__u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode) -{ - __u32 omode = hdev->flags & HCI_MODE_MASK; - - hdev->flags &= ~HCI_MODE_MASK; - hdev->flags |= (mode & HCI_MODE_MASK); - return omode; -} +/* ---- Interface to HCI drivers ---- */ -__u32 hci_dev_getmode(struct hci_dev *hdev) +/* Register HCI device */ +int hci_register_dev(struct hci_dev *hdev) { - return hdev->flags & HCI_MODE_MASK; -} + struct list_head *head = &hdev_list, *p; + int id = 0; -int hci_conn_list(unsigned long arg) -{ - struct hci_conn_list_req req, *cl; - struct hci_conn_info *ci; - struct hci_dev *hdev; - struct list_head *p; - int n = 0, size; + DBG("%p name %s type %d", hdev, hdev->name, hdev->type); - if (copy_from_user(&req, (void *) arg, sizeof(req))) - return -EFAULT; + if (!hdev->open || !hdev->close || !hdev->destruct) + return -EINVAL; - if (!(hdev = hci_dev_get(req.dev_id))) - return -ENODEV; + spin_lock_bh(&hdev_list_lock); - /* Set a limit to avoid overlong loops, and also numeric overflow - AC */ - if(req.conn_num < 2048) - return -EINVAL; + /* Find first available device id */ + list_for_each(p, &hdev_list) { + if (list_entry(p, struct hci_dev, list)->id != id) + break; + head = p; id++; + } - size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req); + sprintf(hdev->name, "hci%d", id); + hdev->id = id; + list_add(&hdev->list, head); - if (!(cl = kmalloc(size, GFP_KERNEL))) - return -ENOMEM; - ci = cl->conn_info; + atomic_set(&hdev->refcnt, 1); + spin_lock_init(&hdev->lock); + + hdev->flags = 0; + hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); + hdev->link_mode = (HCI_LM_ACCEPT); - local_bh_disable(); - conn_hash_lock(&hdev->conn_hash); - list_for_each(p, &hdev->conn_hash.list) { - register struct hci_conn *c; - c = list_entry(p, struct hci_conn, list); + tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev); + tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); + tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); - (ci + n)->handle = c->handle; - bacpy(&(ci + n)->bdaddr, &c->dst); - n++; - } - conn_hash_unlock(&hdev->conn_hash); - local_bh_enable(); - - cl->dev_id = hdev->id; - cl->conn_num = n; - size = n * sizeof(struct hci_conn_info) + sizeof(req); + skb_queue_head_init(&hdev->rx_q); + skb_queue_head_init(&hdev->cmd_q); + skb_queue_head_init(&hdev->raw_q); - hci_dev_put(hdev); + init_waitqueue_head(&hdev->req_wait_q); + init_MUTEX(&hdev->req_lock); - if(copy_to_user((void *) arg, cl, size)) - return -EFAULT; - return 0; -} + inquiry_cache_init(hdev); -int hci_inquiry(unsigned long arg) -{ - struct inquiry_cache *cache; - struct hci_inquiry_req ir; - struct hci_dev *hdev; - int err = 0, do_inquiry = 0; - long timeo; - __u8 *buf, *ptr; + conn_hash_init(hdev); - ptr = (void *) arg; - if (copy_from_user(&ir, ptr, sizeof(ir))) - return -EFAULT; + memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); - if (!(hdev = hci_dev_get(ir.dev_id))) - return -ENODEV; + atomic_set(&hdev->promisc, 0); + + hci_notify(hdev, HCI_DEV_REG); - cache = &hdev->inq_cache; + MOD_INC_USE_COUNT; - inquiry_cache_lock(cache); - if (inquiry_cache_age(cache) > INQUIRY_CACHE_AGE_MAX || ir.flags & IREQ_CACHE_FLUSH) { - inquiry_cache_flush(cache); - do_inquiry = 1; - } - inquiry_cache_unlock(cache); + spin_unlock_bh(&hdev_list_lock); - /* Limit inquiry time, also avoid overflows */ + return id; +} - if(ir.length > 2048 || ir.num_rsp > 2048) - { - err = -EINVAL; - goto done; - } +/* Unregister HCI device */ +int hci_unregister_dev(struct hci_dev *hdev) +{ + DBG("%p name %s type %d", hdev, hdev->name, hdev->type); - timeo = ir.length * 2 * HZ; - if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0) - goto done; - - /* cache_dump can't sleep. Therefore we allocate temp buffer and then - * copy it to the user space. - */ - if (!(buf = kmalloc(sizeof(inquiry_info) * ir.num_rsp, GFP_KERNEL))) { - err = -ENOMEM; - goto done; - } - ir.num_rsp = inquiry_cache_dump(cache, ir.num_rsp, buf); - - DBG("num_rsp %d", ir.num_rsp); - - if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + (sizeof(inquiry_info) * ir.num_rsp))) { - copy_to_user(ptr, &ir, sizeof(ir)); - ptr += sizeof(ir); - copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp); - } else - err = -EFAULT; - - kfree(buf); - -done: - hci_dev_put(hdev); - - return err; -} - -/* Interface to HCI drivers */ - -/* Register HCI device */ -int hci_register_dev(struct hci_dev *hdev) -{ - int i; - - DBG("%p name %s type %d", hdev, hdev->name, hdev->type); - - /* Find free slot */ spin_lock_bh(&hdev_list_lock); - for (i = 0; i < HCI_MAX_DEV; i++) { - if (!hdev_list[i]) { - hdev_list[i] = hdev; - - sprintf(hdev->name, "hci%d", i); - atomic_set(&hdev->refcnt, 0); - hdev->id = i; - hdev->flags = HCI_NORMAL; - - hdev->pkt_type = (HCI_DM1 | HCI_DH1); - - tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev); - tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); - tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); - - skb_queue_head_init(&hdev->rx_q); - skb_queue_head_init(&hdev->cmd_q); - skb_queue_head_init(&hdev->raw_q); - - init_waitqueue_head(&hdev->req_wait_q); - init_MUTEX(&hdev->req_lock); - - inquiry_cache_init(&hdev->inq_cache); - - conn_hash_init(&hdev->conn_hash); - - memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); + list_del(&hdev->list); + spin_unlock_bh(&hdev_list_lock); - hci_notify(hdev, HCI_DEV_REG); + hci_dev_do_close(hdev); - MOD_INC_USE_COUNT; - break; - } - } - spin_unlock_bh(&hdev_list_lock); + hci_notify(hdev, HCI_DEV_UNREG); + hci_dev_put(hdev); - return (i == HCI_MAX_DEV) ? -1 : i; + MOD_DEC_USE_COUNT; + return 0; } -/* Unregister HCI device */ -int hci_unregister_dev(struct hci_dev *hdev) +/* Receive frame from HCI drivers */ +int hci_recv_frame(struct sk_buff *skb) { - int i; - - DBG("%p name %s type %d", hdev, hdev->name, hdev->type); - - if (hdev->flags & HCI_UP) - hci_dev_close(hdev->id); + struct hci_dev *hdev = (struct hci_dev *) skb->dev; - /* Find device slot */ - spin_lock(&hdev_list_lock); - for (i = 0; i < HCI_MAX_DEV; i++) { - if (hdev_list[i] == hdev) { - hdev_list[i] = NULL; - MOD_DEC_USE_COUNT; - break; - } + if (!hdev || (!test_bit(HCI_UP, &hdev->flags) && + !test_bit(HCI_INIT, &hdev->flags)) ) { + kfree_skb(skb); + return -1; } - spin_unlock(&hdev_list_lock); - - hci_notify(hdev, HCI_DEV_UNREG); - /* Sleep while device is in use */ - while (atomic_read(&hdev->refcnt)) { - int sleep_cnt = 100; + DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); - DBG("%s sleeping on lock %d", hdev->name, atomic_read(&hdev->refcnt)); + /* Incomming skb */ + bluez_cb(skb)->incomming = 1; - sleep_on_timeout(&hdev->req_wait_q, HZ*10); - if (!(--sleep_cnt)) - break; - } + /* Time stamp */ + do_gettimeofday(&skb->stamp); + /* Queue frame for rx task */ + skb_queue_tail(&hdev->rx_q, skb); + hci_sched_rx(hdev); return 0; } -/* Interface to upper protocols */ +/* ---- Interface to upper protocols ---- */ /* Register/Unregister protocols. - * hci_task_lock is used to ensure that no tasks are running. - */ -int hci_register_proto(struct hci_proto *hproto) + * hci_task_lock is used to ensure that no tasks are running. */ +int hci_register_proto(struct hci_proto *hp) { int err = 0; - DBG("%p name %s", hproto, hproto->name); + DBG("%p name %s id %d", hp, hp->name, hp->id); - if (hproto->id >= HCI_MAX_PROTO) + if (hp->id >= HCI_MAX_PROTO) return -EINVAL; write_lock_bh(&hci_task_lock); - if (!hproto_list[hproto->id]) - hproto_list[hproto->id] = hproto; + if (!hci_proto[hp->id]) + hci_proto[hp->id] = hp; else - err = -1; + err = -EEXIST; write_unlock_bh(&hci_task_lock); return err; } -int hci_unregister_proto(struct hci_proto *hproto) +int hci_unregister_proto(struct hci_proto *hp) { int err = 0; - DBG("%p name %s", hproto, hproto->name); + DBG("%p name %s id %d", hp, hp->name, hp->id); - if (hproto->id > HCI_MAX_PROTO) + if (hp->id >= HCI_MAX_PROTO) return -EINVAL; write_lock_bh(&hci_task_lock); - if (hproto_list[hproto->id]) - hproto_list[hproto->id] = NULL; + if (hci_proto[hp->id]) + hci_proto[hp->id] = NULL; else err = -ENOENT; @@ -1072,8 +916,12 @@ DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); - if (hdev->flags & HCI_SOCK) + if (atomic_read(&hdev->promisc)) { + /* Time stamp */ + do_gettimeofday(&skb->stamp); + hci_send_to_sock(hdev, skb); + } /* Get rid of skb owner, prior to sending to the driver. */ skb_orphan(skb); @@ -1081,94 +929,6 @@ return hdev->send(skb); } -/* Connection scheduler */ -static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote) -{ - struct conn_hash *h = &hdev->conn_hash; - struct hci_conn *conn = NULL; - int num = 0, min = 0xffff; - struct list_head *p; - - conn_hash_lock(h); - list_for_each(p, &h->list) { - register struct hci_conn *c; - - c = list_entry(p, struct hci_conn, list); - - if (c->type != type || skb_queue_empty(&c->data_q)) - continue; - num++; - - if (c->sent < min) { - min = c->sent; - conn = c; - } - } - conn_hash_unlock(h); - - if (conn) { - int q = hdev->acl_cnt / num; - *quote = q ? q : 1; - } else - *quote = 0; - - DBG("conn %p quote %d", conn, *quote); - - return conn; -} - -static inline void hci_sched_acl(struct hci_dev *hdev) -{ - struct hci_conn *conn; - struct sk_buff *skb; - int quote; - - DBG("%s", hdev->name); - - while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) { - while (quote && (skb = skb_dequeue(&conn->data_q))) { - DBG("skb %p len %d", skb, skb->len); - - hci_send_frame(skb); - - conn->sent++; - hdev->acl_cnt--; - quote--; - } - } -} - -/* Schedule SCO */ -static inline void hci_sched_sco(struct hci_dev *hdev) -{ - /* FIXME: For now we queue SCO packets to the raw queue - - while (hdev->sco_cnt && (skb = skb_dequeue(&conn->data_q))) { - hci_send_frame(skb); - conn->sco_sent++; - hdev->sco_cnt--; - } - */ -} - -/* Get data from the previously sent command */ -static void * hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf) -{ - hci_command_hdr *hc; - - if (!hdev->sent_cmd) - return NULL; - - hc = (void *) hdev->sent_cmd->data; - - if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf))) - return NULL; - - DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf); - - return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE; -} - /* Send raw HCI frame */ int hci_send_raw(struct sk_buff *skb) { @@ -1181,7 +941,7 @@ DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); - if (hdev->flags & HCI_NORMAL) { + if (!test_bit(HCI_RAW, &hdev->flags)) { /* Queue frame according it's type */ switch (skb->pkt_type) { case HCI_COMMAND_PKT: @@ -1234,10 +994,28 @@ return 0; } +/* Get data from the previously sent command */ +void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf) +{ + hci_command_hdr *hc; + + if (!hdev->sent_cmd) + return NULL; + + hc = (void *) hdev->sent_cmd->data; + + if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf))) + return NULL; + + DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf); + + return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE; +} + /* Send ACL data */ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags) { - int len = skb->len; + int len = skb->len; hci_acl_hdr *ah; ah = (hci_acl_hdr *) skb_push(skb, HCI_ACL_HDR_SIZE); @@ -1315,544 +1093,120 @@ skb->pkt_type = HCI_SCODATA_PKT; skb_queue_tail(&conn->data_q, skb); hci_sched_tx(hdev); - return 0; } -/* Handle HCI Event packets */ +/* ---- HCI TX task (outgoing data) ---- */ -/* Command Complete OGF LINK_CTL */ -static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) +/* HCI Connection scheduler */ +static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote) { - DBG("%s ocf 0x%x", hdev->name, ocf); + struct conn_hash *h = &hdev->conn_hash; + struct hci_conn *conn = NULL; + int num = 0, min = 0xffff; + struct list_head *p; - switch (ocf) { - default: - DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf); - break; - }; -} + /* We don't have to lock device here. Connections are always + * added and removed with TX task disabled. */ + list_for_each(p, &h->list) { + struct hci_conn *c; -/* Command Complete OGF LINK_POLICY */ -static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) -{ - DBG("%s ocf 0x%x", hdev->name, ocf); + c = list_entry(p, struct hci_conn, list); - switch (ocf) { - default: - DBG("%s: Command complete: ogf LINK_POLICY ocf %x", hdev->name, ocf); - break; - }; -} + if (c->type != type || c->state != BT_CONNECTED + || skb_queue_empty(&c->data_q)) + continue; + num++; -/* Command Complete OGF HOST_CTL */ -static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) -{ - __u8 status, param; - void *sent; + if (c->sent < min || type == SCO_LINK) { + min = c->sent; + conn = c; + } + } + if (conn) { + int q = hdev->acl_cnt / num; + *quote = q ? q : 1; + } else + *quote = 0; - DBG("%s ocf 0x%x", hdev->name, ocf); + DBG("conn %p quote %d", conn, *quote); + return conn; +} - switch (ocf) { - case OCF_RESET: - status = *((__u8 *) skb->data); +static inline void hci_sched_acl(struct hci_dev *hdev) +{ + struct hci_conn *conn; + struct sk_buff *skb; + int quote; - hci_req_complete(hdev, status); - break; + DBG("%s", hdev->name); - case OCF_SET_EVENT_FLT: - status = *((__u8 *) skb->data); + if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > HZ*5) { + ERR("%s ACL tx timeout", hdev->name); + hdev->acl_cnt++; + } + + while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) { + while (quote && (skb = skb_dequeue(&conn->data_q))) { + DBG("skb %p len %d", skb, skb->len); - if (status) { - DBG("%s SET_EVENT_FLT failed %d", hdev->name, status); - } else { - DBG("%s SET_EVENT_FLT succeseful", hdev->name); + hci_send_frame(skb); + hdev->acl_last_tx = jiffies; + + conn->sent++; + hdev->acl_cnt--; + quote--; } - break; + } +} - case OCF_WRITE_AUTH_ENABLE: - if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE))) - break; +/* Schedule SCO */ +static inline void hci_sched_sco(struct hci_dev *hdev) +{ + struct hci_conn *conn; + struct sk_buff *skb; + int quote; - status = *((__u8 *) skb->data); - param = *((__u8 *) sent); + DBG("%s", hdev->name); - if (!status) { - if (param == AUTH_ENABLED) - hdev->flags |= HCI_AUTH; - else - hdev->flags &= ~HCI_AUTH; - } - hci_req_complete(hdev, status); - break; + while ((conn = hci_low_sent(hdev, SCO_LINK, "e))) { + while (quote && (skb = skb_dequeue(&conn->data_q))) { + DBG("skb %p len %d", skb, skb->len); - case OCF_WRITE_CA_TIMEOUT: - status = *((__u8 *) skb->data); + hci_send_frame(skb); - if (status) { - DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status); - } else { - DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name); + //conn->sent++; + //hdev->sco_cnt--; + quote--; } - break; + } +} - case OCF_WRITE_PG_TIMEOUT: - status = *((__u8 *) skb->data); +static void hci_tx_task(unsigned long arg) +{ + struct hci_dev *hdev = (struct hci_dev *) arg; + struct sk_buff *skb; - if (status) { - DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status); - } else { - DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name); - } - break; + read_lock(&hci_task_lock); - case OCF_WRITE_SCAN_ENABLE: - if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE))) - break; - status = *((__u8 *) skb->data); - param = *((__u8 *) sent); + DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt); - DBG("param 0x%x", param); + /* Schedule queues and send stuff to HCI driver */ - if (!status) { - switch (param) { - case IS_ENA_PS_ENA: - hdev->flags |= HCI_PSCAN | HCI_ISCAN; - break; + hci_sched_acl(hdev); - case IS_ENA_PS_DIS: - hdev->flags &= ~HCI_PSCAN; - hdev->flags |= HCI_ISCAN; - break; + hci_sched_sco(hdev); - case IS_DIS_PS_ENA: - hdev->flags &= ~HCI_ISCAN; - hdev->flags |= HCI_PSCAN; - break; - - default: - hdev->flags &= ~(HCI_ISCAN | HCI_PSCAN); - break; - }; - } - hci_req_complete(hdev, status); - break; - - default: - DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf); - break; - }; -} - -/* Command Complete OGF INFO_PARAM */ -static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) -{ - read_local_features_rp *lf; - read_buffer_size_rp *bs; - read_bd_addr_rp *ba; - - DBG("%s ocf 0x%x", hdev->name, ocf); - - switch (ocf) { - case OCF_READ_LOCAL_FEATURES: - lf = (read_local_features_rp *) skb->data; - - if (lf->status) { - DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status); - break; - } - - memcpy(hdev->features, lf->features, sizeof(hdev->features)); - - /* Adjust default settings according to features - * supported by device. */ - if (hdev->features[0] & LMP_3SLOT) - hdev->pkt_type |= (HCI_DM3 | HCI_DH3); - - if (hdev->features[0] & LMP_5SLOT) - hdev->pkt_type |= (HCI_DM5 | HCI_DH5); - - DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]); - - break; - - case OCF_READ_BUFFER_SIZE: - bs = (read_buffer_size_rp *) skb->data; - - if (bs->status) { - DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status); - break; - } - - hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu); - hdev->sco_mtu = bs->sco_mtu; - hdev->acl_max = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt); - hdev->sco_max = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt); - - DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name, - hdev->acl_mtu, hdev->sco_mtu, hdev->acl_max, hdev->sco_max); - - break; - - case OCF_READ_BD_ADDR: - ba = (read_bd_addr_rp *) skb->data; - - if (!ba->status) { - bacpy(&hdev->bdaddr, &ba->bdaddr); - } else { - DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status); - } - - hci_req_complete(hdev, ba->status); - break; - - default: - DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf); - break; - }; -} - -/* Command Status OGF LINK_CTL */ -static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) -{ - struct hci_proto * hp; - - DBG("%s ocf 0x%x", hdev->name, ocf); - - switch (ocf) { - case OCF_CREATE_CONN: - if (status) { - create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN); - - if (!cc) - break; - - DBG("%s Create connection error: status 0x%x %s", hdev->name, - status, batostr(&cc->bdaddr)); - - /* Notify upper protocols */ - if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm) { - tasklet_disable(&hdev->tx_task); - hp->connect_cfm(hdev, &cc->bdaddr, status, NULL); - tasklet_enable(&hdev->tx_task); - } - } - break; - - case OCF_INQUIRY: - if (status) { - DBG("%s Inquiry error: status 0x%x", hdev->name, status); - hci_req_complete(hdev, status); - } - break; - - default: - DBG("%s Command status: ogf LINK_CTL ocf %x", hdev->name, ocf); - break; - }; -} - -/* Command Status OGF LINK_POLICY */ -static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status) -{ - DBG("%s ocf 0x%x", hdev->name, ocf); - - switch (ocf) { - default: - DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf); - break; - }; -} - -/* Command Status OGF HOST_CTL */ -static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) -{ - DBG("%s ocf 0x%x", hdev->name, ocf); - - switch (ocf) { - default: - DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf); - break; - }; -} - -/* Command Status OGF INFO_PARAM */ -static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status) -{ - DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf); - - switch (ocf) { - default: - DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf); - break; - }; -} - -/* Inquiry Complete */ -static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) -{ - __u8 status = *((__u8 *) skb->data); - - DBG("%s status %d", hdev->name, status); - - hci_req_complete(hdev, status); -} - -/* Inquiry Result */ -static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) -{ - inquiry_info *info = (inquiry_info *) (skb->data + 1); - int num_rsp = *((__u8 *) skb->data); - - DBG("%s num_rsp %d", hdev->name, num_rsp); - - for (; num_rsp; num_rsp--) - inquiry_cache_update(&hdev->inq_cache, info++); -} - -/* Connect Request */ -static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) -{ - evt_conn_request *cr = (evt_conn_request *) skb->data; - struct hci_proto *hp; - accept_conn_req_cp ac; - int accept = 0; - - DBG("%s Connection request: %s type 0x%x", hdev->name, batostr(&cr->bdaddr), cr->link_type); - - /* Notify upper protocols */ - if (cr->link_type == ACL_LINK) { - /* ACL link notify L2CAP */ - if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_ind) { - tasklet_disable(&hdev->tx_task); - accept = hp->connect_ind(hdev, &cr->bdaddr); - tasklet_enable(&hdev->tx_task); - } - } else { - /* SCO link (no notification) */ - /* FIXME: Should be accept it here or let the requester (app) accept it ? */ - accept = 1; - } - - if (accept) { - /* Connection accepted by upper layer */ - bacpy(&ac.bdaddr, &cr->bdaddr); - ac.role = 0x01; /* Remain slave */ - hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, ACCEPT_CONN_REQ_CP_SIZE, &ac); - } else { - /* Connection rejected by upper layer */ - /* FIXME: - * Should we use HCI reject here ? - */ - return; - } -} - -/* Connect Complete */ -static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) -{ - evt_conn_complete *cc = (evt_conn_complete *) skb->data; - struct hci_conn *conn = NULL; - struct hci_proto *hp; - - DBG("%s", hdev->name); - - tasklet_disable(&hdev->tx_task); - - if (!cc->status) - conn = hci_conn_add(hdev, __le16_to_cpu(cc->handle), cc->link_type, &cc->bdaddr); - - /* Notify upper protocols */ - if (cc->link_type == ACL_LINK) { - /* ACL link notify L2CAP layer */ - if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm) - hp->connect_cfm(hdev, &cc->bdaddr, cc->status, conn); - } else { - /* SCO link (no notification) */ - } - - tasklet_enable(&hdev->tx_task); -} - -/* Disconnect Complete */ -static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) -{ - evt_disconn_complete *dc = (evt_disconn_complete *) skb->data; - struct hci_conn *conn = NULL; - struct hci_proto *hp; - __u16 handle = __le16_to_cpu(dc->handle); - - DBG("%s", hdev->name); - - if (!dc->status && (conn = conn_hash_lookup(&hdev->conn_hash, handle))) { - tasklet_disable(&hdev->tx_task); - - /* Notify upper protocols */ - if (conn->type == ACL_LINK) { - /* ACL link notify L2CAP layer */ - if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind) - hp->disconn_ind(conn, dc->reason); - } else { - /* SCO link (no notification) */ - } - - hci_conn_del(hdev, conn); - - tasklet_enable(&hdev->tx_task); - } -} - -/* Number of completed packets */ -static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb) -{ - evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data; - __u16 *ptr; - int i; - - skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE); - - DBG("%s num_hndl %d", hdev->name, nc->num_hndl); - - if (skb->len < nc->num_hndl * 4) { - DBG("%s bad parameters", hdev->name); - return; - } - - tasklet_disable(&hdev->tx_task); - - for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) { - struct hci_conn *conn; - __u16 handle, count; - - handle = __le16_to_cpu(get_unaligned(ptr++)); - count = __le16_to_cpu(get_unaligned(ptr++)); - - hdev->acl_cnt += count; - - if ((conn = conn_hash_lookup(&hdev->conn_hash, handle))) - conn->sent -= count; - } + /* Send next queued raw (unknown type) packet */ + while ((skb = skb_dequeue(&hdev->raw_q))) + hci_send_frame(skb); - tasklet_enable(&hdev->tx_task); - - hci_sched_tx(hdev); + read_unlock(&hci_task_lock); } -static inline void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) -{ - hci_event_hdr *he = (hci_event_hdr *) skb->data; - evt_cmd_status *cs; - evt_cmd_complete *ec; - __u16 opcode, ocf, ogf; - - skb_pull(skb, HCI_EVENT_HDR_SIZE); - - DBG("%s evt 0x%x", hdev->name, he->evt); - - switch (he->evt) { - case EVT_NUM_COMP_PKTS: - hci_num_comp_pkts_evt(hdev, skb); - break; - - case EVT_INQUIRY_COMPLETE: - hci_inquiry_complete_evt(hdev, skb); - break; - - case EVT_INQUIRY_RESULT: - hci_inquiry_result_evt(hdev, skb); - break; - - case EVT_CONN_REQUEST: - hci_conn_request_evt(hdev, skb); - break; - - case EVT_CONN_COMPLETE: - hci_conn_complete_evt(hdev, skb); - break; - - case EVT_DISCONN_COMPLETE: - hci_disconn_complete_evt(hdev, skb); - break; - - case EVT_CMD_STATUS: - cs = (evt_cmd_status *) skb->data; - skb_pull(skb, EVT_CMD_STATUS_SIZE); - - opcode = __le16_to_cpu(cs->opcode); - ogf = cmd_opcode_ogf(opcode); - ocf = cmd_opcode_ocf(opcode); - - switch (ogf) { - case OGF_INFO_PARAM: - hci_cs_info_param(hdev, ocf, cs->status); - break; - - case OGF_HOST_CTL: - hci_cs_host_ctl(hdev, ocf, cs->status); - break; - - case OGF_LINK_CTL: - hci_cs_link_ctl(hdev, ocf, cs->status); - break; - - case OGF_LINK_POLICY: - hci_cs_link_policy(hdev, ocf, cs->status); - break; - - default: - DBG("%s Command Status OGF %x", hdev->name, ogf); - break; - }; - - if (cs->ncmd) { - atomic_set(&hdev->cmd_cnt, 1); - if (!skb_queue_empty(&hdev->cmd_q)) - hci_sched_cmd(hdev); - } - break; - - case EVT_CMD_COMPLETE: - ec = (evt_cmd_complete *) skb->data; - skb_pull(skb, EVT_CMD_COMPLETE_SIZE); - - opcode = __le16_to_cpu(ec->opcode); - ogf = cmd_opcode_ogf(opcode); - ocf = cmd_opcode_ocf(opcode); - - switch (ogf) { - case OGF_INFO_PARAM: - hci_cc_info_param(hdev, ocf, skb); - break; - - case OGF_HOST_CTL: - hci_cc_host_ctl(hdev, ocf, skb); - break; - - case OGF_LINK_CTL: - hci_cc_link_ctl(hdev, ocf, skb); - break; - - case OGF_LINK_POLICY: - hci_cc_link_policy(hdev, ocf, skb); - break; - - default: - DBG("%s Command Completed OGF %x", hdev->name, ogf); - break; - }; - if (ec->ncmd) { - atomic_set(&hdev->cmd_cnt, 1); - if (!skb_queue_empty(&hdev->cmd_q)) - hci_sched_cmd(hdev); - } - break; - }; - - kfree_skb(skb); - hdev->stat.evt_rx++; -} +/* ----- HCI RX task (incomming data proccessing) ----- */ /* ACL data packet */ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) @@ -1869,33 +1223,63 @@ DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags); - if ((conn = conn_hash_lookup(&hdev->conn_hash, handle))) { + hdev->stat.acl_rx++; + + hci_dev_lock(hdev); + conn = conn_hash_lookup_handle(hdev, handle); + hci_dev_unlock(hdev); + + if (conn) { register struct hci_proto *hp; /* Send to upper protocol */ - if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->recv_acldata) { + if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) { hp->recv_acldata(conn, skb, flags); - goto sent; + return; } } else { - ERR("%s ACL packet for unknown connection handle %d", hdev->name, handle); + ERR("%s ACL packet for unknown connection handle %d", + hdev->name, handle); } kfree_skb(skb); -sent: - hdev->stat.acl_rx++; } /* SCO data packet */ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) { - DBG("%s len %d", hdev->name, skb->len); + hci_sco_hdr *sh = (void *) skb->data; + struct hci_conn *conn; + __u16 handle; + + skb_pull(skb, HCI_SCO_HDR_SIZE); + + handle = __le16_to_cpu(sh->handle); + + DBG("%s len %d handle 0x%x", hdev->name, skb->len, handle); - kfree_skb(skb); hdev->stat.sco_rx++; + + hci_dev_lock(hdev); + conn = conn_hash_lookup_handle(hdev, handle); + hci_dev_unlock(hdev); + + if (conn) { + register struct hci_proto *hp; + + /* Send to upper protocol */ + if ((hp = hci_proto[HCI_PROTO_SCO]) && hp->recv_scodata) { + hp->recv_scodata(conn, skb); + return; + } + } else { + ERR("%s SCO packet for unknown connection handle %d", + hdev->name, handle); + } + + kfree_skb(skb); } -/* ----- HCI tasks ----- */ void hci_rx_task(unsigned long arg) { struct hci_dev *hdev = (struct hci_dev *) arg; @@ -1906,12 +1290,17 @@ read_lock(&hci_task_lock); while ((skb = skb_dequeue(&hdev->rx_q))) { - if (hdev->flags & HCI_SOCK) { + if (atomic_read(&hdev->promisc)) { /* Send copy to the sockets */ hci_send_to_sock(hdev, skb); } - if (hdev->flags & HCI_INIT) { + if (test_bit(HCI_RAW, &hdev->flags)) { + kfree_skb(skb); + continue; + } + + if (test_bit(HCI_INIT, &hdev->flags)) { /* Don't process data packets in this states. */ switch (skb->pkt_type) { case HCI_ACLDATA_PKT: @@ -1921,57 +1310,31 @@ }; } - if (hdev->flags & HCI_NORMAL) { - /* Process frame */ - switch (skb->pkt_type) { - case HCI_EVENT_PKT: - hci_event_packet(hdev, skb); - break; + /* Process frame */ + switch (skb->pkt_type) { + case HCI_EVENT_PKT: + hci_event_packet(hdev, skb); + break; - case HCI_ACLDATA_PKT: - DBG("%s ACL data packet", hdev->name); - hci_acldata_packet(hdev, skb); - break; + case HCI_ACLDATA_PKT: + DBG("%s ACL data packet", hdev->name); + hci_acldata_packet(hdev, skb); + break; - case HCI_SCODATA_PKT: - DBG("%s SCO data packet", hdev->name); - hci_scodata_packet(hdev, skb); - break; + case HCI_SCODATA_PKT: + DBG("%s SCO data packet", hdev->name); + hci_scodata_packet(hdev, skb); + break; - default: - kfree_skb(skb); - break; - }; - } else { + default: kfree_skb(skb); + break; } } read_unlock(&hci_task_lock); } -static void hci_tx_task(unsigned long arg) -{ - struct hci_dev *hdev = (struct hci_dev *) arg; - struct sk_buff *skb; - - read_lock(&hci_task_lock); - - DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt); - - /* Schedule queues and send stuff to HCI driver */ - - hci_sched_acl(hdev); - - hci_sched_sco(hdev); - - /* Send next queued raw (unknown type) packet */ - while ((skb = skb_dequeue(&hdev->raw_q))) - hci_send_frame(skb); - - read_unlock(&hci_task_lock); -} - static void hci_cmd_task(unsigned long arg) { struct hci_dev *hdev = (struct hci_dev *) arg; @@ -1979,6 +1342,11 @@ DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); + if (!atomic_read(&hdev->cmd_cnt) && (jiffies - hdev->cmd_last_tx) > HZ) { + ERR("%s command tx timeout", hdev->name); + atomic_set(&hdev->cmd_cnt, 1); + } + /* Send queued commands */ if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) { if (hdev->sent_cmd) @@ -1987,6 +1355,7 @@ if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) { atomic_dec(&hdev->cmd_cnt); hci_send_frame(skb); + hdev->cmd_last_tx = jiffies; } else { skb_queue_head(&hdev->cmd_q, skb); hci_sched_cmd(hdev); @@ -1994,27 +1363,7 @@ } } -/* Receive frame from HCI drivers */ -int hci_recv_frame(struct sk_buff *skb) -{ - struct hci_dev *hdev = (struct hci_dev *) skb->dev; - - if (!hdev || !(hdev->flags & (HCI_UP | HCI_INIT))) { - kfree_skb(skb); - return -1; - } - - DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); - - /* Incomming skb */ - bluez_cb(skb)->incomming = 1; - - /* Queue frame for rx task */ - skb_queue_tail(&hdev->rx_q, skb); - hci_sched_rx(hdev); - - return 0; -} +/* ---- Initialization ---- */ int hci_core_init(void) { @@ -2028,5 +1377,3 @@ { return 0; } - -MODULE_LICENSE("GPL"); diff -urN linux-2.4.19-pre6/net/bluetooth/hci_event.c linux-2.4.19-pre7/net/bluetooth/hci_event.c --- linux-2.4.19-pre6/net/bluetooth/hci_event.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/net/bluetooth/hci_event.c Mon Apr 15 21:55:00 2002 @@ -0,0 +1,874 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * HCI Events. + * + * $Id: hci_event.c,v 1.2 2002/03/26 17:56:44 maxk Exp $ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#ifndef HCI_CORE_DEBUG +#undef DBG +#define DBG( A... ) +#endif + +/* Handle HCI Event packets */ + +/* Command Complete OGF LINK_CTL */ +static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) +{ + DBG("%s ocf 0x%x", hdev->name, ocf); + + switch (ocf) { + default: + DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf); + break; + }; +} + +/* Command Complete OGF LINK_POLICY */ +static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) +{ + struct hci_conn *conn; + role_discovery_rp *rd; + + DBG("%s ocf 0x%x", hdev->name, ocf); + + switch (ocf) { + case OCF_ROLE_DISCOVERY: + rd = (void *) skb->data; + + if (rd->status) + break; + + hci_dev_lock(hdev); + + conn = conn_hash_lookup_handle(hdev, __le16_to_cpu(rd->handle)); + if (conn) { + if (rd->role) + conn->link_mode &= ~HCI_LM_MASTER; + else + conn->link_mode |= HCI_LM_MASTER; + } + + hci_dev_unlock(hdev); + break; + + default: + DBG("%s: Command complete: ogf LINK_POLICY ocf %x", + hdev->name, ocf); + break; + }; +} + +/* Command Complete OGF HOST_CTL */ +static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) +{ + __u8 status, param; + void *sent; + + DBG("%s ocf 0x%x", hdev->name, ocf); + + switch (ocf) { + case OCF_RESET: + status = *((__u8 *) skb->data); + hci_req_complete(hdev, status); + break; + + case OCF_SET_EVENT_FLT: + status = *((__u8 *) skb->data); + if (status) { + DBG("%s SET_EVENT_FLT failed %d", hdev->name, status); + } else { + DBG("%s SET_EVENT_FLT succeseful", hdev->name); + } + break; + + case OCF_WRITE_AUTH_ENABLE: + sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE); + if (!sent) + break; + + status = *((__u8 *) skb->data); + param = *((__u8 *) sent); + + if (!status) { + if (param == AUTH_ENABLED) + set_bit(HCI_AUTH, &hdev->flags); + else + clear_bit(HCI_AUTH, &hdev->flags); + } + hci_req_complete(hdev, status); + break; + + case OCF_WRITE_ENCRYPT_MODE: + sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE); + if (!sent) + break; + + status = *((__u8 *) skb->data); + param = *((__u8 *) sent); + + if (!status) { + if (param) + set_bit(HCI_ENCRYPT, &hdev->flags); + else + clear_bit(HCI_ENCRYPT, &hdev->flags); + } + hci_req_complete(hdev, status); + break; + + case OCF_WRITE_CA_TIMEOUT: + status = *((__u8 *) skb->data); + if (status) { + DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status); + } else { + DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name); + } + break; + + case OCF_WRITE_PG_TIMEOUT: + status = *((__u8 *) skb->data); + if (status) { + DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status); + } else { + DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name); + } + break; + + case OCF_WRITE_SCAN_ENABLE: + sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE); + if (!sent) + break; + status = *((__u8 *) skb->data); + param = *((__u8 *) sent); + + DBG("param 0x%x", param); + + if (!status) { + clear_bit(HCI_PSCAN, &hdev->flags); + clear_bit(HCI_ISCAN, &hdev->flags); + if (param & SCAN_INQUIRY) + set_bit(HCI_ISCAN, &hdev->flags); + + if (param & SCAN_PAGE) + set_bit(HCI_PSCAN, &hdev->flags); + } + hci_req_complete(hdev, status); + break; + + case OCF_HOST_BUFFER_SIZE: + status = *((__u8 *) skb->data); + if (status) { + DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status); + hci_req_complete(hdev, status); + } + break; + + default: + DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf); + break; + }; +} + +/* Command Complete OGF INFO_PARAM */ +static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) +{ + read_local_features_rp *lf; + read_buffer_size_rp *bs; + read_bd_addr_rp *ba; + + DBG("%s ocf 0x%x", hdev->name, ocf); + + switch (ocf) { + case OCF_READ_LOCAL_FEATURES: + lf = (read_local_features_rp *) skb->data; + + if (lf->status) { + DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status); + break; + } + + memcpy(hdev->features, lf->features, sizeof(hdev->features)); + + /* Adjust default settings according to features + * supported by device. */ + if (hdev->features[0] & LMP_3SLOT) + hdev->pkt_type |= (HCI_DM3 | HCI_DH3); + + if (hdev->features[0] & LMP_5SLOT) + hdev->pkt_type |= (HCI_DM5 | HCI_DH5); + + if (hdev->features[1] & LMP_HV2) + hdev->pkt_type |= (HCI_HV2); + + if (hdev->features[1] & LMP_HV3) + hdev->pkt_type |= (HCI_HV3); + + DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]); + + break; + + case OCF_READ_BUFFER_SIZE: + bs = (read_buffer_size_rp *) skb->data; + + if (bs->status) { + DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status); + hci_req_complete(hdev, bs->status); + break; + } + + hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu); + hdev->sco_mtu = bs->sco_mtu ? bs->sco_mtu : 64; + hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt); + hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt); + + DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name, + hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts); + break; + + case OCF_READ_BD_ADDR: + ba = (read_bd_addr_rp *) skb->data; + + if (!ba->status) { + bacpy(&hdev->bdaddr, &ba->bdaddr); + } else { + DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status); + } + + hci_req_complete(hdev, ba->status); + break; + + default: + DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf); + break; + }; +} + +/* Command Status OGF LINK_CTL */ +static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) +{ + struct hci_conn *conn; + create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN); + + if (!cc) + return; + + hci_dev_lock(hdev); + + conn = conn_hash_lookup_ba(hdev, ACL_LINK, &cc->bdaddr); + + DBG("%s status 0x%x bdaddr %s conn %p", hdev->name, + status, batostr(&cc->bdaddr), conn); + + if (status) { + if (conn) { + conn->state = BT_CLOSED; + hci_proto_connect_cfm(conn, status); + hci_conn_del(conn); + } + } else { + if (!conn) { + conn = hci_conn_add(hdev, ACL_LINK, &cc->bdaddr); + if (conn) { + conn->out = 1; + conn->link_mode |= HCI_LM_MASTER; + } else + ERR("No memmory for new connection"); + } + } + + hci_dev_unlock(hdev); +} + +static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) +{ + DBG("%s ocf 0x%x", hdev->name, ocf); + + switch (ocf) { + case OCF_CREATE_CONN: + hci_cs_create_conn(hdev, status); + break; + + case OCF_ADD_SCO: + if (status) { + struct hci_conn *acl, *sco; + add_sco_cp *cp = hci_sent_cmd_data(hdev, + OGF_LINK_CTL, OCF_ADD_SCO); + __u16 handle; + + if (!cp) + break; + + handle = __le16_to_cpu(cp->handle); + + DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status); + + hci_dev_lock(hdev); + + acl = conn_hash_lookup_handle(hdev, handle); + if (!acl || !(sco = acl->link)) { + hci_dev_unlock(hdev); + break; + } + + sco->state = BT_CLOSED; + + hci_proto_connect_cfm(sco, status); + hci_conn_del(sco); + + hci_dev_unlock(hdev); + } + break; + + case OCF_INQUIRY: + if (status) { + DBG("%s Inquiry error: status 0x%x", hdev->name, status); + hci_req_complete(hdev, status); + } else { + set_bit(HCI_INQUIRY, &hdev->flags); + } + break; + + default: + DBG("%s Command status: ogf LINK_CTL ocf %x status %d", + hdev->name, ocf, status); + break; + }; +} + +/* Command Status OGF LINK_POLICY */ +static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status) +{ + DBG("%s ocf 0x%x", hdev->name, ocf); + + switch (ocf) { + default: + DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf); + break; + }; +} + +/* Command Status OGF HOST_CTL */ +static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) +{ + DBG("%s ocf 0x%x", hdev->name, ocf); + + switch (ocf) { + default: + DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf); + break; + }; +} + +/* Command Status OGF INFO_PARAM */ +static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status) +{ + DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf); + + switch (ocf) { + default: + DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf); + break; + }; +} + +/* Inquiry Complete */ +static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + __u8 status = *((__u8 *) skb->data); + + DBG("%s status %d", hdev->name, status); + + clear_bit(HCI_INQUIRY, &hdev->flags); + hci_req_complete(hdev, status); +} + +/* Inquiry Result */ +static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + inquiry_info *info = (inquiry_info *) (skb->data + 1); + int num_rsp = *((__u8 *) skb->data); + + DBG("%s num_rsp %d", hdev->name, num_rsp); + + hci_dev_lock(hdev); + for (; num_rsp; num_rsp--) + inquiry_cache_update(hdev, info++); + hci_dev_unlock(hdev); +} + +/* Connect Request */ +static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + evt_conn_request *cr = (evt_conn_request *) skb->data; + int mask = hdev->link_mode; + + DBG("%s Connection request: %s type 0x%x", hdev->name, + batostr(&cr->bdaddr), cr->link_type); + + mask |= hci_proto_connect_ind(hdev, &cr->bdaddr, cr->link_type); + + if (mask & HCI_LM_ACCEPT) { + /* Connection accepted */ + struct hci_conn *conn; + accept_conn_req_cp ac; + + hci_dev_lock(hdev); + conn = conn_hash_lookup_ba(hdev, cr->link_type, &cr->bdaddr); + if (!conn) { + if (!(conn = hci_conn_add(hdev, cr->link_type, &cr->bdaddr))) { + ERR("No memmory for new connection"); + hci_dev_unlock(hdev); + return; + } + } + conn->state = BT_CONNECT; + hci_dev_unlock(hdev); + + bacpy(&ac.bdaddr, &cr->bdaddr); + + if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) + ac.role = 0x00; /* Become master */ + else + ac.role = 0x01; /* Remain slave */ + + hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, + ACCEPT_CONN_REQ_CP_SIZE, &ac); + } else { + /* Connection rejected */ + reject_conn_req_cp rc; + + bacpy(&rc.bdaddr, &cr->bdaddr); + rc.reason = 0x0f; + hci_send_cmd(hdev, OGF_LINK_CTL, OCF_REJECT_CONN_REQ, + REJECT_CONN_REQ_CP_SIZE, &rc); + } +} + +/* Connect Complete */ +static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + evt_conn_complete *cc = (evt_conn_complete *) skb->data; + struct hci_conn *conn = NULL; + + DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + conn = conn_hash_lookup_ba(hdev, cc->link_type, &cc->bdaddr); + if (!conn) { + hci_dev_unlock(hdev); + return; + } + + if (!cc->status) { + conn->handle = __le16_to_cpu(cc->handle); + conn->state = BT_CONNECTED; + + if (test_bit(HCI_AUTH, &hdev->flags)) + conn->link_mode |= HCI_LM_AUTH; + + if (test_bit(HCI_ENCRYPT, &hdev->flags)) + conn->link_mode |= HCI_LM_ENCRYPT; + + + /* Set link policy */ + if (conn->type == ACL_LINK && hdev->link_policy) { + write_link_policy_cp lp; + lp.handle = cc->handle; + lp.policy = __cpu_to_le16(hdev->link_policy); + hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY, + WRITE_LINK_POLICY_CP_SIZE, &lp); + } + + /* Set packet type for incomming connection */ + if (!conn->out) { + change_conn_ptype_cp cp; + cp.handle = cc->handle; + cp.pkt_type = (conn->type == ACL_LINK) ? + __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK): + __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); + + hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE, + CHANGE_CONN_PTYPE_CP_SIZE, &cp); + } + } else + conn->state = BT_CLOSED; + + if (conn->type == ACL_LINK) { + struct hci_conn *sco = conn->link; + if (sco) { + if (!cc->status) + hci_add_sco(sco, conn->handle); + else { + hci_proto_connect_cfm(sco, cc->status); + hci_conn_del(sco); + } + } + } + + hci_proto_connect_cfm(conn, cc->status); + if (cc->status) + hci_conn_del(conn); + + hci_dev_unlock(hdev); +} + +/* Disconnect Complete */ +static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + evt_disconn_complete *dc = (evt_disconn_complete *) skb->data; + struct hci_conn *conn = NULL; + __u16 handle = __le16_to_cpu(dc->handle); + + DBG("%s status %d", hdev->name, dc->status); + + if (dc->status) + return; + + hci_dev_lock(hdev); + + conn = conn_hash_lookup_handle(hdev, handle); + if (conn) { + conn->state = BT_CLOSED; + hci_proto_disconn_ind(conn, dc->reason); + hci_conn_del(conn); + } + + hci_dev_unlock(hdev); +} + +/* Number of completed packets */ +static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data; + __u16 *ptr; + int i; + + skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE); + + DBG("%s num_hndl %d", hdev->name, nc->num_hndl); + + if (skb->len < nc->num_hndl * 4) { + DBG("%s bad parameters", hdev->name); + return; + } + + tasklet_disable(&hdev->tx_task); + + for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) { + struct hci_conn *conn; + __u16 handle, count; + + handle = __le16_to_cpu(get_unaligned(ptr++)); + count = __le16_to_cpu(get_unaligned(ptr++)); + + conn = conn_hash_lookup_handle(hdev, handle); + if (conn) { + conn->sent -= count; + + if (conn->type == SCO_LINK) { + if ((hdev->sco_cnt += count) > hdev->sco_pkts) + hdev->sco_cnt = hdev->sco_pkts; + } else { + if ((hdev->acl_cnt += count) > hdev->acl_pkts) + hdev->acl_cnt = hdev->acl_pkts; + } + } + } + hci_sched_tx(hdev); + + tasklet_enable(&hdev->tx_task); +} + +/* Role Change */ +static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + evt_role_change *rc = (evt_role_change *) skb->data; + struct hci_conn *conn = NULL; + + DBG("%s status %d", hdev->name, rc->status); + + if (rc->status) + return; + + hci_dev_lock(hdev); + + conn = conn_hash_lookup_ba(hdev, ACL_LINK, &rc->bdaddr); + if (conn) { + if (rc->role) + conn->link_mode &= ~HCI_LM_MASTER; + else + conn->link_mode |= HCI_LM_MASTER; + } + + hci_dev_unlock(hdev); +} + +/* Authentication Complete */ +static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + evt_auth_complete *ac = (evt_auth_complete *) skb->data; + struct hci_conn *conn = NULL; + __u16 handle = __le16_to_cpu(ac->handle); + + DBG("%s status %d", hdev->name, ac->status); + + hci_dev_lock(hdev); + + conn = conn_hash_lookup_handle(hdev, handle); + if (conn) { + if (!ac->status) + conn->link_mode |= HCI_LM_AUTH; + clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); + + hci_proto_auth_cfm(conn, ac->status); + + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { + if (!ac->status) { + set_conn_encrypt_cp ce; + ce.handle = __cpu_to_le16(conn->handle); + ce.encrypt = 1; + hci_send_cmd(conn->hdev, OGF_LINK_CTL, + OCF_SET_CONN_ENCRYPT, + SET_CONN_ENCRYPT_CP_SIZE, &ce); + } else { + clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); + hci_proto_encrypt_cfm(conn, ac->status); + } + } + } + + hci_dev_unlock(hdev); +} + +/* Encryption Change */ +static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + evt_encrypt_change *ec = (evt_encrypt_change *) skb->data; + struct hci_conn *conn = NULL; + __u16 handle = __le16_to_cpu(ec->handle); + + DBG("%s status %d", hdev->name, ec->status); + + hci_dev_lock(hdev); + + conn = conn_hash_lookup_handle(hdev, handle); + if (conn) { + if (!ec->status) { + if (ec->encrypt) + conn->link_mode |= HCI_LM_ENCRYPT; + else + conn->link_mode &= ~HCI_LM_ENCRYPT; + } + clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); + + hci_proto_encrypt_cfm(conn, ec->status); + } + + hci_dev_unlock(hdev); +} + +void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) +{ + hci_event_hdr *he = (hci_event_hdr *) skb->data; + evt_cmd_status *cs; + evt_cmd_complete *ec; + __u16 opcode, ocf, ogf; + + skb_pull(skb, HCI_EVENT_HDR_SIZE); + + DBG("%s evt 0x%x", hdev->name, he->evt); + + switch (he->evt) { + case EVT_NUM_COMP_PKTS: + hci_num_comp_pkts_evt(hdev, skb); + break; + + case EVT_INQUIRY_COMPLETE: + hci_inquiry_complete_evt(hdev, skb); + break; + + case EVT_INQUIRY_RESULT: + hci_inquiry_result_evt(hdev, skb); + break; + + case EVT_CONN_REQUEST: + hci_conn_request_evt(hdev, skb); + break; + + case EVT_CONN_COMPLETE: + hci_conn_complete_evt(hdev, skb); + break; + + case EVT_DISCONN_COMPLETE: + hci_disconn_complete_evt(hdev, skb); + break; + + case EVT_ROLE_CHANGE: + hci_role_change_evt(hdev, skb); + break; + + case EVT_AUTH_COMPLETE: + hci_auth_complete_evt(hdev, skb); + break; + + case EVT_ENCRYPT_CHANGE: + hci_encrypt_change_evt(hdev, skb); + break; + + case EVT_CMD_STATUS: + cs = (evt_cmd_status *) skb->data; + skb_pull(skb, EVT_CMD_STATUS_SIZE); + + opcode = __le16_to_cpu(cs->opcode); + ogf = cmd_opcode_ogf(opcode); + ocf = cmd_opcode_ocf(opcode); + + switch (ogf) { + case OGF_INFO_PARAM: + hci_cs_info_param(hdev, ocf, cs->status); + break; + + case OGF_HOST_CTL: + hci_cs_host_ctl(hdev, ocf, cs->status); + break; + + case OGF_LINK_CTL: + hci_cs_link_ctl(hdev, ocf, cs->status); + break; + + case OGF_LINK_POLICY: + hci_cs_link_policy(hdev, ocf, cs->status); + break; + + default: + DBG("%s Command Status OGF %x", hdev->name, ogf); + break; + }; + + if (cs->ncmd) { + atomic_set(&hdev->cmd_cnt, 1); + if (!skb_queue_empty(&hdev->cmd_q)) + hci_sched_cmd(hdev); + } + break; + + case EVT_CMD_COMPLETE: + ec = (evt_cmd_complete *) skb->data; + skb_pull(skb, EVT_CMD_COMPLETE_SIZE); + + opcode = __le16_to_cpu(ec->opcode); + ogf = cmd_opcode_ogf(opcode); + ocf = cmd_opcode_ocf(opcode); + + switch (ogf) { + case OGF_INFO_PARAM: + hci_cc_info_param(hdev, ocf, skb); + break; + + case OGF_HOST_CTL: + hci_cc_host_ctl(hdev, ocf, skb); + break; + + case OGF_LINK_CTL: + hci_cc_link_ctl(hdev, ocf, skb); + break; + + case OGF_LINK_POLICY: + hci_cc_link_policy(hdev, ocf, skb); + break; + + default: + DBG("%s Command Completed OGF %x", hdev->name, ogf); + break; + }; + + if (ec->ncmd) { + atomic_set(&hdev->cmd_cnt, 1); + if (!skb_queue_empty(&hdev->cmd_q)) + hci_sched_cmd(hdev); + } + break; + }; + + kfree_skb(skb); + hdev->stat.evt_rx++; +} + +/* General internal stack event */ +void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) +{ + hci_event_hdr *eh; + evt_stack_internal *si; + struct sk_buff *skb; + int size; + void *ptr; + + size = HCI_EVENT_HDR_SIZE + EVT_STACK_INTERNAL_SIZE + dlen; + skb = bluez_skb_alloc(size, GFP_ATOMIC); + if (!skb) + return; + + ptr = skb_put(skb, size); + + eh = ptr; + eh->evt = EVT_STACK_INTERNAL; + eh->plen = EVT_STACK_INTERNAL_SIZE + dlen; + ptr += HCI_EVENT_HDR_SIZE; + + si = ptr; + si->type = type; + memcpy(si->data, data, dlen); + + skb->pkt_type = HCI_EVENT_PKT; + skb->dev = (void *) hdev; + hci_send_to_sock(hdev, skb); + kfree_skb(skb); +} diff -urN linux-2.4.19-pre6/net/bluetooth/hci_sock.c linux-2.4.19-pre7/net/bluetooth/hci_sock.c --- linux-2.4.19-pre6/net/bluetooth/hci_sock.c Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/net/bluetooth/hci_sock.c Mon Apr 15 21:55:00 2002 @@ -25,7 +25,7 @@ /* * BlueZ HCI socket layer. * - * $Id: hci_sock.c,v 1.9 2001/08/05 06:02:16 maxk Exp $ + * $Id: hci_sock.c,v 1.2 2002/03/26 17:56:44 maxk Exp $ */ #include @@ -51,7 +51,6 @@ #include #include -#include #include #ifndef HCI_SOCK_DEBUG @@ -59,25 +58,31 @@ #define DBG( A... ) #endif -/* HCI socket interface */ +/* ----- HCI socket interface ----- */ + +/* Security filter */ +static struct hci_sec_filter hci_sec_filter = { + /* Packet types */ + 0x10, + /* Events */ + { 0xd9fe, 0x0 }, + /* Commands */ + { + /* OGF_LINK_CTL */ + { 0x2a000002, 0x0, 0x0, 0x0 }, + /* OGF_LINK_POLICY */ + { 0x1200, 0x0, 0x0, 0x0 }, + /* OGF_HOST_CTL */ + { 0x80100000, 0xa, 0x0, 0x0 }, + /* OGF_INFO_PARAM */ + { 0x22a, 0x0, 0x0, 0x0 } + } +}; static struct bluez_sock_list hci_sk_list = { lock: RW_LOCK_UNLOCKED }; -static struct sock *hci_sock_lookup(struct hci_dev *hdev) -{ - struct sock *sk; - - read_lock(&hci_sk_list.lock); - for (sk = hci_sk_list.head; sk; sk = sk->next) { - if (hci_pi(sk)->hdev == hdev) - break; - } - read_unlock(&hci_sk_list.lock); - return sk; -} - /* Send frame to RAW socket */ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) { @@ -87,7 +92,7 @@ read_lock(&hci_sk_list.lock); for (sk = hci_sk_list.head; sk; sk = sk->next) { - struct hci_filter *flt; + struct hci_filter *flt; struct sk_buff *nskb; if (sk->state != BT_BOUND || hci_pi(sk)->hdev != hdev) @@ -100,14 +105,20 @@ /* Apply filter */ flt = &hci_pi(sk)->filter; - if (!test_bit(skb->pkt_type, &flt->type_mask)) + if (!test_bit((skb->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask)) continue; if (skb->pkt_type == HCI_EVENT_PKT) { - register int evt = (*(__u8 *)skb->data & 63); - + register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS); + if (!test_bit(evt, &flt->event_mask)) continue; + + if (flt->opcode && ((evt == EVT_CMD_COMPLETE && + flt->opcode != *(__u16 *)(skb->data + 3)) || + (evt == EVT_CMD_STATUS && + flt->opcode != *(__u16 *)(skb->data + 4)))) + continue; } if (!(nskb = skb_clone(skb, GFP_ATOMIC))) @@ -116,8 +127,9 @@ /* Put type byte before the data */ memcpy(skb_push(nskb, 1), &nskb->pkt_type, 1); - skb_queue_tail(&sk->receive_queue, nskb); - sk->data_ready(sk, nskb->len); + if (sock_queue_rcv_skb(sk, nskb)) + kfree_skb(nskb); + } read_unlock(&hci_sk_list.lock); } @@ -135,9 +147,7 @@ bluez_sock_unlink(&hci_sk_list, sk); if (hdev) { - if (!hci_sock_lookup(hdev)) - hdev->flags &= ~HCI_SOCK; - + atomic_dec(&hdev->promisc); hci_dev_put(hdev); } @@ -149,24 +159,55 @@ sock_put(sk); MOD_DEC_USE_COUNT; - return 0; } +/* Ioctls that require bound socket */ +static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) +{ + struct hci_dev *hdev = hci_pi(sk)->hdev; + + if (!hdev) + return -EBADFD; + + switch (cmd) { + case HCISETRAW: + if (!capable(CAP_NET_ADMIN)) + return -EACCES; + + if (arg) + set_bit(HCI_RAW, &hdev->flags); + else + clear_bit(HCI_RAW, &hdev->flags); + + return 0; + + case HCIGETCONNINFO: + return hci_get_conn_info(hdev, arg); + + default: + if (hdev->ioctl) + return hdev->ioctl(hdev, cmd, arg); + return -EINVAL; + } +} + static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; - struct hci_dev *hdev = hci_pi(sk)->hdev; - __u32 mode; + int err; DBG("cmd %x arg %lx", cmd, arg); switch (cmd) { - case HCIGETINFO: - return hci_dev_info(arg); - case HCIGETDEVLIST: - return hci_dev_list(arg); + return hci_get_dev_list(arg); + + case HCIGETDEVINFO: + return hci_get_dev_info(arg); + + case HCIGETCONNLIST: + return hci_get_conn_list(arg); case HCIDEVUP: if (!capable(CAP_NET_ADMIN)) @@ -183,48 +224,31 @@ return -EACCES; return hci_dev_reset(arg); - case HCIRESETSTAT: + case HCIDEVRESTAT: if (!capable(CAP_NET_ADMIN)) return -EACCES; return hci_dev_reset_stat(arg); case HCISETSCAN: - if (!capable(CAP_NET_ADMIN)) - return -EACCES; - return hci_dev_setscan(arg); - case HCISETAUTH: - if (!capable(CAP_NET_ADMIN)) - return -EACCES; - return hci_dev_setauth(arg); - - case HCISETRAW: - if (!capable(CAP_NET_ADMIN)) - return -EACCES; - - if (!hdev) - return -EBADFD; - - if (arg) - mode = HCI_RAW; - else - mode = HCI_NORMAL; - - return hci_dev_setmode(hdev, mode); - + case HCISETENCRYPT: case HCISETPTYPE: + case HCISETLINKPOL: + case HCISETLINKMODE: + case HCISETACLMTU: + case HCISETSCOMTU: if (!capable(CAP_NET_ADMIN)) return -EACCES; - return hci_dev_setptype(arg); + return hci_dev_cmd(cmd, arg); case HCIINQUIRY: return hci_inquiry(arg); - case HCIGETCONNLIST: - return hci_conn_list(arg); - default: - return -EINVAL; + lock_sock(sk); + err = hci_sock_bound_ioctl(sk, cmd, arg); + release_sock(sk); + return err; }; } @@ -233,28 +257,35 @@ struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr; struct sock *sk = sock->sk; struct hci_dev *hdev = NULL; + int err = 0; DBG("sock %p sk %p", sock, sk); if (!haddr || haddr->hci_family != AF_BLUETOOTH) return -EINVAL; + lock_sock(sk); + if (hci_pi(sk)->hdev) { - /* Already bound */ - return 0; + err = -EALREADY; + goto done; } if (haddr->hci_dev != HCI_DEV_NONE) { - if (!(hdev = hci_dev_get(haddr->hci_dev))) - return -ENODEV; + if (!(hdev = hci_dev_get(haddr->hci_dev))) { + err = -ENODEV; + goto done; + } - hdev->flags |= HCI_SOCK; + atomic_inc(&hdev->promisc); } hci_pi(sk)->hdev = hdev; sk->state = BT_BOUND; - return 0; +done: + release_sock(sk); + return err; } static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer) @@ -264,71 +295,42 @@ DBG("sock %p sk %p", sock, sk); + lock_sock(sk); + *addr_len = sizeof(*haddr); haddr->hci_family = AF_BLUETOOTH; haddr->hci_dev = hci_pi(sk)->hdev->id; + release_sock(sk); return 0; } -static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, - struct scm_cookie *scm) -{ - struct sock *sk = sock->sk; - struct hci_dev *hdev = hci_pi(sk)->hdev; - struct sk_buff *skb; - int err; - - DBG("sock %p sk %p", sock, sk); - - if (msg->msg_flags & MSG_OOB) - return -EOPNOTSUPP; - - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE)) - return -EINVAL; - - if (!hdev) - return -EBADFD; - - if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err))) - return err; - - if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { - kfree_skb(skb); - return -EFAULT; - } - - skb->dev = (void *) hdev; - skb->pkt_type = *((unsigned char *) skb->data); - skb_pull(skb, 1); - - /* Send frame to HCI core */ - hci_send_raw(skb); - - return len; -} - static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) { __u32 mask = hci_pi(sk)->cmsg_mask; if (mask & HCI_CMSG_DIR) put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(int), &bluez_cb(skb)->incomming); + + if (mask & HCI_CMSG_TSTAMP) + put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(skb->stamp), &skb->stamp); } -static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, - int flags, struct scm_cookie *scm) +static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm) { int noblock = flags & MSG_DONTWAIT; struct sock *sk = sock->sk; struct sk_buff *skb; int copied, err; - DBG("sock %p sk %p", sock, sk); + DBG("sock %p, sk %p", sock, sk); - if (flags & (MSG_OOB | MSG_PEEK)) + if (flags & (MSG_OOB)) return -EOPNOTSUPP; + if (sk->state == BT_CLOSED) + return 0; + if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) return err; @@ -343,18 +345,83 @@ skb->h.raw = skb->data; err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); - if (hci_pi(sk)->cmsg_mask) - hci_sock_cmsg(sk, msg, skb); - + hci_sock_cmsg(sk, msg, skb); + skb_free_datagram(sk, skb); return err ? : copied; } +static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, + struct scm_cookie *scm) +{ + struct sock *sk = sock->sk; + struct hci_dev *hdev; + struct sk_buff *skb; + int err; + + DBG("sock %p sk %p", sock, sk); + + if (msg->msg_flags & MSG_OOB) + return -EOPNOTSUPP; + + if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE)) + return -EINVAL; + + if (len < 4) + return -EINVAL; + + lock_sock(sk); + + if (!(hdev = hci_pi(sk)->hdev)) { + err = -EBADFD; + goto done; + } + + if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err))) + goto done; + + if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { + err = -EFAULT; + goto drop; + } + + skb->pkt_type = *((unsigned char *) skb->data); + skb_pull(skb, 1); + + if (!capable(CAP_NET_RAW)) { + err = -EPERM; + + if (skb->pkt_type == HCI_COMMAND_PKT) { + __u16 opcode = __le16_to_cpu(*(__u16 *)skb->data); + __u16 ogf = cmd_opcode_ogf(opcode) - 1; + __u16 ocf = cmd_opcode_ocf(opcode) & HCI_FLT_OCF_BITS; + + if (ogf > HCI_SFLT_MAX_OGF || + !test_bit(ocf, &hci_sec_filter.ocf_mask[ogf])) + goto drop; + } else + goto drop; + } + + /* Send frame to HCI core */ + skb->dev = (void *) hdev; + hci_send_raw(skb); + err = len; + +done: + release_sock(sk); + return err; + +drop: + kfree_skb(skb); + goto done; +} + int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int len) { struct sock *sk = sock->sk; - struct hci_filter flt; + struct hci_filter flt = { opcode: 0 }; int err = 0, opt = 0; DBG("sk %p, opt %d", sk, optname); @@ -363,8 +430,10 @@ switch (optname) { case HCI_DATA_DIR: - if (get_user(opt, (int *)optval)) - return -EFAULT; + if (get_user(opt, (int *)optval)) { + err = -EFAULT; + break; + } if (opt) hci_pi(sk)->cmsg_mask |= HCI_CMSG_DIR; @@ -372,12 +441,31 @@ hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_DIR; break; + case HCI_TIME_STAMP: + if (get_user(opt, (int *)optval)) { + err = -EFAULT; + break; + } + + if (opt) + hci_pi(sk)->cmsg_mask |= HCI_CMSG_TSTAMP; + else + hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_TSTAMP; + break; + case HCI_FILTER: len = MIN(len, sizeof(struct hci_filter)); if (copy_from_user(&flt, optval, len)) { err = -EFAULT; break; } + + if (!capable(CAP_NET_RAW)) { + flt.type_mask &= hci_sec_filter.type_mask; + flt.event_mask[0] &= hci_sec_filter.event_mask[0]; + flt.event_mask[1] &= hci_sec_filter.event_mask[1]; + } + memcpy(&hci_pi(sk)->filter, &flt, len); break; @@ -409,6 +497,16 @@ return -EFAULT; break; + case HCI_TIME_STAMP: + if (hci_pi(sk)->cmsg_mask & HCI_CMSG_TSTAMP) + opt = 1; + else + opt = 0; + + if (put_user(opt, optval)) + return -EFAULT; + break; + case HCI_FILTER: len = MIN(len, sizeof(struct hci_filter)); if (copy_to_user(optval, &hci_pi(sk)->filter, len)) @@ -464,44 +562,31 @@ sk->protocol = protocol; sk->state = BT_OPEN; - /* Initialize filter */ - hci_pi(sk)->filter.type_mask = (1<filter.event_mask[0] = ~0L; - hci_pi(sk)->filter.event_mask[1] = ~0L; - bluez_sock_link(&hci_sk_list, sk); MOD_INC_USE_COUNT; - return 0; } static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct hci_dev *hdev = (struct hci_dev *) ptr; - struct sk_buff *skb; - + evt_si_device sd; + DBG("hdev %s event %ld", hdev->name, event); /* Send event to sockets */ - if ((skb = bluez_skb_alloc(HCI_EVENT_HDR_SIZE + EVT_HCI_DEV_EVENT_SIZE, GFP_ATOMIC))) { - hci_event_hdr eh = { EVT_HCI_DEV_EVENT, EVT_HCI_DEV_EVENT_SIZE }; - evt_hci_dev_event he = { event, hdev->id }; - - skb->pkt_type = HCI_EVENT_PKT; - memcpy(skb_put(skb, HCI_EVENT_HDR_SIZE), &eh, HCI_EVENT_HDR_SIZE); - memcpy(skb_put(skb, EVT_HCI_DEV_EVENT_SIZE), &he, EVT_HCI_DEV_EVENT_SIZE); - - hci_send_to_sock(NULL, skb); - kfree_skb(skb); - } - + sd.event = event; + sd.dev_id = hdev->id; + hci_si_event(NULL, EVT_SI_DEVICE, EVT_SI_DEVICE_SIZE, &sd); + if (event == HCI_DEV_UNREG) { struct sock *sk; /* Detach sockets from device */ read_lock(&hci_sk_list.lock); for (sk = hci_sk_list.head; sk; sk = sk->next) { + bh_lock_sock(sk); if (hci_pi(sk)->hdev == hdev) { hci_pi(sk)->hdev = NULL; sk->err = EPIPE; @@ -510,6 +595,7 @@ hci_dev_put(hdev); } + bh_unlock_sock(sk); } read_unlock(&hci_sk_list.lock); } @@ -534,7 +620,6 @@ } hci_register_notifier(&hci_sock_nblock); - return 0; } @@ -544,6 +629,5 @@ ERR("Can't unregister HCI socket"); hci_unregister_notifier(&hci_sock_nblock); - return 0; } diff -urN linux-2.4.19-pre6/net/bluetooth/l2cap.c linux-2.4.19-pre7/net/bluetooth/l2cap.c --- linux-2.4.19-pre6/net/bluetooth/l2cap.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/net/bluetooth/l2cap.c Mon Apr 15 21:55:00 2002 @@ -0,0 +1,2046 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * BlueZ L2CAP core and sockets. + * + * $Id: l2cap.c,v 1.6 2002/04/03 23:34:37 maxk Exp $ + */ +#define VERSION "2.0" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#ifndef L2CAP_DEBUG +#undef DBG +#define DBG( A... ) +#endif + +static struct proto_ops l2cap_sock_ops; + +struct bluez_sock_list l2cap_sk_list = { + lock: RW_LOCK_UNLOCKED +}; + +static int l2cap_conn_del(struct hci_conn *conn, int err); + +static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent); +static void l2cap_chan_del(struct sock *sk, int err); +static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len); + +static void __l2cap_sock_close(struct sock *sk, int reason); +static void l2cap_sock_close(struct sock *sk); +static void l2cap_sock_kill(struct sock *sk); + +static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data); +static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data); + +/* ----- L2CAP timers ------ */ +static void l2cap_sock_timeout(unsigned long arg) +{ + struct sock *sk = (struct sock *) arg; + + DBG("sock %p state %d", sk, sk->state); + + bh_lock_sock(sk); + __l2cap_sock_close(sk, ETIMEDOUT); + bh_unlock_sock(sk); + + l2cap_sock_kill(sk); + sock_put(sk); +} + +static void l2cap_sock_set_timer(struct sock *sk, long timeout) +{ + DBG("sk %p state %d timeout %ld", sk, sk->state, timeout); + + if (!mod_timer(&sk->timer, jiffies + timeout)) + sock_hold(sk); +} + +static void l2cap_sock_clear_timer(struct sock *sk) +{ + DBG("sock %p state %d", sk, sk->state); + + if (timer_pending(&sk->timer) && del_timer(&sk->timer)) + __sock_put(sk); +} + +static void l2cap_sock_init_timer(struct sock *sk) +{ + init_timer(&sk->timer); + sk->timer.function = l2cap_sock_timeout; + sk->timer.data = (unsigned long)sk; +} + +/* -------- L2CAP connections --------- */ +static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, __u8 status) +{ + struct l2cap_conn *conn; + + if ((conn = hcon->l2cap_data)) + return conn; + + if (status) + return conn; + + if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_ATOMIC))) + return NULL; + memset(conn, 0, sizeof(struct l2cap_conn)); + + hcon->l2cap_data = conn; + conn->hcon = hcon; + + conn->mtu = hcon->hdev->acl_mtu; + conn->src = &hcon->hdev->bdaddr; + conn->dst = &hcon->dst; + + spin_lock_init(&conn->lock); + conn->chan_list.lock = RW_LOCK_UNLOCKED; + + DBG("hcon %p conn %p", hcon, conn); + + MOD_INC_USE_COUNT; + return conn; +} + +static int l2cap_conn_del(struct hci_conn *hcon, int err) +{ + struct l2cap_conn *conn; + struct sock *sk; + + if (!(conn = hcon->l2cap_data)) + return 0; + + DBG("hcon %p conn %p, err %d", hcon, conn, err); + + if (conn->rx_skb) + kfree_skb(conn->rx_skb); + + /* Kill channels */ + while ((sk = conn->chan_list.head)) { + bh_lock_sock(sk); + l2cap_chan_del(sk, err); + bh_unlock_sock(sk); + l2cap_sock_kill(sk); + } + + hcon->l2cap_data = NULL; + kfree(conn); + + MOD_DEC_USE_COUNT; + return 0; +} + +int l2cap_connect(struct sock *sk) +{ + bdaddr_t *src = &bluez_pi(sk)->src; + bdaddr_t *dst = &bluez_pi(sk)->dst; + struct l2cap_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; + int err = 0; + + DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm); + + if (!(hdev = hci_get_route(dst, src))) + return -EHOSTUNREACH; + + hci_dev_lock_bh(hdev); + + err = -ENOMEM; + + hcon = hci_connect(hdev, ACL_LINK, dst); + if (!hcon) + goto done; + + conn = l2cap_conn_add(hcon, 0); + if (!conn) { + hci_conn_put(hcon); + goto done; + } + + err = 0; + + /* Update source addr of the socket */ + bacpy(src, conn->src); + + l2cap_chan_add(conn, sk, NULL); + + sk->state = BT_CONNECT; + l2cap_sock_set_timer(sk, sk->sndtimeo); + + if (hcon->state == BT_CONNECTED) { + if (sk->type == SOCK_SEQPACKET) { + l2cap_conn_req req; + req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); + req.psm = l2cap_pi(sk)->psm; + l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req); + } else { + l2cap_sock_clear_timer(sk); + sk->state = BT_CONNECTED; + } + } + +done: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + return err; +} + +/* -------- Socket interface ---------- */ +static struct sock *__l2cap_get_sock_by_addr(struct sockaddr_l2 *addr) +{ + bdaddr_t *src = &addr->l2_bdaddr; + __u16 psm = addr->l2_psm; + struct sock *sk; + + for (sk = l2cap_sk_list.head; sk; sk = sk->next) { + if (l2cap_pi(sk)->psm == psm && + !bacmp(&bluez_pi(sk)->src, src)) + break; + } + + return sk; +} + +/* Find socket listening on psm and source bdaddr. + * Returns closest match. + */ +static struct sock *l2cap_get_sock_listen(bdaddr_t *src, __u16 psm) +{ + struct sock *sk, *sk1 = NULL; + + read_lock(&l2cap_sk_list.lock); + + for (sk = l2cap_sk_list.head; sk; sk = sk->next) { + if (sk->state != BT_LISTEN) + continue; + + if (l2cap_pi(sk)->psm == psm) { + /* Exact match. */ + if (!bacmp(&bluez_pi(sk)->src, src)) + break; + + /* Closest match */ + if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY)) + sk1 = sk; + } + } + + read_unlock(&l2cap_sk_list.lock); + return sk ? sk : sk1; +} + +static void l2cap_sock_destruct(struct sock *sk) +{ + DBG("sk %p", sk); + + skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->write_queue); + + MOD_DEC_USE_COUNT; +} + +static void l2cap_sock_cleanup_listen(struct sock *parent) +{ + struct sock *sk; + + DBG("parent %p", parent); + + /* Close not yet accepted channels */ + while ((sk = bluez_accept_dequeue(parent, NULL))) + l2cap_sock_close(sk); + + parent->state = BT_CLOSED; + parent->zapped = 1; +} + +/* Kill socket (only if zapped and orphan) + * Must be called on unlocked socket. + */ +static void l2cap_sock_kill(struct sock *sk) +{ + if (!sk->zapped || sk->socket) + return; + + DBG("sk %p state %d", sk, sk->state); + + /* Kill poor orphan */ + bluez_sock_unlink(&l2cap_sk_list, sk); + sk->dead = 1; + sock_put(sk); +} + +/* Close socket. + */ +static void __l2cap_sock_close(struct sock *sk, int reason) +{ + DBG("sk %p state %d socket %p", sk, sk->state, sk->socket); + + switch (sk->state) { + case BT_LISTEN: + l2cap_sock_cleanup_listen(sk); + break; + + case BT_CONNECTED: + case BT_CONFIG: + if (sk->type == SOCK_SEQPACKET) { + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + l2cap_disconn_req req; + + sk->state = BT_DISCONN; + l2cap_sock_set_timer(sk, HZ * 5); + + req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); + req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); + l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req); + } else { + l2cap_chan_del(sk, reason); + } + break; + + case BT_CONNECT: + case BT_CONNECT2: + case BT_DISCONN: + l2cap_chan_del(sk, reason); + break; + + default: + sk->zapped = 1; + break; + }; +} + +/* Must be called on unlocked socket. */ +static void l2cap_sock_close(struct sock *sk) +{ + l2cap_sock_clear_timer(sk); + + lock_sock(sk); + __l2cap_sock_close(sk, ECONNRESET); + release_sock(sk); + + l2cap_sock_kill(sk); +} + +static void l2cap_sock_init(struct sock *sk, struct sock *parent) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + + DBG("sk %p", sk); + + if (parent) { + sk->type = parent->type; + + pi->imtu = l2cap_pi(parent)->imtu; + pi->omtu = l2cap_pi(parent)->omtu; + pi->link_mode = l2cap_pi(parent)->link_mode; + } else { + pi->imtu = L2CAP_DEFAULT_MTU; + pi->omtu = 0; + pi->link_mode = 0; + } + + /* Default config options */ + pi->conf_mtu = L2CAP_DEFAULT_MTU; + pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; +} + +static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio) +{ + struct sock *sk; + + if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1))) + return NULL; + + bluez_sock_init(sock, sk); + + sk->zapped = 0; + + sk->destruct = l2cap_sock_destruct; + sk->sndtimeo = L2CAP_CONN_TIMEOUT; + + sk->protocol = proto; + sk->state = BT_OPEN; + + l2cap_sock_init_timer(sk); + + bluez_sock_link(&l2cap_sk_list, sk); + + MOD_INC_USE_COUNT; + return sk; +} + +static int l2cap_sock_create(struct socket *sock, int protocol) +{ + struct sock *sk; + + DBG("sock %p", sock); + + sock->state = SS_UNCONNECTED; + + if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_RAW) + return -ESOCKTNOSUPPORT; + + sock->ops = &l2cap_sock_ops; + + if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL))) + return -ENOMEM; + + l2cap_sock_init(sk, NULL); + return 0; +} + +static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) +{ + struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; + struct sock *sk = sock->sk; + int err = 0; + + DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm); + + if (!addr || addr->sa_family != AF_BLUETOOTH) + return -EINVAL; + + lock_sock(sk); + + if (sk->state != BT_OPEN) { + err = -EBADFD; + goto done; + } + + write_lock(&l2cap_sk_list.lock); + + if (la->l2_psm && __l2cap_get_sock_by_addr(la)) { + err = -EADDRINUSE; + goto unlock; + } + + /* Save source address */ + bacpy(&bluez_pi(sk)->src, &la->l2_bdaddr); + l2cap_pi(sk)->psm = la->l2_psm; + sk->state = BT_BOUND; + +unlock: + write_unlock(&l2cap_sk_list.lock); + +done: + release_sock(sk); + return err; +} + +static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) +{ + struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; + struct sock *sk = sock->sk; + int err = 0; + + lock_sock(sk); + + DBG("sk %p", sk); + + if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) { + err = -EINVAL; + goto done; + } + + if (sk->type == SOCK_SEQPACKET && !la->l2_psm) { + err = -EINVAL; + goto done; + } + + switch(sk->state) { + case BT_CONNECT: + case BT_CONNECT2: + case BT_CONFIG: + /* Already connecting */ + goto wait; + + case BT_CONNECTED: + /* Already connected */ + goto done; + + case BT_OPEN: + case BT_BOUND: + /* Can connect */ + break; + + default: + err = -EBADFD; + goto done; + } + + /* Set destination address and psm */ + bacpy(&bluez_pi(sk)->dst, &la->l2_bdaddr); + l2cap_pi(sk)->psm = la->l2_psm; + + if ((err = l2cap_connect(sk))) + goto done; + +wait: + err = bluez_sock_w4_connect(sk, flags); + +done: + release_sock(sk); + return err; +} + +int l2cap_sock_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + int err = 0; + + DBG("sk %p backlog %d", sk, backlog); + + lock_sock(sk); + + if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) { + err = -EBADFD; + goto done; + } + + if (!l2cap_pi(sk)->psm) { + err = -EINVAL; + goto done; + } + + sk->max_ack_backlog = backlog; + sk->ack_backlog = 0; + sk->state = BT_LISTEN; + +done: + release_sock(sk); + return err; +} + +int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags) +{ + DECLARE_WAITQUEUE(wait, current); + struct sock *sk = sock->sk, *nsk; + long timeo; + int err = 0; + + lock_sock(sk); + + if (sk->state != BT_LISTEN) { + err = -EBADFD; + goto done; + } + + timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); + + DBG("sk %p timeo %ld", sk, timeo); + + /* Wait for an incoming connection. (wake-one). */ + add_wait_queue_exclusive(sk->sleep, &wait); + while (!(nsk = bluez_accept_dequeue(sk, newsock))) { + set_current_state(TASK_INTERRUPTIBLE); + if (!timeo) { + err = -EAGAIN; + break; + } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); + + if (sk->state != BT_LISTEN) { + err = -EBADFD; + break; + } + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + break; + } + } + set_current_state(TASK_RUNNING); + remove_wait_queue(sk->sleep, &wait); + + if (err) + goto done; + + newsock->state = SS_CONNECTED; + + DBG("new socket %p", nsk); + +done: + release_sock(sk); + return err; +} + +static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer) +{ + struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; + struct sock *sk = sock->sk; + + DBG("sock %p, sk %p", sock, sk); + + addr->sa_family = AF_BLUETOOTH; + *len = sizeof(struct sockaddr_l2); + + if (peer) + bacpy(&la->l2_bdaddr, &bluez_pi(sk)->dst); + else + bacpy(&la->l2_bdaddr, &bluez_pi(sk)->src); + + la->l2_psm = l2cap_pi(sk)->psm; + + return 0; +} + +static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) +{ + struct sock *sk = sock->sk; + int err = 0; + + DBG("sock %p, sk %p", sock, sk); + + if (sk->err) + return sock_error(sk); + + if (msg->msg_flags & MSG_OOB) + return -EOPNOTSUPP; + + lock_sock(sk); + + if (sk->state == BT_CONNECTED) + err = l2cap_chan_send(sk, msg, len); + else + err = -ENOTCONN; + + release_sock(sk); + return err; +} + +static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) +{ + struct sock *sk = sock->sk; + struct l2cap_options opts; + int err = 0, len; + __u32 opt; + + DBG("sk %p", sk); + + lock_sock(sk); + + switch (optname) { + case L2CAP_OPTIONS: + len = MIN(sizeof(opts), optlen); + if (copy_from_user((char *)&opts, optval, len)) { + err = -EFAULT; + break; + } + l2cap_pi(sk)->imtu = opts.imtu; + l2cap_pi(sk)->omtu = opts.omtu; + break; + + case L2CAP_LM: + if (get_user(opt, (__u32 *)optval)) { + err = -EFAULT; + break; + } + + l2cap_pi(sk)->link_mode = opt; + break; + + default: + err = -ENOPROTOOPT; + break; + }; + + release_sock(sk); + return err; +} + +static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) +{ + struct sock *sk = sock->sk; + struct l2cap_options opts; + struct l2cap_conninfo cinfo; + int len, err = 0; + + if (get_user(len, optlen)) + return -EFAULT; + + lock_sock(sk); + + switch (optname) { + case L2CAP_OPTIONS: + opts.imtu = l2cap_pi(sk)->imtu; + opts.omtu = l2cap_pi(sk)->omtu; + opts.flush_to = l2cap_pi(sk)->flush_to; + + len = MIN(len, sizeof(opts)); + if (copy_to_user(optval, (char *)&opts, len)) + err = -EFAULT; + + break; + + case L2CAP_LM: + if (put_user(l2cap_pi(sk)->link_mode, (__u32 *)optval)) + err = -EFAULT; + break; + + case L2CAP_CONNINFO: + if (sk->state != BT_CONNECTED) { + err = -ENOTCONN; + break; + } + + cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle; + + len = MIN(len, sizeof(cinfo)); + if (copy_to_user(optval, (char *)&cinfo, len)) + err = -EFAULT; + + break; + + default: + err = -ENOPROTOOPT; + break; + }; + + release_sock(sk); + return err; +} + +static int l2cap_sock_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + + DBG("sock %p, sk %p", sock, sk); + + if (!sk) + return 0; + + sock_orphan(sk); + l2cap_sock_close(sk); + return 0; +} + +/* --------- L2CAP channels --------- */ +static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid) +{ + struct sock *s; + + for (s = l->head; s; s = l2cap_pi(s)->next_c) { + if (l2cap_pi(s)->dcid == cid) + break; + } + + return s; +} + +static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid) +{ + struct sock *s; + + for (s = l->head; s; s = l2cap_pi(s)->next_c) { + if (l2cap_pi(s)->scid == cid) + break; + } + + return s; +} + +/* Find channel with given SCID. + * Returns locked socket */ +static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid) +{ + struct sock *s; + read_lock(&l->lock); + s = __l2cap_get_chan_by_scid(l, cid); + if (s) bh_lock_sock(s); + read_unlock(&l->lock); + return s; +} + +static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l) +{ + __u16 cid = 0x0040; + + for (; cid < 0xffff; cid++) { + if(!__l2cap_get_chan_by_scid(l, cid)) + return cid; + } + + return 0; +} + +static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk) +{ + sock_hold(sk); + + if (l->head) + l2cap_pi(l->head)->prev_c = sk; + + l2cap_pi(sk)->next_c = l->head; + l2cap_pi(sk)->prev_c = NULL; + l->head = sk; +} + +static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) +{ + struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; + + write_lock(&l->lock); + if (sk == l->head) + l->head = next; + + if (next) + l2cap_pi(next)->prev_c = prev; + if (prev) + l2cap_pi(prev)->next_c = next; + write_unlock(&l->lock); + + __sock_put(sk); +} + +static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +{ + struct l2cap_chan_list *l = &conn->chan_list; + + DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); + + l2cap_pi(sk)->conn = conn; + + if (sk->type == SOCK_SEQPACKET) { + /* Alloc CID for normal socket */ + l2cap_pi(sk)->scid = l2cap_alloc_cid(l); + } else { + /* Raw socket can send only signalling messages */ + l2cap_pi(sk)->scid = 0x0001; + l2cap_pi(sk)->dcid = 0x0001; + l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; + } + + __l2cap_chan_link(l, sk); + + if (parent) + bluez_accept_enqueue(parent, sk); +} + +static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +{ + struct l2cap_chan_list *l = &conn->chan_list; + write_lock(&l->lock); + __l2cap_chan_add(conn, sk, parent); + write_unlock(&l->lock); +} + +/* Delete channel. + * Must be called on the locked socket. */ +static void l2cap_chan_del(struct sock *sk, int err) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct sock *parent = bluez_pi(sk)->parent; + + l2cap_sock_clear_timer(sk); + + DBG("sk %p, conn %p, err %d", sk, conn, err); + + if (conn) { + /* Unlink from channel list */ + l2cap_chan_unlink(&conn->chan_list, sk); + l2cap_pi(sk)->conn = NULL; + hci_conn_put(conn->hcon); + } + + sk->state = BT_CLOSED; + sk->err = err; + sk->zapped = 1; + + if (parent) + parent->data_ready(parent, 0); + else + sk->state_change(sk); +} + +static void l2cap_conn_ready(struct l2cap_conn *conn) +{ + struct l2cap_chan_list *l = &conn->chan_list; + struct sock *sk; + + DBG("conn %p", conn); + + read_lock(&l->lock); + + for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + bh_lock_sock(sk); + + if (sk->type != SOCK_SEQPACKET) { + l2cap_sock_clear_timer(sk); + sk->state = BT_CONNECTED; + sk->state_change(sk); + } else if (sk->state == BT_CONNECT) { + l2cap_conn_req req; + req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); + req.psm = l2cap_pi(sk)->psm; + l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req); + } + + bh_unlock_sock(sk); + } + + read_unlock(&l->lock); +} + +static void l2cap_chan_ready(struct sock *sk) +{ + struct sock *parent = bluez_pi(sk)->parent; + + DBG("sk %p, parent %p", sk, parent); + + l2cap_pi(sk)->conf_state = 0; + l2cap_sock_clear_timer(sk); + + if (!parent) { + /* Outgoing channel. + * Wake up socket sleeping on connect. + */ + sk->state = BT_CONNECTED; + sk->state_change(sk); + } else { + /* Incomming channel. + * Wake up socket sleeping on accept. + */ + parent->data_ready(parent, 0); + } +} + +/* Copy frame to all raw sockets on that connection */ +void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) +{ + struct l2cap_chan_list *l = &conn->chan_list; + struct sk_buff *nskb; + struct sock * sk; + + DBG("conn %p", conn); + + read_lock(&l->lock); + for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + if (sk->type != SOCK_RAW) + continue; + + /* Don't send frame to the socket it came from */ + if (skb->sk == sk) + continue; + + if (!(nskb = skb_clone(skb, GFP_ATOMIC))) + continue; + + if (sock_queue_rcv_skb(sk, nskb)) + kfree_skb(nskb); + } + read_unlock(&l->lock); +} + +static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct sk_buff *skb, **frag; + int err, size, count, sent=0; + l2cap_hdr *lh; + + /* Check outgoing MTU */ + if (len > l2cap_pi(sk)->omtu) + return -EINVAL; + + DBG("sk %p len %d", sk, len); + + /* First fragment (with L2CAP header) */ + count = MIN(conn->mtu - L2CAP_HDR_SIZE, len); + size = L2CAP_HDR_SIZE + count; + if (!(skb = bluez_skb_send_alloc(sk, size, msg->msg_flags & MSG_DONTWAIT, &err))) + return err; + + /* Create L2CAP header */ + lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); + lh->len = __cpu_to_le16(len); + lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid); + + if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { + err = -EFAULT; + goto fail; + } + + sent += count; + len -= count; + + /* Continuation fragments (no L2CAP header) */ + frag = &skb_shinfo(skb)->frag_list; + while (len) { + count = MIN(conn->mtu, len); + + *frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err); + if (!*frag) + goto fail; + + if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) { + err = -EFAULT; + goto fail; + } + + sent += count; + len -= count; + + frag = &(*frag)->next; + } + + if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0) + goto fail; + + return sent; + +fail: + kfree_skb(skb); + return err; +} + +/* --------- L2CAP signalling commands --------- */ +static inline __u8 l2cap_get_ident(struct l2cap_conn *conn) +{ + __u8 id; + + /* Get next available identificator. + * 1 - 199 are used by kernel. + * 200 - 254 are used by utilities like l2ping, etc + */ + + spin_lock(&conn->lock); + + if (++conn->tx_ident > 199) + conn->tx_ident = 1; + + id = conn->tx_ident; + + spin_unlock(&conn->lock); + + return id; +} + +static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, + __u8 code, __u8 ident, __u16 dlen, void *data) +{ + struct sk_buff *skb, **frag; + l2cap_cmd_hdr *cmd; + l2cap_hdr *lh; + int len, count; + + DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", conn, code, ident, dlen); + + len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen; + count = MIN(conn->mtu, len); + + skb = bluez_skb_alloc(count, GFP_ATOMIC); + if (!skb) + return NULL; + + lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); + lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen); + lh->cid = __cpu_to_le16(0x0001); + + cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE); + cmd->code = code; + cmd->ident = ident; + cmd->len = __cpu_to_le16(dlen); + + if (dlen) { + count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE; + memcpy(skb_put(skb, count), data, count); + data += count; + } + + len -= skb->len; + + /* Continuation fragments (no L2CAP header) */ + frag = &skb_shinfo(skb)->frag_list; + while (len) { + count = MIN(conn->mtu, len); + + *frag = bluez_skb_alloc(count, GFP_ATOMIC); + if (!*frag) + goto fail; + + memcpy(skb_put(*frag, count), data, count); + + len -= count; + data += count; + + frag = &(*frag)->next; + } + + return skb; + +fail: + kfree_skb(skb); + return NULL; +} + +static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data) +{ + __u8 ident = l2cap_get_ident(conn); + struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data); + + DBG("code 0x%2.2x", code); + + if (!skb) + return -ENOMEM; + return hci_send_acl(conn->hcon, skb, 0); +} + +static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data) +{ + struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data); + + DBG("code 0x%2.2x", code); + + if (!skb) + return -ENOMEM; + return hci_send_acl(conn->hcon, skb, 0); +} + +static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val) +{ + l2cap_conf_opt *opt = *ptr; + int len; + + len = L2CAP_CONF_OPT_SIZE + opt->len; + *ptr += len; + + *type = opt->type; + *olen = opt->len; + + switch (opt->len) { + case 1: + *val = *((__u8 *) opt->val); + break; + + case 2: + *val = __le16_to_cpu(*((__u16 *)opt->val)); + break; + + case 4: + *val = __le32_to_cpu(*((__u32 *)opt->val)); + break; + + default: + *val = (unsigned long) opt->val; + break; + }; + + DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val); + return len; +} + +static inline void l2cap_parse_conf_req(struct sock *sk, void *data, int len) +{ + int type, hint, olen; + unsigned long val; + void *ptr = data; + + DBG("sk %p len %d", sk, len); + + while (len >= L2CAP_CONF_OPT_SIZE) { + len -= l2cap_get_conf_opt(&ptr, &type, &olen, &val); + + hint = type & 0x80; + type &= 0x7f; + + switch (type) { + case L2CAP_CONF_MTU: + l2cap_pi(sk)->conf_mtu = val; + break; + + case L2CAP_CONF_FLUSH_TO: + l2cap_pi(sk)->flush_to = val; + break; + + case L2CAP_CONF_QOS: + break; + + default: + if (hint) + break; + + /* FIXME: Reject unknown option */ + break; + }; + } +} + +static void l2cap_add_conf_opt(void **ptr, __u8 type, __u8 len, unsigned long val) +{ + register l2cap_conf_opt *opt = *ptr; + + DBG("type 0x%2.2x len %d val 0x%lx", type, len, val); + + opt->type = type; + opt->len = len; + + switch (len) { + case 1: + *((__u8 *) opt->val) = val; + break; + + case 2: + *((__u16 *) opt->val) = __cpu_to_le16(val); + break; + + case 4: + *((__u32 *) opt->val) = __cpu_to_le32(val); + break; + + default: + memcpy(opt->val, (void *) val, len); + break; + }; + + *ptr += L2CAP_CONF_OPT_SIZE + len; +} + +static int l2cap_build_conf_req(struct sock *sk, void *data) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + l2cap_conf_req *req = (l2cap_conf_req *) data; + void *ptr = req->data; + + DBG("sk %p", sk); + + if (pi->imtu != L2CAP_DEFAULT_MTU) + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); + + /* FIXME. Need actual value of the flush timeout */ + //if (flush_to != L2CAP_DEFAULT_FLUSH_TO) + // l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to); + + req->dcid = __cpu_to_le16(pi->dcid); + req->flags = __cpu_to_le16(0); + + return ptr - data; +} + +static inline int l2cap_conf_output(struct sock *sk, void **ptr) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + int result = 0; + + /* Configure output options and let the other side know + * which ones we don't like. + */ + if (pi->conf_mtu < pi->omtu) { + l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, pi->omtu); + result = L2CAP_CONF_UNACCEPT; + } else { + pi->omtu = pi->conf_mtu; + } + + DBG("sk %p result %d", sk, result); + return result; +} + +static int l2cap_build_conf_rsp(struct sock *sk, void *data, int *result) +{ + l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data; + void *ptr = rsp->data; + + DBG("sk %p complete %d", sk, result ? 1 : 0); + + if (result) + *result = l2cap_conf_output(sk, &ptr); + + rsp->scid = __cpu_to_le16(l2cap_pi(sk)->dcid); + rsp->result = __cpu_to_le16(result ? *result : 0); + rsp->flags = __cpu_to_le16(0); + + return ptr - data; +} + +static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +{ + struct l2cap_chan_list *list = &conn->chan_list; + l2cap_conn_req *req = (l2cap_conn_req *) data; + l2cap_conn_rsp rsp; + struct sock *sk, *parent; + int result = 0, status = 0; + + __u16 dcid = 0, scid = __le16_to_cpu(req->scid); + __u16 psm = req->psm; + + DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); + + /* Check if we have socket listening on psm */ + if (!(parent = l2cap_get_sock_listen(conn->src, psm))) { + result = L2CAP_CR_BAD_PSM; + goto resp; + } + + write_lock(&list->lock); + bh_lock_sock(parent); + + result = L2CAP_CR_NO_MEM; + + /* Check if we already have channel with that dcid */ + if (__l2cap_get_chan_by_dcid(list, scid)) + goto unlock; + + /* Check for backlog size */ + if (parent->ack_backlog > parent->max_ack_backlog) { + DBG("backlog full %d", parent->ack_backlog); + goto unlock; + } + + if (!(sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC))) + goto unlock; + + l2cap_sock_init(sk, parent); + + bacpy(&bluez_pi(sk)->src, conn->src); + bacpy(&bluez_pi(sk)->dst, conn->dst); + l2cap_pi(sk)->psm = psm; + l2cap_pi(sk)->dcid = scid; + + hci_conn_hold(conn->hcon); + + __l2cap_chan_add(conn, sk, parent); + dcid = l2cap_pi(sk)->scid; + + l2cap_sock_set_timer(sk, sk->sndtimeo); + + /* Service level security */ + result = L2CAP_CR_PEND; + status = L2CAP_CS_AUTHEN_PEND; + sk->state = BT_CONNECT2; + l2cap_pi(sk)->ident = cmd->ident; + + if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) { + if (!hci_conn_encrypt(conn->hcon)) + goto unlock; + } else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) { + if (!hci_conn_auth(conn->hcon)) + goto unlock; + } + + sk->state = BT_CONFIG; + result = status = 0; + +unlock: + bh_unlock_sock(parent); + write_unlock(&list->lock); + +resp: + rsp.scid = __cpu_to_le16(scid); + rsp.dcid = __cpu_to_le16(dcid); + rsp.result = __cpu_to_le16(result); + rsp.status = __cpu_to_le16(status); + l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp); + return 0; +} + +static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +{ + l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data; + __u16 scid, dcid, result, status; + struct sock *sk; + char req[128]; + + scid = __le16_to_cpu(rsp->scid); + dcid = __le16_to_cpu(rsp->dcid); + result = __le16_to_cpu(rsp->result); + status = __le16_to_cpu(rsp->status); + + DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); + + if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) + return -ENOENT; + + switch (result) { + case L2CAP_CR_SUCCESS: + sk->state = BT_CONFIG; + l2cap_pi(sk)->dcid = dcid; + l2cap_pi(sk)->conf_state |= CONF_REQ_SENT; + + l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); + break; + + case L2CAP_CR_PEND: + break; + + default: + l2cap_chan_del(sk, ECONNREFUSED); + break; + } + + bh_unlock_sock(sk); + return 0; +} + +static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +{ + l2cap_conf_req * req = (l2cap_conf_req *) data; + __u16 dcid, flags; + __u8 rsp[64]; + struct sock *sk; + int result; + + dcid = __le16_to_cpu(req->dcid); + flags = __le16_to_cpu(req->flags); + + DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); + + if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) + return -ENOENT; + + l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE); + + if (flags & 0x01) { + /* Incomplete config. Send empty response. */ + l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp); + goto unlock; + } + + /* Complete config. */ + l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp); + + if (result) + goto unlock; + + /* Output config done */ + l2cap_pi(sk)->conf_state |= CONF_OUTPUT_DONE; + + if (l2cap_pi(sk)->conf_state & CONF_INPUT_DONE) { + sk->state = BT_CONNECTED; + l2cap_chan_ready(sk); + } else if (!(l2cap_pi(sk)->conf_state & CONF_REQ_SENT)) { + char req[64]; + l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); + } + +unlock: + bh_unlock_sock(sk); + return 0; +} + +static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +{ + l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data; + __u16 scid, flags, result; + struct sock *sk; + int err = 0; + + scid = __le16_to_cpu(rsp->scid); + flags = __le16_to_cpu(rsp->flags); + result = __le16_to_cpu(rsp->result); + + DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result); + + if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) + return -ENOENT; + + if (result) { + l2cap_disconn_req req; + + /* They didn't like our options. Well... we do not negotiate. + * Close channel. + */ + sk->state = BT_DISCONN; + l2cap_sock_set_timer(sk, HZ * 5); + + req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); + req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); + l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req); + goto done; + } + + if (flags & 0x01) + goto done; + + /* Input config done */ + l2cap_pi(sk)->conf_state |= CONF_INPUT_DONE; + + if (l2cap_pi(sk)->conf_state & CONF_OUTPUT_DONE) { + sk->state = BT_CONNECTED; + l2cap_chan_ready(sk); + } + +done: + bh_unlock_sock(sk); + return err; +} + +static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +{ + l2cap_disconn_req *req = (l2cap_disconn_req *) data; + l2cap_disconn_rsp rsp; + __u16 dcid, scid; + struct sock *sk; + + scid = __le16_to_cpu(req->scid); + dcid = __le16_to_cpu(req->dcid); + + DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); + + if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) + return 0; + + rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); + rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); + l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp); + + sk->shutdown = SHUTDOWN_MASK; + + l2cap_chan_del(sk, ECONNRESET); + bh_unlock_sock(sk); + + l2cap_sock_kill(sk); + return 0; +} + +static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +{ + l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data; + __u16 dcid, scid; + struct sock *sk; + + scid = __le16_to_cpu(rsp->scid); + dcid = __le16_to_cpu(rsp->dcid); + + DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); + + if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) + return 0; + l2cap_chan_del(sk, ECONNABORTED); + bh_unlock_sock(sk); + + l2cap_sock_kill(sk); + return 0; +} + +static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) +{ + __u8 *data = skb->data; + int len = skb->len; + l2cap_cmd_hdr cmd; + int err = 0; + + while (len >= L2CAP_CMD_HDR_SIZE) { + memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE); + data += L2CAP_CMD_HDR_SIZE; + len -= L2CAP_CMD_HDR_SIZE; + + cmd.len = __le16_to_cpu(cmd.len); + + DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident); + + if (cmd.len > len || !cmd.ident) { + DBG("corrupted command"); + break; + } + + switch (cmd.code) { + case L2CAP_CONN_REQ: + err = l2cap_connect_req(conn, &cmd, data); + break; + + case L2CAP_CONN_RSP: + err = l2cap_connect_rsp(conn, &cmd, data); + break; + + case L2CAP_CONF_REQ: + err = l2cap_config_req(conn, &cmd, data); + break; + + case L2CAP_CONF_RSP: + err = l2cap_config_rsp(conn, &cmd, data); + break; + + case L2CAP_DISCONN_REQ: + err = l2cap_disconnect_req(conn, &cmd, data); + break; + + case L2CAP_DISCONN_RSP: + err = l2cap_disconnect_rsp(conn, &cmd, data); + break; + + case L2CAP_COMMAND_REJ: + /* FIXME: We should process this */ + l2cap_raw_recv(conn, skb); + break; + + case L2CAP_ECHO_REQ: + l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data); + break; + + case L2CAP_ECHO_RSP: + case L2CAP_INFO_REQ: + case L2CAP_INFO_RSP: + l2cap_raw_recv(conn, skb); + break; + + default: + ERR("Uknown signaling command 0x%2.2x", cmd.code); + err = -EINVAL; + break; + }; + + if (err) { + l2cap_cmd_rej rej; + DBG("error %d", err); + + /* FIXME: Map err to a valid reason. */ + rej.reason = __cpu_to_le16(0); + l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej); + } + + data += cmd.len; + len -= cmd.len; + } + + kfree_skb(skb); +} + +static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb) +{ + struct sock *sk; + + sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); + if (!sk) { + DBG("unknown cid 0x%4.4x", cid); + goto drop; + } + + DBG("sk %p, len %d", sk, skb->len); + + if (sk->state != BT_CONNECTED) + goto drop; + + if (l2cap_pi(sk)->imtu < skb->len) + goto drop; + + /* If socket recv buffers overflows we drop data here + * which is *bad* because L2CAP has to be reliable. + * But we don't have any other choice. L2CAP doesn't + * provide flow control mechanism */ + + if (!sock_queue_rcv_skb(sk, skb)) + goto done; + +drop: + kfree_skb(skb); + +done: + if (sk) bh_unlock_sock(sk); + return 0; +} + +static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) +{ + l2cap_hdr *lh = (l2cap_hdr *) skb->data; + __u16 cid, len; + + skb_pull(skb, L2CAP_HDR_SIZE); + cid = __le16_to_cpu(lh->cid); + len = __le16_to_cpu(lh->len); + + DBG("len %d, cid 0x%4.4x", len, cid); + + if (cid == 0x0001) + l2cap_sig_channel(conn, skb); + else + l2cap_data_channel(conn, cid, skb); +} + +/* ------------ L2CAP interface with lower layer (HCI) ------------- */ + +static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) +{ + int exact = 0, lm1 = 0, lm2 = 0; + register struct sock *sk; + + if (type != ACL_LINK) + return 0; + + DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); + + /* Find listening sockets and check their link_mode */ + read_lock(&l2cap_sk_list.lock); + for (sk = l2cap_sk_list.head; sk; sk = sk->next) { + if (sk->state != BT_LISTEN) + continue; + + if (!bacmp(&bluez_pi(sk)->src, bdaddr)) { + lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode); + exact++; + } else if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY)) + lm2 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode); + } + read_unlock(&l2cap_sk_list.lock); + + return exact ? lm1 : lm2; +} + +static int l2cap_connect_cfm(struct hci_conn *hcon, __u8 status) +{ + DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); + + if (hcon->type != ACL_LINK) + return 0; + + if (!status) { + struct l2cap_conn *conn; + + conn = l2cap_conn_add(hcon, status); + if (conn) + l2cap_conn_ready(conn); + } else + l2cap_conn_del(hcon, bterr(status)); + + return 0; +} + +static int l2cap_disconn_ind(struct hci_conn *hcon, __u8 reason) +{ + DBG("hcon %p reason %d", hcon, reason); + + if (hcon->type != ACL_LINK) + return 0; + + l2cap_conn_del(hcon, bterr(reason)); + return 0; +} + +static int l2cap_auth_cfm(struct hci_conn *hcon, __u8 status) +{ + struct l2cap_chan_list *l; + struct l2cap_conn *conn; + l2cap_conn_rsp rsp; + struct sock *sk; + int result; + + if (!(conn = hcon->l2cap_data)) + return 0; + l = &conn->chan_list; + + DBG("conn %p", conn); + + read_lock(&l->lock); + + for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + bh_lock_sock(sk); + + if (sk->state != BT_CONNECT2 || + (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT)) + continue; + + if (!status) { + sk->state = BT_CONFIG; + result = 0; + } else { + sk->state = BT_DISCONN; + l2cap_sock_set_timer(sk, HZ/10); + result = L2CAP_CR_SEC_BLOCK; + } + + rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); + rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); + rsp.result = __cpu_to_le16(result); + rsp.status = __cpu_to_le16(0); + l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, + L2CAP_CONN_RSP_SIZE, &rsp); + + bh_unlock_sock(sk); + } + + read_unlock(&l->lock); + return 0; +} + +static int l2cap_encrypt_cfm(struct hci_conn *hcon, __u8 status) +{ + struct l2cap_chan_list *l; + struct l2cap_conn *conn; + l2cap_conn_rsp rsp; + struct sock *sk; + int result; + + if (!(conn = hcon->l2cap_data)) + return 0; + l = &conn->chan_list; + + DBG("conn %p", conn); + + read_lock(&l->lock); + + for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + bh_lock_sock(sk); + + if (sk->state != BT_CONNECT2) + continue; + + if (!status) { + sk->state = BT_CONFIG; + result = 0; + } else { + sk->state = BT_DISCONN; + l2cap_sock_set_timer(sk, HZ/10); + result = L2CAP_CR_SEC_BLOCK; + } + + rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); + rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); + rsp.result = __cpu_to_le16(result); + rsp.status = __cpu_to_le16(0); + l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, + L2CAP_CONN_RSP_SIZE, &rsp); + + bh_unlock_sock(sk); + } + + read_unlock(&l->lock); + return 0; +} + +static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, __u16 flags) +{ + struct l2cap_conn *conn = hcon->l2cap_data; + + if (!conn && !(conn = l2cap_conn_add(hcon, 0))) + goto drop; + + DBG("conn %p len %d flags 0x%x", conn, skb->len, flags); + + if (flags & ACL_START) { + int flen, tlen, size; + l2cap_hdr *lh; + + if (conn->rx_len) { + ERR("Unexpected start frame (len %d)", skb->len); + kfree_skb(conn->rx_skb); + conn->rx_skb = NULL; + conn->rx_len = 0; + } + + if (skb->len < L2CAP_HDR_SIZE) { + ERR("Frame is too small (len %d)", skb->len); + goto drop; + } + + lh = (l2cap_hdr *)skb->data; + tlen = __le16_to_cpu(lh->len); + flen = skb->len - L2CAP_HDR_SIZE; + + DBG("Start: total len %d, frag len %d", tlen, flen); + + if (flen == tlen) { + /* Complete frame received */ + l2cap_recv_frame(conn, skb); + return 0; + } + + /* Allocate skb for the complete frame (with header) */ + size = L2CAP_HDR_SIZE + tlen; + if (!(conn->rx_skb = bluez_skb_alloc(size, GFP_ATOMIC))) + goto drop; + + memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len); + conn->rx_len = tlen - flen; + } else { + DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len); + + if (!conn->rx_len) { + ERR("Unexpected continuation frame (len %d)", skb->len); + goto drop; + } + + if (skb->len > conn->rx_len) { + ERR("Fragment is too large (len %d, expect %d)", + skb->len, conn->rx_len); + kfree_skb(conn->rx_skb); + conn->rx_skb = NULL; + conn->rx_len = 0; + goto drop; + } + + memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len); + conn->rx_len -= skb->len; + + if (!conn->rx_len) { + /* Complete frame received */ + l2cap_recv_frame(conn, conn->rx_skb); + conn->rx_skb = NULL; + } + } + +drop: + kfree_skb(skb); + return 0; +} + +/* ----- Proc fs support ------ */ +static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list) +{ + struct l2cap_pinfo *pi; + struct sock *sk; + char *ptr = buf; + + write_lock(&list->lock); + + for (sk = list->head; sk; sk = sk->next) { + pi = l2cap_pi(sk); + ptr += sprintf(ptr, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n", + batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), + sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu, + pi->link_mode); + } + + write_unlock(&list->lock); + + ptr += sprintf(ptr, "\n"); + return ptr - buf; +} + +static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) +{ + char *ptr = buf; + int len; + + DBG("count %d, offset %ld", count, offset); + + ptr += l2cap_sock_dump(ptr, &l2cap_sk_list); + len = ptr - buf; + + if (len <= count + offset) + *eof = 1; + + *start = buf + offset; + len -= offset; + + if (len > count) + len = count; + if (len < 0) + len = 0; + + return len; +} + +static struct proto_ops l2cap_sock_ops = { + family: PF_BLUETOOTH, + release: l2cap_sock_release, + bind: l2cap_sock_bind, + connect: l2cap_sock_connect, + listen: l2cap_sock_listen, + accept: l2cap_sock_accept, + getname: l2cap_sock_getname, + sendmsg: l2cap_sock_sendmsg, + recvmsg: bluez_sock_recvmsg, + poll: bluez_sock_poll, + socketpair: sock_no_socketpair, + ioctl: sock_no_ioctl, + shutdown: sock_no_shutdown, + setsockopt: l2cap_sock_setsockopt, + getsockopt: l2cap_sock_getsockopt, + mmap: sock_no_mmap +}; + +static struct net_proto_family l2cap_sock_family_ops = { + family: PF_BLUETOOTH, + create: l2cap_sock_create +}; + +static struct hci_proto l2cap_hci_proto = { + name: "L2CAP", + id: HCI_PROTO_L2CAP, + connect_ind: l2cap_connect_ind, + connect_cfm: l2cap_connect_cfm, + disconn_ind: l2cap_disconn_ind, + recv_acldata: l2cap_recv_acldata, + auth_cfm: l2cap_auth_cfm, + encrypt_cfm: l2cap_encrypt_cfm +}; + +int __init l2cap_init(void) +{ + int err; + + if ((err = bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops))) { + ERR("Can't register L2CAP socket"); + return err; + } + + if ((err = hci_register_proto(&l2cap_hci_proto))) { + ERR("Can't register L2CAP protocol"); + return err; + } + + create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL); + + INF("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); + INF("Written 2000,2001 by Maxim Krasnyansky "); + return 0; +} + +void l2cap_cleanup(void) +{ + remove_proc_entry("bluetooth/l2cap", NULL); + + /* Unregister socket and protocol */ + if (bluez_sock_unregister(BTPROTO_L2CAP)) + ERR("Can't unregister L2CAP socket"); + + if (hci_unregister_proto(&l2cap_hci_proto)) + ERR("Can't unregister L2CAP protocol"); +} + +module_init(l2cap_init); +module_exit(l2cap_cleanup); + +MODULE_AUTHOR("Maxim Krasnyansky "); +MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.19-pre6/net/bluetooth/l2cap_core.c linux-2.4.19-pre7/net/bluetooth/l2cap_core.c --- linux-2.4.19-pre6/net/bluetooth/l2cap_core.c Sun Sep 30 12:26:08 2001 +++ linux-2.4.19-pre7/net/bluetooth/l2cap_core.c Wed Dec 31 16:00:00 1969 @@ -1,2316 +0,0 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * BlueZ L2CAP core and sockets. - * - * $Id: l2cap_core.c,v 1.19 2001/08/03 04:19:50 maxk Exp $ - */ -#define VERSION "1.1" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#ifndef L2CAP_DEBUG -#undef DBG -#define DBG( A... ) -#endif - -struct proto_ops l2cap_sock_ops; - -struct bluez_sock_list l2cap_sk_list = { - lock: RW_LOCK_UNLOCKED -}; - -struct list_head l2cap_iff_list = LIST_HEAD_INIT(l2cap_iff_list); -rwlock_t l2cap_rt_lock = RW_LOCK_UNLOCKED; - -static int l2cap_conn_del(struct l2cap_conn *conn, int err); - -static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent); -static void l2cap_chan_del(struct sock *sk, int err); -static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len); - -static void l2cap_sock_close(struct sock *sk); -static void l2cap_sock_kill(struct sock *sk); - -static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data); -static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data); - -/* -------- L2CAP interfaces & routing --------- */ -/* Add/delete L2CAP interface. - * Must be called with locked rt_lock - */ - -static void l2cap_iff_add(struct hci_dev *hdev) -{ - struct l2cap_iff *iff; - - DBG("%s", hdev->name); - - DBG("iff_list %p next %p prev %p", &l2cap_iff_list, l2cap_iff_list.next, l2cap_iff_list.prev); - - /* Allocate new interface and lock HCI device */ - if (!(iff = kmalloc(sizeof(struct l2cap_iff), GFP_KERNEL))) { - ERR("Can't allocate new interface %s", hdev->name); - return; - } - memset(iff, 0, sizeof(struct l2cap_iff)); - - hci_dev_hold(hdev); - hdev->l2cap_data = iff; - iff->hdev = hdev; - iff->mtu = hdev->acl_mtu - HCI_ACL_HDR_SIZE; - iff->bdaddr = &hdev->bdaddr; - - spin_lock_init(&iff->lock); - INIT_LIST_HEAD(&iff->conn_list); - - list_add(&iff->list, &l2cap_iff_list); -} - -static void l2cap_iff_del(struct hci_dev *hdev) -{ - struct l2cap_iff *iff; - - if (!(iff = hdev->l2cap_data)) - return; - - DBG("%s iff %p", hdev->name, iff); - - list_del(&iff->list); - - l2cap_iff_lock(iff); - - /* Drop connections */ - while (!list_empty(&iff->conn_list)) { - struct l2cap_conn *c; - - c = list_entry(iff->conn_list.next, struct l2cap_conn, list); - l2cap_conn_del(c, ENODEV); - } - - l2cap_iff_unlock(iff); - - /* Unlock HCI device */ - hdev->l2cap_data = NULL; - hci_dev_put(hdev); - - kfree(iff); -} - -/* Get route. Returns L2CAP interface. - * Must be called with locked rt_lock - */ -static struct l2cap_iff *l2cap_get_route(bdaddr_t *src, bdaddr_t *dst) -{ - struct list_head *p; - int use_src; - - DBG("%s -> %s", batostr(src), batostr(dst)); - - use_src = bacmp(src, BDADDR_ANY) ? 0 : 1; - - /* Simple routing: - * No source address - find interface with bdaddr != dst - * Source address - find interface with bdaddr == src - */ - - list_for_each(p, &l2cap_iff_list) { - struct l2cap_iff *iff; - - iff = list_entry(p, struct l2cap_iff, list); - - if (use_src && !bacmp(iff->bdaddr, src)) - return iff; - else if (bacmp(iff->bdaddr, dst)) - return iff; - } - return NULL; -} - -/* ----- L2CAP timers ------ */ -static void l2cap_sock_timeout(unsigned long arg) -{ - struct sock *sk = (struct sock *) arg; - - DBG("sock %p state %d", sk, sk->state); - - bh_lock_sock(sk); - switch (sk->state) { - case BT_DISCONN: - l2cap_chan_del(sk, ETIMEDOUT); - break; - - default: - sk->err = ETIMEDOUT; - sk->state_change(sk); - break; - }; - bh_unlock_sock(sk); - - l2cap_sock_kill(sk); - sock_put(sk); -} - -static void l2cap_sock_set_timer(struct sock *sk, long timeout) -{ - DBG("sock %p state %d timeout %ld", sk, sk->state, timeout); - - if (!mod_timer(&sk->timer, jiffies + timeout)) - sock_hold(sk); -} - -static void l2cap_sock_clear_timer(struct sock *sk) -{ - DBG("sock %p state %d", sk, sk->state); - - if (timer_pending(&sk->timer) && del_timer(&sk->timer)) - __sock_put(sk); -} - -static void l2cap_sock_init_timer(struct sock *sk) -{ - init_timer(&sk->timer); - sk->timer.function = l2cap_sock_timeout; - sk->timer.data = (unsigned long)sk; -} - -static void l2cap_conn_timeout(unsigned long arg) -{ - struct l2cap_conn *conn = (void *)arg; - - DBG("conn %p state %d", conn, conn->state); - - if (conn->state == BT_CONNECTED) { - hci_disconnect(conn->hconn, 0x13); - } - - return; -} - -static void l2cap_conn_set_timer(struct l2cap_conn *conn, long timeout) -{ - DBG("conn %p state %d timeout %ld", conn, conn->state, timeout); - - mod_timer(&conn->timer, jiffies + timeout); -} - -static void l2cap_conn_clear_timer(struct l2cap_conn *conn) -{ - DBG("conn %p state %d", conn, conn->state); - - del_timer(&conn->timer); -} - -static void l2cap_conn_init_timer(struct l2cap_conn *conn) -{ - init_timer(&conn->timer); - conn->timer.function = l2cap_conn_timeout; - conn->timer.data = (unsigned long)conn; -} - -/* -------- L2CAP connections --------- */ -/* Add new connection to the interface. - * Interface must be locked - */ -static struct l2cap_conn *l2cap_conn_add(struct l2cap_iff *iff, bdaddr_t *dst) -{ - struct l2cap_conn *conn; - bdaddr_t *src = iff->bdaddr; - - if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_KERNEL))) - return NULL; - - memset(conn, 0, sizeof(struct l2cap_conn)); - - conn->state = BT_OPEN; - conn->iff = iff; - bacpy(&conn->src, src); - bacpy(&conn->dst, dst); - - spin_lock_init(&conn->lock); - conn->chan_list.lock = RW_LOCK_UNLOCKED; - - l2cap_conn_init_timer(conn); - - __l2cap_conn_link(iff, conn); - - DBG("%s -> %s, %p", batostr(src), batostr(dst), conn); - - MOD_INC_USE_COUNT; - - return conn; -} - -/* Delete connection on the interface. - * Interface must be locked - */ -static int l2cap_conn_del(struct l2cap_conn *conn, int err) -{ - struct sock *sk; - - DBG("conn %p, state %d, err %d", conn, conn->state, err); - - l2cap_conn_clear_timer(conn); - __l2cap_conn_unlink(conn->iff, conn); - - conn->state = BT_CLOSED; - - if (conn->rx_skb) - kfree_skb(conn->rx_skb); - - /* Kill channels */ - while ((sk = conn->chan_list.head)) { - bh_lock_sock(sk); - l2cap_sock_clear_timer(sk); - l2cap_chan_del(sk, err); - bh_unlock_sock(sk); - - l2cap_sock_kill(sk); - } - - kfree(conn); - - MOD_DEC_USE_COUNT; - return 0; -} - -static inline struct l2cap_conn *l2cap_get_conn_by_addr(struct l2cap_iff *iff, bdaddr_t *dst) -{ - struct list_head *p; - - list_for_each(p, &iff->conn_list) { - struct l2cap_conn *c; - - c = list_entry(p, struct l2cap_conn, list); - if (!bacmp(&c->dst, dst)) - return c; - } - return NULL; -} - -int l2cap_connect(struct sock *sk) -{ - bdaddr_t *src = &l2cap_pi(sk)->src; - bdaddr_t *dst = &l2cap_pi(sk)->dst; - struct l2cap_conn *conn; - struct l2cap_iff *iff; - int err = 0; - - DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm); - - read_lock_bh(&l2cap_rt_lock); - - /* Get route to remote BD address */ - if (!(iff = l2cap_get_route(src, dst))) { - err = -EHOSTUNREACH; - goto done; - } - - /* Update source addr of the socket */ - bacpy(src, iff->bdaddr); - - l2cap_iff_lock(iff); - - if (!(conn = l2cap_get_conn_by_addr(iff, dst))) { - /* Connection doesn't exist */ - if (!(conn = l2cap_conn_add(iff, dst))) { - l2cap_iff_unlock(iff); - err = -ENOMEM; - goto done; - } - conn->out = 1; - } - - l2cap_iff_unlock(iff); - - l2cap_chan_add(conn, sk, NULL); - - sk->state = BT_CONNECT; - l2cap_sock_set_timer(sk, sk->sndtimeo); - - switch (conn->state) { - case BT_CONNECTED: - if (sk->type == SOCK_SEQPACKET) { - l2cap_conn_req req; - req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); - req.psm = l2cap_pi(sk)->psm; - l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req); - } else { - l2cap_sock_clear_timer(sk); - sk->state = BT_CONNECTED; - } - break; - - case BT_CONNECT: - break; - - default: - /* Create ACL connection */ - conn->state = BT_CONNECT; - hci_connect(iff->hdev, dst); - break; - }; - -done: - read_unlock_bh(&l2cap_rt_lock); - return err; -} - -/* ------ Channel queues for listening sockets ------ */ -void l2cap_accept_queue(struct sock *parent, struct sock *sk) -{ - struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q; - - DBG("parent %p, sk %p", parent, sk); - - sock_hold(sk); - l2cap_pi(sk)->parent = parent; - l2cap_pi(sk)->next_q = NULL; - - if (!q->head) { - q->head = q->tail = sk; - } else { - struct sock *tail = q->tail; - - l2cap_pi(sk)->prev_q = tail; - l2cap_pi(tail)->next_q = sk; - q->tail = sk; - } - - parent->ack_backlog++; -} - -void l2cap_accept_unlink(struct sock *sk) -{ - struct sock *parent = l2cap_pi(sk)->parent; - struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q; - struct sock *next, *prev; - - DBG("sk %p", sk); - - next = l2cap_pi(sk)->next_q; - prev = l2cap_pi(sk)->prev_q; - - if (sk == q->head) - q->head = next; - if (sk == q->tail) - q->tail = prev; - - if (next) - l2cap_pi(next)->prev_q = prev; - if (prev) - l2cap_pi(prev)->next_q = next; - - l2cap_pi(sk)->parent = NULL; - - parent->ack_backlog--; - __sock_put(sk); -} - -/* Get next connected channel in queue. */ -struct sock *l2cap_accept_dequeue(struct sock *parent, int state) -{ - struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q; - struct sock *sk; - - for (sk = q->head; sk; sk = l2cap_pi(sk)->next_q) { - if (!state || sk->state == state) { - l2cap_accept_unlink(sk); - break; - } - } - - DBG("parent %p, sk %p", parent, sk); - - return sk; -} - -/* -------- Socket interface ---------- */ -static struct sock *__l2cap_get_sock_by_addr(struct sockaddr_l2 *addr) -{ - bdaddr_t *src = &addr->l2_bdaddr; - __u16 psm = addr->l2_psm; - struct sock *sk; - - for (sk = l2cap_sk_list.head; sk; sk = sk->next) { - if (l2cap_pi(sk)->psm == psm && - !bacmp(&l2cap_pi(sk)->src, src)) - break; - } - - return sk; -} - -/* Find socket listening on psm and source bdaddr. - * Returns closest match. - */ -static struct sock *l2cap_get_sock_listen(bdaddr_t *src, __u16 psm) -{ - struct sock *sk, *sk1 = NULL; - - read_lock(&l2cap_sk_list.lock); - - for (sk = l2cap_sk_list.head; sk; sk = sk->next) { - struct l2cap_pinfo *pi; - - if (sk->state != BT_LISTEN) - continue; - - pi = l2cap_pi(sk); - - if (pi->psm == psm) { - /* Exact match. */ - if (!bacmp(&pi->src, src)) - break; - - /* Closest match */ - if (!bacmp(&pi->src, BDADDR_ANY)) - sk1 = sk; - } - } - - read_unlock(&l2cap_sk_list.lock); - - return sk ? sk : sk1; -} - -static void l2cap_sock_destruct(struct sock *sk) -{ - DBG("sk %p", sk); - - skb_queue_purge(&sk->receive_queue); - skb_queue_purge(&sk->write_queue); - - MOD_DEC_USE_COUNT; -} - -static void l2cap_sock_cleanup_listen(struct sock *parent) -{ - struct sock *sk; - - DBG("parent %p", parent); - - /* Close not yet accepted channels */ - while ((sk = l2cap_accept_dequeue(parent, 0))) - l2cap_sock_close(sk); - - parent->state = BT_CLOSED; - parent->zapped = 1; -} - -/* Kill socket (only if zapped and orphan) - * Must be called on unlocked socket. - */ -static void l2cap_sock_kill(struct sock *sk) -{ - if (!sk->zapped || sk->socket) - return; - - DBG("sk %p state %d", sk, sk->state); - - /* Kill poor orphan */ - bluez_sock_unlink(&l2cap_sk_list, sk); - sk->dead = 1; - sock_put(sk); -} - -/* Close socket. - * Must be called on unlocked socket. - */ -static void l2cap_sock_close(struct sock *sk) -{ - struct l2cap_conn *conn; - - l2cap_sock_clear_timer(sk); - - lock_sock(sk); - - conn = l2cap_pi(sk)->conn; - - DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket); - - switch (sk->state) { - case BT_LISTEN: - l2cap_sock_cleanup_listen(sk); - break; - - case BT_CONNECTED: - case BT_CONFIG: - if (sk->type == SOCK_SEQPACKET) { - l2cap_disconn_req req; - - sk->state = BT_DISCONN; - - req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); - req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); - l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req); - - l2cap_sock_set_timer(sk, sk->sndtimeo); - } else { - l2cap_chan_del(sk, ECONNRESET); - } - break; - - case BT_CONNECT: - case BT_DISCONN: - l2cap_chan_del(sk, ECONNRESET); - break; - - default: - sk->zapped = 1; - break; - }; - - release_sock(sk); - - l2cap_sock_kill(sk); -} - -static void l2cap_sock_init(struct sock *sk, struct sock *parent) -{ - struct l2cap_pinfo *pi = l2cap_pi(sk); - - DBG("sk %p", sk); - - if (parent) { - sk->type = parent->type; - - pi->imtu = l2cap_pi(parent)->imtu; - pi->omtu = l2cap_pi(parent)->omtu; - } else { - pi->imtu = L2CAP_DEFAULT_MTU; - pi->omtu = 0; - } - - /* Default config options */ - pi->conf_mtu = L2CAP_DEFAULT_MTU; - pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; -} - -static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio) -{ - struct sock *sk; - - if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1))) - return NULL; - - sock_init_data(sock, sk); - - sk->zapped = 0; - - sk->destruct = l2cap_sock_destruct; - sk->sndtimeo = L2CAP_CONN_TIMEOUT; - - sk->protocol = proto; - sk->state = BT_OPEN; - - l2cap_sock_init_timer(sk); - - bluez_sock_link(&l2cap_sk_list, sk); - - MOD_INC_USE_COUNT; - - return sk; -} - -static int l2cap_sock_create(struct socket *sock, int protocol) -{ - struct sock *sk; - - DBG("sock %p", sock); - - sock->state = SS_UNCONNECTED; - - if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_RAW) - return -ESOCKTNOSUPPORT; - - sock->ops = &l2cap_sock_ops; - - if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL))) - return -ENOMEM; - - l2cap_sock_init(sk, NULL); - - return 0; -} - -static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) -{ - struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; - struct sock *sk = sock->sk; - int err = 0; - - DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm); - - if (!addr || addr->sa_family != AF_BLUETOOTH) - return -EINVAL; - - lock_sock(sk); - - if (sk->state != BT_OPEN) { - err = -EBADFD; - goto done; - } - - write_lock(&l2cap_sk_list.lock); - - if (la->l2_psm && __l2cap_get_sock_by_addr(la)) { - err = -EADDRINUSE; - goto unlock; - } - - /* Save source address */ - bacpy(&l2cap_pi(sk)->src, &la->l2_bdaddr); - l2cap_pi(sk)->psm = la->l2_psm; - sk->state = BT_BOUND; - -unlock: - write_unlock(&l2cap_sk_list.lock); - -done: - release_sock(sk); - - return err; -} - -static int l2cap_sock_w4_connect(struct sock *sk, int flags) -{ - DECLARE_WAITQUEUE(wait, current); - long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); - int err = 0; - - DBG("sk %p", sk); - - add_wait_queue(sk->sleep, &wait); - current->state = TASK_INTERRUPTIBLE; - - while (sk->state != BT_CONNECTED) { - if (!timeo) { - err = -EAGAIN; - break; - } - - release_sock(sk); - timeo = schedule_timeout(timeo); - lock_sock(sk); - - err = 0; - if (sk->state == BT_CONNECTED) - break; - - if (sk->err) { - err = sock_error(sk); - break; - } - - if (signal_pending(current)) { - err = sock_intr_errno(timeo); - break; - } - } - current->state = TASK_RUNNING; - remove_wait_queue(sk->sleep, &wait); - - return err; -} - -static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) -{ - struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; - struct sock *sk = sock->sk; - int err = 0; - - lock_sock(sk); - - DBG("sk %p", sk); - - if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) { - err = -EINVAL; - goto done; - } - - if (sk->state != BT_OPEN && sk->state != BT_BOUND) { - err = -EBADFD; - goto done; - } - - if (sk->type == SOCK_SEQPACKET && !la->l2_psm) { - err = -EINVAL; - goto done; - } - - /* Set destination address and psm */ - bacpy(&l2cap_pi(sk)->dst, &la->l2_bdaddr); - l2cap_pi(sk)->psm = la->l2_psm; - - if ((err = l2cap_connect(sk))) - goto done; - - err = l2cap_sock_w4_connect(sk, flags); - -done: - release_sock(sk); - return err; -} - -int l2cap_sock_listen(struct socket *sock, int backlog) -{ - struct sock *sk = sock->sk; - int err = 0; - - DBG("sk %p backlog %d", sk, backlog); - - lock_sock(sk); - - if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) { - err = -EBADFD; - goto done; - } - - if (!l2cap_pi(sk)->psm) { - err = -EINVAL; - goto done; - } - - sk->max_ack_backlog = backlog; - sk->ack_backlog = 0; - sk->state = BT_LISTEN; - -done: - release_sock(sk); - return err; -} - -int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags) -{ - DECLARE_WAITQUEUE(wait, current); - struct sock *sk = sock->sk, *ch; - long timeo; - int err = 0; - - lock_sock(sk); - - if (sk->state != BT_LISTEN) { - err = -EBADFD; - goto done; - } - - timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); - - DBG("sk %p timeo %ld", sk, timeo); - - /* Wait for an incoming connection. (wake-one). */ - add_wait_queue_exclusive(sk->sleep, &wait); - current->state = TASK_INTERRUPTIBLE; - while (!(ch = l2cap_accept_dequeue(sk, BT_CONNECTED))) { - if (!timeo) { - err = -EAGAIN; - break; - } - - release_sock(sk); - timeo = schedule_timeout(timeo); - lock_sock(sk); - - if (sk->state != BT_LISTEN) { - err = -EBADFD; - break; - } - - if (signal_pending(current)) { - err = sock_intr_errno(timeo); - break; - } - } - current->state = TASK_RUNNING; - remove_wait_queue(sk->sleep, &wait); - - if (err) - goto done; - - sock_graft(ch, newsock); - newsock->state = SS_CONNECTED; - - DBG("new socket %p", ch); - -done: - release_sock(sk); - - return err; -} - -static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer) -{ - struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; - struct sock *sk = sock->sk; - - DBG("sock %p, sk %p", sock, sk); - - addr->sa_family = AF_BLUETOOTH; - *len = sizeof(struct sockaddr_l2); - - if (peer) - bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->dst); - else - bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->src); - - la->l2_psm = l2cap_pi(sk)->psm; - - return 0; -} - -static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) -{ - struct sock *sk = sock->sk; - int err = 0; - - DBG("sock %p, sk %p", sock, sk); - - if (sk->err) - return sock_error(sk); - - if (msg->msg_flags & MSG_OOB) - return -EOPNOTSUPP; - - lock_sock(sk); - - if (sk->state == BT_CONNECTED) - err = l2cap_chan_send(sk, msg, len); - else - err = -ENOTCONN; - - release_sock(sk); - return err; -} - -static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm) -{ - struct sock *sk = sock->sk; - int noblock = flags & MSG_DONTWAIT; - int copied, err; - struct sk_buff *skb; - - DBG("sock %p, sk %p", sock, sk); - - if (flags & (MSG_OOB)) - return -EOPNOTSUPP; - - if (sk->state == BT_CLOSED) - return 0; - - if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) - return err; - - msg->msg_namelen = 0; - - copied = skb->len; - if (len < copied) { - msg->msg_flags |= MSG_TRUNC; - copied = len; - } - - skb->h.raw = skb->data; - err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); - - skb_free_datagram(sk, skb); - - return err ? : copied; -} - -int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) -{ - struct sock *sk = sock->sk; - struct l2cap_options opts; - int err = 0; - - DBG("sk %p", sk); - - lock_sock(sk); - - switch (optname) { - case L2CAP_OPTIONS: - if (copy_from_user((char *)&opts, optval, optlen)) { - err = -EFAULT; - break; - } - l2cap_pi(sk)->imtu = opts.imtu; - l2cap_pi(sk)->omtu = opts.omtu; - break; - - default: - err = -ENOPROTOOPT; - break; - }; - - release_sock(sk); - return err; -} - -int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) -{ - struct sock *sk = sock->sk; - struct l2cap_options opts; - struct l2cap_conninfo cinfo; - int len, err = 0; - - if (get_user(len, optlen)) - return -EFAULT; - - lock_sock(sk); - - switch (optname) { - case L2CAP_OPTIONS: - opts.imtu = l2cap_pi(sk)->imtu; - opts.omtu = l2cap_pi(sk)->omtu; - opts.flush_to = l2cap_pi(sk)->flush_to; - - len = MIN(len, sizeof(opts)); - if (copy_to_user(optval, (char *)&opts, len)) - err = -EFAULT; - - break; - - case L2CAP_CONNINFO: - if (sk->state != BT_CONNECTED) { - err = -ENOTCONN; - break; - } - - cinfo.hci_handle = l2cap_pi(sk)->conn->hconn->handle; - - len = MIN(len, sizeof(cinfo)); - if (copy_to_user(optval, (char *)&cinfo, len)) - err = -EFAULT; - - break; - - default: - err = -ENOPROTOOPT; - break; - }; - - release_sock(sk); - return err; -} - -static unsigned int l2cap_sock_poll(struct file * file, struct socket *sock, poll_table *wait) -{ - struct sock *sk = sock->sk; - struct l2cap_accept_q *aq; - unsigned int mask; - - DBG("sock %p, sk %p", sock, sk); - - poll_wait(file, sk->sleep, wait); - mask = 0; - - if (sk->err || !skb_queue_empty(&sk->error_queue)) - mask |= POLLERR; - - if (sk->shutdown == SHUTDOWN_MASK) - mask |= POLLHUP; - - aq = &l2cap_pi(sk)->accept_q; - if (!skb_queue_empty(&sk->receive_queue) || aq->head || (sk->shutdown & RCV_SHUTDOWN)) - mask |= POLLIN | POLLRDNORM; - - if (sk->state == BT_CLOSED) - mask |= POLLHUP; - - if (sock_writeable(sk)) - mask |= POLLOUT | POLLWRNORM | POLLWRBAND; - else - set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); - - return mask; -} - -static int l2cap_sock_release(struct socket *sock) -{ - struct sock *sk = sock->sk; - - DBG("sock %p, sk %p", sock, sk); - - if (!sk) - return 0; - - sock_orphan(sk); - - l2cap_sock_close(sk); - - return 0; -} - -/* --------- L2CAP channels --------- */ -static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid) -{ - struct sock *s; - - for (s = l->head; s; s = l2cap_pi(s)->next_c) { - if (l2cap_pi(s)->dcid == cid) - break; - } - - return s; -} - -static inline struct sock *l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid) -{ - struct sock *s; - - read_lock(&l->lock); - s = __l2cap_get_chan_by_dcid(l, cid); - read_unlock(&l->lock); - - return s; -} - -static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid) -{ - struct sock *s; - - for (s = l->head; s; s = l2cap_pi(s)->next_c) { - if (l2cap_pi(s)->scid == cid) - break; - } - - return s; -} -static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid) -{ - struct sock *s; - - read_lock(&l->lock); - s = __l2cap_get_chan_by_scid(l, cid); - read_unlock(&l->lock); - - return s; -} - -static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident) -{ - struct sock *s; - - for (s = l->head; s; s = l2cap_pi(s)->next_c) { - if (l2cap_pi(s)->ident == ident) - break; - } - - return s; -} - -static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident) -{ - struct sock *s; - - read_lock(&l->lock); - s = __l2cap_get_chan_by_ident(l, ident); - read_unlock(&l->lock); - - return s; -} - -static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l) -{ - __u16 cid = 0x0040; - - for (; cid < 0xffff; cid++) { - if(!__l2cap_get_chan_by_scid(l, cid)) - return cid; - } - - return 0; -} - -static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk) -{ - sock_hold(sk); - - if (l->head) - l2cap_pi(l->head)->prev_c = sk; - - l2cap_pi(sk)->next_c = l->head; - l2cap_pi(sk)->prev_c = NULL; - l->head = sk; -} - -static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) -{ - struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; - - write_lock(&l->lock); - if (sk == l->head) - l->head = next; - - if (next) - l2cap_pi(next)->prev_c = prev; - if (prev) - l2cap_pi(prev)->next_c = next; - write_unlock(&l->lock); - - __sock_put(sk); -} - -static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) -{ - struct l2cap_chan_list *l = &conn->chan_list; - - DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); - - l2cap_conn_clear_timer(conn); - - atomic_inc(&conn->refcnt); - l2cap_pi(sk)->conn = conn; - - if (sk->type == SOCK_SEQPACKET) { - /* Alloc CID for normal socket */ - l2cap_pi(sk)->scid = l2cap_alloc_cid(l); - } else { - /* Raw socket can send only signalling messages */ - l2cap_pi(sk)->scid = 0x0001; - l2cap_pi(sk)->dcid = 0x0001; - l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; - } - - __l2cap_chan_link(l, sk); - - if (parent) - l2cap_accept_queue(parent, sk); -} - -static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) -{ - struct l2cap_chan_list *l = &conn->chan_list; - - write_lock(&l->lock); - __l2cap_chan_add(conn, sk, parent); - write_unlock(&l->lock); -} - -/* Delete channel. - * Must be called on the locked socket. */ -static void l2cap_chan_del(struct sock *sk, int err) -{ - struct l2cap_conn *conn; - struct sock *parent; - - conn = l2cap_pi(sk)->conn; - parent = l2cap_pi(sk)->parent; - - DBG("sk %p, conn %p, err %d", sk, conn, err); - - if (parent) { - /* Unlink from parent accept queue */ - bh_lock_sock(parent); - l2cap_accept_unlink(sk); - bh_unlock_sock(parent); - } - - if (conn) { - long timeout; - - /* Unlink from channel list */ - l2cap_chan_unlink(&conn->chan_list, sk); - l2cap_pi(sk)->conn = NULL; - - if (conn->out) - timeout = L2CAP_DISCONN_TIMEOUT; - else - timeout = L2CAP_CONN_IDLE_TIMEOUT; - - if (atomic_dec_and_test(&conn->refcnt) && conn->state == BT_CONNECTED) { - /* Schedule Baseband disconnect */ - l2cap_conn_set_timer(conn, timeout); - } - } - - sk->state = BT_CLOSED; - sk->err = err; - sk->state_change(sk); - - sk->zapped = 1; -} - -static void l2cap_conn_ready(struct l2cap_conn *conn) -{ - struct l2cap_chan_list *l = &conn->chan_list; - struct sock *sk; - - DBG("conn %p", conn); - - read_lock(&l->lock); - - for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { - bh_lock_sock(sk); - - if (sk->type != SOCK_SEQPACKET) { - sk->state = BT_CONNECTED; - sk->state_change(sk); - l2cap_sock_clear_timer(sk); - } else if (sk->state == BT_CONNECT) { - l2cap_conn_req req; - req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); - req.psm = l2cap_pi(sk)->psm; - l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req); - - l2cap_sock_set_timer(sk, sk->sndtimeo); - } - - bh_unlock_sock(sk); - } - - read_unlock(&l->lock); -} - -static void l2cap_chan_ready(struct sock *sk) -{ - struct sock *parent = l2cap_pi(sk)->parent; - - DBG("sk %p, parent %p", sk, parent); - - l2cap_pi(sk)->conf_state = 0; - l2cap_sock_clear_timer(sk); - - if (!parent) { - /* Outgoing channel. - * Wake up socket sleeping on connect. - */ - sk->state = BT_CONNECTED; - sk->state_change(sk); - } else { - /* Incomming channel. - * Wake up socket sleeping on accept. - */ - parent->data_ready(parent, 1); - } -} - -/* Copy frame to all raw sockets on that connection */ -void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) -{ - struct l2cap_chan_list *l = &conn->chan_list; - struct sk_buff *nskb; - struct sock * sk; - - DBG("conn %p", conn); - - read_lock(&l->lock); - for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { - if (sk->type != SOCK_RAW) - continue; - - /* Don't send frame to the socket it came from */ - if (skb->sk == sk) - continue; - - if (!(nskb = skb_clone(skb, GFP_ATOMIC))) - continue; - - skb_queue_tail(&sk->receive_queue, nskb); - sk->data_ready(sk, nskb->len); - } - read_unlock(&l->lock); -} - -static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len) -{ - struct l2cap_conn *conn = l2cap_pi(sk)->conn; - struct sk_buff *skb, **frag; - int err, size, count, sent=0; - l2cap_hdr *lh; - - /* Check outgoing MTU */ - if (len > l2cap_pi(sk)->omtu) - return -EINVAL; - - DBG("sk %p len %d", sk, len); - - /* First fragment (with L2CAP header) */ - count = MIN(conn->iff->mtu - L2CAP_HDR_SIZE, len); - size = L2CAP_HDR_SIZE + count; - if (!(skb = bluez_skb_send_alloc(sk, size, msg->msg_flags & MSG_DONTWAIT, &err))) - return err; - - /* Create L2CAP header */ - lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->len = __cpu_to_le16(len); - lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid); - - if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { - err = -EFAULT; - goto fail; - } - - sent += count; - len -= count; - - /* Continuation fragments (no L2CAP header) */ - frag = &skb_shinfo(skb)->frag_list; - while (len) { - count = MIN(conn->iff->mtu, len); - - *frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err); - if (!*frag) - goto fail; - - if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) { - err = -EFAULT; - goto fail; - } - - sent += count; - len -= count; - - frag = &(*frag)->next; - } - - if ((err = hci_send_acl(conn->hconn, skb, 0)) < 0) - goto fail; - - return sent; - -fail: - kfree_skb(skb); - return err; -} - -/* --------- L2CAP signalling commands --------- */ -static inline __u8 l2cap_get_ident(struct l2cap_conn *conn) -{ - __u8 id; - - /* Get next available identificator. - * 1 - 199 are used by kernel. - * 200 - 254 are used by utilities like l2ping, etc - */ - - spin_lock(&conn->lock); - - if (++conn->tx_ident > 199) - conn->tx_ident = 1; - - id = conn->tx_ident; - - spin_unlock(&conn->lock); - - return id; -} - -static inline struct sk_buff *l2cap_build_cmd(__u8 code, __u8 ident, __u16 len, void *data) -{ - struct sk_buff *skb; - l2cap_cmd_hdr *cmd; - l2cap_hdr *lh; - int size; - - DBG("code 0x%2.2x, ident 0x%2.2x, len %d", code, ident, len); - - size = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + len; - if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) - return NULL; - - lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + len); - lh->cid = __cpu_to_le16(0x0001); - - cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE); - cmd->code = code; - cmd->ident = ident; - cmd->len = __cpu_to_le16(len); - - if (len) - memcpy(skb_put(skb, len), data, len); - - return skb; -} - -static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data) -{ - struct sk_buff *skb; - __u8 ident; - - DBG("code 0x%2.2x", code); - - ident = l2cap_get_ident(conn); - if (!(skb = l2cap_build_cmd(code, ident, len, data))) - return -ENOMEM; - return hci_send_acl(conn->hconn, skb, 0); -} - -static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data) -{ - struct sk_buff *skb; - - DBG("code 0x%2.2x", code); - - if (!(skb = l2cap_build_cmd(code, ident, len, data))) - return -ENOMEM; - return hci_send_acl(conn->hconn, skb, 0); -} - -static inline int l2cap_get_conf_opt(__u8 **ptr, __u8 *type, __u32 *val) -{ - l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr); - int len; - - *type = opt->type; - switch (opt->len) { - case 1: - *val = *((__u8 *) opt->val); - break; - - case 2: - *val = __le16_to_cpu(*((__u16 *)opt->val)); - break; - - case 4: - *val = __le32_to_cpu(*((__u32 *)opt->val)); - break; - - default: - *val = 0L; - break; - }; - - DBG("type 0x%2.2x len %d val 0x%8.8x", *type, opt->len, *val); - - len = L2CAP_CONF_OPT_SIZE + opt->len; - - *ptr += len; - - return len; -} - -static inline void l2cap_parse_conf_req(struct sock *sk, char *data, int len) -{ - __u8 type, hint; __u32 val; - __u8 *ptr = data; - - DBG("sk %p len %d", sk, len); - - while (len >= L2CAP_CONF_OPT_SIZE) { - len -= l2cap_get_conf_opt(&ptr, &type, &val); - - hint = type & 0x80; - type &= 0x7f; - - switch (type) { - case L2CAP_CONF_MTU: - l2cap_pi(sk)->conf_mtu = val; - break; - - case L2CAP_CONF_FLUSH_TO: - l2cap_pi(sk)->flush_to = val; - break; - - case L2CAP_CONF_QOS: - break; - - default: - if (hint) - break; - - /* FIXME: Reject unknon option */ - break; - }; - } -} - -static inline void l2cap_add_conf_opt(__u8 **ptr, __u8 type, __u8 len, __u32 val) -{ - register l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr); - - DBG("type 0x%2.2x len %d val 0x%8.8x", type, len, val); - - opt->type = type; - opt->len = len; - switch (len) { - case 1: - *((__u8 *) opt->val) = val; - break; - - case 2: - *((__u16 *) opt->val) = __cpu_to_le16(val); - break; - - case 4: - *((__u32 *) opt->val) = __cpu_to_le32(val); - break; - }; - - *ptr += L2CAP_CONF_OPT_SIZE + len; -} - -static int l2cap_build_conf_req(struct sock *sk, __u8 *data) -{ - struct l2cap_pinfo *pi = l2cap_pi(sk); - l2cap_conf_req *req = (l2cap_conf_req *) data; - __u8 *ptr = req->data; - - DBG("sk %p", sk); - - if (pi->imtu != L2CAP_DEFAULT_MTU) - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); - - /* FIXME. Need actual value of the flush timeout */ - //if (flush_to != L2CAP_DEFAULT_FLUSH_TO) - // l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to); - - req->dcid = __cpu_to_le16(pi->dcid); - req->flags = __cpu_to_le16(0); - - return ptr - data; -} - -static int l2cap_conf_output(struct sock *sk, __u8 **ptr) -{ - struct l2cap_pinfo *pi = l2cap_pi(sk); - int result = 0; - - /* Configure output options and let other side know - * which ones we don't like. - */ - if (pi->conf_mtu < pi->omtu) { - l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, l2cap_pi(sk)->omtu); - result = L2CAP_CONF_UNACCEPT; - } else { - pi->omtu = pi->conf_mtu; - } - - DBG("sk %p result %d", sk, result); - return result; -} - -static int l2cap_build_conf_rsp(struct sock *sk, __u8 *data, int *result) -{ - l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data; - __u8 *ptr = rsp->data; - - DBG("sk %p complete %d", sk, result ? 1 : 0); - - if (result) - *result = l2cap_conf_output(sk, &ptr); - - rsp->scid = __cpu_to_le16(l2cap_pi(sk)->dcid); - rsp->result = __cpu_to_le16(result ? *result : 0); - rsp->flags = __cpu_to_le16(0); - - return ptr - data; -} - -static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) -{ - struct l2cap_chan_list *list = &conn->chan_list; - l2cap_conn_req *req = (l2cap_conn_req *) data; - l2cap_conn_rsp rsp; - struct sock *sk, *parent; - - __u16 scid = __le16_to_cpu(req->scid); - __u16 psm = req->psm; - - DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); - - /* Check if we have socket listening on psm */ - if (!(parent = l2cap_get_sock_listen(&conn->src, psm))) - goto reject; - - bh_lock_sock(parent); - write_lock(&list->lock); - - /* Check if we already have channel with that dcid */ - if (__l2cap_get_chan_by_dcid(list, scid)) - goto unlock; - - /* Check for backlog size */ - if (parent->ack_backlog > parent->max_ack_backlog) - goto unlock; - - if (!(sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC))) - goto unlock; - - l2cap_sock_init(sk, parent); - - bacpy(&l2cap_pi(sk)->src, &conn->src); - bacpy(&l2cap_pi(sk)->dst, &conn->dst); - l2cap_pi(sk)->psm = psm; - l2cap_pi(sk)->dcid = scid; - - __l2cap_chan_add(conn, sk, parent); - sk->state = BT_CONFIG; - - write_unlock(&list->lock); - bh_unlock_sock(parent); - - rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); - rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.result = __cpu_to_le16(0); - rsp.status = __cpu_to_le16(0); - l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp); - - return 0; - -unlock: - write_unlock(&list->lock); - bh_unlock_sock(parent); - -reject: - rsp.scid = __cpu_to_le16(scid); - rsp.dcid = __cpu_to_le16(0); - rsp.status = __cpu_to_le16(0); - rsp.result = __cpu_to_le16(L2CAP_CONN_NO_MEM); - l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp); - - return 0; -} - -static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) -{ - l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data; - __u16 scid, dcid, result, status; - struct sock *sk; - - scid = __le16_to_cpu(rsp->scid); - dcid = __le16_to_cpu(rsp->dcid); - result = __le16_to_cpu(rsp->result); - status = __le16_to_cpu(rsp->status); - - DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); - - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) - return -ENOENT; - - bh_lock_sock(sk); - - if (!result) { - char req[64]; - - sk->state = BT_CONFIG; - l2cap_pi(sk)->dcid = dcid; - l2cap_pi(sk)->conf_state |= CONF_REQ_SENT; - - l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); - } else { - l2cap_chan_del(sk, ECONNREFUSED); - } - - bh_unlock_sock(sk); - return 0; -} - -static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) -{ - l2cap_conf_req * req = (l2cap_conf_req *) data; - __u16 dcid, flags; - __u8 rsp[64]; - struct sock *sk; - int result; - - dcid = __le16_to_cpu(req->dcid); - flags = __le16_to_cpu(req->flags); - - DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); - - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) - return -ENOENT; - - bh_lock_sock(sk); - - l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE); - - if (flags & 0x01) { - /* Incomplete config. Send empty response. */ - l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp); - goto unlock; - } - - /* Complete config. */ - l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp); - - if (result) - goto unlock; - - /* Output config done */ - l2cap_pi(sk)->conf_state |= CONF_OUTPUT_DONE; - - if (l2cap_pi(sk)->conf_state & CONF_INPUT_DONE) { - sk->state = BT_CONNECTED; - l2cap_chan_ready(sk); - } else if (!(l2cap_pi(sk)->conf_state & CONF_REQ_SENT)) { - char req[64]; - l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); - } - -unlock: - bh_unlock_sock(sk); - - return 0; -} - -static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) -{ - l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data; - __u16 scid, flags, result; - struct sock *sk; - int err = 0; - - scid = __le16_to_cpu(rsp->scid); - flags = __le16_to_cpu(rsp->flags); - result = __le16_to_cpu(rsp->result); - - DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result); - - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) - return -ENOENT; - - bh_lock_sock(sk); - - if (result) { - l2cap_disconn_req req; - - /* They didn't like our options. Well... we do not negotiate. - * Close channel. - */ - sk->state = BT_DISCONN; - - req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); - req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); - l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req); - - l2cap_sock_set_timer(sk, sk->sndtimeo); - goto done; - } - - if (flags & 0x01) - goto done; - - /* Input config done */ - l2cap_pi(sk)->conf_state |= CONF_INPUT_DONE; - - if (l2cap_pi(sk)->conf_state & CONF_OUTPUT_DONE) { - sk->state = BT_CONNECTED; - l2cap_chan_ready(sk); - } - -done: - bh_unlock_sock(sk); - - return err; -} - -static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) -{ - l2cap_disconn_req *req = (l2cap_disconn_req *) data; - l2cap_disconn_rsp rsp; - __u16 dcid, scid; - struct sock *sk; - - scid = __le16_to_cpu(req->scid); - dcid = __le16_to_cpu(req->dcid); - - DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); - - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) - return 0; - - bh_lock_sock(sk); - - rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); - rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); - l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp); - - l2cap_chan_del(sk, ECONNRESET); - - bh_unlock_sock(sk); - - l2cap_sock_kill(sk); - - return 0; -} - -static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) -{ - l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data; - __u16 dcid, scid; - struct sock *sk; - - scid = __le16_to_cpu(rsp->scid); - dcid = __le16_to_cpu(rsp->dcid); - - DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); - - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) - return -ENOENT; - - bh_lock_sock(sk); - l2cap_sock_clear_timer(sk); - l2cap_chan_del(sk, ECONNABORTED); - bh_unlock_sock(sk); - - l2cap_sock_kill(sk); - - return 0; -} - -static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) -{ - __u8 *data = skb->data; - int len = skb->len; - l2cap_cmd_hdr cmd; - int err = 0; - - while (len >= L2CAP_CMD_HDR_SIZE) { - memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE); - data += L2CAP_CMD_HDR_SIZE; - len -= L2CAP_CMD_HDR_SIZE; - - cmd.len = __le16_to_cpu(cmd.len); - - DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident); - - if (cmd.len > len || !cmd.ident) { - DBG("corrupted command"); - break; - } - - switch (cmd.code) { - case L2CAP_CONN_REQ: - err = l2cap_connect_req(conn, &cmd, data); - break; - - case L2CAP_CONN_RSP: - err = l2cap_connect_rsp(conn, &cmd, data); - break; - - case L2CAP_CONF_REQ: - err = l2cap_config_req(conn, &cmd, data); - break; - - case L2CAP_CONF_RSP: - err = l2cap_config_rsp(conn, &cmd, data); - break; - - case L2CAP_DISCONN_REQ: - err = l2cap_disconnect_req(conn, &cmd, data); - break; - - case L2CAP_DISCONN_RSP: - err = l2cap_disconnect_rsp(conn, &cmd, data); - break; - - case L2CAP_COMMAND_REJ: - /* FIXME: We should process this */ - l2cap_raw_recv(conn, skb); - break; - - case L2CAP_ECHO_REQ: - l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data); - break; - - case L2CAP_ECHO_RSP: - case L2CAP_INFO_REQ: - case L2CAP_INFO_RSP: - l2cap_raw_recv(conn, skb); - break; - - default: - ERR("Uknown signaling command 0x%2.2x", cmd.code); - err = -EINVAL; - break; - }; - - if (err) { - l2cap_cmd_rej rej; - DBG("error %d", err); - - /* FIXME: Map err to a valid reason. */ - rej.reason = __cpu_to_le16(0); - l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej); - } - - data += cmd.len; - len -= cmd.len; - } - - kfree_skb(skb); -} - -static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb) -{ - struct sock *sk; - - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, cid))) { - DBG("unknown cid 0x%4.4x", cid); - goto drop; - } - - DBG("sk %p, len %d", sk, skb->len); - - if (sk->state != BT_CONNECTED) - goto drop; - - if (l2cap_pi(sk)->imtu < skb->len) - goto drop; - - skb_queue_tail(&sk->receive_queue, skb); - sk->data_ready(sk, skb->len); - - return 0; - -drop: - kfree_skb(skb); - - return 0; -} - -static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) -{ - l2cap_hdr *lh = (l2cap_hdr *) skb->data; - __u16 cid, len; - - skb_pull(skb, L2CAP_HDR_SIZE); - cid = __le16_to_cpu(lh->cid); - len = __le16_to_cpu(lh->len); - - DBG("len %d, cid 0x%4.4x", len, cid); - - if (cid == 0x0001) - l2cap_sig_channel(conn, skb); - else - l2cap_data_channel(conn, cid, skb); -} - -/* ------------ L2CAP interface with lower layer (HCI) ------------- */ -static int l2cap_dev_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct hci_dev *hdev = (struct hci_dev *) ptr; - - DBG("hdev %s, event %ld", hdev->name, event); - - write_lock(&l2cap_rt_lock); - - switch (event) { - case HCI_DEV_UP: - l2cap_iff_add(hdev); - break; - - case HCI_DEV_DOWN: - l2cap_iff_del(hdev); - break; - }; - - write_unlock(&l2cap_rt_lock); - - return NOTIFY_DONE; -} - -int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) -{ - struct l2cap_iff *iff; - - DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); - - if (!(iff = hdev->l2cap_data)) { - ERR("unknown interface"); - return 0; - } - - /* Always accept connection */ - return 1; -} - -int l2cap_connect_cfm(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *hconn) -{ - struct l2cap_conn *conn; - struct l2cap_iff *iff; - int err = 0; - - DBG("hdev %s bdaddr %s hconn %p", hdev->name, batostr(bdaddr), hconn); - - if (!(iff = hdev->l2cap_data)) { - ERR("unknown interface"); - return 0; - } - - l2cap_iff_lock(iff); - - conn = l2cap_get_conn_by_addr(iff, bdaddr); - - if (conn) { - /* Outgoing connection */ - DBG("Outgoing connection: %s -> %s, %p, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), conn, status); - - if (!status && hconn) { - conn->state = BT_CONNECTED; - conn->hconn = hconn; - - hconn->l2cap_data = (void *)conn; - - /* Establish channels */ - l2cap_conn_ready(conn); - } else { - l2cap_conn_del(conn, bterr(status)); - } - } else { - /* Incomming connection */ - DBG("Incomming connection: %s -> %s, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), status); - - if (status || !hconn) - goto done; - - if (!(conn = l2cap_conn_add(iff, bdaddr))) { - err = -ENOMEM; - goto done; - } - - conn->hconn = hconn; - hconn->l2cap_data = (void *)conn; - - conn->state = BT_CONNECTED; - } - -done: - l2cap_iff_unlock(iff); - - return err; -} - -int l2cap_disconn_ind(struct hci_conn *hconn, __u8 reason) -{ - struct l2cap_conn *conn = hconn->l2cap_data; - - DBG("hconn %p reason %d", hconn, reason); - - if (!conn) { - ERR("unknown connection"); - return 0; - } - conn->hconn = NULL; - - l2cap_iff_lock(conn->iff); - l2cap_conn_del(conn, bterr(reason)); - l2cap_iff_unlock(conn->iff); - - return 0; -} - -int l2cap_recv_acldata(struct hci_conn *hconn, struct sk_buff *skb, __u16 flags) -{ - struct l2cap_conn *conn = hconn->l2cap_data; - - if (!conn) { - ERR("unknown connection %p", hconn); - goto drop; - } - - DBG("conn %p len %d flags 0x%x", conn, skb->len, flags); - - if (flags & ACL_START) { - int flen, tlen, size; - l2cap_hdr *lh; - - if (conn->rx_len) { - ERR("Unexpected start frame (len %d)", skb->len); - kfree_skb(conn->rx_skb); conn->rx_skb = NULL; - conn->rx_len = 0; - } - - if (skb->len < L2CAP_HDR_SIZE) { - ERR("Frame is too small (len %d)", skb->len); - goto drop; - } - - lh = (l2cap_hdr *)skb->data; - tlen = __le16_to_cpu(lh->len); - flen = skb->len - L2CAP_HDR_SIZE; - - DBG("Start: total len %d, frag len %d", tlen, flen); - - if (flen == tlen) { - /* Complete frame received */ - l2cap_recv_frame(conn, skb); - return 0; - } - - /* Allocate skb for the complete frame (with header) */ - size = L2CAP_HDR_SIZE + tlen; - if (!(conn->rx_skb = bluez_skb_alloc(size, GFP_ATOMIC))) - goto drop; - - memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len); - - conn->rx_len = tlen - flen; - } else { - DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len); - - if (!conn->rx_len) { - ERR("Unexpected continuation frame (len %d)", skb->len); - goto drop; - } - - if (skb->len > conn->rx_len) { - ERR("Fragment is too large (len %d)", skb->len); - kfree_skb(conn->rx_skb); conn->rx_skb = NULL; - goto drop; - } - - memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len); - conn->rx_len -= skb->len; - - if (!conn->rx_len) { - /* Complete frame received */ - l2cap_recv_frame(conn, conn->rx_skb); - conn->rx_skb = NULL; - } - } - -drop: - kfree_skb(skb); - return 0; -} - -struct proto_ops l2cap_sock_ops = { - family: PF_BLUETOOTH, - release: l2cap_sock_release, - bind: l2cap_sock_bind, - connect: l2cap_sock_connect, - listen: l2cap_sock_listen, - accept: l2cap_sock_accept, - getname: l2cap_sock_getname, - sendmsg: l2cap_sock_sendmsg, - recvmsg: l2cap_sock_recvmsg, - poll: l2cap_sock_poll, - socketpair: sock_no_socketpair, - ioctl: sock_no_ioctl, - shutdown: sock_no_shutdown, - setsockopt: l2cap_sock_setsockopt, - getsockopt: l2cap_sock_getsockopt, - mmap: sock_no_mmap -}; - -struct net_proto_family l2cap_sock_family_ops = { - family: PF_BLUETOOTH, - create: l2cap_sock_create -}; - -struct hci_proto l2cap_hci_proto = { - name: "L2CAP", - id: HCI_PROTO_L2CAP, - connect_ind: l2cap_connect_ind, - connect_cfm: l2cap_connect_cfm, - disconn_ind: l2cap_disconn_ind, - recv_acldata: l2cap_recv_acldata, -}; - -struct notifier_block l2cap_nblock = { - notifier_call: l2cap_dev_event -}; - -int __init l2cap_init(void) -{ - INF("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc", - VERSION); - INF("Written 2000,2001 by Maxim Krasnyansky "); - - if (bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops)) { - ERR("Can't register L2CAP socket"); - return -EPROTO; - } - - if (hci_register_proto(&l2cap_hci_proto) < 0) { - ERR("Can't register L2CAP protocol"); - return -EPROTO; - } - - hci_register_notifier(&l2cap_nblock); - - l2cap_register_proc(); - - return 0; -} - -void l2cap_cleanup(void) -{ - l2cap_unregister_proc(); - - /* Unregister socket, protocol and notifier */ - if (bluez_sock_unregister(BTPROTO_L2CAP)) - ERR("Can't unregister L2CAP socket"); - - if (hci_unregister_proto(&l2cap_hci_proto) < 0) - ERR("Can't unregister L2CAP protocol"); - - hci_unregister_notifier(&l2cap_nblock); - - /* We _must_ not have any sockets and/or connections - * at this stage. - */ - - /* Free interface list and unlock HCI devices */ - { - struct list_head *list = &l2cap_iff_list; - - while (!list_empty(list)) { - struct l2cap_iff *iff; - - iff = list_entry(list->next, struct l2cap_iff, list); - l2cap_iff_del(iff->hdev); - } - } -} - -module_init(l2cap_init); -module_exit(l2cap_cleanup); - -MODULE_AUTHOR("Maxim Krasnyansky "); -MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION); -MODULE_LICENSE("GPL"); - diff -urN linux-2.4.19-pre6/net/bluetooth/l2cap_proc.c linux-2.4.19-pre7/net/bluetooth/l2cap_proc.c --- linux-2.4.19-pre6/net/bluetooth/l2cap_proc.c Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/net/bluetooth/l2cap_proc.c Wed Dec 31 16:00:00 1969 @@ -1,165 +0,0 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * BlueZ L2CAP proc fs support. - * - * $Id: l2cap_proc.c,v 1.2 2001/06/02 01:40:09 maxk Exp $ - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#ifndef L2CAP_DEBUG -#undef DBG -#define DBG( A... ) -#endif - -/* ----- PROC fs support ----- */ -static int l2cap_conn_dump(char *buf, struct l2cap_iff *iff) -{ - struct list_head *p; - char *ptr = buf; - - list_for_each(p, &iff->conn_list) { - struct l2cap_conn *c; - - c = list_entry(p, struct l2cap_conn, list); - ptr += sprintf(ptr, " %p %d %p %p %s %s\n", - c, c->state, c->iff, c->hconn, batostr(&c->src), batostr(&c->dst)); - } - - return ptr - buf; -} - -static int l2cap_iff_dump(char *buf) -{ - struct list_head *p; - char *ptr = buf; - - ptr += sprintf(ptr, "Interfaces:\n"); - - write_lock(&l2cap_rt_lock); - - list_for_each(p, &l2cap_iff_list) { - struct l2cap_iff *iff; - - iff = list_entry(p, struct l2cap_iff, list); - - ptr += sprintf(ptr, " %s %p %p\n", iff->hdev->name, iff, iff->hdev); - - l2cap_iff_lock(iff); - ptr += l2cap_conn_dump(ptr, iff); - l2cap_iff_unlock(iff); - } - - write_unlock(&l2cap_rt_lock); - - ptr += sprintf(ptr, "\n"); - - return ptr - buf; -} - -static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list) -{ - struct l2cap_pinfo *pi; - struct sock *sk; - char *ptr = buf; - - ptr += sprintf(ptr, "Sockets:\n"); - - write_lock(&list->lock); - - for (sk = list->head; sk; sk = sk->next) { - pi = l2cap_pi(sk); - ptr += sprintf(ptr, " %p %d %p %d %s %s 0x%4.4x 0x%4.4x %d %d\n", sk, sk->state, pi->conn, pi->psm, - batostr(&pi->src), batostr(&pi->dst), pi->scid, pi->dcid, pi->imtu, pi->omtu ); - } - - write_unlock(&list->lock); - - ptr += sprintf(ptr, "\n"); - - return ptr - buf; -} - -static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) -{ - char *ptr = buf; - int len; - - DBG("count %d, offset %ld", count, offset); - - ptr += l2cap_iff_dump(ptr); - ptr += l2cap_sock_dump(ptr, &l2cap_sk_list); - len = ptr - buf; - - if (len <= count + offset) - *eof = 1; - - *start = buf + offset; - len -= offset; - - if (len > count) - len = count; - if (len < 0) - len = 0; - - return len; -} - -void l2cap_register_proc(void) -{ - create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL); -} - -void l2cap_unregister_proc(void) -{ - remove_proc_entry("bluetooth/l2cap", NULL); -} diff -urN linux-2.4.19-pre6/net/bluetooth/lib.c linux-2.4.19-pre7/net/bluetooth/lib.c --- linux-2.4.19-pre6/net/bluetooth/lib.c Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/net/bluetooth/lib.c Mon Apr 15 21:55:00 2002 @@ -25,7 +25,7 @@ /* * BlueZ kernel library. * - * $Id: lib.c,v 1.3 2001/06/22 23:14:23 maxk Exp $ + * $Id: lib.c,v 1.1 2002/03/08 21:06:59 maxk Exp $ */ #include diff -urN linux-2.4.19-pre6/net/bluetooth/sco.c linux-2.4.19-pre7/net/bluetooth/sco.c --- linux-2.4.19-pre6/net/bluetooth/sco.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/net/bluetooth/sco.c Mon Apr 15 21:55:00 2002 @@ -0,0 +1,1013 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * BlueZ SCO sockets. + * + * $Id: sco.c,v 1.2 2002/03/18 19:16:40 maxk Exp $ + */ +#define VERSION "0.2" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#ifndef SCO_DEBUG +#undef DBG +#define DBG( A... ) +#endif + +static struct proto_ops sco_sock_ops; + +static struct bluez_sock_list sco_sk_list = { + lock: RW_LOCK_UNLOCKED +}; + +static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent); +static void sco_chan_del(struct sock *sk, int err); +static inline struct sock * sco_chan_get(struct sco_conn *conn); + +static int sco_conn_del(struct hci_conn *conn, int err); + +static void sco_sock_close(struct sock *sk); +static void sco_sock_kill(struct sock *sk); + +/* ----- SCO timers ------ */ +static void sco_sock_timeout(unsigned long arg) +{ + struct sock *sk = (struct sock *) arg; + + DBG("sock %p state %d", sk, sk->state); + + bh_lock_sock(sk); + sk->err = ETIMEDOUT; + sk->state_change(sk); + bh_unlock_sock(sk); + + sco_sock_kill(sk); + sock_put(sk); +} + +static void sco_sock_set_timer(struct sock *sk, long timeout) +{ + DBG("sock %p state %d timeout %ld", sk, sk->state, timeout); + + if (!mod_timer(&sk->timer, jiffies + timeout)) + sock_hold(sk); +} + +static void sco_sock_clear_timer(struct sock *sk) +{ + DBG("sock %p state %d", sk, sk->state); + + if (timer_pending(&sk->timer) && del_timer(&sk->timer)) + __sock_put(sk); +} + +static void sco_sock_init_timer(struct sock *sk) +{ + init_timer(&sk->timer); + sk->timer.function = sco_sock_timeout; + sk->timer.data = (unsigned long)sk; +} + +/* -------- SCO connections --------- */ +static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status) +{ + struct hci_dev *hdev = hcon->hdev; + struct sco_conn *conn; + + if ((conn = hcon->sco_data)) + return conn; + + if (status) + return conn; + + if (!(conn = kmalloc(sizeof(struct sco_conn), GFP_ATOMIC))) + return NULL; + memset(conn, 0, sizeof(struct sco_conn)); + + spin_lock_init(&conn->lock); + + hcon->sco_data = conn; + conn->hcon = hcon; + + conn->src = &hdev->bdaddr; + conn->dst = &hcon->dst; + + if (hdev->sco_mtu > 0) + conn->mtu = hdev->sco_mtu; + else + conn->mtu = 60; + + DBG("hcon %p conn %p", hcon, conn); + + MOD_INC_USE_COUNT; + return conn; +} + +static int sco_conn_del(struct hci_conn *hcon, int err) +{ + struct sco_conn *conn; + struct sock *sk; + + if (!(conn = hcon->sco_data)) + return 0; + + DBG("hcon %p conn %p, err %d", hcon, conn, err); + + /* Kill socket */ + if ((sk = sco_chan_get(conn))) { + bh_lock_sock(sk); + sco_sock_clear_timer(sk); + sco_chan_del(sk, err); + bh_unlock_sock(sk); + sco_sock_kill(sk); + } + + hcon->sco_data = NULL; + kfree(conn); + + MOD_DEC_USE_COUNT; + return 0; +} + +int sco_connect(struct sock *sk) +{ + bdaddr_t *src = &bluez_pi(sk)->src; + bdaddr_t *dst = &bluez_pi(sk)->dst; + struct sco_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; + int err = 0; + + DBG("%s -> %s", batostr(src), batostr(dst)); + + if (!(hdev = hci_get_route(dst, src))) + return -EHOSTUNREACH; + + hci_dev_lock_bh(hdev); + + err = -ENOMEM; + + hcon = hci_connect(hdev, SCO_LINK, dst); + if (!hcon) + goto done; + + conn = sco_conn_add(hcon, 0); + if (!conn) { + hci_conn_put(hcon); + goto done; + } + + /* Update source addr of the socket */ + bacpy(src, conn->src); + + err = sco_chan_add(conn, sk, NULL); + if (err) + goto done; + + if (hcon->state == BT_CONNECTED) { + sco_sock_clear_timer(sk); + sk->state = BT_CONNECTED; + } else { + sk->state = BT_CONNECT; + sco_sock_set_timer(sk, sk->sndtimeo); + } +done: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + return err; +} + +static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) +{ + struct sco_conn *conn = sco_pi(sk)->conn; + struct sk_buff *skb; + int err, count; + + /* Check outgoing MTU */ + if (len > conn->mtu) + return -EINVAL; + + DBG("sk %p len %d", sk, len); + + count = MIN(conn->mtu, len); + if (!(skb = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err))) + return err; + + if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { + err = -EFAULT; + goto fail; + } + + if ((err = hci_send_sco(conn->hcon, skb)) < 0) + goto fail; + + return count; + +fail: + kfree_skb(skb); + return err; +} + +static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) +{ + struct sock *sk = sco_chan_get(conn); + + if (!sk) + goto drop; + + DBG("sk %p len %d", sk, skb->len); + + if (sk->state != BT_CONNECTED) + goto drop; + + if (!sock_queue_rcv_skb(sk, skb)) + return; + +drop: + kfree_skb(skb); + return; +} + +/* -------- Socket interface ---------- */ +static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba) +{ + struct sock *sk; + + for (sk = sco_sk_list.head; sk; sk = sk->next) { + if (!bacmp(&bluez_pi(sk)->src, ba)) + break; + } + + return sk; +} + +/* Find socket listening on source bdaddr. + * Returns closest match. + */ +static struct sock *sco_get_sock_listen(bdaddr_t *src) +{ + struct sock *sk, *sk1 = NULL; + + read_lock(&sco_sk_list.lock); + + for (sk = sco_sk_list.head; sk; sk = sk->next) { + if (sk->state != BT_LISTEN) + continue; + + /* Exact match. */ + if (!bacmp(&bluez_pi(sk)->src, src)) + break; + + /* Closest match */ + if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY)) + sk1 = sk; + } + + read_unlock(&sco_sk_list.lock); + + return sk ? sk : sk1; +} + +static void sco_sock_destruct(struct sock *sk) +{ + DBG("sk %p", sk); + + skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->write_queue); + + MOD_DEC_USE_COUNT; +} + +static void sco_sock_cleanup_listen(struct sock *parent) +{ + struct sock *sk; + + DBG("parent %p", parent); + + /* Close not yet accepted channels */ + while ((sk = bluez_accept_dequeue(parent, NULL))) + sco_sock_close(sk); + + parent->state = BT_CLOSED; + parent->zapped = 1; +} + +/* Kill socket (only if zapped and orphan) + * Must be called on unlocked socket. + */ +static void sco_sock_kill(struct sock *sk) +{ + if (!sk->zapped || sk->socket) + return; + + DBG("sk %p state %d", sk, sk->state); + + /* Kill poor orphan */ + bluez_sock_unlink(&sco_sk_list, sk); + sk->dead = 1; + sock_put(sk); +} + +/* Close socket. + * Must be called on unlocked socket. + */ +static void sco_sock_close(struct sock *sk) +{ + struct sco_conn *conn; + + sco_sock_clear_timer(sk); + + lock_sock(sk); + + conn = sco_pi(sk)->conn; + + DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket); + + switch (sk->state) { + case BT_LISTEN: + sco_sock_cleanup_listen(sk); + break; + + case BT_CONNECTED: + case BT_CONFIG: + case BT_CONNECT: + case BT_DISCONN: + sco_chan_del(sk, ECONNRESET); + break; + + default: + sk->zapped = 1; + break; + }; + + release_sock(sk); + + sco_sock_kill(sk); +} + +static void sco_sock_init(struct sock *sk, struct sock *parent) +{ + DBG("sk %p", sk); + + if (parent) + sk->type = parent->type; +} + +static struct sock *sco_sock_alloc(struct socket *sock, int proto, int prio) +{ + struct sock *sk; + + if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1))) + return NULL; + + bluez_sock_init(sock, sk); + + sk->zapped = 0; + + sk->destruct = sco_sock_destruct; + sk->sndtimeo = SCO_CONN_TIMEOUT; + + sk->protocol = proto; + sk->state = BT_OPEN; + + sco_sock_init_timer(sk); + + bluez_sock_link(&sco_sk_list, sk); + + MOD_INC_USE_COUNT; + return sk; +} + +static int sco_sock_create(struct socket *sock, int protocol) +{ + struct sock *sk; + + DBG("sock %p", sock); + + sock->state = SS_UNCONNECTED; + + if (sock->type != SOCK_SEQPACKET) + return -ESOCKTNOSUPPORT; + + sock->ops = &sco_sock_ops; + + if (!(sk = sco_sock_alloc(sock, protocol, GFP_KERNEL))) + return -ENOMEM; + + sco_sock_init(sk, NULL); + return 0; +} + +static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) +{ + struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; + struct sock *sk = sock->sk; + bdaddr_t *src = &sa->sco_bdaddr; + int err = 0; + + DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr)); + + if (!addr || addr->sa_family != AF_BLUETOOTH) + return -EINVAL; + + lock_sock(sk); + + if (sk->state != BT_OPEN) { + err = -EBADFD; + goto done; + } + + write_lock(&sco_sk_list.lock); + + if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) { + err = -EADDRINUSE; + goto unlock; + } + + /* Save source address */ + bacpy(&bluez_pi(sk)->src, &sa->sco_bdaddr); + sk->state = BT_BOUND; + +unlock: + write_unlock(&sco_sk_list.lock); + +done: + release_sock(sk); + + return err; +} + +static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) +{ + struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; + struct sock *sk = sock->sk; + int err = 0; + + + DBG("sk %p", sk); + + if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco)) + return -EINVAL; + + if (sk->state != BT_OPEN && sk->state != BT_BOUND) + return -EBADFD; + + if (sk->type != SOCK_SEQPACKET) + return -EINVAL; + + lock_sock(sk); + + /* Set destination address and psm */ + bacpy(&bluez_pi(sk)->dst, &sa->sco_bdaddr); + + if ((err = sco_connect(sk))) + goto done; + + err = bluez_sock_w4_connect(sk, flags); + +done: + release_sock(sk); + return err; +} + +int sco_sock_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + int err = 0; + + DBG("sk %p backlog %d", sk, backlog); + + lock_sock(sk); + + if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) { + err = -EBADFD; + goto done; + } + + sk->max_ack_backlog = backlog; + sk->ack_backlog = 0; + sk->state = BT_LISTEN; + +done: + release_sock(sk); + return err; +} + +int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags) +{ + DECLARE_WAITQUEUE(wait, current); + struct sock *sk = sock->sk, *ch; + long timeo; + int err = 0; + + lock_sock(sk); + + if (sk->state != BT_LISTEN) { + err = -EBADFD; + goto done; + } + + timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); + + DBG("sk %p timeo %ld", sk, timeo); + + /* Wait for an incoming connection. (wake-one). */ + add_wait_queue_exclusive(sk->sleep, &wait); + while (!(ch = bluez_accept_dequeue(sk, newsock))) { + set_current_state(TASK_INTERRUPTIBLE); + if (!timeo) { + err = -EAGAIN; + break; + } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); + + if (sk->state != BT_LISTEN) { + err = -EBADFD; + break; + } + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + break; + } + } + set_current_state(TASK_RUNNING); + remove_wait_queue(sk->sleep, &wait); + + if (err) + goto done; + + newsock->state = SS_CONNECTED; + + DBG("new socket %p", ch); + +done: + release_sock(sk); + return err; +} + +static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer) +{ + struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; + struct sock *sk = sock->sk; + + DBG("sock %p, sk %p", sock, sk); + + addr->sa_family = AF_BLUETOOTH; + *len = sizeof(struct sockaddr_sco); + + if (peer) + bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->dst); + else + bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->src); + + return 0; +} + +static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) +{ + struct sock *sk = sock->sk; + int err = 0; + + DBG("sock %p, sk %p", sock, sk); + + if (sk->err) + return sock_error(sk); + + if (msg->msg_flags & MSG_OOB) + return -EOPNOTSUPP; + + lock_sock(sk); + + if (sk->state == BT_CONNECTED) + err = sco_send_frame(sk, msg, len); + else + err = -ENOTCONN; + + release_sock(sk); + return err; +} + +int sco_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) +{ + struct sock *sk = sock->sk; + int err = 0; + + DBG("sk %p", sk); + + lock_sock(sk); + + switch (optname) { + default: + err = -ENOPROTOOPT; + break; + }; + + release_sock(sk); + return err; +} + +int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) +{ + struct sock *sk = sock->sk; + struct sco_options opts; + struct sco_conninfo cinfo; + int len, err = 0; + + DBG("sk %p", sk); + + if (get_user(len, optlen)) + return -EFAULT; + + lock_sock(sk); + + switch (optname) { + case SCO_OPTIONS: + if (sk->state != BT_CONNECTED) { + err = -ENOTCONN; + break; + } + + opts.mtu = sco_pi(sk)->conn->mtu; + + INF("mtu %d", opts.mtu); + + len = MIN(len, sizeof(opts)); + if (copy_to_user(optval, (char *)&opts, len)) + err = -EFAULT; + + break; + + case SCO_CONNINFO: + if (sk->state != BT_CONNECTED) { + err = -ENOTCONN; + break; + } + + cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle; + + len = MIN(len, sizeof(cinfo)); + if (copy_to_user(optval, (char *)&cinfo, len)) + err = -EFAULT; + + break; + + default: + err = -ENOPROTOOPT; + break; + }; + + release_sock(sk); + return err; +} + +static int sco_sock_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + + DBG("sock %p, sk %p", sock, sk); + + if (!sk) + return 0; + + sock_orphan(sk); + sco_sock_close(sk); + + return 0; +} + +static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) +{ + DBG("conn %p", conn); + + sco_pi(sk)->conn = conn; + conn->sk = sk; + + if (parent) + bluez_accept_enqueue(parent, sk); +} + +static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) +{ + int err = 0; + + sco_conn_lock(conn); + if (conn->sk) { + err = -EBUSY; + } else { + __sco_chan_add(conn, sk, parent); + } + sco_conn_unlock(conn); + return err; +} + +static inline struct sock * sco_chan_get(struct sco_conn *conn) +{ + struct sock *sk = NULL; + sco_conn_lock(conn); + sk = conn->sk; + sco_conn_unlock(conn); + return sk; +} + +/* Delete channel. + * Must be called on the locked socket. */ +static void sco_chan_del(struct sock *sk, int err) +{ + struct sco_conn *conn; + + conn = sco_pi(sk)->conn; + + DBG("sk %p, conn %p, err %d", sk, conn, err); + + if (conn) { + sco_conn_lock(conn); + conn->sk = NULL; + sco_pi(sk)->conn = NULL; + sco_conn_unlock(conn); + hci_conn_put(conn->hcon); + } + + sk->state = BT_CLOSED; + sk->err = err; + sk->state_change(sk); + + sk->zapped = 1; +} + +static void sco_conn_ready(struct sco_conn *conn) +{ + struct sock *parent, *sk; + + DBG("conn %p", conn); + + sco_conn_lock(conn); + + if ((sk = conn->sk)) { + sco_sock_clear_timer(sk); + bh_lock_sock(sk); + sk->state = BT_CONNECTED; + sk->state_change(sk); + bh_unlock_sock(sk); + } else { + parent = sco_get_sock_listen(conn->src); + if (!parent) + goto done; + + bh_lock_sock(parent); + + sk = sco_sock_alloc(NULL, BTPROTO_SCO, GFP_ATOMIC); + if (!sk) { + bh_unlock_sock(parent); + goto done; + } + + sco_sock_init(sk, parent); + + bacpy(&bluez_pi(sk)->src, conn->src); + bacpy(&bluez_pi(sk)->dst, conn->dst); + + hci_conn_hold(conn->hcon); + __sco_chan_add(conn, sk, parent); + + sk->state = BT_CONNECTED; + + /* Wake up parent */ + parent->data_ready(parent, 1); + + bh_unlock_sock(parent); + } + +done: + sco_conn_unlock(conn); +} + +/* ----- SCO interface with lower layer (HCI) ----- */ +int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) +{ + DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); + + /* Always accept connection */ + return HCI_LM_ACCEPT; +} + +int sco_connect_cfm(struct hci_conn *hcon, __u8 status) +{ + DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); + + if (hcon->type != SCO_LINK) + return 0; + + if (!status) { + struct sco_conn *conn; + + conn = sco_conn_add(hcon, status); + if (conn) + sco_conn_ready(conn); + } else + sco_conn_del(hcon, bterr(status)); + + return 0; +} + +int sco_disconn_ind(struct hci_conn *hcon, __u8 reason) +{ + DBG("hcon %p reason %d", hcon, reason); + + if (hcon->type != SCO_LINK) + return 0; + + sco_conn_del(hcon, bterr(reason)); + return 0; +} + +int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) +{ + struct sco_conn *conn = hcon->sco_data; + + if (!conn) + goto drop; + + DBG("conn %p len %d", conn, skb->len); + + if (skb->len) { + sco_recv_frame(conn, skb); + return 0; + } + +drop: + kfree_skb(skb); + return 0; +} + +/* ----- Proc fs support ------ */ +static int sco_sock_dump(char *buf, struct bluez_sock_list *list) +{ + struct sco_pinfo *pi; + struct sock *sk; + char *ptr = buf; + + write_lock(&list->lock); + + for (sk = list->head; sk; sk = sk->next) { + pi = sco_pi(sk); + ptr += sprintf(ptr, "%s %s %d\n", + batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), + sk->state); + } + + write_unlock(&list->lock); + + ptr += sprintf(ptr, "\n"); + + return ptr - buf; +} + +static int sco_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) +{ + char *ptr = buf; + int len; + + DBG("count %d, offset %ld", count, offset); + + ptr += sco_sock_dump(ptr, &sco_sk_list); + len = ptr - buf; + + if (len <= count + offset) + *eof = 1; + + *start = buf + offset; + len -= offset; + + if (len > count) + len = count; + if (len < 0) + len = 0; + + return len; +} + +static struct proto_ops sco_sock_ops = { + family: PF_BLUETOOTH, + release: sco_sock_release, + bind: sco_sock_bind, + connect: sco_sock_connect, + listen: sco_sock_listen, + accept: sco_sock_accept, + getname: sco_sock_getname, + sendmsg: sco_sock_sendmsg, + recvmsg: bluez_sock_recvmsg, + poll: bluez_sock_poll, + socketpair: sock_no_socketpair, + ioctl: sock_no_ioctl, + shutdown: sock_no_shutdown, + setsockopt: sco_sock_setsockopt, + getsockopt: sco_sock_getsockopt, + mmap: sock_no_mmap +}; + +static struct net_proto_family sco_sock_family_ops = { + family: PF_BLUETOOTH, + create: sco_sock_create +}; + +static struct hci_proto sco_hci_proto = { + name: "SCO", + id: HCI_PROTO_SCO, + connect_ind: sco_connect_ind, + connect_cfm: sco_connect_cfm, + disconn_ind: sco_disconn_ind, + recv_scodata: sco_recv_scodata, +}; + +int __init sco_init(void) +{ + int err; + + if ((err = bluez_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) { + ERR("Can't register SCO socket layer"); + return err; + } + + if ((err = hci_register_proto(&sco_hci_proto))) { + ERR("Can't register SCO protocol"); + return err; + } + + create_proc_read_entry("bluetooth/sco", 0, 0, sco_read_proc, NULL); + + INF("BlueZ SCO ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); + INF("Written 2000,2001 by Maxim Krasnyansky "); + return 0; +} + +void sco_cleanup(void) +{ + int err; + + remove_proc_entry("bluetooth/sco", NULL); + + /* Unregister socket, protocol and notifier */ + if ((err = bluez_sock_unregister(BTPROTO_SCO))) + ERR("Can't unregister SCO socket layer %d", err); + + if ((err = hci_unregister_proto(&sco_hci_proto))) + ERR("Can't unregister SCO protocol %d", err); +} + +module_init(sco_init); +module_exit(sco_cleanup); + +MODULE_AUTHOR("Maxim Krasnyansky "); +MODULE_DESCRIPTION("BlueZ SCO ver " VERSION); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.19-pre6/net/bluetooth/syms.c linux-2.4.19-pre7/net/bluetooth/syms.c --- linux-2.4.19-pre6/net/bluetooth/syms.c Fri Sep 7 09:28:38 2001 +++ linux-2.4.19-pre7/net/bluetooth/syms.c Mon Apr 15 21:55:00 2002 @@ -25,7 +25,7 @@ /* * BlueZ symbols. * - * $Id: syms.c,v 1.1 2001/07/12 19:31:24 maxk Exp $ + * $Id: syms.c,v 1.1 2002/03/08 21:06:59 maxk Exp $ */ #include @@ -39,7 +39,6 @@ #include #include -#include #include /* HCI Core */ @@ -47,17 +46,18 @@ EXPORT_SYMBOL(hci_unregister_dev); EXPORT_SYMBOL(hci_register_proto); EXPORT_SYMBOL(hci_unregister_proto); -EXPORT_SYMBOL(hci_register_notifier); -EXPORT_SYMBOL(hci_unregister_notifier); +EXPORT_SYMBOL(hci_get_route); EXPORT_SYMBOL(hci_connect); -EXPORT_SYMBOL(hci_disconnect); EXPORT_SYMBOL(hci_dev_get); +EXPORT_SYMBOL(hci_conn_auth); +EXPORT_SYMBOL(hci_conn_encrypt); EXPORT_SYMBOL(hci_recv_frame); EXPORT_SYMBOL(hci_send_acl); EXPORT_SYMBOL(hci_send_sco); EXPORT_SYMBOL(hci_send_raw); +EXPORT_SYMBOL(hci_si_event); /* BlueZ lib */ EXPORT_SYMBOL(bluez_dump); @@ -68,5 +68,11 @@ /* BlueZ sockets */ EXPORT_SYMBOL(bluez_sock_register); EXPORT_SYMBOL(bluez_sock_unregister); +EXPORT_SYMBOL(bluez_sock_init); EXPORT_SYMBOL(bluez_sock_link); EXPORT_SYMBOL(bluez_sock_unlink); +EXPORT_SYMBOL(bluez_sock_recvmsg); +EXPORT_SYMBOL(bluez_sock_poll); +EXPORT_SYMBOL(bluez_accept_enqueue); +EXPORT_SYMBOL(bluez_accept_dequeue); +EXPORT_SYMBOL(bluez_sock_w4_connect); diff -urN linux-2.4.19-pre6/net/core/sock.c linux-2.4.19-pre7/net/core/sock.c --- linux-2.4.19-pre6/net/core/sock.c Fri Dec 21 09:42:05 2001 +++ linux-2.4.19-pre7/net/core/sock.c Mon Apr 15 21:55:00 2002 @@ -108,6 +108,7 @@ #include #include #include +#include #include #include diff -urN linux-2.4.19-pre6/net/ipv4/tcp.c linux-2.4.19-pre7/net/ipv4/tcp.c --- linux-2.4.19-pre6/net/ipv4/tcp.c Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/net/ipv4/tcp.c Mon Apr 15 21:55:02 2002 @@ -251,6 +251,7 @@ #include #include #include +#include #include #include @@ -1157,7 +1158,8 @@ from += copy; copied += copy; - seglen -= copy; + if ((seglen -= copy) == 0 && iovlen == 0) + goto out; if (skb->len != mss_now || (flags&MSG_OOB)) continue; @@ -1376,6 +1378,83 @@ tp->ucopy.memory = 0; } +static inline +struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off) +{ + struct sk_buff *skb; + u32 offset; + + skb_queue_walk(&sk->receive_queue, skb) { + offset = seq - TCP_SKB_CB(skb)->seq; + if (skb->h.th->syn) + offset--; + if (offset < skb->len || skb->h.th->fin) { + *off = offset; + return skb; + } + } + return NULL; +} + +/* + * This routine provides an alternative to tcp_recvmsg() for routines + * that would like to handle copying from skbuffs directly in 'sendfile' + * fashion. + * Note: + * - It is assumed that the socket was locked by the caller. + * - The routine does not block. + * - At present, there is no support for reading OOB data + * or for 'peeking' the socket using this routine + * (although both would be easy to implement). + */ +int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, + sk_read_actor_t recv_actor) +{ + struct sk_buff *skb; + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + u32 seq = tp->copied_seq; + u32 offset; + int copied = 0; + + if (sk->state == TCP_LISTEN) + return -ENOTCONN; + while ((skb = tcp_recv_skb(sk, seq, &offset)) != NULL) { + if (offset < skb->len) { + size_t used, len; + + len = skb->len - offset; + /* Stop reading if we hit a patch of urgent data */ + if (tp->urg_data) { + u32 urg_offset = tp->urg_seq - seq; + if (urg_offset < len) + len = urg_offset; + if (!len) + break; + } + used = recv_actor(desc, skb, offset, len); + if (used <= len) { + seq += used; + copied += used; + offset += used; + } + if (offset != skb->len) + break; + } + if (skb->h.th->fin) { + tcp_eat_skb(sk, skb); + ++seq; + break; + } + tcp_eat_skb(sk, skb); + if (!desc->count) + break; + } + /* Clean up data we have read: This will do ACK frames. */ + if (copied) + cleanup_rbuf(sk, copied); + return copied; +} + /* * This routine copies from a sock struct into the user buffer. * diff -urN linux-2.4.19-pre6/net/ipv6/netfilter/ip6_tables.c linux-2.4.19-pre7/net/ipv6/netfilter/ip6_tables.c --- linux-2.4.19-pre6/net/ipv6/netfilter/ip6_tables.c Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/net/ipv6/netfilter/ip6_tables.c Mon Apr 15 21:55:04 2002 @@ -110,7 +110,7 @@ #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0) #ifdef CONFIG_SMP -#define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*cpu_number_map(p)) +#define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p)) #else #define TABLE_OFFSET(t,p) 0 #endif @@ -336,7 +336,8 @@ read_lock_bh(&table->lock); IP_NF_ASSERT(table->valid_hooks & (1 << hook)); table_base = (void *)table->private->entries - + TABLE_OFFSET(table->private, smp_processor_id()); + + TABLE_OFFSET(table->private, + cpu_number_map(smp_processor_id())); e = get_entry(table_base, table->private->hook_entry[hook]); #ifdef CONFIG_NETFILTER_DEBUG @@ -426,7 +427,7 @@ #endif /* Target might have changed stuff. */ ipv6 = (*pskb)->nh.ipv6h; - protohdr = (u_int32_t *)ipv6 + IPV6_HDR_LEN; + protohdr = (u_int32_t *)((void *)ipv6 + IPV6_HDR_LEN); datalen = (*pskb)->len - IPV6_HDR_LEN; if (verdict == IP6T_CONTINUE) @@ -1795,9 +1796,15 @@ } #ifdef CONFIG_PROC_FS - if (!proc_net_create("ip6_tables_names", 0, ip6t_get_tables)) { - nf_unregister_sockopt(&ip6t_sockopts); - return -ENOMEM; + { + struct proc_dir_entry *proc; + proc = proc_net_create("ip6_tables_names", 0, + ip6t_get_tables); + if (!proc) { + nf_unregister_sockopt(&ip6t_sockopts); + return -ENOMEM; + } + proc->owner = THIS_MODULE; } #endif diff -urN linux-2.4.19-pre6/net/ipv6/netfilter/ip6t_mac.c linux-2.4.19-pre7/net/ipv6/netfilter/ip6t_mac.c --- linux-2.4.19-pre6/net/ipv6/netfilter/ip6t_mac.c Tue Oct 30 15:08:12 2001 +++ linux-2.4.19-pre7/net/ipv6/netfilter/ip6t_mac.c Mon Apr 15 21:55:04 2002 @@ -34,8 +34,10 @@ unsigned int hook_mask) { if (hook_mask - & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN))) { - printk("ip6t_mac: only valid for PRE_ROUTING or LOCAL_IN.\n"); + & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) + | (1 << NF_IP6_FORWARD))) { + printk("ip6t_mac: only valid for PRE_ROUTING, LOCAL_IN or" + " FORWARD\n"); return 0; } @@ -60,3 +62,5 @@ module_init(init); module_exit(fini); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MAC address matching module for IPv6"); diff -urN linux-2.4.19-pre6/net/netsyms.c linux-2.4.19-pre7/net/netsyms.c --- linux-2.4.19-pre6/net/netsyms.c Mon Apr 15 21:54:13 2002 +++ linux-2.4.19-pre7/net/netsyms.c Mon Apr 15 21:55:05 2002 @@ -408,6 +408,8 @@ #endif +EXPORT_SYMBOL(tcp_read_sock); + EXPORT_SYMBOL(netlink_set_err); EXPORT_SYMBOL(netlink_broadcast); EXPORT_SYMBOL(netlink_unicast); diff -urN linux-2.4.19-pre6/scripts/kernel-doc linux-2.4.19-pre7/scripts/kernel-doc --- linux-2.4.19-pre6/scripts/kernel-doc Fri Oct 5 12:06:51 2001 +++ linux-2.4.19-pre7/scripts/kernel-doc Mon Apr 15 21:55:05 2002 @@ -870,7 +870,7 @@ my ($parameter, $section); my $count; - print ".TH \"$args{'module'}\" 9 \"$args{'function'}\" \"$man_date\" \"API Manual\" LINUX\n"; + print ".TH \"$args{'function'}\" 9 \"$args{'function'}\" \"25 May 1998\" \"Kernel Hacker's Manual\" LINUX\n"; print ".SH NAME\n"; print $args{'function'}." \\- ".$args{'purpose'}."\n"; @@ -896,13 +896,13 @@ $parenth = ""; } - print ".SH Arguments\n"; + print ".SH ARGUMENTS\n"; foreach $parameter (@{$args{'parameterlist'}}) { print ".IP \"".$parameter."\" 12\n"; output_highlight($args{'parameterdescs'}{$parameter}); } foreach $section (@{$args{'sectionlist'}}) { - print ".SH \"$section\"\n"; + print ".SH \"", uc $section, "\"\n"; output_highlight($args{'sections'}{$section}); } } diff -urN linux-2.4.19-pre6/scripts/split-man linux-2.4.19-pre7/scripts/split-man --- linux-2.4.19-pre6/scripts/split-man Wed Dec 31 16:00:00 1969 +++ linux-2.4.19-pre7/scripts/split-man Mon Apr 15 21:55:06 2002 @@ -0,0 +1,33 @@ +#!/usr/bin/perl +# +# split-man: create man pages from kernel-doc -man output +# +# Author: Tim Waugh +# Modified by: Christoph Hellwig +# + +use strict; + +die "$0: where do I put the results?\n" unless ($#ARGV >= 0); +die "$0: can't create $ARGV[0]: $!\n" unless mkdir $ARGV[0], 0777; + +my $state = 0; + +while () { + s/&(\w+)/\\fB\1\\fP/g; # fix smgl uglinesses + if (/^\.TH \"[^\"]*\" 9 \"([^\"]*)\"/) { + close OUT unless ($state++ == 0); + my $fn = "$ARGV[0]/$1.9"; + if (open OUT, ">$fn") { + print STDERR "creating $fn\n"; + } else { + die "can't open $fn: $!\n"; + } + + print OUT $_; + } elsif ($state != 0) { + print OUT $_; + } +} + +close OUT;