This feature can be very useful because there are a lot of
programs that malloc() huge amounts of memory "just-in-case"
-and don't much of it.
+and don't use much of it.
Look at: mm/mmap.c::vm_enough_memory() for more information.
#include <linux/pci.h>
#include <linux/apm_bios.h>
#include <linux/kernel.h>
+#include <linux/string.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
#include <asm/irq.h>
#include <asm/mmx.h>
#include <asm/desc.h>
+#include <asm/pgtable.h>
extern void dump_thread(struct pt_regs *, struct user *);
extern spinlock_t rtc_lock;
EXPORT_SYMBOL(get_wchan);
EXPORT_SYMBOL(rtc_lock);
+
+#undef memcpy
+#undef memset
+extern void * memset(void *,int,__kernel_size_t);
+extern void * memcpy(void *,const void *,__kernel_size_t);
+EXPORT_SYMBOL_NOVERS(memcpy);
+EXPORT_SYMBOL_NOVERS(memset);
+
+#ifdef CONFIG_X86_PAE
+EXPORT_SYMBOL(empty_zero_page);
+#endif
L_TARGET = lib.a
L_OBJS = checksum.o old-checksum.o delay.o \
- usercopy.o getuser.o putuser.o iodebug.o
+ usercopy.o getuser.o putuser.o iodebug.o \
+ memcpy.o
ifdef CONFIG_X86_USE_3DNOW
L_OBJS += mmx.o
--- /dev/null
+#include <linux/config.h>
+#include <linux/string.h>
+
+#undef memcpy
+#undef memset
+
+void * memcpy(void * to, const void * from, size_t n)
+{
+#ifdef CONFIG_X86_USE_3DNOW
+ return __memcpy3d(to, from, n);
+#else
+ return __memcpy(to, from, n);
+#endif
+}
+
+void * memset(void * s, int c, size_t count)
+{
+ return __memset(s, c, count);
+}
static int create_strip_zones (mddev_t *mddev)
{
int i, c, j, j1, j2;
- int current_offset, curr_zone_offset;
+ unsigned long current_offset, curr_zone_offset;
raid0_conf_t *conf = mddev_to_conf(mddev);
mdk_rdev_t *smallest, *rdev1, *rdev2, *rdev;
static int raid0_make_request (mddev_t *mddev,
int rw, struct buffer_head * bh)
{
- unsigned int sect_in_chunk, chunksize_bits, chunk, chunk_size;
+ unsigned int sect_in_chunk, chunksize_bits, chunk_size;
raid0_conf_t *conf = mddev_to_conf(mddev);
struct raid0_hash *hash;
struct strip_zone *zone;
mdk_rdev_t *tmp_dev;
- unsigned long block, rsect;
+ unsigned long chunk, block, rsect;
chunk_size = mddev->param.chunk_size >> 10;
chunksize_bits = ffz(~chunk_size);
{
int new_disk = conf->last_used;
const int sectors = bh->b_size >> 9;
- const long this_sector = bh->b_blocknr * sectors;
+ const unsigned long this_sector = bh->b_rsector;
int disk = new_disk;
unsigned long new_distance;
unsigned long current_distance;
raid5_conf_t *conf = sh->raid_conf;
char *b_data;
struct page *b_page;
- int block = sh->sector / (sh->size >> 9);
+ unsigned long block = sh->sector / (sh->size >> 9);
b_data = bh->b_data;
b_page = bh->b_page;
* Input: a 'big' sector number,
* Output: index of the data and parity disk, and the sector # in them.
*/
-static unsigned long raid5_compute_sector(int r_sector, unsigned int raid_disks,
+static unsigned long raid5_compute_sector(unsigned long r_sector, unsigned int raid_disks,
unsigned int data_disks, unsigned int * dd_idx,
unsigned int * pd_idx, raid5_conf_t *conf)
{
- unsigned int stripe;
- int chunk_number, chunk_offset;
+ unsigned long stripe;
+ unsigned long chunk_number;
+ unsigned int chunk_offset;
unsigned long new_sector;
int sectors_per_chunk = conf->chunk_size >> 9;
tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP
if [ "$CONFIG_AGP" != "n" ]; then
bool ' Intel 440LX/BX/GX 840 support' CONFIG_AGP_INTEL
- bool ' Intel I810/I810 DC100/I810e support' CONFIG_AGP_I810
+ bool ' Intel I810/I815 support' CONFIG_AGP_I810
bool ' VIA chipset support' CONFIG_AGP_VIA
bool ' AMD Irongate support' CONFIG_AGP_AMD
bool ' Generic SiS support' CONFIG_AGP_SIS
#ifndef PCI_DEVICE_ID_INTEL_810_E_1
#define PCI_DEVICE_ID_INTEL_810_E_1 0x7125
#endif
+#ifndef PCI_DEVICE_ID_INTEL_815_0
+#define PCI_DEVICE_ID_INTEL_815_0 0x1130
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_815_1
+#define PCI_DEVICE_ID_INTEL_815_1 0x1132
+#endif
#ifndef PCI_DEVICE_ID_INTEL_82443GX_1
#define PCI_DEVICE_ID_INTEL_82443GX_1 0x71a1
#endif
int agp_backend_acquire(void)
{
+ if (agp_bridge.type == NOT_SUPPORTED) {
+ return -EINVAL;
+ }
atomic_inc(&agp_bridge.agp_in_use);
if (atomic_read(&agp_bridge.agp_in_use) != 1) {
void agp_backend_release(void)
{
+ if (agp_bridge.type == NOT_SUPPORTED) {
+ return;
+ }
atomic_dec(&agp_bridge.agp_in_use);
MOD_DEC_USE_COUNT;
}
{
int i;
- if (curr == NULL) {
+ if ((agp_bridge.type == NOT_SUPPORTED) || (curr == NULL)) {
return;
}
if (curr->is_bound == TRUE) {
agp_memory *new;
int i;
+ if (agp_bridge.type == NOT_SUPPORTED) {
+ return NULL;
+ }
if ((atomic_read(&agp_bridge.current_memory_agp) + page_count) >
agp_bridge.max_memory_agp) {
return NULL;
void agp_copy_info(agp_kern_info * info)
{
memset(info, 0, sizeof(agp_kern_info));
+ if (agp_bridge.type == NOT_SUPPORTED) {
+ info->chipset = agp_bridge.type;
+ return;
+ }
info->version.major = agp_bridge.version->major;
info->version.minor = agp_bridge.version->minor;
info->device = agp_bridge.dev;
{
int ret_val;
- if ((curr == NULL) || (curr->is_bound == TRUE)) {
+ if ((agp_bridge.type == NOT_SUPPORTED) ||
+ (curr == NULL) || (curr->is_bound == TRUE)) {
return -EINVAL;
}
if (curr->is_flushed == FALSE) {
{
int ret_val;
- if (curr == NULL) {
+ if ((agp_bridge.type == NOT_SUPPORTED) || (curr == NULL)) {
return -EINVAL;
}
if (curr->is_bound != TRUE) {
}
table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
- for (page = virt_to_page(table); page < get_mem_map(table_end); page++)
+ for (page = virt_to_page(table); page < virt_to_page(table_end); page++)
set_bit(PG_reserved, &page->flags);
agp_bridge.gatt_table_real = (unsigned long *) table;
CACHE_FLUSH();
if (agp_bridge.gatt_table == NULL) {
- for (page = virt_to_page(table); page < get_mem_map(table_end); page++)
+ for (page = virt_to_page(table); page < virt_to_page(table_end); page++)
clear_bit(PG_reserved, &page->flags);
free_pages((unsigned long) table, page_order);
table = (char *) agp_bridge.gatt_table_real;
table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
- for (page = virt_to_page(table); page < get_mem_map(table_end); page++)
+ for (page = virt_to_page(table); page < virt_to_page(table_end); page++)
clear_bit(PG_reserved, &page->flags);
free_pages((unsigned long) agp_bridge.gatt_table_real, page_order);
void agp_enable(u32 mode)
{
+ if (agp_bridge.type == NOT_SUPPORTED) return;
agp_bridge.agp_enable(mode);
}
agp_bridge.type = INTEL_I810;
return intel_i810_setup(i810_dev);
+ case PCI_DEVICE_ID_INTEL_815_0:
+ /* The i815 can operate either as an i810 style
+ * integrated device, or as an AGP4X motherboard.
+ *
+ * This only addresses the first mode:
+ */
+ i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_815_1,
+ NULL);
+ if (i810_dev == NULL) {
+ printk(KERN_ERR PFX "agpgart: Detected an "
+ "Intel i815, but could not find the"
+ " secondary device.\n");
+ agp_bridge.type = NOT_SUPPORTED;
+ return -ENODEV;
+ }
+ printk(KERN_INFO PFX "agpgart: Detected an Intel i815 "
+ "Chipset.\n");
+ agp_bridge.type = INTEL_I810;
+ return intel_i810_setup(i810_dev);
+
default:
break;
}
AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR);
ret_val = agp_backend_initialize();
- if (ret_val)
+ if (ret_val) {
+ agp_bridge.type = NOT_SUPPORTED;
return ret_val;
-
+ }
ret_val = agp_frontend_initialize();
if (ret_val) {
+ agp_bridge.type = NOT_SUPPORTED;
agp_backend_cleanup();
return ret_val;
}
}
if (redraw) {
+ int update;
set_origin(currcons);
- if (sw->con_switch(vc_cons[currcons].d) && vcmode != KD_GRAPHICS) {
- /* Update the screen contents */
- set_palette(currcons);
+ update = sw->con_switch(vc_cons[currcons].d);
+ set_palette(currcons);
+ if (update && vcmode != KD_GRAPHICS)
do_update_region(currcons, origin, screenbuf_size/2);
- }
}
set_cursor(currcons);
if (is_switch) {
EXPORT_SYMBOL(vc_resize);
EXPORT_SYMBOL(fg_console);
EXPORT_SYMBOL(console_blank_hook);
-
+#ifdef CONFIG_VT
+EXPORT_SYMBOL(vt_cons);
+#endif
#ifndef VT_SINGLE_DRIVER
EXPORT_SYMBOL(take_over_console);
EXPORT_SYMBOL(give_up_console);
# Direct Rendering Infrastructure (DRI) in XFree86 4.x.
#
-tristate 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
+bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
if [ "$CONFIG_DRM" != "n" ]; then
tristate ' 3dfx Banshee/Voodoo3+' CONFIG_DRM_TDFX
tristate ' 3dlabs GMX 2000' CONFIG_DRM_GAMMA
+************************************************************
+* For the very latest on DRI development, please see: *
+* http://dri.sourceforge.net/ *
+************************************************************
The Direct Rendering Manager (drm) is a device-independent kernel-level
device driver that provides support for the XFree86 Direct Rendering
A Security Analysis of the Direct Rendering Infrastructure
http://precisioninsight.com/dr/security.html
-
-
-$XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/README.drm,v 1.2 1999/09/27 14:59:24 dawes Exp $
+************************************************************
+* For the very latest on DRI development, please see: *
+* http://dri.sourceforge.net/ *
+************************************************************
return NULL;
memset((void *)head, 0, sizeof(*head));
(*drm_agp.copy_info)(&head->agp_info);
+ if (head->agp_info.chipset == NOT_SUPPORTED) {
+ drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS);
+ return NULL;
+ }
head->memory = NULL;
switch (head->agp_info.chipset) {
- case INTEL_GENERIC: head->chipset = "Intel"; break;
- case INTEL_LX: head->chipset = "Intel 440LX"; break;
- case INTEL_BX: head->chipset = "Intel 440BX"; break;
- case INTEL_GX: head->chipset = "Intel 440GX"; break;
- case INTEL_I810: head->chipset = "Intel i810"; break;
- case VIA_GENERIC: head->chipset = "VIA"; break;
- case VIA_VP3: head->chipset = "VIA VP3"; break;
- case VIA_MVP3: head->chipset = "VIA MVP3"; break;
- case VIA_APOLLO_PRO: head->chipset = "VIA Apollo Pro"; break;
- case VIA_APOLLO_SUPER: head->chipset = "VIA Apollo Super"; break;
- case SIS_GENERIC: head->chipset = "SiS"; break;
- case AMD_GENERIC: head->chipset = "AMD"; break;
- case AMD_IRONGATE: head->chipset = "AMD Irongate"; break;
- case ALI_GENERIC: head->chipset = "ALi"; break;
- case ALI_M1541: head->chipset = "ALi M1541"; break;
- default:
+ case INTEL_GENERIC: head->chipset = "Intel"; break;
+ case INTEL_LX: head->chipset = "Intel 440LX"; break;
+ case INTEL_BX: head->chipset = "Intel 440BX"; break;
+ case INTEL_GX: head->chipset = "Intel 440GX"; break;
+ case INTEL_I810: head->chipset = "Intel i810"; break;
+
+#if LINUX_VERSION_CODE >= 0x020400
+ case INTEL_I840: head->chipset = "Intel i840"; break;
+#endif
+
+ case VIA_GENERIC: head->chipset = "VIA"; break;
+ case VIA_VP3: head->chipset = "VIA VP3"; break;
+ case VIA_MVP3: head->chipset = "VIA MVP3"; break;
+
+#if LINUX_VERSION_CODE >= 0x020400
+ case VIA_MVP4: head->chipset = "VIA MVP4"; break;
+ case VIA_APOLLO_SUPER: head->chipset = "VIA Apollo Super";
+ break;
+#endif
+
+ case VIA_APOLLO_PRO: head->chipset = "VIA Apollo Pro";
+ break;
+ case SIS_GENERIC: head->chipset = "SiS"; break;
+ case AMD_GENERIC: head->chipset = "AMD"; break;
+ case AMD_IRONGATE: head->chipset = "AMD Irongate"; break;
+ case ALI_GENERIC: head->chipset = "ALi"; break;
+ case ALI_M1541: head->chipset = "ALi M1541"; break;
+ default: head->chipset = "Unknown"; break;
}
DRM_INFO("AGP %d.%d on %s @ 0x%08lx %dMB\n",
head->agp_info.version.major,
#endif
#ifndef module_exit
#define module_exit(x) void cleanup_module(void) { x(); }
+#endif
+
+ /* virt_to_page added in 2.4.0-test6 */
+#ifndef virt_to_page
+#define virt_to_page(kaddr) (mem_map + MAP_NR(kaddr))
#endif
/* Generic cmpxchg added in 2.3.x */
extern unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma,
unsigned long address,
int write_access);
+extern unsigned long drm_vm_shm_nopage_lock(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access);
extern unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma,
unsigned long address,
int write_access);
extern struct page *drm_vm_shm_nopage(struct vm_area_struct *vma,
unsigned long address,
int write_access);
+extern struct page *drm_vm_shm_nopage_lock(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access);
extern struct page *drm_vm_dma_nopage(struct vm_area_struct *vma,
unsigned long address,
int write_access);
extern int drm_mmap_dma(struct file *filp,
struct vm_area_struct *vma);
extern int drm_mmap(struct file *filp, struct vm_area_struct *vma);
-extern struct vm_operations_struct drm_vm_ops;
-extern struct vm_operations_struct drm_vm_shm_ops;
-extern struct vm_operations_struct drm_vm_dma_ops;
+
/* Proc support (proc.c) */
extern int drm_proc_init(drm_device_t *dev);
+++ /dev/null
-#include <linux/config.h>
-#include "drmP.h"
-
-/* Misc. support (init.c) */
-EXPORT_SYMBOL(drm_flags);
-EXPORT_SYMBOL(drm_parse_options);
-EXPORT_SYMBOL(drm_cpu_valid);
-
-/* Device support (fops.c) */
-EXPORT_SYMBOL(drm_open_helper);
-EXPORT_SYMBOL(drm_flush);
-EXPORT_SYMBOL(drm_release);
-EXPORT_SYMBOL(drm_fasync);
-EXPORT_SYMBOL(drm_read);
-EXPORT_SYMBOL(drm_write_string);
-EXPORT_SYMBOL(drm_poll);
-
-/* Mapping support (vm.c) */
-#if LINUX_VERSION_CODE < 0x020317
-EXPORT_SYMBOL(drm_vm_nopage);
-EXPORT_SYMBOL(drm_vm_shm_nopage);
-EXPORT_SYMBOL(drm_vm_dma_nopage);
-#else
-/* Return type changed in 2.3.23 */
-EXPORT_SYMBOL(drm_vm_nopage);
-EXPORT_SYMBOL(drm_vm_shm_nopage);
-EXPORT_SYMBOL(drm_vm_dma_nopage);
-#endif
-
-EXPORT_SYMBOL(drm_vm_open);
-EXPORT_SYMBOL(drm_vm_close);
-EXPORT_SYMBOL(drm_mmap_dma);
-EXPORT_SYMBOL(drm_mmap);
-EXPORT_SYMBOL(drm_vm_ops);
-EXPORT_SYMBOL(drm_vm_shm_ops);
-EXPORT_SYMBOL(drm_vm_dma_ops);
-
-/* Proc support (proc.c) */
-EXPORT_SYMBOL(drm_proc_init);
-EXPORT_SYMBOL(drm_proc_cleanup);
-
-/* Memory management support (memory.c) */
-EXPORT_SYMBOL(drm_mem_init);
-EXPORT_SYMBOL(drm_mem_info);
-EXPORT_SYMBOL(drm_alloc);
-EXPORT_SYMBOL(drm_realloc);
-EXPORT_SYMBOL(drm_strdup);
-EXPORT_SYMBOL(drm_strfree);
-EXPORT_SYMBOL(drm_free);
-EXPORT_SYMBOL(drm_alloc_pages);
-EXPORT_SYMBOL(drm_free_pages);
-EXPORT_SYMBOL(drm_ioremap);
-EXPORT_SYMBOL(drm_ioremapfree);
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
-EXPORT_SYMBOL(drm_alloc_agp);
-EXPORT_SYMBOL(drm_free_agp);
-EXPORT_SYMBOL(drm_bind_agp);
-EXPORT_SYMBOL(drm_unbind_agp);
-#endif
-
-/* Buffer management support (bufs.c) */
-EXPORT_SYMBOL(drm_order);
-EXPORT_SYMBOL(drm_addmap);
-EXPORT_SYMBOL(drm_addbufs);
-EXPORT_SYMBOL(drm_infobufs);
-EXPORT_SYMBOL(drm_markbufs);
-EXPORT_SYMBOL(drm_freebufs);
-EXPORT_SYMBOL(drm_mapbufs);
-
-/* Buffer list management support (lists.c) */
-EXPORT_SYMBOL(drm_waitlist_create);
-EXPORT_SYMBOL(drm_waitlist_destroy);
-EXPORT_SYMBOL(drm_waitlist_put);
-EXPORT_SYMBOL(drm_waitlist_get);
-EXPORT_SYMBOL(drm_freelist_create);
-EXPORT_SYMBOL(drm_freelist_destroy);
-EXPORT_SYMBOL(drm_freelist_put);
-EXPORT_SYMBOL(drm_freelist_get);
-
-/* DMA support (gen_dma.c) */
-EXPORT_SYMBOL(drm_dma_setup);
-EXPORT_SYMBOL(drm_dma_takedown);
-EXPORT_SYMBOL(drm_free_buffer);
-EXPORT_SYMBOL(drm_reclaim_buffers);
-EXPORT_SYMBOL(drm_context_switch);
-EXPORT_SYMBOL(drm_context_switch_complete);
-EXPORT_SYMBOL(drm_clear_next_buffer);
-EXPORT_SYMBOL(drm_select_queue);
-EXPORT_SYMBOL(drm_dma_enqueue);
-EXPORT_SYMBOL(drm_dma_get_buffers);
-#if DRM_DMA_HISTOGRAM
-EXPORT_SYMBOL(drm_histogram_slot);
-EXPORT_SYMBOL(drm_histogram_compute);
-#endif
-
-/* Misc. IOCTL support (ioctl.c) */
-EXPORT_SYMBOL(drm_irq_busid);
-EXPORT_SYMBOL(drm_getunique);
-EXPORT_SYMBOL(drm_setunique);
-
-/* Context IOCTL support (context.c) */
-EXPORT_SYMBOL(drm_resctx);
-EXPORT_SYMBOL(drm_addctx);
-EXPORT_SYMBOL(drm_modctx);
-EXPORT_SYMBOL(drm_getctx);
-EXPORT_SYMBOL(drm_switchctx);
-EXPORT_SYMBOL(drm_newctx);
-EXPORT_SYMBOL(drm_rmctx);
-
-/* Drawable IOCTL support (drawable.c) */
-EXPORT_SYMBOL(drm_adddraw);
-EXPORT_SYMBOL(drm_rmdraw);
-
-/* Authentication IOCTL support (auth.c) */
-EXPORT_SYMBOL(drm_add_magic);
-EXPORT_SYMBOL(drm_remove_magic);
-EXPORT_SYMBOL(drm_getmagic);
-EXPORT_SYMBOL(drm_authmagic);
-
-/* Locking IOCTL support (lock.c) */
-EXPORT_SYMBOL(drm_block);
-EXPORT_SYMBOL(drm_unblock);
-EXPORT_SYMBOL(drm_lock_take);
-EXPORT_SYMBOL(drm_lock_transfer);
-EXPORT_SYMBOL(drm_lock_free);
-EXPORT_SYMBOL(drm_finish);
-EXPORT_SYMBOL(drm_flush_unblock);
-EXPORT_SYMBOL(drm_flush_block_and_flush);
-
-/* Context Bitmap support (ctxbitmap.c) */
-EXPORT_SYMBOL(drm_ctxbitmap_init);
-EXPORT_SYMBOL(drm_ctxbitmap_cleanup);
-EXPORT_SYMBOL(drm_ctxbitmap_next);
-EXPORT_SYMBOL(drm_ctxbitmap_free);
-
-/* AGP/GART support (agpsupport.c) */
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
-EXPORT_SYMBOL(drm_agp);
-EXPORT_SYMBOL(drm_agp_init);
-EXPORT_SYMBOL(drm_agp_uninit);
-EXPORT_SYMBOL(drm_agp_acquire);
-EXPORT_SYMBOL(drm_agp_release);
-EXPORT_SYMBOL(drm_agp_enable);
-EXPORT_SYMBOL(drm_agp_info);
-EXPORT_SYMBOL(drm_agp_alloc);
-EXPORT_SYMBOL(drm_agp_free);
-EXPORT_SYMBOL(drm_agp_unbind);
-EXPORT_SYMBOL(drm_agp_bind);
-#endif
static drm_device_t gamma_device;
static struct file_operations gamma_fops = {
-#if LINUX_VERSION_CODE >= 0x020322
- /* This started being used approx. 2.3.34 */
+#if LINUX_VERSION_CODE >= 0x020400
+ /* This started being used during 2.4.0-test */
owner: THIS_MODULE,
#endif
open: gamma_open,
drm_ctx_t i810_res_ctx;
static struct file_operations i810_fops = {
-#if LINUX_VERSION_CODE >= 0x020322
- /* This started being used approx. 2.3.34 */
+#if LINUX_VERSION_CODE >= 0x020400
+ /* This started being used during 2.4.0-test */
owner: THIS_MODULE,
#endif
open: i810_open,
#define __NO_VERSION__
#include <linux/config.h>
#include "drmP.h"
+#include <linux/wrapper.h>
typedef struct drm_mem_stats {
const char *name;
for (addr = address, sz = bytes;
sz > 0;
addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+#if LINUX_VERSION_CODE >= 0x020400
+ /* Argument type changed in 2.4.0-test6/pre8 */
mem_map_reserve(virt_to_page(addr));
+#else
+ mem_map_reserve(MAP_NR(addr));
+#endif
}
return address;
for (addr = address, sz = bytes;
sz > 0;
addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+#if LINUX_VERSION_CODE >= 0x020400
+ /* Argument type changed in 2.4.0-test6/pre8 */
mem_map_unreserve(virt_to_page(addr));
+#else
+ mem_map_unreserve(MAP_NR(addr));
+#endif
}
free_pages(address, order);
}
drm_ctx_t mga_res_ctx;
static struct file_operations mga_fops = {
-#if LINUX_VERSION_CODE >= 0x020322
- /* This started being used approx. 2.3.34 */
+#if LINUX_VERSION_CODE >= 0x020400
+ /* This started being used during 2.4.0-test */
owner: THIS_MODULE,
#endif
open: mga_open,
drm_ctx_t r128_res_ctx;
static struct file_operations r128_fops = {
-#if LINUX_VERSION_CODE >= 0x020322
- /* This started being used approx. 2.3.34 */
+#if LINUX_VERSION_CODE >= 0x020400
+ /* This started being used during 2.4.0-test */
owner: THIS_MODULE,
#endif
open: r128_open,
drm_ctx_t tdfx_res_ctx;
static struct file_operations tdfx_fops = {
-#if LINUX_VERSION_CODE >= 0x020322
- /* This started being used approx. 2.3.34 */
+#if LINUX_VERSION_CODE >= 0x020400
+ /* This started being used during 2.4.0-test */
owner: THIS_MODULE,
#endif
open: tdfx_open,
close: drm_vm_close,
};
+struct vm_operations_struct drm_vm_shm_lock_ops = {
+ nopage: drm_vm_shm_nopage_lock,
+ open: drm_vm_open,
+ close: drm_vm_close,
+};
+
struct vm_operations_struct drm_vm_dma_ops = {
nopage: drm_vm_dma_nopage,
open: drm_vm_open,
unsigned long address,
int write_access)
#endif
+{
+#if LINUX_VERSION_CODE >= 0x020300
+ drm_map_t *map = (drm_map_t *)vma->vm_private_data;
+#else
+ drm_map_t *map = (drm_map_t *)vma->vm_pte;
+#endif
+ unsigned long physical;
+ unsigned long offset;
+
+ if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */
+ if (!map) return NOPAGE_OOM; /* Nothing allocated */
+
+ offset = address - vma->vm_start;
+ physical = (unsigned long)map->handle + offset;
+ atomic_inc(&virt_to_page(physical)->count); /* Dec. by kernel */
+
+ DRM_DEBUG("0x%08lx => 0x%08lx\n", address, physical);
+#if LINUX_VERSION_CODE < 0x020317
+ return physical;
+#else
+ return virt_to_page(physical);
+#endif
+}
+
+#if LINUX_VERSION_CODE < 0x020317
+unsigned long drm_vm_shm_nopage_lock(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+#else
+ /* Return type changed in 2.3.23 */
+struct page *drm_vm_shm_nopage_lock(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+#endif
{
drm_file_t *priv = vma->vm_file->private_data;
drm_device_t *dev = priv->dev;
offset = address - vma->vm_start;
page = offset >> PAGE_SHIFT;
physical = (unsigned long)dev->lock.hw_lock + offset;
- atomic_inc(&virt_to_page(physical)->count); /* Dec. by kernel */
+ atomic_inc(&virt_to_page(physical)->count); /* Dec. by kernel */
DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical);
#if LINUX_VERSION_CODE < 0x020317
return physical;
#else
- return (virt_to_page(physical));
+ return virt_to_page(physical);
#endif
}
#if LINUX_VERSION_CODE < 0x020317
return physical;
#else
- return (virt_to_page(physical));
+ return virt_to_page(physical);
#endif
}
vma->vm_ops = &drm_vm_ops;
break;
case _DRM_SHM:
- vma->vm_ops = &drm_vm_shm_ops;
+ if (map->flags & _DRM_CONTAINS_LOCK)
+ vma->vm_ops = &drm_vm_shm_lock_ops;
+ else {
+ vma->vm_ops = &drm_vm_shm_ops;
+#if LINUX_VERSION_CODE >= 0x020300
+ vma->vm_private_data = (void *)map;
+#else
+ vma->vm_pte = (unsigned long)map;
+#endif
+ }
+
/* Don't let this area swap. Change when
DRM_KERNEL advisory is supported. */
vma->vm_flags |= VM_LOCKED;
if (addr) {
struct page *page;
- for (page = virt_to_page(addr); page < get_mem_map(addr+size); page++)
+ for (page = virt_to_page(addr); page < virt_to_page(addr+size); page++)
mem_map_reserve(page);
}
return (void *)addr;
* No need to return "unknown" for calls without OAD,
* cause that's handled in linklevel now (replaced by '0')
*/
- ic.parm.setup = chanp->proc->para.setup;
+ memcpy (&ic.parm.setup, &chanp->proc->para.setup, sizeof(ic.parm.setup));
ret = chanp->cs->iif.statcallb(&ic);
if (chanp->debug & 1)
link_debug(chanp, 1, "statcallb ret=%d", ret);
FsmChangeState(fi, ST_IN_PROCEED_SEND);
chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc);
if (ret == 5) {
- chanp->setup = ic.parm.setup;
+ memcpy (&chanp->setup, &ic.parm.setup, sizeof(chanp->setup));
chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
}
break;
link_debug(chanp, 1, "DIAL %s -> %s (%d,%d)",
ic->parm.setup.eazmsn, ic->parm.setup.phone,
ic->parm.setup.si1, ic->parm.setup.si2);
- chanp->setup = ic->parm.setup;
+ memcpy (&chanp->setup, &ic->parm.setup, sizeof (chanp->setup));
if (!strcmp(chanp->setup.eazmsn, "0"))
chanp->setup.eazmsn[0] = '\0';
/* this solution is dirty and may be change, if
chanp = csta->channel + ic->arg;
if (chanp->debug & 1)
link_debug(chanp, 1, "REDIR");
- chanp->setup = ic->parm.setup;
+ memcpy (&chanp->setup, &ic->parm.setup, sizeof(chanp->setup));
FsmEvent(&chanp->fi, EV_REDIR, NULL);
break;
} else {
proc->chan = chan;
chan->proc = proc;
- proc->para.setup = chan->setup;
+ memcpy (&proc->para.setup, &chan->setup, sizeof (chan->setup));
proc->callref = cr;
}
} else {
if ((proc = dss1_new_l3_process(st, cr))) {
proc->chan = chan;
chan->proc = proc;
- proc->para.setup = chan->setup;
+ memcpy (&proc->para.setup, &chan->setup, sizeof (chan->setup));
proc->callref = cr;
}
} else {
isdn_dev *dev = (isdn_dev *) 0;
-static char *isdn_revision = "$Revision: 1.101 $";
+static char *isdn_revision = "$Revision: 1.108 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
static void set_global_features(void);
static void isdn_register_devfs(int);
static void isdn_unregister_devfs(int);
+static int isdn_wildmat(char *s, char *p);
void
isdn_lock_drivers(void)
* [^xyz] matches any single character not in the set of characters
*/
-int
+static int
isdn_wildmat(char *s, char *p)
{
register int last;
return (*s == '\0')?0:nostar;
}
+int isdn_msncmp( const char * msn1, const char * msn2 )
+{
+ char TmpMsn1[ ISDN_MSNLEN ];
+ char TmpMsn2[ ISDN_MSNLEN ];
+ char *p;
+
+ for ( p = TmpMsn1; *msn1 && *msn1 != ':'; ) // Strip off a SPID
+ *p++ = *msn1++;
+ *p = '\0';
+
+ for ( p = TmpMsn2; *msn2 && *msn2 != ':'; ) // Strip off a SPID
+ *p++ = *msn2++;
+ *p = '\0';
+
+ return isdn_wildmat( TmpMsn1, TmpMsn2 );
+}
+
static void
isdn_free_queue(struct sk_buff_head *queue)
{
}
if (tf & ISDN_TIMER_CARRIER)
isdn_tty_carrier_timeout();
-#if (defined CONFIG_ISDN_PPP) && (defined CONFIG_ISDN_MPP)
- if (tf & ISDN_TIMER_IPPP)
- isdn_ppp_timer_timeout();
-#endif
}
}
if (tf)
int r;
int retval = 0;
isdn_ctrl cmd;
+ isdn_net_dev *p;
di = c->driver;
i = isdn_dc2minor(di, c->arg);
return 0;
}
/* Try to find a network-interface which will accept incoming call */
- r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, c->parm.setup));
+ r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, &c->parm.setup));
switch (r) {
case 0:
/* No network-device replies.
* 3 on eventually match, if CID is longer.
*/
if (c->command == ISDN_STAT_ICALL)
- if ((retval = isdn_tty_find_icall(di, c->arg, c->parm.setup))) return(retval);
+ if ((retval = isdn_tty_find_icall(di, c->arg, &c->parm.setup))) return(retval);
#ifdef CONFIG_ISDN_DIVERSION
if (divert_if)
if ((retval = divert_if->stat_callback(c)))
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_ACCEPTD;
- isdn_command(&cmd);
- retval = 1;
+ for ( p = dev->netdev; p; p = p->next )
+ if ( p->local->isdn_channel == cmd.arg )
+ {
+ strcpy( cmd.parm.setup.eazmsn, p->local->msn );
+ isdn_command(&cmd);
+ retval = 1;
+ break;
+ }
break;
+
case 2: /* For calling back, first reject incoming call ... */
case 3: /* Interface found, but down, reject call actively */
retval = 2;
ulong flags;
int drvidx;
int chidx;
+ int retval;
char *p;
if (off != &file->f_pos)
return -ESPIPE;
+ lock_kernel();
if (minor == ISDN_MINOR_STATUS) {
if (!file->private_data) {
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto out;
+ }
interruptible_sleep_on(&(dev->info_waitq));
}
p = isdn_statstr();
file->private_data = 0;
if ((len = strlen(p)) <= count) {
- if (copy_to_user(buf, p, len))
- return -EFAULT;
+ if (copy_to_user(buf, p, len)) {
+ retval = -EFAULT;
+ goto out;
+ }
*off += len;
- return len;
+ retval = len;
+ goto out;
}
- return 0;
+ retval = 0;
+ goto out;
+ }
+ if (!dev->drivers) {
+ retval = -ENODEV;
+ goto out;
}
- if (!dev->drivers)
- return -ENODEV;
if (minor < ISDN_MINOR_CTRL) {
+ printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor);
drvidx = isdn_minor2drv(minor);
- if (drvidx < 0)
- return -ENODEV;
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
- return -ENODEV;
+ if (drvidx < 0) {
+ retval = -ENODEV;
+ goto out;
+ }
+ if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
+ retval = -ENODEV;
+ goto out;
+ }
chidx = isdn_minor2chan(minor);
- if( ! (p = kmalloc(count,GFP_KERNEL)) ) return -ENOMEM;
+ if (!(p = kmalloc(count, GFP_KERNEL))) {
+ retval = -ENOMEM;
+ goto out;
+ }
save_flags(flags);
cli();
len = isdn_readbchan(drvidx, chidx, p, 0, count,
&dev->drv[drvidx]->rcv_waitq[chidx]);
*off += len;
restore_flags(flags);
- if( copy_to_user(buf,p,len) ) len = -EFAULT;
+ if (copy_to_user(buf,p,len))
+ len = -EFAULT;
kfree(p);
- return len;
+ retval = len;
+ goto out;
}
if (minor <= ISDN_MINOR_CTRLMAX) {
drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0)
- return -ENODEV;
+ if (drvidx < 0) {
+ retval = -ENODEV;
+ goto out;
+ }
if (!dev->drv[drvidx]->stavail) {
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto out;
+ }
interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
}
if (dev->drv[drvidx]->interface->readstat)
dev->drv[drvidx]->stavail = 0;
restore_flags(flags);
*off += len;
- return len;
+ retval = len;
+ goto out;
}
#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX)
- return (isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count));
+ if (minor <= ISDN_MINOR_PPPMAX) {
+ retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count);
+ goto out;
+ }
#endif
- return -ENODEV;
+ retval = -ENODEV;
+ out:
+ unlock_kernel();
+ return retval;
}
static loff_t
-isdn_lseek(struct file *file, loff_t offset, int orig)
+isdn_llseek(struct file *file, loff_t offset, int orig)
{
return -ESPIPE;
}
uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
int drvidx;
int chidx;
+ int retval;
if (off != &file->f_pos)
return -ESPIPE;
return -EPERM;
if (!dev->drivers)
return -ENODEV;
+
+ lock_kernel();
if (minor < ISDN_MINOR_CTRL) {
+ printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
drvidx = isdn_minor2drv(minor);
- if (drvidx < 0)
- return -ENODEV;
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
- return -ENODEV;
+ if (drvidx < 0) {
+ retval = -ENODEV;
+ goto out;
+ }
+ if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
+ retval = -ENODEV;
+ goto out;
+ }
chidx = isdn_minor2chan(minor);
while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count)
interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
- return count;
+ retval = count;
+ goto out;
}
if (minor <= ISDN_MINOR_CTRLMAX) {
drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0)
- return -ENODEV;
+ if (drvidx < 0) {
+ retval = -ENODEV;
+ goto out;
+ }
/*
* We want to use the isdnctrl device to load the firmware
*
return -ENODEV;
*/
if (dev->drv[drvidx]->interface->writecmd)
- return (dev->drv[drvidx]->interface->
- writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor)));
+ retval = dev->drv[drvidx]->interface->
+ writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor));
else
- return count;
+ retval = count;
+ goto out;
}
#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX)
- return (isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count));
+ if (minor <= ISDN_MINOR_PPPMAX) {
+ retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count);
+ goto out;
+ }
#endif
- return -ENODEV;
+ retval = -ENODEV;
+ out:
+ unlock_kernel();
+ return retval;
}
static unsigned int
unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+ lock_kernel();
if (minor == ISDN_MINOR_STATUS) {
poll_wait(file, &(dev->info_waitq), wait);
/* mask = POLLOUT | POLLWRNORM; */
if (file->private_data) {
mask |= POLLIN | POLLRDNORM;
}
- return mask;
+ goto out;
}
if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
if (drvidx < 0) {
/* driver deregistered while file open */
- return POLLHUP;
+ mask = POLLHUP;
+ goto out;
}
poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
mask = POLLOUT | POLLWRNORM;
if (dev->drv[drvidx]->stavail) {
mask |= POLLIN | POLLRDNORM;
}
- return mask;
+ goto out;
}
#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX)
- return (isdn_ppp_poll(file, wait));
+ if (minor <= ISDN_MINOR_PPPMAX) {
+ mask = isdn_ppp_poll(file, wait);
+ goto out;
+ }
#endif
- printk(KERN_ERR "isdn_common: isdn_poll 2 -> what the hell\n");
- return POLLERR;
+ mask = POLLERR;
+ out:
+ unlock_kernel();
+ return mask;
}
if (!dev->channels)
return -ENODEV;
if (minor < ISDN_MINOR_CTRL) {
+ printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
drvidx = isdn_minor2drv(minor);
if (drvidx < 0)
return -ENODEV;
static struct file_operations isdn_fops =
{
owner: THIS_MODULE,
- llseek: isdn_lseek,
+ llseek: isdn_llseek,
read: isdn_read,
write: isdn_write,
poll: isdn_poll,
skb_pull(nskb, sizeof(int));
if (!nskb->len) {
dev_kfree_skb(nskb);
- dev_kfree_skb(skb);
return v110_ret;
}
/* V.110 must always be acknowledged */
atomic_inc(&dev->v110use[idx]);
dev->v110[idx]->skbuser++;
atomic_dec(&dev->v110use[idx]);
- dev_kfree_skb(skb);
/* For V.110 return unencoded data length */
ret = v110_ret;
+ /* if the complete frame was send we free the skb;
+ if not upper function will requeue the skb */
if (ret == skb->len)
dev_kfree_skb(skb);
}
&isdn_fops, NULL);
dev->devfs_handle_isdnctrl =
devfs_register (devfs_handle, "isdnctrl", DEVFS_FL_DEFAULT,
- ISDN_MAJOR, ISDN_MINOR_CTRL, 0600 | S_IFCHR,
+ ISDN_MAJOR, ISDN_MINOR_CTRL, 0600 | S_IFCHR,
&isdn_fops, NULL);
}
extern int isdn_get_free_channel(int, int, int, int, int, char *);
extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
extern int register_isdn(isdn_if * i);
-extern int isdn_wildmat(char *, char *);
+extern int isdn_msncmp( const char *, const char *);
extern int isdn_add_channels(driver *, int, int, int);
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
extern void isdn_dumppkt(char *, u_char *, int, int);
#endif /* CONFIG_ISDN_X25 */
if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
#ifdef CONFIG_ISDN_PPP
- isdn_ppp_free(lp);
+ if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+ isdn_ppp_free(lp);
#endif
isdn_net_lp_disconnected(lp);
isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
#endif
if (lp->flags & ISDN_NET_CONNECTED) {
+ if (lp->slave != NULL) {
+ isdn_net_local *slp = (isdn_net_local *)lp->slave->priv;
+ if (slp->flags & ISDN_NET_CONNECTED) {
+ printk(KERN_INFO
+ "isdn_net: hang up slave %s before %s\n",
+ slp->name, lp->name);
+ isdn_net_hangup(lp->slave);
+ }
+ }
printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name);
#ifdef CONFIG_ISDN_PPP
- isdn_ppp_free(lp);
+ if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+ isdn_ppp_free(lp);
#endif
isdn_net_lp_disconnected(lp);
#ifdef CONFIG_ISDN_X25
}
spin_lock_bh(&lp->xmit_lock);
- if (!isdn_net_lp_busy(lp))
- {
+ if (!isdn_net_lp_busy(lp)) {
isdn_net_writebuf_skb(lp, skb);
} else {
skb_queue_tail(&lp->super_tx_queue, skb);
lp = isdn_net_get_locked_lp(nd);
if (!lp) {
- printk(KERN_WARNING "%s: all channels busy - requeuing!\n", lp->name);
+ printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name);
return 1;
}
/* we have our lp locked from now on */
* would eventually match if CID was longer.
*/
int
-isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
+isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
{
char *eaz;
int si1;
/* Search name in netdev-chain */
save_flags(flags);
cli();
- if (!setup.phone[0]) {
+ if (!setup->phone[0]) {
nr[0] = '0';
nr[1] = '\0';
printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n");
} else
- strcpy(nr, setup.phone);
- si1 = (int) setup.si1;
- si2 = (int) setup.si2;
- if (!setup.eazmsn[0]) {
+ strcpy(nr, setup->phone);
+ si1 = (int) setup->si1;
+ si2 = (int) setup->si2;
+ if (!setup->eazmsn[0]) {
printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n");
eaz = "0";
} else
- eaz = setup.eazmsn;
+ eaz = setup->eazmsn;
if (dev->net_verbose > 1)
printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz);
/* Accept only calls with Si1 = 7 (Data-Transmission) */
break;
}
swapped = 0;
- if (!(matchret = isdn_wildmat(eaz, isdn_map_eaz2msn(lp->msn, di))))
+ if (!(matchret = isdn_msncmp(eaz, isdn_map_eaz2msn(lp->msn, di))))
ematch = 1;
/* Remember if more numbers eventually can match */
if (matchret > wret)
n = lp->phone[0];
if (lp->flags & ISDN_NET_SECURE) {
while (n) {
- if (!isdn_wildmat(nr, n->num))
+ if (!isdn_msncmp(nr, n->num))
break;
n = (isdn_net_phone *) n->next;
}
}
netdev->local->magic = ISDN_NET_MAGIC;
-#ifdef CONFIG_ISDN_PPP
- netdev->mp_last = NULL; /* mpqueue is empty */
- netdev->ib.next_num = 0;
- netdev->ib.last = NULL;
-#endif
netdev->queue = netdev->local;
spin_lock_init(&netdev->queue_lock);
extern int isdn_net_getphones(isdn_net_ioctl_phone *, char *);
extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone *);
extern int isdn_net_delphone(isdn_net_ioctl_phone *);
-extern int isdn_net_find_icall(int, int, int, setup_parm);
+extern int isdn_net_find_icall(int, int, int, setup_parm *);
extern void isdn_net_hangup(struct net_device *);
extern void isdn_net_dial(void);
extern void isdn_net_autohup(void);
while (isdn_net_lp_busy(nd->queue)) {
spin_unlock_bh(&nd->queue->xmit_lock);
nd->queue = nd->queue->next;
- if (nd->queue == lp) /* not found -- should never happen */
- return 0;
+ if (nd->queue == lp) { /* not found -- should never happen */
+ lp = NULL;
+ goto errout;
+ }
spin_lock_bh(&nd->queue->xmit_lock);
}
lp = nd->queue;
-
nd->queue = nd->queue->next;
+errout:
spin_unlock_irqrestore(&nd->queue_lock, flags);
return lp;
}
#ifdef CONFIG_ISDN_MPP
-static int isdn_ppp_bundle(struct ippp_struct *, int unit);
-static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask);
-static void isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min);
-static void isdn_ppp_cleanup_sqqueue(isdn_net_dev * dev, isdn_net_local *, long min);
-static void isdn_ppp_free_sqqueue(isdn_net_dev *);
-static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb,
- int BEbyte, long *sqno, int min_sqno);
-static void isdn_ppp_free_mpqueue(isdn_net_dev *);
-#endif
+static ippp_bundle * isdn_ppp_bundle_arr = NULL;
+
+static int isdn_ppp_mp_bundle_array_init(void);
+static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to );
+static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
+ struct sk_buff *skb);
+static void isdn_ppp_mp_cleanup( isdn_net_local * lp );
-char *isdn_ppp_revision = "$Revision: 1.69 $";
+static int isdn_ppp_bundle(struct ippp_struct *, int unit);
+#endif /* CONFIG_ISDN_MPP */
+
+char *isdn_ppp_revision = "$Revision: 1.77 $";
static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
int
isdn_ppp_free(isdn_net_local * lp)
{
- isdn_net_local *master_lp = lp;
unsigned long flags;
struct ippp_struct *is;
cli();
#ifdef CONFIG_ISDN_MPP
- if (lp->next == lp) { /* last link in queue? */
- master_lp->netdev->ib.bundled = 0;
- isdn_ppp_free_mpqueue(master_lp->netdev);
- isdn_ppp_free_sqqueue(master_lp->netdev);
- }
+ spin_lock(&lp->netdev->pb->lock);
#endif
-
isdn_net_rm_from_bundle(lp);
+#ifdef CONFIG_ISDN_MPP
+ if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */
+ isdn_ppp_mp_cleanup(lp);
+
+ lp->netdev->pb->ref_ct--;
+ spin_unlock(&lp->netdev->pb->lock);
+#endif /* CONFIG_ISDN_MPP */
is = ippp_table[lp->ppp_slot];
-
if ((is->state & IPPP_CONNECT))
isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */
else if (is->state & IPPP_ASSIGNED)
lp->ppp_slot = -1; /* is this OK ?? */
restore_flags(flags);
-
return 0;
}
save_flags(flags);
cli();
-
if (lp->pppbind < 0) { /* device bounded to ippp device ? */
isdn_net_dev *net_dev = dev->netdev;
char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */
printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name);
return -1;
}
+
lp->ppp_slot = i;
-
- /* reset some values */
- lp->netdev->ib.bundled = 0;
- lp->netdev->ib.next_num = 0;
- lp->netdev->ib.modify = 0;
- lp->netdev->ib.last = NULL;
- lp->netdev->ib.min = 0;
- lp->netdev->ib.sq = NULL;
-
is = ippp_table[i];
is->lp = lp;
is->unit = unit;
is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */
+#ifdef CONFIG_ISDN_MPP
+ if (isdn_ppp_mp_init(lp, NULL) < 0)
+ return -ENOMEM;
+#endif /* CONFIG_ISDN_MPP */
restore_flags(flags);
is->mp_seqno = 0; /* MP sequence number */
is->pppcfg = 0; /* ppp configuration */
is->mpppcfg = 0; /* mppp configuration */
- is->range = 0x1000000; /* MP: 24 bit range */
is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */
is->unit = -1; /* set, when we have our interface */
is->mru = 1524; /* MRU, default 1524 */
{
int i,
j;
+
+#ifdef CONFIG_ISDN_MPP
+ if( isdn_ppp_mp_bundle_array_init() < 0 )
+ return -ENOMEM;
+#endif /* CONFIG_ISDN_MPP */
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
if (!(ippp_table[i] = (struct ippp_struct *)
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
kfree(ippp_table[i]);
+
+#ifdef CONFIG_ISDN_MPP
+ if (isdn_ppp_bundle_arr)
+ kfree(isdn_ppp_bundle_arr);
+#endif /* CONFIG_ISDN_MPP */
+
}
/*
void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb)
{
struct ippp_struct *is;
+ int slot;
int proto;
- is = ippp_table[lp->ppp_slot];
+ slot = lp->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot %d\n", lp->ppp_slot);
+ kfree_skb(skb);
+ return;
+ }
+ is = ippp_table[slot];
if (is->debug & 0x4) {
printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n",
#ifdef CONFIG_ISDN_MPP
if (!(is->mpppcfg & SC_REJ_MP_PROT)) {
- int sqno_end;
if(is->compflags & SC_LINK_DECOMP_ON) {
if(proto == PPP_COMPFRAG) {
}
if (proto == PPP_MP) {
- isdn_net_local *lpq;
- long sqno, min_sqno, tseq;
-
- u_char BEbyte = skb->data[0];
- if (is->debug & 0x8)
- printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_slot, proto,
- (int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
- (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
- if (!(is->mpppcfg & SC_IN_SHORT_SEQ)) {
- sqno = ((int) skb->data[1] << 16) + ((int) skb->data[2] << 8) + (int) skb->data[3];
- skb_pull(skb, 4);
- } else {
- sqno = (((int) skb->data[0] & 0xf) << 8) + (int) skb->data[1];
- skb_pull(skb, 2);
- }
-
- /*
- * new sequence number lower than last number? (this is only allowed
- * for overflow case)
- */
- if ((tseq = is->last_link_seqno) >= sqno) {
- int range = is->range;
- if (tseq + 1024 < range + sqno) /* redundancy check .. not MP conform */
- printk(KERN_WARNING "isdn_ppp_receive, MP, detected overflow with sqno: %ld, last: %ld !!!\n", sqno, tseq);
- else {
- sqno += range;
- is->last_link_seqno = sqno;
- }
- } else {
- /* here, we should also add an redundancy check */
- is->last_link_seqno = sqno;
- }
-
- /*
- * step over all links to find lowest link number
- */
- for (min_sqno = LONG_MAX, lpq = net_dev->queue;;) {
- long lls = ippp_table[lpq->ppp_slot]->last_link_seqno;
- if (lls >= 0 && lls < min_sqno)
- min_sqno = lls;
- lpq = lpq->next;
- if (lpq == net_dev->queue)
- break;
- }
-
- /*
- * for the case, that the last frame numbers of all
- * links are overflowed: mask/reduce the sequenece number to
- * 'normal' numbering.
- */
- if (min_sqno >= ippp_table[lpq->ppp_slot]->range) {
- int mask = ippp_table[lpq->ppp_slot]->range-1; /* range is power of two, so a mask will do the job */
- isdn_ppp_mask_queue(net_dev, mask);
- net_dev->ib.next_num &= mask;
- {
- struct sqqueue *q = net_dev->ib.sq;
- while (q) {
- q->sqno_start &= mask;
- q->sqno_end &= mask;
- }
- }
- min_sqno &= mask;
- for (lpq = net_dev->queue;;) {
- if(ippp_table[lpq->ppp_slot]->last_link_seqno >= 0)
- ippp_table[lpq->ppp_slot]->last_link_seqno &= mask;
- lpq = lpq->next;
- if (lpq == net_dev->queue)
- break;
- }
- }
- if ((BEbyte & (MP_BEGIN_FRAG | MP_END_FRAG)) != (MP_BEGIN_FRAG | MP_END_FRAG)) {
- static int dmes = 0;
- if( !dmes ) {
- printk(KERN_DEBUG "ippp: trying ;) to fill mp_queue %d .. UNTESTED!!\n", lp->ppp_slot);
- dmes = 1;
- }
- if ((sqno_end = isdn_ppp_fill_mpqueue(net_dev, &skb, BEbyte, &sqno, min_sqno)) < 0) {
- net_dev->ib.modify = 1; /* block timeout-timer */
- isdn_ppp_cleanup_sqqueue(net_dev, lp, min_sqno);
- net_dev->ib.modify = 0;
- return; /* no packet complete */
- }
- } else
- sqno_end = sqno;
-
- if (is->debug & 0x40)
- printk(KERN_DEBUG "min_sqno: %ld sqno_end %d next: %ld\n", min_sqno, sqno_end, net_dev->ib.next_num);
-
- /*
- * MP buffer management .. reorders incoming packets ..
- * lotsa mem-copies and not heavily tested.
- *
- * first check whether there is more than one link in the bundle
- * then check whether the number is in order
- */
- net_dev->ib.modify = 1; /* block timeout-timer */
- if (net_dev->ib.bundled && net_dev->ib.next_num != sqno) {
- /*
- * packet is not 'in order'
- */
- struct sqqueue *q;
-
- q = (struct sqqueue *) kmalloc(sizeof(struct sqqueue), GFP_ATOMIC);
- if (!q) {
- net_dev->ib.modify = 0;
- printk(KERN_WARNING "ippp/MPPP: Bad! Can't alloc sq node!\n");
- dev_kfree_skb(skb);
- return; /* discard */
- }
- q->skb = skb;
- q->sqno_end = sqno_end;
- q->sqno_start = sqno;
- q->timer = jiffies + (ISDN_TIMER_1SEC) * 5; /* timeout after 5 seconds */
-
- if (!net_dev->ib.sq) {
- net_dev->ib.sq = q;
- q->next = NULL;
- } else {
- struct sqqueue *ql = net_dev->ib.sq;
- if (ql->sqno_start > q->sqno_start) {
- q->next = ql;
- net_dev->ib.sq = q;
- } else {
- while (ql->next && ql->next->sqno_start < q->sqno_start)
- ql = ql->next;
- q->next = ql->next;
- ql->next = q;
- }
- }
- } else {
- /*
- * packet was 'in order' .. push it higher
- */
- net_dev->ib.next_num = sqno_end + 1;
- proto = isdn_ppp_strip_proto(skb);
- isdn_ppp_push_higher(net_dev, lp, skb, proto);
- }
- isdn_ppp_cleanup_sqqueue(net_dev, lp, min_sqno);
- net_dev->ib.modify = 0;
-
- } else
+ isdn_ppp_mp_receive(net_dev, lp, skb);
+ }
+ else
isdn_ppp_push_higher(net_dev, lp, skb, proto);
} else
-#endif
+#endif /* CONFIG_ISDN_MPP */
isdn_ppp_push_higher(net_dev, lp, skb, proto);
}
isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto)
{
struct net_device *dev = &net_dev->dev;
- struct ippp_struct *is = ippp_table[lp->ppp_slot];
+ struct ippp_struct *is;
+ int slot;
+ slot = lp->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot %d\n", lp->ppp_slot);
+ kfree_skb(skb);
+ return;
+ }
+ is = ippp_table[slot];
if (is->debug & 0x10) {
printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
isdn_net_dev *nd;
unsigned int proto = PPP_IP; /* 0x21 */
struct ippp_struct *ipt,*ipts;
+ int slot;
mlp = (isdn_net_local *) (netdev->priv);
-
nd = mlp->netdev; /* get master lp */
- ipts = ippp_table[mlp->ppp_slot];
+
+ slot = mlp->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot %d\n", mlp->ppp_slot);
+ kfree_skb(skb);
+ return 0;
+ }
+ ipts = ippp_table[slot];
if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
if (ipts->debug & 0x1)
lp = isdn_net_get_locked_lp(nd);
if (!lp) {
- printk(KERN_WARNING "%s: all channels busy - requeuing!\n", lp->name);
+ printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
return 1;
}
/* we have our lp locked from now on */
- ipt = ippp_table[lp->ppp_slot];
+ slot = lp->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot %d\n", lp->ppp_slot);
+ kfree_skb(skb);
+ return 0;
+ }
+ ipt = ippp_table[slot];
lp->huptimer = 0;
/*
#ifdef CONFIG_ISDN_MPP
-/*
- * free SQ queue
- * -------------
- * Note: We need two queues for MPPP. The SQ queue holds fully (re)assembled frames,
- * that can't be delivered, because there is an outstanding earlier frame
+/* this is _not_ rfc1990 header, but something we convert both short and long
+ * headers to for convinience's sake:
+ * byte 0 is flags as in rfc1990
+ * bytes 1...4 is 24-bit seqence number converted to host byte order
*/
-static void
-isdn_ppp_free_sqqueue(isdn_net_dev * p)
-{
- struct sqqueue *q = p->ib.sq;
+#define MP_HEADER_LEN 5
- p->ib.sq = NULL;
- while (q) {
- struct sqqueue *qn = q->next;
- if (q->skb)
- dev_kfree_skb(q->skb);
- kfree(q);
- q = qn;
- }
+#define MP_LONGSEQ_MASK 0x00ffffff
+#define MP_SHORTSEQ_MASK 0x00000fff
+#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK
+#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK
+#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK+1)>>1)
+#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK+1)>>1)
-}
+/* sequence-wrap safe comparisions (for long sequence)*/
+#define MP_LT(a,b) ((a-b)&MP_LONGSEQ_MAXBIT)
+#define MP_LE(a,b) !((b-a)&MP_LONGSEQ_MAXBIT)
+#define MP_GT(a,b) ((b-a)&MP_LONGSEQ_MAXBIT)
+#define MP_GE(a,b) !((a-b)&MP_LONGSEQ_MAXBIT)
-/*
- * free MP queue
- * -------------
- * Note: The MP queue holds all frame fragments of frames, that can't be
- * reassembled, because there is at least one missing fragment.
- */
-static void
-isdn_ppp_free_mpqueue(isdn_net_dev * p)
-{
- struct mpqueue *q = p->mp_last;
- p->mp_last = NULL;
+#define MP_SEQ(f) ((*(u32*)(f->data+1)))
+#define MP_FLAGS(f) (f->data[0])
- while (q) {
- struct mpqueue *ql = q->next;
- dev_kfree_skb(q->skb);
- kfree(q);
- q = ql;
- }
+static int isdn_ppp_mp_bundle_array_init(void)
+{
+ int i;
+ int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle);
+ if( (isdn_ppp_bundle_arr = (ippp_bundle*)kmalloc(sz,
+ GFP_KERNEL)) == NULL )
+ return -ENOMEM;
+ memset(isdn_ppp_bundle_arr, 0, sz);
+ for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
+ spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
+ return 0;
}
-static int
-isdn_ppp_bundle(struct ippp_struct *is, int unit)
+static ippp_bundle * isdn_ppp_mp_bundle_alloc(void)
{
- char ifn[IFNAMSIZ + 1];
- long flags;
- isdn_net_dev *p;
- isdn_net_local *lp, *nlp;
-
- sprintf(ifn, "ippp%d", unit);
- p = isdn_net_findif(ifn);
- if (!p)
- return -1;
-
- save_flags(flags);
- cli();
- isdn_timer_ctrl(ISDN_TIMER_IPPP, 1); /* enable timer for ippp/MP */
-
- nlp = is->lp;
- lp = p->queue;
- isdn_net_add_to_bundle(p, nlp);
- p->ib.bundled = 1;
-
- ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
-/* maybe also SC_CCP stuff */
- ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
- (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
-
- ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
- (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
- restore_flags(flags);
- return 0;
+ int i;
+ for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
+ if (isdn_ppp_bundle_arr[i].ref_ct <= 0)
+ return (isdn_ppp_bundle_arr + i);
+ return NULL;
}
-/*
- * Mask sequence numbers in MP queue
- */
-static void
-isdn_ppp_mask_queue(isdn_net_dev * dev, long mask)
+static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
{
- struct mpqueue *q = dev->mp_last;
- while (q) {
- q->sqno &= mask;
- q = q->next;
- }
+ struct ippp_struct * is = ippp_table[lp->ppp_slot];
+
+ if (add_to) {
+ if( lp->netdev->pb )
+ lp->netdev->pb->ref_ct--;
+ lp->netdev->pb = add_to;
+ } else { /* first link in a bundle */
+ is->mp_seqno = 0;
+ if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
+ return -ENOMEM;
+ lp->next = lp->last = lp; /* nobody else in a queue */
+ lp->netdev->pb->frags = NULL;
+ lp->netdev->pb->frames = 0;
+ lp->netdev->pb->seq = LONG_MAX;
+ }
+ lp->netdev->pb->ref_ct++;
+
+ is->last_link_seqno = 0;
+ return 0;
}
-/*
- * put a fragment at the right place into the MP queue
- * Also checks, whether this fragment completes a frame. In this case
- * the fragments are copied together into one SKB
- */
-static int
-isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff **skb, int BEbyte, long *sqnop, int min_sqno)
+static u32 isdn_ppp_mp_get_seq( int short_seq,
+ struct sk_buff * skb, u32 last_seq );
+struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
+ struct sk_buff * from, struct sk_buff * to );
+void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
+ struct sk_buff * from, struct sk_buff * to );
+static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb );
+static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb );
+
+static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
+ struct sk_buff *skb)
{
- struct mpqueue *qe,
- *q1,
- *q;
- long cnt,
- flags;
- int pktlen,
- sqno_end;
- int sqno = *sqnop;
-
- q1 = (struct mpqueue *) kmalloc(sizeof(struct mpqueue), GFP_ATOMIC);
- if (!q1) {
- printk(KERN_WARNING "isdn_ppp_fill_mpqueue: Can't alloc struct memory.\n");
- save_flags(flags);
- cli();
- isdn_ppp_cleanup_mpqueue(dev, min_sqno);
- restore_flags(flags);
- return -1;
+ struct ippp_struct *is;
+ isdn_net_local * lpq;
+ ippp_bundle * mp;
+ isdn_mppp_stats * stats;
+ struct sk_buff * newfrag, * frag, * start, *nextf;
+ u32 newseq, minseq, thisseq;
+ unsigned long flags;
+ int slot;
+
+ spin_lock_irqsave(&net_dev->pb->lock, flags);
+ mp = net_dev->pb;
+ stats = &mp->stats;
+ slot = lp->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ printk(KERN_ERR "isdn_ppp_mp_receive: lp->ppp_slot %d\n", lp->ppp_slot);
+ stats->frame_drops++;
+ dev_kfree_skb(skb);
+ spin_unlock_irqrestore(&mp->lock, flags);
+ return;
}
- q1->skb = *skb;
- q1->sqno = sqno;
- q1->BEbyte = BEbyte;
- q1->time = jiffies;
+ is = ippp_table[slot];
+ if( ++mp->frames > stats->max_queue_len )
+ stats->max_queue_len = mp->frames;
+
+ if (is->debug & 0x8)
+ isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);
- save_flags(flags);
- cli();
+ newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,
+ skb, is->last_link_seqno);
- if (!(q = dev->mp_last)) {
- dev->mp_last = q1;
- q1->next = NULL;
- q1->last = NULL;
- isdn_ppp_cleanup_mpqueue(dev, min_sqno); /* not necessary */
- restore_flags(flags);
- return -1; /* -1 is not an error. Just says, that this fragment hasn't complete a full frame */
+
+ /* if this packet seq # is less than last already processed one,
+ * toss it right away, but check for sequence start case first
+ */
+ if( mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT) ) {
+ mp->seq = newseq; /* the first packet: required for
+ * rfc1990 non-compliant clients --
+ * prevents constant packet toss */
+ } else if( MP_LT(newseq, mp->seq) ) {
+ stats->frame_drops++;
+ isdn_ppp_mp_free_skb(mp, skb);
+ spin_unlock_irqrestore(&mp->lock, flags);
+ return;
}
- for (;;) { /* the faster way would be to step from the queue-end to the start */
- if (sqno > q->sqno) {
- if (q->next) {
- q = q->next;
- continue;
- }
- q->next = q1;
- q1->next = NULL;
- q1->last = q;
- break;
+
+ /* find the minimum received sequence number over all links */
+ is->last_link_seqno = minseq = newseq;
+ for (lpq = net_dev->queue;;) {
+ slot = lpq->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ printk(KERN_ERR "isdn_ppp_mp_receive: lpq->ppp_slot %d\n", lpq->ppp_slot);
+ } else {
+ u32 lls = ippp_table[slot]->last_link_seqno;
+ if (MP_LT(lls, minseq))
+ minseq = lls;
}
- if (sqno == q->sqno)
- printk(KERN_WARNING "isdn_fill_mpqueue: illegal sqno received!!\n");
- q1->last = q->last;
- q1->next = q;
- if (q->last) {
- q->last->next = q1;
- } else
- dev->mp_last = q1;
- q->last = q1;
- break;
+ if ((lpq = lpq->next) == net_dev->queue)
+ break;
}
-
-/* now we check whether we completed a packet with this fragment */
- pktlen = -q1->skb->len;
- q = q1;
- cnt = q1->sqno;
- while (!(q->BEbyte & MP_END_FRAG)) {
- cnt++;
- if (!(q->next) || q->next->sqno != cnt) {
- isdn_ppp_cleanup_mpqueue(dev, min_sqno);
- restore_flags(flags);
- return -1;
+ if (MP_LT(minseq, mp->seq))
+ minseq = mp->seq; /* can't go beyond already processed
+ * packets */
+ newfrag = skb;
+
+ /* if this new fragment is before the first one, then enqueue it now. */
+ if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {
+ newfrag->next = frag;
+ mp->frags = frag = newfrag;
+ newfrag = NULL;
+ }
+
+ start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&
+ MP_SEQ(frag) == mp->seq ? frag : NULL;
+
+ /*
+ * main fragment traversing loop
+ *
+ * try to accomplish several tasks:
+ * - insert new fragment into the proper sequence slot (once that's done
+ * newfrag will be set to NULL)
+ * - reassemble any complete fragment sequence (non-null 'start'
+ * indicates there is a continguous sequence present)
+ * - discard any incomplete sequences that are below minseq -- due
+ * to the fact that sender always increment sequence number, if there
+ * is an incomplete sequence below minseq, no new fragments would
+ * come to complete such sequence and it should be discarded
+ *
+ * loop completes when we accomplished the following tasks:
+ * - new fragment is inserted in the proper sequence ('newfrag' is
+ * set to NULL)
+ * - we hit a gap in the sequence, so no reassembly/processing is
+ * possible ('start' would be set to NULL)
+ *
+ * algorightm for this code is derived from code in the book
+ * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
+ */
+ while (start != NULL || newfrag != NULL) {
+
+ thisseq = MP_SEQ(frag);
+ nextf = frag->next;
+
+ /* drop any duplicate fragments */
+ if (newfrag != NULL && thisseq == newseq) {
+ isdn_ppp_mp_free_skb(mp, newfrag);
+ newfrag = NULL;
+ }
+
+ /* insert new fragment before next element if possible. */
+ if (newfrag != NULL && (nextf == NULL ||
+ MP_LT(newseq, MP_SEQ(nextf)))) {
+ newfrag->next = nextf;
+ frag->next = nextf = newfrag;
+ newfrag = NULL;
+ }
+
+ if (start != NULL) {
+ /* check for misplaced start */
+ if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
+ printk(KERN_WARNING"isdn_mppp(seq %d): new "
+ "BEGIN flag with no prior END", thisseq);
+ stats->seqerrs++;
+ stats->frame_drops++;
+ start = isdn_ppp_mp_discard(mp, start,frag);
+ nextf = frag->next;
+ }
+ } else if (MP_LE(thisseq, minseq)) {
+ if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
+ start = frag;
+ else {
+ if (MP_FLAGS(frag) & MP_END_FRAG)
+ stats->frame_drops++;
+ if( mp->frags == frag )
+ mp->frags = nextf;
+ isdn_ppp_mp_free_skb(mp, frag);
+ frag = nextf;
+ continue;
+ }
}
- pktlen += q->skb->len;
- q = q->next;
- }
- pktlen += q->skb->len;
- qe = q;
-
- q = q1;
- cnt = q1->sqno;
- while (!(q->BEbyte & MP_BEGIN_FRAG)) {
- cnt--;
- if (!(q->last) || q->last->sqno != cnt) {
- isdn_ppp_cleanup_mpqueue(dev, min_sqno);
- restore_flags(flags);
- return -1;
+
+ /* if start is non-null and we have end fragment, then
+ * we have full reassembly sequence -- reassemble
+ * and process packet now
+ */
+ if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
+ minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;
+ /* Reassemble the packet then dispatch it */
+ isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);
+
+ start = NULL;
+ frag = NULL;
+
+ mp->frags = nextf;
+ }
+
+ /* check if need to update start pointer: if we just
+ * reassembled the packet and sequence is contiguous
+ * then next fragment should be the start of new reassembly
+ * if sequence is contiguous, but we haven't reassembled yet,
+ * keep going.
+ * if sequence is not contiguous, either clear everyting
+ * below low watermark and set start to the next frag or
+ * clear start ptr.
+ */
+ if (nextf != NULL &&
+ ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {
+ /* if we just reassembled and the next one is here,
+ * then start another reassembly. */
+
+ if (frag == NULL) {
+ if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
+ start = nextf;
+ else
+ {
+ printk(KERN_WARNING"isdn_mppp(seq %d):"
+ " END flag with no following "
+ "BEGIN", thisseq);
+ stats->seqerrs++;
+ }
+ }
+
+ } else {
+ if ( nextf != NULL && frag != NULL &&
+ MP_LT(thisseq, minseq)) {
+ /* we've got a break in the sequence
+ * and we not at the end yet
+ * and we did not just reassembled
+ *(if we did, there wouldn't be anything before)
+ * and we below the low watermark
+ * discard all the frames below low watermark
+ * and start over */
+ stats->frame_drops++;
+ mp->frags = isdn_ppp_mp_discard(mp,start,nextf);
+ }
+ /* break in the sequence, no reassembly */
+ start = NULL;
+ }
+
+ frag = nextf;
+ } /* while -- main loop */
+
+ if (mp->frags == NULL)
+ mp->frags = frag;
+
+ /* rather straighforward way to deal with (not very) possible
+ * queue overflow */
+ if (mp->frames > MP_MAX_QUEUE_LEN) {
+ stats->overflows++;
+ while (mp->frames > MP_MAX_QUEUE_LEN) {
+ frag = mp->frags->next;
+ isdn_ppp_mp_free_skb(mp, mp->frags);
+ mp->frags = frag;
}
- pktlen += q->skb->len;
- q = q->last;
}
- pktlen += q->skb->len;
+ spin_unlock_irqrestore(&mp->lock, flags);
+}
- if (q->last)
- q->last->next = qe->next;
+static void isdn_ppp_mp_cleanup( isdn_net_local * lp )
+{
+ struct sk_buff * frag = lp->netdev->pb->frags;
+ struct sk_buff * nextfrag;
+ while( frag ) {
+ nextfrag = frag->next;
+ isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
+ frag = nextfrag;
+ }
+ lp->netdev->pb->frags = NULL;
+}
+
+static u32 isdn_ppp_mp_get_seq( int short_seq,
+ struct sk_buff * skb, u32 last_seq )
+{
+ u32 seq;
+ int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);
+
+ if( !short_seq )
+ {
+ seq = ntohl(*(u32*)skb->data) & MP_LONGSEQ_MASK;
+ skb_push(skb,1);
+ }
else
- dev->mp_last = qe->next;
+ {
+ /* convert 12-bit short seq number to 24-bit long one
+ */
+ seq = ntohs(*(u16*)skb->data) & MP_SHORTSEQ_MASK;
+
+ /* check for seqence wrap */
+ if( !(seq & MP_SHORTSEQ_MAXBIT) &&
+ (last_seq & MP_SHORTSEQ_MAXBIT) &&
+ (unsigned long)last_seq <= MP_LONGSEQ_MAX )
+ seq |= (last_seq + MP_SHORTSEQ_MAX+1) &
+ (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
+ else
+ seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
+
+ skb_push(skb, 3); /* put converted seqence back in skb */
+ }
+ *(u32*)(skb->data+1) = seq; /* put seqence back in _host_ byte
+ * order */
+ skb->data[0] = flags; /* restore flags */
+ return seq;
+}
- if (qe->next)
- qe->next->last = q->last;
- qe->next = NULL;
- sqno_end = qe->sqno;
- *sqnop = q->sqno;
+struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
+ struct sk_buff * from, struct sk_buff * to )
+{
+ if( from )
+ while (from != to) {
+ struct sk_buff * next = from->next;
+ isdn_ppp_mp_free_skb(mp, from);
+ from = next;
+ }
+ return from;
+}
- isdn_ppp_cleanup_mpqueue(dev, min_sqno);
- restore_flags(flags);
+void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
+ struct sk_buff * from, struct sk_buff * to )
+{
+ ippp_bundle * mp = net_dev->pb;
+ int proto;
+ struct sk_buff * skb;
+ unsigned int tot_len;
+
+ if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {
+ if( ippp_table[lp->ppp_slot]->debug & 0x40 )
+ printk(KERN_DEBUG"isdn_mppp: reassembly: frame %d, "
+ "len %d\n", MP_SEQ(from), from->len );
+ skb = from;
+ skb_pull(skb, MP_HEADER_LEN);
+ mp->frames--;
+ } else {
+ struct sk_buff * frag;
+ int n;
+
+ for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++)
+ tot_len += frag->len - MP_HEADER_LEN;
+
+ if( ippp_table[lp->ppp_slot]->debug & 0x40 )
+ printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
+ "to %d, len %d\n", MP_SEQ(from),
+ (MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len );
+ if( (skb = dev_alloc_skb(tot_len)) == NULL ) {
+ printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
+ "of size %d\n", tot_len);
+ isdn_ppp_mp_discard(mp, from, to);
+ return;
+ }
- *skb = dev_alloc_skb(pktlen + 40); /* not needed: +40 for VJ compression .. */
+ while( from != to ) {
+ unsigned int len = from->len - MP_HEADER_LEN;
- if (!(*skb)) {
- while (q) {
- struct mpqueue *ql = q->next;
- dev_kfree_skb(q->skb);
- kfree(q);
- q = ql;
+ memcpy(skb_put(skb,len), from->data+MP_HEADER_LEN, len);
+ frag = from->next;
+ isdn_ppp_mp_free_skb(mp, from);
+ from = frag;
}
- return -2;
}
- cnt = 0;
- skb_put(*skb, pktlen);
- while (q) {
- struct mpqueue *ql = q->next;
- memcpy((*skb)->data + cnt, q->skb->data, q->skb->len);
- cnt += q->skb->len;
- dev_kfree_skb(q->skb);
- kfree(q);
- q = ql;
- }
-
- return sqno_end;
+ proto = isdn_ppp_strip_proto(skb);
+ isdn_ppp_push_higher(net_dev, lp, skb, proto);
}
-/*
- * check sq-queue, whether we have still buffered the next packet(s)
- * or packets with a sqno less or equal to min_sqno
- * net_dev: master netdevice , lp: 'real' local connection
- */
-static void
-isdn_ppp_cleanup_sqqueue(isdn_net_dev * net_dev, isdn_net_local * lp, long min_sqno)
+static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb)
{
- struct sqqueue *q;
+ dev_kfree_skb(skb);
+ mp->frames--;
+}
- while ((q = net_dev->ib.sq) && (q->sqno_start == net_dev->ib.next_num || q->sqno_end <= min_sqno)) {
- int proto;
- if (q->sqno_start != net_dev->ib.next_num) {
- printk(KERN_DEBUG "ippp: MP, stepping over missing frame: %ld\n", net_dev->ib.next_num);
-#ifdef CONFIG_ISDN_PPP_VJ
- slhc_toss(ippp_table[net_dev->local->ppp_slot]->slcomp);
-#endif
- }
- proto = isdn_ppp_strip_proto(q->skb);
- isdn_ppp_push_higher(net_dev, lp, q->skb, proto);
- net_dev->ib.sq = q->next;
- net_dev->ib.next_num = q->sqno_end + 1;
- kfree(q);
- }
+static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb )
+{
+ printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n",
+ slot, (int) skb->len,
+ (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
+ (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
}
-/*
- * remove stale packets from list
- */
-static void
-isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno)
+static int
+isdn_ppp_bundle(struct ippp_struct *is, int unit)
{
-#ifdef CONFIG_ISDN_PPP_VJ
- int toss = 0;
-#endif
- /* currently we just discard ancient packets.
- To do:
- Maybe, as long as there's no B-packet in front and sqno <= min_sqno: discard.
- If sqno < min_sqno and there are gaps: discard (the gaps won't be filled anyway).
- Packets with sqno > min_sqno: Larger than mp_mrru: If sum of all pktlen of pending
- packets large than mrru: discard - packets need to be consecutive, though, if not
- there could be an B and an E-packet in between.
- */
+ char ifn[IFNAMSIZ + 1];
+ isdn_net_dev *p;
+ isdn_net_local *lp, *nlp;
+ int rc;
+ unsigned long flags;
- struct mpqueue *ql,
- *q = dev->mp_last;
- while(q && (q->sqno < min_sqno) ) {
- if ( (q->BEbyte & MP_END_FRAG) ||
- (q->next && (q->next->sqno <= min_sqno) && (q->next->BEbyte & MP_BEGIN_FRAG)) ) {
- printk(KERN_DEBUG "ippp: freeing stale packet(s), min_sq: %ld!\n",min_sqno);
- if ((dev->mp_last = q->next))
- q->next->last = NULL;
- while (q) {
- ql = q->last;
- printk(KERN_DEBUG "ippp, freeing packet with sqno: %ld\n",q->sqno);
- dev_kfree_skb(q->skb);
- kfree(q);
-#ifdef CONFIG_ISDN_PPP_VJ
- toss = 1;
-#endif
- q = ql;
- }
- q = dev->mp_last;
- } else
- q = q->next;
+ sprintf(ifn, "ippp%d", unit);
+ p = isdn_net_findif(ifn);
+ if (!p) {
+ printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn);
+ return -EINVAL;
}
-#ifdef CONFIG_ISDN_PPP_VJ
- /* did we free a stale frame ? */
- if (toss)
- slhc_toss(ippp_table[dev->local->ppp_slot]->slcomp);
-#endif
-}
-#endif
-/*
- * a buffered packet timed-out?
- */
-void
-isdn_ppp_timer_timeout(void)
-{
-#ifdef CONFIG_ISDN_MPP
- isdn_net_dev *net_dev = dev->netdev;
- struct sqqueue *q,
- *ql = NULL,
- *qn;
-
- while (net_dev) {
- isdn_net_local *lp = net_dev->local;
- if (net_dev->ib.modify || lp->master) { /* interface locked or slave? */
- net_dev = net_dev->next;
- continue;
- }
- q = net_dev->ib.sq;
- while (q) {
- if (q->sqno_start == net_dev->ib.next_num || q->timer < jiffies) {
+ spin_lock_irqsave(&p->pb->lock, flags);
-#ifdef CONFIG_ISDN_PPP_VJ
- /* did we step over a missing frame ? */
- if (q->sqno_start != net_dev->ib.next_num)
- slhc_toss(ippp_table[lp->ppp_slot]->slcomp);
-#endif
+ nlp = is->lp;
+ lp = p->queue;
+ if( nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ||
+ lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS ) {
+ printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
+ nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ?
+ nlp->ppp_slot : lp->ppp_slot );
+ rc = -EINVAL;
+ goto out;
+ }
- ql = net_dev->ib.sq;
- net_dev->ib.sq = q->next;
- net_dev->ib.next_num = q->sqno_end + 1;
- q->next = NULL;
- for (; ql;) {
- int proto = isdn_ppp_strip_proto(ql->skb);
- isdn_ppp_push_higher(net_dev, lp, ql->skb, proto);
- qn = ql->next;
- kfree(ql);
- ql = qn;
- }
- q = net_dev->ib.sq;
- } else
- q = q->next;
- }
- net_dev = net_dev->next;
- }
-#endif
-}
+ isdn_net_add_to_bundle(p, nlp);
+
+ ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
+ /* maybe also SC_CCP stuff */
+ ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
+ (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
+ ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
+ (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
+ rc = isdn_ppp_mp_init(nlp, p->pb);
+out:
+ spin_unlock_irqrestore(&p->pb->lock, flags);
+ return rc;
+}
+
+#endif /* CONFIG_ISDN_MPP */
+
/*
* network device ioctl handlers
*/
#include <linux/ppp_defs.h> /* for PPP_PROTOCOL */
#include <linux/isdn_ppp.h> /* for isdn_ppp info */
-extern void isdn_ppp_timer_timeout(void);
extern int isdn_ppp_read(int, struct file *, char *, int);
extern int isdn_ppp_write(int, struct file *, const char *, int);
extern int isdn_ppp_open(int, struct file *);
-/* $Id: isdn_tty.c,v 1.92 2000/06/21 09:54:29 keil Exp $
+/* $Id: isdn_tty.c,v 1.93 2000/08/05 09:58:26 armin Exp $
* Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
*
static int si2bit[8] =
{4, 1, 4, 4, 4, 4, 4, 4};
-char *isdn_tty_revision = "$Revision: 1.92 $";
+char *isdn_tty_revision = "$Revision: 1.93 $";
/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
int c;
int total = 0;
modem_info *info = (modem_info *) tty->driver_data;
+ atemu *m = &info->emu;
if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write"))
return 0;
|| (info->vonline & 3)
#endif
) {
- atemu *m = &info->emu;
-
#ifdef CONFIG_ISDN_AUDIO
if (!info->vonline)
#endif
isdn_command(&c);
}
info->vonline = 0;
- printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc,c);
+#ifdef ISDN_DEBUG_MODEM_VOICE
+ printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc, c);
+#endif
info->xmit_count += cc;
} else
#endif
count -= c;
total += c;
}
- if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
- isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
atomic_dec(&info->xmit_lock);
+ if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) {
+ if (m->mdmreg[REG_DXMT] & BIT_DXMT) {
+ isdn_tty_senddown(info);
+ isdn_tty_tint(info);
+ }
+ isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
+ }
if (from_user)
up(&info->write_sem);
return total;
while (1) {
if ((q = strchr(p, ';')))
*q = '\0';
- if ((tmp = isdn_wildmat(cid, isdn_map_eaz2msn(p, di))) > ret)
+ if ((tmp = isdn_msncmp(cid, isdn_map_eaz2msn(p, di))) > ret)
ret = tmp;
#ifdef ISDN_DEBUG_MODEM_ICALL
printk(KERN_DEBUG "m_fi: lmsnX=%s mmsn=%s -> tmp=%d\n",
return ret;
} else {
int tmp;
- tmp = isdn_wildmat(cid, isdn_map_eaz2msn(emu->msn, di));
+ tmp = isdn_msncmp(cid, isdn_map_eaz2msn(emu->msn, di));
#ifdef ISDN_DEBUG_MODEM_ICALL
printk(KERN_DEBUG "m_fi: mmsn=%s -> tmp=%d\n",
isdn_map_eaz2msn(emu->msn, di), tmp);
* CID is longer.
*/
int
-isdn_tty_find_icall(int di, int ch, setup_parm setup)
+isdn_tty_find_icall(int di, int ch, setup_parm *setup)
{
char *eaz;
int i;
char *nr;
ulong flags;
- if (!setup.phone[0]) {
+ if (!setup->phone[0]) {
nr = "0";
printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n");
} else
- nr = setup.phone;
- si1 = (int) setup.si1;
- si2 = (int) setup.si2;
- if (!setup.eazmsn[0]) {
+ nr = setup->phone;
+ si1 = (int) setup->si1;
+ si2 = (int) setup->si2;
+ if (!setup->eazmsn[0]) {
printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n");
eaz = "0";
} else
- eaz = setup.eazmsn;
+ eaz = setup->eazmsn;
#ifdef ISDN_DEBUG_MODEM_ICALL
printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2);
#endif
strcpy(dev->num[idx], nr);
strcpy(info->emu.cpn, eaz);
info->emu.mdmreg[REG_SI1I] = si2bit[si1];
- info->emu.mdmreg[REG_PLAN] = setup.plan;
- info->emu.mdmreg[REG_SCREEN] = setup.screen;
+ info->emu.mdmreg[REG_PLAN] = setup->plan;
+ info->emu.mdmreg[REG_SCREEN] = setup->screen;
isdn_info_update();
restore_flags(flags);
printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
#ifdef ISDN_TTY_STAT_DEBUG
printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line);
#endif
+ /* Wake up any processes waiting
+ * for incoming call of this device when
+ * DCD follow the state of incoming carrier
+ */
+ if (info->blocked_open &&
+ (info->emu.mdmreg[REG_DCD] & BIT_DCD)) {
+ wake_up_interruptible(&info->open_wait);
+ }
+
/* Schedule CONNECT-Message to any tty
* waiting for it and
* set DCD-bit of its modem-status.
*/
- if (TTY_IS_ACTIVE(info)) {
+ if (TTY_IS_ACTIVE(info) ||
+ (info->blocked_open && (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
info->msr |= UART_MSR_DCD;
info->emu.charge = 0;
if (info->dialing & 0xf)
int limit = ISDN_MSNLEN - 1;
while (((*p[0] >= '0' && *p[0] <= '9') ||
- /* Why a comma ??? */
- (*p[0] == ',')) &&
+ /* Why a comma ??? */
+ (*p[0] == ',') || (*p[0] == ':')) &&
(limit--))
*n++ = *p[0]++;
*n = '\0';
#define REG_CPPP 12
#define BIT_CPPP 128
+#define REG_DXMT 13
+#define BIT_DXMT 1
#define REG_T70 13
#define BIT_T70 2
#define BIT_T70_EXT 32
extern void isdn_tty_modem_xmit(void);
extern int isdn_tty_modem_init(void);
extern void isdn_tty_readmodem(void);
-extern int isdn_tty_find_icall(int, int, setup_parm);
+extern int isdn_tty_find_icall(int, int, setup_parm *);
extern void isdn_tty_cleanup_xmit(modem_info *);
extern int isdn_tty_stat_callback(int, isdn_ctrl *);
extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
spin_lock_irqsave (&lp->lock, flags);
if (wait_cmd(dev,lp,1000,"timed out waiting to issue RX_START")) {
- spin_unlock_irqrestore ((&lp->lock, flags);
+ spin_unlock_irqrestore (&lp->lock, flags);
goto failed;
}
DEB(DEB_INIT,printk("%s: Issuing RX_START\n", dev->name));
{
int i;
int retcode;
- unsigned char dummy_packet[64] = { 0 };
+ unsigned char dummy_packet[64];
/* Powerup the chip */
outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
dummy_packet[12] = 0x00;
dummy_packet[13] = 0x04;
+ memset(dummy_packet + 14, 0, sizeof(dummy_packet) - 14);
eth16i_select_regbank(2, ioaddr);
* to use vverify()?
*/
- if (MAP_NR(insn) < 1 || MAP_NR(insn + 8) > MAP_NR(high_memory) ||
+ if (virt_to_phys((void *)insn) < PAGE_SIZE ||
+ virt_to_phys((void *)(insn + 8)) > virt_to_phys(high_memory) ||
((((dcmd = (insn[0] >> 24) & 0xff) & DCMD_TYPE_MMI) == DCMD_TYPE_MMI) &&
- MAP_NR(insn + 12) > MAP_NR(high_memory))) {
+ virt_to_phys((void *)(insn + 12)) > virt_to_phys(high_memory))) {
size = 0;
sprintf (buf, "%s%p: address out of range\n",
prefix, insn);
static int
check_address (unsigned long addr, int size) {
- return (MAP_NR(addr) < 1 || MAP_NR(addr + size) > MAP_NR(high_memory) ?
- -1 : 0);
+ return (virt_to_phys((void *)addr) < PAGE_SIZE || virt_to_phys((void *)(addr + size)) > virt_to_phys(high_memory) ? -1 : 0);
}
#ifdef MODULE
* to use vverify()?
*/
- if (MAP_NR(insn) < 1 || MAP_NR(insn + 8) > MAP_NR(high_memory) ||
+ if (virt_to_phys((void *)insn) < PAGE_SIZE ||
+ virt_to_phys((void *)(insn + 8)) > virt_to_phys(high_memory) ||
((((dcmd = (insn[0] >> 24) & 0xff) & DCMD_TYPE_MMI) == DCMD_TYPE_MMI) &&
- MAP_NR(insn + 12) > MAP_NR(high_memory))) {
+ virt_to_phys((void *)(insn + 12)) > virt_to_phys(high_memory))) {
size = 0;
sprintf (buf, "%s%p: address out of range\n",
prefix, insn);
static int
check_address (unsigned long addr, int size) {
- return (MAP_NR(addr) < 1 || MAP_NR(addr + size) > MAP_NR(high_memory) ?
- -1 : 0);
+ return (virt_to_phys((void *)addr) < PAGE_SIZE || virt_to_phys((void *)(addr + size)) > virt_to_phys(high_memory) ? -1 : 0);
}
#ifdef MODULE
The driver is currently maintained by Kai M{kisara (email
Kai.Makisara@metla.fi)
-Last modified: Sat Apr 22 14:50:25 2000 by makisara@kai.makisara.local
+Last modified: Sat Aug 5 10:29:07 2000 by makisara@kai.makisara.local
BASICS
In variable block mode, the byte count in write() determines the size
of the physical block on tape. When reading, the drive reads the next
tape block and returns to the user the data if the read() byte count
-is at least the block size. Otherwise the data is truncated.
+is at least the block size. Otherwise, error ENOMEM is returned.
In fixed block mode, the data transfer between the drive and the
driver is in multiples of the block size. The write() byte count must
Copyright 1992 - 2000 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Sat Jun 17 15:21:49 2000 by makisara@kai.makisara.local
+ Last modified: Sun Aug 6 23:02:13 2000 by makisara@kai.makisara.local
Some small formal changes - aeb, 950809
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
+
+ Reminder: write_lock_irqsave() can be replaced by write_lock() when the old SCSI
+ error handling will be discarded.
*/
#include <linux/module.h>
static int modes_defined;
-static ST_buffer *new_tape_buffer(int, int);
+static ST_buffer *new_tape_buffer(int, int, int);
static int enlarge_buffer(ST_buffer *, int, int);
static void normalize_buffer(ST_buffer *);
static int append_to_buffer(const char *, ST_buffer *, int);
}
\f
-/* Open the device */
-static int scsi_tape_open(struct inode *inode, struct file *filp)
+/* Open the device. Needs to be called with BKL only because of incrementing the SCSI host
+ module count. */
+static int st_open(struct inode *inode, struct file *filp)
{
- unsigned short flags;
+ unsigned short st_flags;
int i, need_dma_buffer, new_session = FALSE;
int retval;
unsigned char cmd[MAX_COMMAND_SIZE];
ST_partstat *STps;
int dev = TAPE_NR(inode->i_rdev);
int mode = TAPE_MODE(inode->i_rdev);
+ unsigned long flags;
- read_lock(&st_dev_arr_lock);
+ write_lock_irqsave(&st_dev_arr_lock, flags);
STp = scsi_tapes[dev];
if (dev >= st_template.dev_max || STp == NULL) {
- read_unlock(&st_dev_arr_lock);
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
return (-ENXIO);
}
- read_unlock(&st_dev_arr_lock);
- if (!scsi_block_when_processing_errors(STp->device)) {
- return -ENXIO;
- }
if (STp->in_use) {
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); )
return (-EBUSY);
}
STp->in_use = 1;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
STp->rew_at_close = STp->autorew_dev = (MINOR(inode->i_rdev) & 0x80) == 0;
if (STp->device->host->hostt->module)
__MOD_INC_USE_COUNT(STp->device->host->hostt->module);
+ if (!scsi_block_when_processing_errors(STp->device)) {
+ retval = (-ENXIO);
+ goto err_out;
+ }
+
if (mode != STp->current_mode) {
DEBC(printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n",
dev, STp->current_mode, mode));
/* Allocate a buffer for this user */
need_dma_buffer = STp->restr_dma;
- read_lock(&st_dev_arr_lock);
+ write_lock_irqsave(&st_dev_arr_lock, flags);
for (i = 0; i < st_nbr_buffers; i++)
if (!st_buffers[i]->in_use &&
(!need_dma_buffer || st_buffers[i]->dma)) {
STp->buffer = st_buffers[i];
+ (STp->buffer)->in_use = 1;
break;
}
- read_unlock(&st_dev_arr_lock);
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
if (i >= st_nbr_buffers) {
- STp->buffer = new_tape_buffer(FALSE, need_dma_buffer);
+ STp->buffer = new_tape_buffer(FALSE, need_dma_buffer, TRUE);
if (STp->buffer == NULL) {
printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev);
retval = (-EBUSY);
}
}
- (STp->buffer)->in_use = 1;
(STp->buffer)->writing = 0;
(STp->buffer)->syscall_result = 0;
(STp->buffer)->use_sg = STp->device->host->sg_tablesize;
(STp->buffer)->buffer_size += (STp->buffer)->sg[i].length;
}
- flags = filp->f_flags;
- STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
+ st_flags = filp->f_flags;
+ STp->write_prot = ((st_flags & O_ACCMODE) == O_RDONLY);
STp->dirty = 0;
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
DEBC(printk(ST_DEB_MSG "st%d: Write protected\n", dev));
- if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
+ if ((st_flags & O_ACCMODE) == O_WRONLY || (st_flags & O_ACCMODE) == O_RDWR) {
retval = (-EROFS);
goto err_out;
}
\f
/* Flush the tape buffer before close */
-static int scsi_tape_flush(struct file *filp)
+static int st_flush(struct file *filp)
{
int result = 0, result2;
unsigned char cmd[MAX_COMMAND_SIZE];
}
-/* Close the device and release it */
-static int scsi_tape_close(struct inode *inode, struct file *filp)
+/* Close the device and release it. BKL is not needed: this is the only thread
+ accessing this tape. */
+static int st_release(struct inode *inode, struct file *filp)
{
int result = 0;
Scsi_Tape *STp;
+ unsigned long flags;
kdev_t devt = inode->i_rdev;
int dev;
dev = TAPE_NR(devt);
- lock_kernel();
read_lock(&st_dev_arr_lock);
STp = scsi_tapes[dev];
read_unlock(&st_dev_arr_lock);
if (STp->buffer != NULL) {
normalize_buffer(STp->buffer);
+ write_lock_irqsave(&st_dev_arr_lock, flags);
(STp->buffer)->in_use = 0;
+ STp->buffer = NULL;
+ }
+ else {
+ write_lock_irqsave(&st_dev_arr_lock, flags);
}
STp->in_use = 0;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
if (STp->device->host->hostt->module)
__MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
- unlock_kernel();
return result;
}
if (SRpnt->sr_sense_buffer[2] & 0x20) { /* ILI */
if (STp->block_size == 0) {
- if (transfer <= 0)
- transfer = 0;
+ if (transfer < 0) {
+ if (STps->drv_block >= 0)
+ STps->drv_block += 1;
+ return (-ENOMEM);
+ }
(STp->buffer)->buffer_bytes = bytes - transfer;
} else {
scsi_release_request(SRpnt);
/* Try to allocate a new tape buffer. Calling function must not hold
dev_arr_lock. */
static ST_buffer *
- new_tape_buffer(int from_initialization, int need_dma)
+ new_tape_buffer(int from_initialization, int need_dma, int in_use)
{
int i, priority, b_size, order, got = 0, segs = 0;
unsigned long flags;
"st: segment sizes: first %d, last %d bytes.\n",
tb->sg[0].length, tb->sg[segs - 1].length);
)
- tb->in_use = 0;
+ tb->in_use = in_use;
tb->dma = need_dma;
tb->buffer_size = got;
tb->writing = 0;
read: st_read,
write: st_write,
ioctl: st_ioctl,
- open: scsi_tape_open,
- flush: scsi_tape_flush,
- release: scsi_tape_close,
+ open: st_open,
+ flush: st_flush,
+ release: st_release,
};
static int st_attach(Scsi_Device * SDp)
if (target_nbr > st_max_buffers)
target_nbr = st_max_buffers;
for (i=st_nbr_buffers; i < target_nbr; i++)
- if (!new_tape_buffer(TRUE, TRUE)) {
+ if (!new_tape_buffer(TRUE, TRUE, FALSE)) {
printk(KERN_INFO "st: Unable to allocate new static buffer.\n");
break;
}
#define SAMPLE_ROUNDUP 0
#include "sound_config.h"
+#include <linux/wrapper.h>
#define DMAP_FREE_ON_CLOSE 0
#define DMAP_KEEP_ON_CLOSE 1
dmap->raw_buf = start_addr;
dmap->raw_buf_phys = virt_to_bus(start_addr);
- for (page = virt_to_page(start_addr); page <= get_mem_map(end_addr); page++)
+ for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++)
mem_map_reserve(page);
return 0;
}
start_addr = (unsigned long) dmap->raw_buf;
end_addr = start_addr + dmap->buffsize;
- for (page = virt_to_page(start_addr); page <= get_mem_map(end_addr); page++)
+ for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++)
mem_map_unreserve(page);
free_pages((unsigned long) dmap->raw_buf, sz);
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
+#include <linux/wrapper.h>
#include "coproc.h"
devc->raw_buf = start_addr;
devc->raw_buf_phys = virt_to_bus(start_addr);
- for (page = virt_to_page(start_addr); page <= get_mem_map(end_addr); page++)
+ for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++)
mem_map_reserve(page);
return 1;
}
start_addr = (unsigned long) devc->raw_buf;
end_addr = start_addr + devc->buffsize;
- for (page = virt_to_page(start_addr); page <= get_mem_map(end_addr); page++)
+ for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++)
mem_map_unreserve(page);
free_pages((unsigned long) devc->raw_buf, sz);
struct file * file;
struct files_struct * files = current->files;
- write_lock(¤t->files->file_lock);
+ write_lock(&files->file_lock);
if (!(file = fcheck(oldfd)))
goto out_unlock;
err = newfd;
FD_SET(newfd, files->open_fds);
write_unlock(&files->file_lock);
- do_close(newfd, 0);
+ do_close(files, newfd, 0);
write_lock(&files->file_lock);
allocate_fd(files, file, newfd);
out:
return err;
out_unlock:
- write_unlock(¤t->files->file_lock);
+ write_unlock(&files->file_lock);
goto out;
}
* or not in the open-files bitmap. dup2 uses this to retain the fd
* without races.
*/
-int do_close(unsigned int fd, int release)
+int do_close(struct files_struct *files, unsigned int fd, int release)
{
int error;
struct file * filp;
- struct files_struct * files = current->files;
error = -EBADF;
write_lock(&files->file_lock);
asmlinkage long sys_close(unsigned int fd)
{
- return do_close(fd, 1);
+ return do_close(current->files, fd, 1);
}
/*
#include <linux/elfcore.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
+#include <asm/io.h>
static int open_kcore(struct inode * inode, struct file * filp)
memset(&dump, 0, sizeof(struct user));
dump.magic = CMAGIC;
- dump.u_dsize = max_mapnr;
+ dump.u_dsize = (virt_to_phys(high_memory) >> PAGE_SHIFT);
#if defined (__i386__)
dump.start_code = PAGE_OFFSET;
#endif
dump.start_data = PAGE_OFFSET;
#endif
- memsize = (max_mapnr + 1) << PAGE_SHIFT;
+ memsize = virt_to_phys(high_memory);
if (p >= memsize)
return 0;
if (count > memsize - p)
struct vfsmount *new_rootmnt)
{
struct task_struct *p;
+ struct fs_struct *fs;
read_lock(&tasklist_lock);
for_each_task(p) {
- /* FIXME - unprotected usage of ->fs + (harmless) race */
- if (!p->fs) continue;
- if (p->fs->root == old_root && p->fs->rootmnt == old_rootmnt)
- set_fs_root(p->fs, new_rootmnt, new_root);
- if (p->fs->pwd == old_root && p->fs->pwdmnt == old_rootmnt)
- set_fs_pwd(p->fs, new_rootmnt, new_root);
+ task_lock(p);
+ fs = p->fs;
+ if (fs) {
+ atomic_inc(&fs->count);
+ task_unlock(p);
+ if (fs->root==old_root && fs->rootmnt==old_rootmnt)
+ set_fs_root(fs, new_rootmnt, new_root);
+ if (fs->pwd==old_root && fs->pwdmnt==old_rootmnt)
+ set_fs_pwd(fs, new_rootmnt, new_root);
+ put_fs_struct(fs);
+ } else
+ task_unlock(p);
}
read_unlock(&tasklist_lock);
}
#define pte_none(x) (!pte_val(x))
#define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
#define pte_clear(xp) do { set_pte(xp, __pte(0)); } while (0)
-#define pte_pagenr(x) ((unsigned long)((pte_val(x) >> PAGE_SHIFT)))
#define pmd_none(x) (!pmd_val(x))
#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
*/
#define page_address(page) ((page)->virtual)
#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
-#define pte_page(x) (mem_map+pte_pagenr(x))
+#define pte_page(x) (mem_map+((unsigned long)((pte_val(x) >> PAGE_SHIFT))))
/*
* The following only work if pte_present() is true.
#ifndef CONFIG_SMP
mm->context = 0;
#else
- /* Make sure not to do anything during a clone-vm operation */
- if ((current == tsk) || (current->mm != mm)) {
- mm->context = (unsigned long)kmalloc(smp_num_cpus *
- sizeof(unsigned long), GFP_KERNEL);
- /*
- * Init the "context" values so that a tlbpid allocation
- * happens on the first switch.
- */
- if (mm->context)
- memset((void *)mm->context, 0, smp_num_cpus *
- sizeof(unsigned long));
- else
- printk("Warning: init_new_context failed\n");
- }
+ mm->context = (unsigned long)kmalloc(smp_num_cpus *
+ sizeof(unsigned long), GFP_KERNEL);
+ /*
+ * Init the "context" values so that a tlbpid allocation
+ * happens on the first switch.
+ */
+ if (mm->context)
+ memset((void *)mm->context, 0, smp_num_cpus *
+ sizeof(unsigned long));
+ else
+ printk("Warning: init_new_context failed\n");
#endif
}
asmlinkage long sys_open(const char *, int, int);
asmlinkage long sys_close(unsigned int); /* yes, it's really unsigned */
-extern int do_close(unsigned int, int); /* yes, it's really unsigned */
+extern int do_close(struct files_struct *, unsigned int, int); /* yes, it's really unsigned */
extern int do_truncate(struct dentry *, loff_t start);
extern struct file *filp_open(const char *, int, int);
#define ISDN_TIMER_MODEMXMIT 8
#define ISDN_TIMER_NETDIAL 16
#define ISDN_TIMER_NETHANGUP 32
-#define ISDN_TIMER_IPPP 64
#define ISDN_TIMER_KEEPALIVE 128 /* Cisco-Keepalive */
#define ISDN_TIMER_CARRIER 256 /* Wait for Carrier */
#define ISDN_TIMER_FAST (ISDN_TIMER_MODEMREAD | ISDN_TIMER_MODEMPLUS | \
typedef struct isdn_net_local_s {
ulong magic;
char name[10]; /* Name of device */
- struct net_device_stats stats; /* Ethernet Statistics */
+ struct net_device_stats stats; /* Ethernet Statistics */
int isdn_device; /* Index to isdn-device */
int isdn_channel; /* Index to isdn-channel */
int ppp_slot; /* PPPD device slot number */
void *next; /* Pointer to next isdn-interface */
struct net_device dev; /* interface to upper levels */
#ifdef CONFIG_ISDN_PPP
- struct mpqueue *mp_last;
- struct ippp_bundle ib;
+ ippp_bundle * pb; /* pointer to the common bundle structure
+ * with the the per-bundle data */
#endif
#ifdef CONFIG_ISDN_X25
struct concap_proto *cprot; /* connection oriented encapsulation protocol */
/* Utility-Macros */
#define MIN(a,b) ((a<b)?a:b)
#define MAX(a,b) ((a>b)?a:b)
+
#endif /* __KERNEL__ */
#endif /* isdn_h */
#define MP_END_FRAG 0x40
#define MP_BEGIN_FRAG 0x80
+#define MP_MAX_QUEUE_LEN 16
+
#define ISDN_PPP_COMP_MAX_OPTIONS 16
#define IPPP_COMP_FLAG_XMIT 0x1
extern int isdn_ppp_dial_slave(char *);
extern int isdn_ppp_hangup_slave(char *);
-struct ippp_bundle {
+typedef struct {
+ unsigned long seqerrs;
+ unsigned long frame_drops;
+ unsigned long overflows;
+ unsigned long max_queue_len;
+} isdn_mppp_stats;
+
+typedef struct {
int mp_mrru; /* unused */
- struct mpqueue *last; /* currently defined in isdn_net_dev */
- int min; /* currently calculated 'on the fly' */
- long next_num; /* we wanna see this seq.-number next */
- struct sqqueue *sq;
- int modify:1; /* set to 1 while modifying sqqueue */
- int bundled:1; /* bundle active ? */
-};
+ struct sk_buff * frags; /* fragments sl list -- use skb->next */
+ long frames; /* number of frames in the frame list */
+ unsigned int seq; /* last processed packet seq #: any packets
+ * with smaller seq # will be dropped
+ * unconditionally */
+ spinlock_t lock;
+ int ref_ct;
+ /* statistics */
+ isdn_mppp_stats stats;
+} ippp_bundle;
#define NUM_RCV_BUFFS 64
-struct sqqueue {
- struct sqqueue *next;
- long sqno_start;
- long sqno_end;
- struct sk_buff *skb;
- long timer;
-};
-
-struct mpqueue {
- struct mpqueue *next;
- struct mpqueue *last;
- long sqno;
- struct sk_buff *skb;
- int BEbyte;
- unsigned long time;
-};
-
struct ippp_buf_queue {
struct ippp_buf_queue *next;
struct ippp_buf_queue *last;
struct isdn_net_local_s *lp;
int unit;
int minor;
- long last_link_seqno;
+ unsigned int last_link_seqno;
long mp_seqno;
- long range;
#ifdef CONFIG_ISDN_PPP_VJ
unsigned char *cbuf;
struct slcompress *slcomp;
-/* $Id: isdnif.h,v 1.33 2000/01/20 19:59:43 keil Exp $
- *
+/* $Id: isdnif.h,v 1.35 2000/06/16 13:19:38 keil Exp $
+
* Linux ISDN subsystem
*
* Definition of the interface between the subsystem and its low-level drivers.
/* STAT_INVOKE_BRD callback. The ll_id is set to 0, the other fields */
/* are supplied by the network and not by the HL. */
/*********************************************************************/
+
+/*****************/
+/* NI1 commands */
+/*****************/
+#define NI1_CMD_INVOKE ((0x00 << 8) | ISDN_PTYPE_NI1) /* invoke a supplementary service */
+#define NI1_CMD_INVOKE_ABORT ((0x01 << 8) | ISDN_PTYPE_NI1) /* abort a invoke cmd */
+
+/*******************************/
+/* NI1 Status callback values */
+/*******************************/
+#define NI1_STAT_INVOKE_RES ((0x80 << 8) | ISDN_PTYPE_NI1) /* Result for invocation */
+#define NI1_STAT_INVOKE_ERR ((0x81 << 8) | ISDN_PTYPE_NI1) /* Error Return for invocation */
+#define NI1_STAT_INVOKE_BRD ((0x82 << 8) | ISDN_PTYPE_NI1) /* Deliver invoke broadcast info */
+
typedef struct
{ ulong ll_id; /* ID supplied by LL when executing */
/* a command and returned by HL for */
/* error value when error callback */
int datalen; /* length of cmd or stat data */
u_char *data;/* pointer to data delivered or send */
- } dss1_cmd_stat;
+ } isdn_cmd_stat;
/*
* Commands from linklevel to lowlevel
setup_parm setup;/* For SETUP msg */
capi_msg cmsg; /* For CAPI like messages */
char display[85];/* display message data */
- dss1_cmd_stat dss1_io; /* DSS1 IO-parameter/result */
+ isdn_cmd_stat isdn_io; /* ISDN IO-parameter/result */
aux_s aux; /* for modem commands/indications */
#ifdef CONFIG_ISDN_TTY_FAX
T30_s *fax; /* Pointer to ttys fax struct */
} parm;
} isdn_ctrl;
+#define dss1_io isdn_io
+#define ni1_io isdn_io
+
/*
* The interface-struct itself (initialized at load-time of lowlevel-driver)
*
/**
* list_del_init - deletes entry from list and reinitialize it.
- * @entry: the element to delete from the list.n
+ * @entry: the element to delete from the list.
*/
static __inline__ void list_del_init(struct list_head *entry)
{
struct dev_info {
kdev_t dev;
- int size;
- unsigned int offset;
+ unsigned long size;
+ unsigned long offset;
};
typedef struct dev_info dev_info_t;
struct strip_zone
{
- int zone_offset; /* Zone offset in md_dev */
- int dev_offset; /* Zone offset in real dev */
- int size; /* Zone size */
+ unsigned long zone_offset; /* Zone offset in md_dev */
+ unsigned long dev_offset; /* Zone offset in real dev */
+ unsigned long size; /* Zone size */
int nb_dev; /* # of devices attached to the zone */
mdk_rdev_t *dev[MAX_REAL]; /* Devices attached to the zone */
};
md_wait_queue_head_t wait_buffer;
/* for use when syncing mirrors: */
- int start_active, start_ready,
+ unsigned long start_active, start_ready,
start_pending, start_future;
int cnt_done, cnt_active, cnt_ready,
cnt_pending, cnt_future;
int buffer_size;
int chunk_size, level, algorithm;
int raid_disks, working_disks, failed_disks;
- int sector_count;
unsigned long next_sector;
atomic_t nr_handle;
struct stripe_head *next_free_stripe;
typedef struct kmem_cache_s kmem_cache_t;
+#include <linux/config.h>
#include <linux/mm.h>
#include <linux/cache.h>
struct vm_area_struct * mpnt, *tmp, **pprev;
int retval;
- /* Kill me slowly. UGLY! FIXME! */
- memcpy(&mm->start_code, ¤t->mm->start_code, 15*sizeof(unsigned long));
-
flush_cache_mm(current->mm);
+ mm->locked_vm = 0;
+ mm->mmap = NULL;
+ mm->mmap_cache = NULL;
+ mm->map_count = 0;
+ mm->context = 0;
+ mm->cpu_vm_mask = 0;
+ mm->swap_cnt = 0;
+ mm->swap_address = 0;
+ mm->segments = NULL;
pprev = &mm->mmap;
for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) {
struct file *file;
return retval;
}
+#define allocate_mm() (kmem_cache_alloc(mm_cachep, SLAB_KERNEL))
+
+static struct mm_struct * mm_init(struct mm_struct * mm)
+{
+ atomic_set(&mm->mm_users, 1);
+ atomic_set(&mm->mm_count, 1);
+ init_MUTEX(&mm->mmap_sem);
+ mm->page_table_lock = SPIN_LOCK_UNLOCKED;
+ mm->pgd = pgd_alloc();
+ if (mm->pgd)
+ return mm;
+ kmem_cache_free(mm_cachep, mm);
+ return NULL;
+}
+
+
/*
* Allocate and initialize an mm_struct.
*/
{
struct mm_struct * mm;
- mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
+ mm = allocate_mm();
if (mm) {
memset(mm, 0, sizeof(*mm));
- atomic_set(&mm->mm_users, 1);
- atomic_set(&mm->mm_count, 1);
- init_MUTEX(&mm->mmap_sem);
- mm->page_table_lock = SPIN_LOCK_UNLOCKED;
- mm->pgd = pgd_alloc();
- if (mm->pgd)
- return mm;
- kmem_cache_free(mm_cachep, mm);
+ return mm_init(mm);
}
return NULL;
}
retval = -ENOMEM;
mm = mm_alloc();
+ mm = allocate_mm();
if (!mm)
goto fail_nomem;
+ /* Copy the current MM stuff.. */
+ memcpy(mm, current->mm, sizeof(*mm));
+ if (!mm_init(mm))
+ goto fail_nomem;
+
tsk->mm = mm;
tsk->active_mm = mm;
if (retval)
goto free_pt;
+ init_new_context(tsk,mm);
+
good_mm:
tsk->mm = mm;
tsk->active_mm = mm;
- init_new_context(tsk,mm);
return 0;
free_pt:
pend = virt_to_page(pg_vec[i] + (PAGE_SIZE << order) - 1);
for (page = virt_to_page(pg_vec[i]); page <= pend; page++)
- mem_map_unreserve(page);
+ clear_bit(PG_reserved, &page->flags);
free_pages(pg_vec[i], order);
}
}
pend = virt_to_page(pg_vec[i] + (PAGE_SIZE << order) - 1);
for (page = virt_to_page(pg_vec[i]); page <= pend; page++)
- mem_map_reserve(page);
+ set_bit(PG_reserved, &page->flags);
}
/* Page vector is allocated */