S: 62-300 Wrzesnia
S: Poland
+N: Carlos Henrique Bauer
+E: chbauer@acm.org
+E: bauer@atlas.unisinos.tche.br
+D: A test for detection of EPP-1.7 and ECP/EPP parports.
+D: Some new sysctl entries for the parport driver.
+S: Universidade do Vale do Rio dos Sinos - UNISINOS
+S: DSI/IDASI
+S: Av. Unisinos, 950
+S: 93022000 Sao Leopoldo RS
+S: Brazil
+
N: Peter Bauer
E: 100136.3530@compuserve.com
D: Driver for depca-ethernet-board
----
If you use kmod, you will find it useful to edit /etc/conf.modules.
-When a driver needs to use the parport subsystem for the first time, a
-module by the name of parport_lowlevel will be automatically loaded
-via kmod. No module actually exists with that name; it's just an
-alias. Here is an example of the lines that need to be added:
+Here is an example of the lines that need to be added:
post-install parport modprobe -k parport_pc
options parport_pc io=0x378,0x278 irq=7,auto
return 0;
}
-/*
- * This routine gets a long from any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- */
-static unsigned long
-get_long(struct task_struct * tsk, struct vm_area_struct * vma,
- unsigned long addr)
-{
- pgd_t * pgdir;
- pmd_t * pgmiddle;
- pte_t * pgtable;
- unsigned long page;
-
- DBG(DBG_MEM_ALL, ("getting long at 0x%lx\n", addr));
- repeat:
- pgdir = pgd_offset(vma->vm_mm, addr);
- if (pgd_none(*pgdir)) {
- handle_mm_fault(tsk, vma, addr, 0);
- goto repeat;
- }
- if (pgd_bad(*pgdir)) {
- printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
- pgd_clear(pgdir);
- return 0;
- }
- pgmiddle = pmd_offset(pgdir, addr);
- if (pmd_none(*pgmiddle)) {
- handle_mm_fault(tsk, vma, addr, 0);
- goto repeat;
- }
- if (pmd_bad(*pgmiddle)) {
- printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
- pmd_clear(pgmiddle);
- return 0;
- }
- pgtable = pte_offset(pgmiddle, addr);
- if (!pte_present(*pgtable)) {
- handle_mm_fault(tsk, vma, addr, 0);
- goto repeat;
- }
- page = pte_page(*pgtable);
- /* this is a hack for non-kernel-mapped video buffers and similar */
- if (MAP_NR(page) >= max_mapnr)
- return 0;
- page += addr & ~PAGE_MASK;
- return *(unsigned long *) page;
-}
-
-/*
- * This routine puts a long into any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- *
- * Now keeps R/W state of page so that a text page stays readonly
- * even if a debugger scribbles breakpoints into it. -M.U-
- */
-static void
-put_long(struct task_struct * tsk, struct vm_area_struct * vma,
- unsigned long addr, unsigned long data)
-{
- pgd_t *pgdir;
- pmd_t *pgmiddle;
- pte_t *pgtable;
- unsigned long page;
-
- repeat:
- pgdir = pgd_offset(vma->vm_mm, addr);
- if (!pgd_present(*pgdir)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
- if (pgd_bad(*pgdir)) {
- printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
- pgd_clear(pgdir);
- return;
- }
- pgmiddle = pmd_offset(pgdir, addr);
- if (pmd_none(*pgmiddle)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
- if (pmd_bad(*pgmiddle)) {
- printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
- pmd_clear(pgmiddle);
- return;
- }
- pgtable = pte_offset(pgmiddle, addr);
- if (!pte_present(*pgtable)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
- page = pte_page(*pgtable);
- if (!pte_write(*pgtable)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
-
- /* This is a hack for non-kernel-mapped video buffers and similar. */
- if (MAP_NR(page) < max_mapnr)
- *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
-
- /* We're bypassing pagetables, so we have to set the dirty bit
- ourselves. This should also re-instate whatever read-only
- mode there was before. */
- set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
- flush_tlb();
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_long() to read a long.
- */
-static int
-read_long(struct task_struct * tsk, unsigned long addr, unsigned long * result)
-{
- struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
- DBG(DBG_MEM_ALL, ("in read_long\n"));
- if (!vma)
- return -EIO;
- if ((addr & ~PAGE_MASK) > (PAGE_SIZE - sizeof(long))) {
- struct vm_area_struct * vma_high = vma;
- unsigned long low, align;
-
- if (addr + sizeof(long) >= vma->vm_end) {
- vma_high = vma->vm_next;
- if (!vma_high || vma_high->vm_start != vma->vm_end)
- return -EIO;
- }
- align = addr & (sizeof(long) - 1);
- addr -= align;
- low = get_long(tsk, vma, addr);
- if (align) {
- unsigned long high;
-
- high = get_long(tsk, vma_high, addr + sizeof(long));
- low >>= align * 8;
- low |= high << (64 - align * 8);
- }
- *result = low;
- } else {
- long l = get_long(tsk, vma, addr);
-
- DBG(DBG_MEM_ALL, ("value is 0x%lx\n", l));
- *result = l;
- }
- return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_long() to write a long.
- */
-static int
-write_long(struct task_struct * tsk, unsigned long addr, unsigned long data)
-{
- struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
- if (!vma)
- return -EIO;
- if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
- unsigned long low, high, align;
- struct vm_area_struct * vma_high = vma;
-
- if (addr + sizeof(long) >= vma->vm_end) {
- vma_high = vma->vm_next;
- if (!vma_high || vma_high->vm_start != vma->vm_end)
- return -EIO;
- }
- align = addr & (sizeof(long) - 1);
- addr -= align;
- low = get_long(tsk, vma, addr);
- high = get_long(tsk, vma_high, addr + sizeof(long));
- low &= ~0UL >> (64 - align * 8);
- high &= ~0UL << (align * 8);
- low |= data << (align * 8);
- high |= data >> (64 - align * 8);
- put_long(tsk, vma, addr, low);
- put_long(tsk, vma_high, addr + sizeof(long), high);
- } else
- put_long(tsk, vma, addr, data);
- return 0;
-}
-
-/*
- * Read a 32bit int from address space TSK.
- */
-static int
-read_int(struct task_struct * tsk, unsigned long addr, unsigned int *data)
+static inline int
+read_int(struct task_struct *task, unsigned long addr, int * data)
{
- unsigned long l, align;
- int res;
-
- align = addr & 0x7;
- addr &= ~0x7;
-
- res = read_long(tsk, addr, &l);
- if (res < 0)
- return res;
-
- if (align == 0) {
- *data = l;
- } else {
- *data = l >> 32;
- }
- return 0;
+ int copied = access_process_vm(task, addr, data, sizeof(int), 0);
+ return (copied == sizeof(int)) ? 0 : -EIO;
}
-/*
- * Write a 32bit word to address space TSK.
- *
- * For simplicity, do a read-modify-write of the 64bit word that
- * contains the 32bit word that we are about to write.
- */
-static int
-write_int(struct task_struct * tsk, unsigned long addr, unsigned int data)
+static inline int
+write_int(struct task_struct *task, unsigned long addr, int data)
{
- unsigned long l, align;
- int res;
-
- align = addr & 0x7;
- addr &= ~0x7;
-
- res = read_long(tsk, addr, &l);
- if (res < 0)
- return res;
-
- if (align == 0) {
- l = (l & 0xffffffff00000000UL) | ((unsigned long) data << 0);
- } else {
- l = (l & 0x00000000ffffffffUL) | ((unsigned long) data << 32);
- }
- return write_long(tsk, addr, l);
+ int copied = access_process_vm(task, addr, &data, sizeof(int), 1);
+ return (copied == sizeof(int)) ? 0 : -EIO;
}
/*
switch (request) {
/* When I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA:
- down(&child->mm->mmap_sem);
- ret = read_long(child, addr, &tmp);
- up(&child->mm->mmap_sem);
- DBG(DBG_MEM, ("peek %#lx->%#lx\n", addr, tmp));
- if (ret < 0)
+ case PTRACE_PEEKDATA: {
+ unsigned long tmp;
+ int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+ ret = -EIO;
+ if (copied != sizeof(tmp))
goto out;
+
regs.r0 = 0; /* special return: no errors */
ret = tmp;
goto out;
+ }
/* Read register number ADDR. */
case PTRACE_PEEKUSR:
/* When I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
- case PTRACE_POKEDATA:
- DBG(DBG_MEM, ("poke %#lx<-%#lx\n", addr, data));
- down(&child->mm->mmap_sem);
- ret = write_long(child, addr, data);
- up(&child->mm->mmap_sem);
+ case PTRACE_POKEDATA: {
+ unsigned long tmp = data;
+ int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1);
+ ret = (copied == sizeof(tmp)) ? 0 : -EIO;
goto out;
+ }
case PTRACE_POKEUSR: /* write the specified register */
DBG(DBG_MEM, ("poke $%ld<-%#lx\n", addr, data));
return 0;
}
-/*
- * This routine gets a long from any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- */
-static unsigned long get_long(struct task_struct * tsk,
- struct vm_area_struct * vma, unsigned long addr)
-{
- pgd_t * pgdir;
- pmd_t * pgmiddle;
- pte_t * pgtable;
- unsigned long page;
-
-repeat:
- pgdir = pgd_offset(vma->vm_mm, addr);
- if (pgd_none(*pgdir)) {
- handle_mm_fault(tsk, vma, addr, 0);
- goto repeat;
- }
- if (pgd_bad(*pgdir)) {
- printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
- pgd_clear(pgdir);
- return 0;
- }
- pgmiddle = pmd_offset(pgdir, addr);
- if (pmd_none(*pgmiddle)) {
- handle_mm_fault(tsk, vma, addr, 0);
- goto repeat;
- }
- if (pmd_bad(*pgmiddle)) {
- printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
- pmd_clear(pgmiddle);
- return 0;
- }
- pgtable = pte_offset(pgmiddle, addr);
- if (!pte_present(*pgtable)) {
- handle_mm_fault(tsk, vma, addr, 0);
- goto repeat;
- }
- page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
- if (MAP_NR(page) >= max_mapnr)
- return 0;
- page += addr & ~PAGE_MASK;
- return *(unsigned long *) page;
-}
-
-/*
- * This routine puts a long into any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- *
- * Now keeps R/W state of page so that a text page stays readonly
- * even if a debugger scribbles breakpoints into it. -M.U-
- */
-static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr,
- unsigned long data)
-{
- pgd_t *pgdir;
- pmd_t *pgmiddle;
- pte_t *pgtable;
- unsigned long page;
-
-repeat:
- pgdir = pgd_offset(vma->vm_mm, addr);
- if (!pgd_present(*pgdir)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
- if (pgd_bad(*pgdir)) {
- printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
- pgd_clear(pgdir);
- return;
- }
- pgmiddle = pmd_offset(pgdir, addr);
- if (pmd_none(*pgmiddle)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
- if (pmd_bad(*pgmiddle)) {
- printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
- pmd_clear(pgmiddle);
- return;
- }
- pgtable = pte_offset(pgmiddle, addr);
- if (!pte_present(*pgtable)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
- page = pte_page(*pgtable);
- if (!pte_write(*pgtable)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
-/* this is a hack for non-kernel-mapped video buffers and similar */
- if (MAP_NR(page) < max_mapnr)
- *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
-/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
-/* this should also re-instate whatever read-only mode there was before */
- set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
- flush_tlb();
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_long() to read a long.
- */
-static int read_long(struct task_struct * tsk, unsigned long addr,
- unsigned long * result)
-{
- struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
- if (!vma)
- return -EIO;
- if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
- unsigned long low,high;
- struct vm_area_struct * vma_high = vma;
-
- if (addr + sizeof(long) >= vma->vm_end) {
- vma_high = vma->vm_next;
- if (!vma_high || vma_high->vm_start != vma->vm_end)
- return -EIO;
- }
- low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
- high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
- switch (addr & (sizeof(long)-1)) {
- case 1:
- low >>= 8;
- low |= high << 24;
- break;
- case 2:
- low >>= 16;
- low |= high << 16;
- break;
- case 3:
- low >>= 24;
- low |= high << 8;
- break;
- }
- *result = low;
- } else
- *result = get_long(tsk, vma, addr);
- return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_long() to write a long.
- */
-static int write_long(struct task_struct * tsk, unsigned long addr,
- unsigned long data)
-{
- struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
- if (!vma)
- return -EIO;
- if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
- unsigned long low,high;
- struct vm_area_struct * vma_high = vma;
-
- if (addr + sizeof(long) >= vma->vm_end) {
- vma_high = vma->vm_next;
- if (!vma_high || vma_high->vm_start != vma->vm_end)
- return -EIO;
- }
- low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
- high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
- switch (addr & (sizeof(long)-1)) {
- case 0: /* shouldn't happen, but safety first */
- low = data;
- break;
- case 1:
- low &= 0x000000ff;
- low |= data << 8;
- high &= ~0xff;
- high |= data >> 24;
- break;
- case 2:
- low &= 0x0000ffff;
- low |= data << 16;
- high &= ~0xffff;
- high |= data >> 16;
- break;
- case 3:
- low &= 0x00ffffff;
- low |= data << 24;
- high &= ~0xffffff;
- high |= data >> 8;
- break;
- }
- put_long(tsk, vma, addr & ~(sizeof(long)-1),low);
- put_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
- } else
- put_long(tsk, vma, addr, data);
- return 0;
-}
-
static int putreg(struct task_struct *child,
unsigned long regno, unsigned long value)
{
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA: {
unsigned long tmp;
+ int copied;
- down(&child->mm->mmap_sem);
- ret = read_long(child, addr, &tmp);
- up(&child->mm->mmap_sem);
- if (ret >= 0)
- ret = put_user(tmp,(unsigned long *) data);
+ copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+ ret = -EIO;
+ if (copied != sizeof(tmp))
+ goto out;
+ ret = put_user(tmp,(unsigned long *) data);
goto out;
}
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
- down(&child->mm->mmap_sem);
- ret = write_long(child,addr,data);
- up(&child->mm->mmap_sem);
+ ret = 0;
+ if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+ goto out;
+ ret = -EIO;
goto out;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
#define MAGIC_CONSTANT 0x80000000
-/*
- * This routine gets a long from any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- */
-static unsigned long get_long(struct task_struct * tsk,
- struct vm_area_struct * vma, unsigned long addr)
-{
- pgd_t * pgdir;
- pmd_t * pgmiddle;
- pte_t * pgtable;
- unsigned long page, retval;
-
-repeat:
- pgdir = pgd_offset(vma->vm_mm, addr);
- if (pgd_none(*pgdir)) {
- handle_mm_fault(tsk, vma, addr, 0);
- goto repeat;
- }
- if (pgd_bad(*pgdir)) {
- printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
- pgd_clear(pgdir);
- return 0;
- }
- pgmiddle = pmd_offset(pgdir, addr);
- if (pmd_none(*pgmiddle)) {
- handle_mm_fault(tsk, vma, addr, 0);
- goto repeat;
- }
- if (pmd_bad(*pgmiddle)) {
- printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
- pmd_clear(pgmiddle);
- return 0;
- }
- pgtable = pte_offset(pgmiddle, addr);
- if (!pte_present(*pgtable)) {
- handle_mm_fault(tsk, vma, addr, 0);
- goto repeat;
- }
- page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
- if (MAP_NR(page) >= max_mapnr)
- return 0;
- page += addr & ~PAGE_MASK;
- retval = *(unsigned long *) page;
- flush_page_to_ram(page);
- return retval;
-}
-
-/*
- * This routine puts a long into any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- *
- * Now keeps R/W state of page so that a text page stays readonly
- * even if a debugger scribbles breakpoints into it. -M.U-
- */
-static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
- unsigned long addr, unsigned long data)
-{
- pgd_t *pgdir;
- pmd_t *pgmiddle;
- pte_t *pgtable;
- unsigned long page;
-
-repeat:
- pgdir = pgd_offset(vma->vm_mm, addr);
- if (!pgd_present(*pgdir)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
- if (pgd_bad(*pgdir)) {
- printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
- pgd_clear(pgdir);
- return;
- }
- pgmiddle = pmd_offset(pgdir, addr);
- if (pmd_none(*pgmiddle)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
- if (pmd_bad(*pgmiddle)) {
- printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
- pmd_clear(pgmiddle);
- return;
- }
- pgtable = pte_offset(pgmiddle, addr);
- if (!pte_present(*pgtable)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
- page = pte_page(*pgtable);
- if (!pte_write(*pgtable)) {
- handle_mm_fault(tsk, vma, addr, 1);
- goto repeat;
- }
-/* this is a hack for non-kernel-mapped video buffers and similar */
- flush_cache_page(vma, addr);
- if (MAP_NR(page) < max_mapnr) {
- *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
- flush_page_to_ram(page);
- }
-/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
-/* this should also re-instate whatever read-only mode there was before */
- set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
- flush_tlb_page(vma, addr);
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_long() to read a long.
- */
-static int read_long(struct task_struct * tsk, unsigned long addr,
- unsigned long * result)
-{
- struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
- if (!vma)
- return -EIO;
- *result = get_long(tsk, vma, addr);
- return 0;
-}
-
-static int read_byte(struct task_struct *tsk, unsigned long addr,
- unsigned char *result)
-{
- struct vm_area_struct *vma = find_extend_vma(tsk, addr&~3);
- unsigned long tmp;
-
- if(!vma)
- return -EIO;
- tmp = get_long(tsk, vma, (addr & ~3));
- switch(addr & 3) {
- case 0:
- *result = (tmp & 0xff000000)>>24;
- break;
- case 1:
- *result = (tmp & 0x00ff0000)>>16;
- break;
- case 2:
- *result = (tmp & 0x0000ff00)>>8;
- break;
- case 3:
- *result = (tmp & 0x000000ff);
- break;
- }
- return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_long() to write a long.
- */
-static int write_long(struct task_struct * tsk, unsigned long addr,
- unsigned long data)
-{
- struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
- if (!vma)
- return -EIO;
- put_long(tsk, vma, addr, data);
- return 0;
-}
-
-static int write_byte(struct task_struct * tsk, unsigned long addr,
- unsigned char data)
-{
- struct vm_area_struct * vma = find_extend_vma(tsk, (addr & ~3));
- unsigned long tmp;
-
- if (!vma)
- return -EIO;
- tmp = get_long(tsk, vma, (addr & ~3));
- switch(addr & 3) {
- case 0:
- tmp &= 0x00ffffff;
- tmp |= (data << 24);
- break;
- case 1:
- tmp &= 0xff00ffff;
- tmp |= ((data << 16) & 0x00ff0000);
- break;
- case 2:
- tmp &= 0xffff00ff;
- tmp |= ((data << 8) & 0x0000ff00);
- break;
- case 3:
- tmp &= 0xffffff00;
- tmp |= (data & 0x000000ff);
- break;
- }
- put_long(tsk, vma, (addr & ~3), tmp);
- return 0;
-}
/* Returning from ptrace is a bit tricky because the syscall return
* low level code assumes any value returned which is negative and
case PTRACE_READTEXT:
case PTRACE_READDATA: {
- unsigned char *dest = (unsigned char *) addr2;
- unsigned long src = addr;
- unsigned char tmp;
- int res, len = data;
+ int res = ptrace_readdata(child, addr, (void *) addr2, data);
- res = verify_area(VERIFY_WRITE, dest, len);
- if(res) {
- pt_error_return(regs, -res);
+ if (res == data) {
+ pt_succ_return(regs, 0);
goto out;
}
- while(len) {
- down(&child->mm->mmap_sem);
- res = read_byte(child, src, &tmp);
- up(&child->mm->mmap_sem);
- if(res < 0) {
- pt_error_return(regs, -res);
- goto out;
- }
- __put_user(tmp, dest);
- src++; dest++; len--;
- }
- pt_succ_return(regs, 0);
+ /* Partial read is an IO failure */
+ if (res >= 0)
+ res = -EIO;
+ pt_error_return(regs, -res);
goto out;
}
case PTRACE_WRITETEXT:
case PTRACE_WRITEDATA: {
- unsigned char *src = (unsigned char *) addr2;
- unsigned long dest = addr;
- int res, len = data;
+ int res = ptrace_writedata(child, (void *) addr2, addr, data);
- res = verify_area(VERIFY_READ, src, len);
- if(res) {
- pt_error_return(regs, -res);
+ if (res == data) {
+ pt_succ_return(regs, 0);
goto out;
}
- while(len) {
- unsigned long tmp;
-
- __get_user(tmp, src);
- down(&child->mm->mmap_sem);
- res = write_byte(child, dest, tmp);
- up(&child->mm->mmap_sem);
- if(res < 0) {
- pt_error_return(regs, -res);
- goto out;
- }
- src++; dest++; len--;
- }
- pt_succ_return(regs, 0);
+ /* Partial write is an IO failure */
+ if (res >= 0)
+ res = -EIO;
+ pt_error_return(regs, -res);
goto out;
}
-/* $Id: asyncd.c,v 1.13 1999/05/12 11:11:34 davem Exp $
+/* $Id: asyncd.c,v 1.15 1999/07/04 04:35:50 davem Exp $
* The asyncd kernel daemon. This handles paging on behalf of
* processes that receive page faults due to remote (async) memory
* accesses.
-/* $Id: fault.c,v 1.101 1999/01/04 06:24:52 jj Exp $
+/* $Id: fault.c,v 1.103 1999/07/04 04:35:51 davem Exp $
* fault.c: Page fault handlers for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
CONFIG_BINFMT_MISC=m
CONFIG_SOLARIS_EMUL=m
CONFIG_PARPORT=m
-CONFIG_PARPORT_AX=m
-CONFIG_PARPORT_LOWLEVEL_MODULE=y
+# CONFIG_PARPORT_PC is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_1284 is not set
CONFIG_PRINTER=m
-CONFIG_PRINTER_READBACK=y
CONFIG_ENVCTRL=m
#
-/* $Id: psycho.c,v 1.85 1999/04/02 14:54:28 davem Exp $
+/* $Id: psycho.c,v 1.86 1999/07/01 10:39:43 davem Exp $
* psycho.c: Ultra/AX U2P PCI controller support.
*
* Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
unsigned short stmp;
unsigned int itmp;
+#if 0
for(pdev = pci_devices; pdev; pdev = pdev->next) {
if(pdev->vendor == PCI_VENDOR_ID_SUN &&
pdev->device == PCI_DEVICE_ID_SUN_SABRE) {
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128);
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
break;
}
}
+#endif
for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) {
if (pdev->vendor == PCI_VENDOR_ID_SUN &&
pdev->device == PCI_DEVICE_ID_SUN_SIMBA) {
pci_read_config_dword(pdev, APB_PCI_CONTROL_LOW, &itmp);
itmp = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f;
pci_write_config_dword(pdev, APB_PCI_CONTROL_LOW, itmp);
-
+#if 0
/* Don't mess with the retry limit and PIO/DMA latency
* timer settings. But do set primary and secondary
* latency timers.
*/
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128);
- pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 128);
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
+ pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 64);
+#endif
}
}
}
-/* $Id: sparc64_ksyms.c,v 1.59 1999/06/28 11:28:50 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.60 1999/07/03 22:11:12 davem Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
/* used by various drivers */
#ifdef __SMP__
+/* Out of line rw-locking implementation. */
+EXPORT_SYMBOL_PRIVATE(read_lock);
+EXPORT_SYMBOL_PRIVATE(read_unlock);
+EXPORT_SYMBOL_PRIVATE(write_lock);
+EXPORT_SYMBOL_PRIVATE(write_unlock);
+
/* Kernel wide locking */
EXPORT_SYMBOL(kernel_flag);
EXPORT_SYMBOL(local_bh_count);
#endif
+/* Atomic counter implementation. */
+EXPORT_SYMBOL_PRIVATE(atomic_add);
+EXPORT_SYMBOL_PRIVATE(atomic_sub);
+
EXPORT_SYMBOL(ivector_table);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
-# $Id: Makefile,v 1.18 1998/10/13 09:07:24 davem Exp $
+# $Id: Makefile,v 1.19 1999/07/03 22:11:08 davem Exp $
# Makefile for Sparc library files..
#
OBJS = PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \
memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
- VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o VISsave.o
+ VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o VISsave.o \
+ atomic.o rwlock.o
lib.a: $(OBJS)
$(AR) rcs lib.a $(OBJS)
--- /dev/null
+/* $Id: atomic.S,v 1.1 1999/07/03 22:11:04 davem Exp $
+ * atomic.S: These things are too big to do inline.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#include <asm/asi.h>
+
+ .text
+ .align 64
+
+ .globl __atomic_add
+__atomic_add:
+ lduw [%g1], %g5
+ add %g5, %g2, %g7
+ cas [%g1], %g5, %g7
+ cmp %g5, %g7
+ bne,pn %icc, __atomic_add
+ nop
+ jmpl %g3 + 8, %g0
+ add %g7, %g2, %g2
+
+ .globl __atomic_sub
+__atomic_sub:
+ lduw [%g1], %g5
+ sub %g5, %g2, %g7
+ cas [%g1], %g5, %g7
+ cmp %g5, %g7
+ bne,pn %icc, __atomic_sub
+ nop
+ jmpl %g3 + 8, %g0
+ sub %g7, %g2, %g2
--- /dev/null
+/* $Id: rwlock.S,v 1.1 1999/07/03 22:11:06 davem Exp $
+ * rwlocks.S: These things are too big to do inline.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+ .text
+ .align 64
+
+ /* The non-contention read lock usage is 2 cache lines. */
+
+ .globl __read_lock, __read_unlock
+ /* g1=lock, g3=retpc, g5/g7=scratch */
+__read_lock:
+ ldsw [%g1], %g5
+ brlz,pn %g5, __read_wait_for_writer
+4: add %g5, 1, %g7
+ cas [%g1], %g5, %g7
+ cmp %g5, %g7
+ bne,pn %icc, __read_lock
+ membar #StoreLoad | #StoreStore
+99: jmpl %g3 + 8, %g0
+ nop
+__read_unlock:
+ lduw [%g1], %g5
+ sub %g5, 1, %g7
+ cas [%g1], %g5, %g7
+ cmp %g5, %g7
+ be,pt %xcc, 99b
+ membar #StoreLoad | #StoreStore
+ b,a,pt %xcc, __read_unlock
+
+__read_wait_for_writer:
+ ldsw [%g1], %g5
+ brlz,pt %g5, __read_wait_for_writer
+ membar #LoadLoad
+ b,a,pt %xcc, 4b
+__write_wait_for_writer:
+ ldsw [%g1], %g5
+ brlz,pt %g5, __write_wait_for_writer
+ membar #LoadLoad
+ b,a,pt %xcc, 4f
+
+ /* Similarly, 2 cache lines for non-contention write locks. */
+
+ .align 64
+ .globl __write_unlock
+ /* g1=lock, g3=retpc, g2/g5/g7=scratch */
+__write_unlock:
+ sethi %hi(0x80000000), %g2
+1: lduw [%g1], %g5
+ andn %g5, %g2, %g7
+ cas [%g1], %g5, %g7
+ cmp %g5, %g7
+ be,pt %icc, 99b
+ membar #StoreLoad | #StoreStore
+ b,a,pt %xcc, 1b
+
+ .globl __write_lock
+__write_lock:
+ sethi %hi(0x80000000), %g2
+1: ldsw [%g1], %g5
+4: brnz,pn %g5, 5f
+ or %g5, %g2, %g7
+ cas [%g1], %g5, %g7
+ cmp %g5, %g7
+ be,pt %icc, 99b
+ membar #StoreLoad | #StoreStore
+
+ b,a,pt %xcc, 1b
+5: brlz %g5, __write_wait_for_writer
+ or %g5, %g2, %g7
+ cas [%g1], %g5, %g7
+ cmp %g5, %g7
+ bne,pn %icc, 5b
+8: ldsw [%g1], %g5
+ cmp %g5, %g2
+ be,pn %icc, 99b
+ membar #LoadLoad
+ b,a,pt %xcc, 99b
+
-/* $Id: asyncd.c,v 1.6 1999/05/12 11:11:48 davem Exp $
+/* $Id: asyncd.c,v 1.8 1999/07/04 04:35:55 davem Exp $
* The asyncd kernel daemon. This handles paging on behalf of
* processes that receive page faults due to remote (async) memory
* accesses.
-/* $Id: fault.c,v 1.34 1999/03/16 12:12:28 jj Exp $
+/* $Id: fault.c,v 1.36 1999/07/04 04:35:56 davem Exp $
* arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
-/* $Id: cmd646.c,v 1.13 1999/05/27 04:49:38 davem Exp $
+/* $Id: cmd646.c,v 1.14 1999/07/03 08:56:09 davem Exp $
* cmd646.c: Enable interrupts at initialization time on Ultra/PCI machines.
* Note, this driver is not used at all on other systems because
* there the "BIOS" has done all of the following already.
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
* have to coordinate with the init process, since all processes associated
* with the current tty must be dead before the new getty is allowed
* to spawn.
+ *
+ * Now, if it would be correct ;-/ The current code has a nasty hole -
+ * it doesn't catch files in flight. We may send the descriptor to ourselves
+ * via AF_UNIX socket, close it and later fetch from socket. FIXME.
*/
void do_SAK( struct tty_struct *tty)
{
((session > 0) && (p->session == session)))
send_sig(SIGKILL, p, 1);
else if (p->files) {
+ read_lock(&p->files->file_lock);
for (i=0; i < p->files->max_fds; i++) {
filp = fcheck_task(p, i);
if (filp && (filp->f_op == &tty_fops) &&
break;
}
}
+ read_unlock(&p->files->file_lock);
}
}
read_unlock(&tasklist_lock);
-/* $Id: parport_ax.c,v 1.19 1999/06/09 08:24:40 davem Exp $
+/* $Id: parport_ax.c,v 1.20 1999/07/03 08:56:21 davem Exp $
* Parallel-port routines for Sun Ultra/AX architecture
*
* Author: Eddie C. Dost <ecd@skynet.be>
EXPORT_SYMBOL(parport_default_proc_unregister);
EXPORT_SYMBOL(parport_parse_irqs);
EXPORT_SYMBOL(parport_parse_dmas);
-#ifdef CONFIG_PARPORT_12843
+#ifdef CONFIG_PARPORT_1284
EXPORT_SYMBOL(parport_open);
EXPORT_SYMBOL(parport_close);
EXPORT_SYMBOL(parport_device_id);
clear_epp_timeout(pb);
udelay(30); /* Wait for possible EPP timeout */
- /* Enable outputs. */
+ /* We must enable the outputs to be able to read the address
+ register. */
+
parport_pc_data_forward (pb);
+
outb (0x55, EPPADDR (pb));
clear_epp_timeout(pb);
udelay(30); /* Wait for possible EPP timeout */
- /* We must enable the outputs to be able to read the address
- register. */
- parport_pc_data_forward (pb);
-
if (inb (EPPADDR (pb)) == 0x55) {
clear_epp_timeout(pb);
udelay(30); /* Wait for possible EPP timeout */
parport_PS2_supported (p);
- if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
- PARPORT_DMA_NONE, &parport_pc_ops))) {
+ if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
+ PARPORT_DMA_NONE, &parport_pc_ops))) {
kfree (priv);
return 0;
}
printk("%s: irq %d detected\n", p->name, probedirq);
parport_proc_register(p);
- request_region (p->base, p->size, p->name);
+ request_region (p->base, 3, p->name);
+ if (p->size > 3)
+ request_region (p->base + 3, p->size - 3, p->name);
if (p->modes & PARPORT_MODE_ECP)
request_region (p->base_hi, 3, p->name);
free_dma(p->dma);
if (p->irq != PARPORT_IRQ_NONE)
free_irq(p->irq, p);
- release_region(p->base, p->size);
+ release_region(p->base, 3);
+ if (p->size > 3);
+ release_region(p->base + 3, p->size - 3);
if (p->modes & PARPORT_MODE_ECP)
release_region(p->base_hi, 3);
parport_proc_unregister(p);
-/* $Id: parport_probe.c,v 1.3 1997/10/19 18:18:46 phil Exp $
+/* $Id: parport_probe.c,v 1.1 1999/07/03 08:56:17 davem Exp $
* Parallel port device probing code
*
* Authors: Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
#undef PARPORT_DEBUG_SHARING /* undef for production */
#include <linux/config.h>
-
#include <linux/string.h>
-
#include <linux/tasks.h>
-
#include <linux/parport.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <asm/spinlock.h>
#include <asm/irq.h>
-#ifdef CONFIG_KMOD
-#include <linux/kmod.h>
-#endif
-
#undef PARPORT_PARANOID
#define PARPORT_DEFAULT_TIMESLICE (HZ/5)
/* Return a list of all the ports we know about. */
struct parport *parport_enumerate(void)
{
-#ifdef CONFIG_KMOD
- if (portlist == NULL) {
- request_module("parport_lowlevel");
- }
-#endif /* CONFIG_KMOD */
return portlist;
}
/* Set the latency timer and cache line size as well,
* PROM leaves it at zero.
*/
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128);
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
#ifdef __sparc_v9__
/* NOTE: Cache line size is in 32-bit word units. */
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10);
-/* $Id: sab82532.c,v 1.31 1999/05/12 11:15:10 davem Exp $
+/* $Id: sab82532.c,v 1.32 1999/07/03 08:57:41 davem Exp $
* sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
__initfunc(static inline void show_serial_version(void))
{
- char *revision = "$Revision: 1.31 $";
+ char *revision = "$Revision: 1.32 $";
char *version, *p;
version = strchr(revision, ' ');
-/* $Id: su.c,v 1.21 1999/06/11 10:23:42 davem Exp $
+/* $Id: su.c,v 1.22 1999/07/03 08:57:43 davem Exp $
* su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
*/
__initfunc(static __inline__ void show_su_version(void))
{
- char *revision = "$Revision: 1.21 $";
+ char *revision = "$Revision: 1.22 $";
char *version, *p;
version = strchr(revision, ' ');
}
if (!latency_timer) {
- latency_timer = 128;
+ latency_timer = 64;
if (initverbose >= 2)
printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fixup)\n", latency_timer);
pcibios_write_config_byte(bus, device_fn,
(td_toggle < 2) ? " " :
(td_toggle & 1) ? "Data1" : "Data0",
"ErrorCnt ", td_errcnt);
- printk(KERN_DEBUG " ComplCode 0x%x, %sAccessed, %sActive\n",
+ printk(KERN_DEBUG " ComplCode 0x%x, %sAccessed\n",
td_cc,
- td_cc_accessed(*td) ? "" : "Not ",
- td_active(*td) ? "" : "Not ");
+ td_cc_accessed(*td) ? "" : "Not ");
printk(KERN_DEBUG " %s%s\n",
td_allocated(*td) ? "Allocated" : "Free",
if (td_dummy(*cur_td)) break;
}
- printk(KERN_DEBUG "--- End TD Chain %lx: ---\n", virt_to_bus(td));
+ printk(KERN_DEBUG "--- End TD Chain %lx. ---\n", virt_to_bus(td));
} /* show_ohci_td_chain () */
/* .......... */
-inline void ohci_start_control(struct ohci *ohci)
+void ohci_start_control(struct ohci *ohci)
{
/* tell the HC to start processing the control list */
writel_set(OHCI_USB_CLE, &ohci->regs->control);
writel_set(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus);
}
-inline void ohci_start_bulk(struct ohci *ohci)
+void ohci_start_bulk(struct ohci *ohci)
{
/* tell the HC to start processing the bulk list */
writel_set(OHCI_USB_BLE, &ohci->regs->control);
writel_set(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus);
}
-inline void ohci_start_periodic(struct ohci *ohci)
+void ohci_start_periodic(struct ohci *ohci)
{
/* enable processing periodic (intr) transfers starting next frame */
writel_set(OHCI_USB_PLE, &ohci->regs->control);
}
-inline void ohci_start_isoc(struct ohci *ohci)
+void ohci_start_isoc(struct ohci *ohci)
{
/* enable processing isoc. transfers starting next frame */
writel_set(OHCI_USB_IE, &ohci->regs->control);
* dir = OHCI_TD_D_IN, OHCI_TD_D_OUT, or OHCI_TD_D_SETUP
* toggle = TOGGLE_AUTO, TOGGLE_DATA0, TOGGLE_DATA1
*/
-inline struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 flags, void *data, __u32 len, void *dev_id, usb_device_irq completed)
+struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 flags, void *data, __u32 len, void *dev_id, usb_device_irq completed)
{
/* hardware fields */
td->info = cpu_to_le32(OHCI_TD_CC_NEW |
return 0;
/* if cur_buf is 0, all data has been transferred */
- bus_data_end = td->cur_buf ? td->cur_buf : td->buf_end;
+ if (!td->cur_buf) {
+ return td->buf_end - bus_data_start + 1;
+ }
+
+ bus_data_end = td->cur_buf;
/* is it on the same page? */
if ((bus_data_start & ~0xfff) == (bus_data_end & ~0xfff)) {
- result = bus_data_end - bus_data_start + 1;
+ result = bus_data_end - bus_data_start;
} else {
/* compute the amount transferred on the first page */
result = 0x1000 - (bus_data_start & 0xfff);
/* add the amount done in the second page */
- result += (bus_data_end & 0xfff) + 1;
+ result += (bus_data_end & 0xfff);
}
return result;
if (stats == USB_ST_NOERROR)
req->_bytes_done += len;
-#ifdef OHCI_DEBUG
- printk(KERN_DEBUG "ohci_bulk_td_handler %d bytes done\n", req->_bytes_done);
-#endif
-
/* call the real completion handler when done or on an error */
if ((stats != USB_ST_NOERROR) ||
(req->_bytes_done >= req->length && req->completion != NULL)) {
*req->bytes_transferred_p += req->_bytes_done;
#ifdef OHCI_DEBUG
- printk(KERN_DEBUG "usb-ohci: bulk request %p ending after %d bytes\n", req, req->_bytes_done);
+ printk(KERN_DEBUG "usb-ohci: bulk request %p ending\n", req);
#endif
req->completion(stats, buffer, req->_bytes_done, req->dev_id);
}
#ifdef OHCI_DEBUG
-/* if (MegaDebug) { */
- /* complete transaction debugging output (before) */
+ if (MegaDebug) {
+ /* complete request debugging output (before) */
printk(KERN_DEBUG " Bulk ED %lx:\n", virt_to_bus(bulk_ed));
show_ohci_ed(bulk_ed);
printk(KERN_DEBUG " Bulk TDs %lx:\n", virt_to_bus(head_td));
show_ohci_td_chain(head_td);
-/* } */
+ }
#endif
/* Give the ED to the HC */
static int ohci_bulk_msg_completed(int stats, void *buffer, int len, void *dev_id)
{
+#ifdef OHCI_DEBUG
+ printk("ohci_bulk_msg_completed %x, %p, %d, %p\n", stats, buffer, len, dev_id);
+#endif
if (dev_id != NULL) {
int *completion_status = (int *)dev_id;
*completion_status = stats;
struct ohci_bulk_request_state req;
struct ohci_ed *req_ed;
- /* ....... */
-
#ifdef OHCI_DEBUG
printk(KERN_DEBUG "ohci_bulk_msg %p pipe %x, data %p, len %d, bytes_transferred %p\n", usb_dev, pipe, data, len, bytes_transferred_p);
#endif
+ /* initialize bytes transferred to nothing */
+ *bytes_transferred_p = 0;
+
+ /* Hopefully this is similar to the "URP" (USB Request Packet) code
+ * that michael gee is working on... */
req.usb_dev = usb_dev;
req.pipe = pipe;
req.data = data;
/* FIXME this should to wait for a caller specified time... */
schedule_timeout(HZ*5);
+ /* it'll only stay in this state of the request never finished */
+ if (completion_status == USB_ST_INTERNALERROR) {
+ struct ohci_device *dev = usb_to_ohci(usb_dev);
+ struct ohci_regs *regs = dev->ohci->regs;
+
#ifdef OHCI_DEBUG
- printk(KERN_DEBUG "ohci_bulk_msg request completed or timed out w/ status %x\n", completion_status);
+ printk(KERN_DEBUG "ohci_bulk_msg timing out\n");
#endif
+ /* XXX This code should go into a function used to stop
+ * a previously requested bulk transfer. -greg */
+
+ /* stop the transfer & collect the number of bytes */
+ ohci_wait_for_ed_safe(regs, req_ed, HCD_ED_BULK);
+
+ /* Get the number of bytes transferred out of the head TD
+ * on the ED if it didn't finish while we were waiting. */
+ if ( ed_head_td(req_ed) &&
+ (ed_head_td(req_ed) != ed_tail_td(req_ed)) ) {
+ struct ohci_td *partial_td;
+ partial_td = bus_to_virt(ed_head_td(req_ed));
+
+#ifdef OHCI_DEBUG
+ if (MegaDebug) {
+ show_ohci_td(partial_td);
+ }
+#endif
+ /* Record the bytes as transferred */
+ *bytes_transferred_p += ohci_td_bytes_done(partial_td);
+
+ /* If there was an unreported error, return it.
+ * Otherwise return a timeout */
+ completion_status = OHCI_TD_CC_GET(partial_td->info);
+ if (completion_status == USB_ST_NOERROR) {
+ completion_status = USB_ST_TIMEOUT;
+ }
+ }
+
+ }
remove_wait_queue(&bulk_wakeup, &wait);
ohci_free_ed(req_ed); /* return it to the pool */
#ifdef OHCI_DEBUG
- printk(KERN_DEBUG "ohci_bulk_msg done.\n");
+ printk(KERN_DEBUG "ohci_bulk_msg done, status %x (bytes_transferred = %ld).\n", completion_status, *bytes_transferred_p);
#endif
return completion_status;
struct ohci_td *td; /* used for walking the list */
/* um... isn't this dangerous to do in an interrupt handler? -greg */
- spin_lock(&ohci_edtd_lock);
+// spin_lock(&ohci_edtd_lock);
/* create the FIFO ordered donelist */
td = ohci_reverse_donelist(ohci);
/* insert it back on its ED */
ohci_add_td_to_ed(td, td, td->ed);
+ ohci_unhalt_ed(td->ed);
} else {
/* return it to the pool of free TDs */
if (can_auto_free(*td))
td = next_td;
}
- spin_unlock(&ohci_edtd_lock);
+// spin_unlock(&ohci_edtd_lock);
} /* ohci_reap_donelist() */
#define td_cc_notaccessed(td) ((le32_to_cpup(&(td).info) >> 29) == 7)
#define td_cc_accessed(td) ((le32_to_cpup(&(td).info) >> 29) != 7)
#define td_cc_noerror(td) (((le32_to_cpup(&(td).info)) & OHCI_TD_CC) == 0)
-#define td_active(td) (!td_cc_noerror((td)) && (td_errorcount((td)) < 3))
#define td_done(td) (td_cc_noerror((td)) || (td_errorcount((td)) == 3))
/*
do {
char *obuf = p->obuf;
unsigned long thistime;
- partial = 0;
thistime = copy_size = (count > p->maxout) ? p->maxout : count;
if (copy_from_user(p->obuf, buffer, copy_size))
minor_data[i] = PPDATA(dev->private);
minor_data[i]->minor = i;
minor_data[i]->pusb_dev = dev;
- minor_data[i]->maxout = interface->endpoint[0].wMaxPacketSize * 16;
+ /* The max packet size can't be more than 64 (& will be 64 for
+ * any decent bulk device); this calculation was silly. -greg
+ * minor_data[i]->maxout = interface->endpoint[0].wMaxPacketSize * 16;
+ */
+ minor_data[i]->maxout = 8192;
if (minor_data[i]->maxout > PAGE_SIZE) {
minor_data[i]->maxout = PAGE_SIZE;
}
return USB_ST_BITSTUFF;
if (status & 0x04) { /* CRC/Timeout */
if (dir_out)
- return USB_ST_TIMEOUT;
+ return USB_ST_NORESPONSE;
else
return USB_ST_CRC;
}
#define USB_RT_HIDD (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
/*
- * Status codes
+ * Status codes (these follow an OHCI controllers condition codes)
*/
#define USB_ST_NOERROR 0x0
#define USB_ST_CRC 0x1
#define USB_ST_BITSTUFF 0x2
-#define USB_ST_DTMISMATCH 0x3
+#define USB_ST_DTMISMATCH 0x3 /* data toggle mismatch */
#define USB_ST_STALL 0x4
-#define USB_ST_TIMEOUT 0x5
-#define USB_ST_PIDCHECK 0x6
-#define USB_ST_PIDUNDEF 0x7
+#define USB_ST_NORESPONSE 0x5 /* device not responding/handshaking */
+#define USB_ST_PIDCHECK 0x6 /* Check bits on PID failed */
+#define USB_ST_PIDUNDEF 0x7 /* PID unexpected/undefined */
#define USB_ST_DATAOVERRUN 0x8
#define USB_ST_DATAUNDERRUN 0x9
#define USB_ST_RESERVED1 0xA
/* internal errors */
#define USB_ST_REMOVED 0x100
+#define USB_ST_TIMEOUT 0x110
#define USB_ST_INTERNALERROR -1
/*
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
i = j * __NFDBITS;
if (i >= files->max_fds)
break;
- set = files->close_on_exec.fds_bits[j];
- files->close_on_exec.fds_bits[j] = 0;
+ set = xchg(&files->close_on_exec.fds_bits[j], 0);
j++;
for ( ; set ; i++,set >>= 1) {
if (set & 1)
extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
-static inline int dupfd(unsigned int fd, unsigned int arg)
+static inline int dupfd(struct file *file, unsigned int arg)
{
struct files_struct * files = current->files;
- struct file * file;
int error;
- error = -EINVAL;
- if (arg >= NR_OPEN)
- goto out;
-
- error = -EBADF;
- file = fget(fd);
- if (!file)
- goto out;
-
error = -EMFILE;
+ write_lock(&files->file_lock);
arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg);
if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur)
goto out_putf;
FD_SET(arg, &files->open_fds);
FD_CLR(arg, &files->close_on_exec);
+ write_unlock(&files->file_lock);
fd_install(arg, file);
error = arg;
out:
asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
{
int err = -EBADF;
+ struct file * file;
- lock_kernel();
- if (!fcheck(oldfd))
- goto out;
+ read_lock(¤t->files->file_lock);
+ if (!(file = fcheck(oldfd)))
+ goto out_unlock;
err = newfd;
if (newfd == oldfd)
- goto out;
+ goto out_unlock;
err = -EBADF;
if (newfd >= NR_OPEN)
- goto out; /* following POSIX.1 6.2.1 */
+ goto out_unlock; /* following POSIX.1 6.2.1 */
+ get_file(file);
+ read_unlock(¤t->files->file_lock);
sys_close(newfd);
- err = dupfd(oldfd, newfd);
+ err = dupfd(file, newfd);
out:
- unlock_kernel();
return err;
+out_unlock:
+ read_unlock(¤t->files->file_lock);
+ goto out;
}
asmlinkage int sys_dup(unsigned int fildes)
{
- int ret;
-
- lock_kernel();
- ret = dupfd(fildes, 0);
- unlock_kernel();
+ int ret = -EBADF;
+ struct file * file = fget(fildes);
+ if (file)
+ ret = dupfd(file, 0);
return ret;
}
struct file * filp;
long err = -EBADF;
- lock_kernel();
filp = fget(fd);
if (!filp)
goto out;
err = 0;
+ lock_kernel();
switch (cmd) {
case F_DUPFD:
- err = dupfd(fd, arg);
+ err = -EINVAL;
+ if (arg < NR_OPEN) {
+ get_file(filp);
+ err = dupfd(filp, arg);
+ }
break;
case F_GETFD:
err = FD_ISSET(fd, ¤t->files->close_on_exec);
break;
}
fput(filp);
-out:
unlock_kernel();
+out:
return err;
}
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
unsigned int flag;
int on, error = -EBADF;
- lock_kernel();
filp = fget(fd);
if (!filp)
goto out;
error = 0;
+ lock_kernel();
switch (cmd) {
case FIOCLEX:
FD_SET(fd, ¤t->files->close_on_exec);
error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
}
fput(filp);
+ unlock_kernel();
out:
- unlock_kernel();
return error;
}
struct super_block * sb;
int error;
- lock_kernel();
error = -EBADF;
file = fget(fd);
if (!file)
goto out;
- error = -ENOENT;
- if (!(dentry = file->f_dentry))
- goto out_putf;
- if (!(inode = dentry->d_inode))
- goto out_putf;
error = -ENODEV;
- sb = inode->i_sb;
+ sb = file->f_dentry->d_inode->i_sb;
+ lock_kernel();
if (sb && sb->s_op && sb->s_op->statfs)
error = sb->s_op->statfs(sb, buf, sizeof(struct statfs));
-out_putf:
+ unlock_kernel();
fput(file);
out:
- unlock_kernel();
return error;
}
struct file * file;
int error;
- lock_kernel();
error = -EBADF;
file = fget(fd);
if (!file)
error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
length<inode->i_size ? length : inode->i_size,
abs(inode->i_size - length));
+ lock_kernel();
if (!error)
error = do_truncate(dentry, length);
+ unlock_kernel();
out_putf:
fput(file);
out:
- unlock_kernel();
return error;
}
struct inode *inode;
int error;
- lock_kernel();
-
error = -EBADF;
file = fget(fd);
if (!file)
if (!S_ISDIR(inode->i_mode))
goto out_putf;
+ lock_kernel();
error = permission(inode, MAY_EXEC);
if (!error) {
struct dentry *tmp = current->fs->pwd;
current->fs->pwd = dget(dentry);
dput(tmp);
}
+ unlock_kernel();
out_putf:
fput(file);
out:
- unlock_kernel();
return error;
}
int err = -EBADF;
struct iattr newattrs;
- lock_kernel();
file = fget(fd);
if (!file)
goto out;
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
+ lock_kernel();
err = notify_change(dentry, &newattrs);
+ unlock_kernel();
out_putf:
fput(file);
out:
- unlock_kernel();
return err;
}
struct file * file;
int error = -EBADF;
- lock_kernel();
file = fget(fd);
if (!file)
goto out;
error = -ENOENT;
+ lock_kernel();
if ((dentry = file->f_dentry) != NULL)
error = chown_common(dentry, user, group);
+ unlock_kernel();
fput(file);
out:
- unlock_kernel();
return error;
}
int fd, error;
error = -EMFILE;
+
+ write_lock(&files->file_lock);
fd = find_first_zero_bit(&files->open_fds, NR_OPEN);
/*
* N.B. For clone tasks sharing a files structure, this test
error = fd;
out:
+ write_unlock(&files->file_lock);
return error;
}
inline void put_unused_fd(unsigned int fd)
{
+ write_lock(¤t->files->file_lock);
FD_CLR(fd, ¤t->files->open_fds);
+ write_unlock(¤t->files->file_lock);
}
asmlinkage int sys_open(const char * filename, int flags, int mode)
tmp = getname(filename);
fd = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
- lock_kernel();
fd = get_unused_fd();
if (fd >= 0) {
- struct file * f = filp_open(tmp, flags, mode);
+ struct file * f;
+ lock_kernel();
+ f = filp_open(tmp, flags, mode);
+ unlock_kernel();
error = PTR_ERR(f);
if (IS_ERR(f))
goto out_error;
fd_install(fd, f);
}
out:
- unlock_kernel();
putname(tmp);
}
return fd;
int retval;
struct dentry *dentry = filp->f_dentry;
- if (!atomic_read(&filp->f_count)) {
+ if (!file_count(filp)) {
printk("VFS: Close: file count is 0\n");
return 0;
}
{
int error;
struct file * filp;
+ struct files_struct * files = current->files;
- lock_kernel();
error = -EBADF;
- filp = fcheck(fd);
- if (filp) {
- struct files_struct * files = current->files;
- files->fd[fd] = NULL;
- put_unused_fd(fd);
- FD_CLR(fd, &files->close_on_exec);
- error = filp_close(filp, files);
- }
+ write_lock(&files->file_lock);
+ filp = frip(fd);
+ if (!filp)
+ goto out_unlock;
+ FD_CLR(fd, &files->close_on_exec);
+ write_unlock(&files->file_lock);
+ put_unused_fd(fd);
+ lock_kernel();
+ error = filp_close(filp, files);
unlock_kernel();
+out:
return error;
+out_unlock:
+ write_unlock(&files->file_lock);
+ goto out;
}
/*
{
int ret = -EPERM;
- lock_kernel();
if (!capable(CAP_SYS_TTY_CONFIG))
goto out;
/* If there is a controlling tty, hang it up */
+ lock_kernel();
if (current->tty)
tty_vhangup(current->tty);
+ unlock_kernel();
ret = 0;
out:
- unlock_kernel();
return ret;
}
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
read_lock(&tasklist_lock);
file = NULL;
p = find_task_by_pid(pid);
- if (p)
+ if (p && p->files)
file = fcheck_task(p, fd);
read_unlock(&tasklist_lock);
* is NULL
*/
- if (!file || !file->f_dentry)
+ if (!file)
goto out;
ino = (pid << 16) + PROC_PID_FD_DIR + fd;
for (fd -= 2 ; p->files && fd < p->files->max_fds; fd++, filp->f_pos++)
{
- struct file * file = fcheck_task(p, fd);
unsigned int i,j;
- if (!file || !file->f_dentry)
+ if (!fcheck_task(p, fd))
continue;
j = NUMBUF;
if (ino & PROC_PID_FD_DIR) {
struct file * file;
ino &= 0x7fff;
+ if (!p->files) /* can we ever get here if that's the case? */
+ goto out_unlock;
+ read_lock(&p->files->file_lock);
file = fcheck_task(p, ino);
if (!file)
- goto out_unlock;
+ goto out_unlock2;
inode->i_op = &proc_link_inode_operations;
inode->i_size = 64;
inode->i_mode |= S_IRUSR | S_IXUSR;
if (file->f_mode & 2)
inode->i_mode |= S_IWUSR | S_IXUSR;
+out_unlock2:
+ read_unlock(&p->files->file_lock);
}
out_unlock:
/* Defer unlocking until we're done with the task */
if (ino & PROC_PID_FD_DIR) {
struct file * file;
ino &= 0x7fff;
+ if (!p->files) /* shouldn't happen here */
+ goto out_unlock;
+ read_lock(&p->files->file_lock);
file = fcheck_task(p, ino);
if (!file || !file->f_dentry)
goto out_unlock;
result = file->f_dentry;
+ read_unlock(&p->files->file_lock);
goto out_dget;
}
}
if (p->nr < __MAX_POLL_TABLE_ENTRIES) {
struct poll_table_entry * entry;
ok_table:
- entry = p->entry + p->nr;
- entry->filp = filp;
- atomic_inc(&filp->f_count);
+ entry = p->entry + p->nr;
+ get_file(filp);
+ entry->filp = filp;
entry->wait_address = wait_address;
init_waitqueue_entry(&entry->wait, current);
add_wait_queue(wait_address,&entry->wait);
wait = wait_table;
}
- lock_kernel();
-
+ read_lock(¤t->files->file_lock);
retval = max_select_fd(n, fds);
+ read_unlock(¤t->files->file_lock);
+
+ lock_kernel();
if (retval < 0)
goto out;
n = retval;
#define ASIZ_mm_map_count 0x00000004
#define AOFF_mm_mmap_sem 0x00000018
#define ASIZ_mm_mmap_sem 0x00000020
-#define AOFF_mm_context 0x00000038
+#define AOFF_mm_page_table_lock 0x00000038
+#define ASIZ_mm_page_table_lock 0x00000001
+#define AOFF_mm_context 0x0000003c
#define ASIZ_mm_context 0x00000004
-#define AOFF_mm_start_code 0x0000003c
+#define AOFF_mm_start_code 0x00000040
#define ASIZ_mm_start_code 0x00000004
-#define AOFF_mm_end_code 0x00000040
+#define AOFF_mm_end_code 0x00000044
#define ASIZ_mm_end_code 0x00000004
-#define AOFF_mm_start_data 0x00000044
+#define AOFF_mm_start_data 0x00000048
#define ASIZ_mm_start_data 0x00000004
-#define AOFF_mm_end_data 0x00000048
+#define AOFF_mm_end_data 0x0000004c
#define ASIZ_mm_end_data 0x00000004
-#define AOFF_mm_start_brk 0x0000004c
+#define AOFF_mm_start_brk 0x00000050
#define ASIZ_mm_start_brk 0x00000004
-#define AOFF_mm_brk 0x00000050
+#define AOFF_mm_brk 0x00000054
#define ASIZ_mm_brk 0x00000004
-#define AOFF_mm_start_stack 0x00000054
+#define AOFF_mm_start_stack 0x00000058
#define ASIZ_mm_start_stack 0x00000004
-#define AOFF_mm_arg_start 0x00000058
+#define AOFF_mm_arg_start 0x0000005c
#define ASIZ_mm_arg_start 0x00000004
-#define AOFF_mm_arg_end 0x0000005c
+#define AOFF_mm_arg_end 0x00000060
#define ASIZ_mm_arg_end 0x00000004
-#define AOFF_mm_env_start 0x00000060
+#define AOFF_mm_env_start 0x00000064
#define ASIZ_mm_env_start 0x00000004
-#define AOFF_mm_env_end 0x00000064
+#define AOFF_mm_env_end 0x00000068
#define ASIZ_mm_env_end 0x00000004
-#define AOFF_mm_rss 0x00000068
+#define AOFF_mm_rss 0x0000006c
#define ASIZ_mm_rss 0x00000004
-#define AOFF_mm_total_vm 0x0000006c
+#define AOFF_mm_total_vm 0x00000070
#define ASIZ_mm_total_vm 0x00000004
-#define AOFF_mm_locked_vm 0x00000070
+#define AOFF_mm_locked_vm 0x00000074
#define ASIZ_mm_locked_vm 0x00000004
-#define AOFF_mm_def_flags 0x00000074
+#define AOFF_mm_def_flags 0x00000078
#define ASIZ_mm_def_flags 0x00000004
-#define AOFF_mm_cpu_vm_mask 0x00000078
+#define AOFF_mm_cpu_vm_mask 0x0000007c
#define ASIZ_mm_cpu_vm_mask 0x00000004
-#define AOFF_mm_swap_cnt 0x0000007c
+#define AOFF_mm_swap_cnt 0x00000080
#define ASIZ_mm_swap_cnt 0x00000004
-#define AOFF_mm_swap_address 0x00000080
+#define AOFF_mm_swap_address 0x00000084
#define ASIZ_mm_swap_address 0x00000004
-#define AOFF_mm_segments 0x00000084
+#define AOFF_mm_segments 0x00000088
#define ASIZ_mm_segments 0x00000004
#define AOFF_thread_uwinmask 0x00000000
#define ASIZ_thread_uwinmask 0x00000004
#define ASIZ_mm_map_count 0x00000004
#define AOFF_mm_mmap_sem 0x00000018
#define ASIZ_mm_mmap_sem 0x00000024
-#define AOFF_mm_context 0x0000003c
+#define AOFF_mm_page_table_lock 0x0000003c
+#define ASIZ_mm_page_table_lock 0x00000008
+#define AOFF_mm_context 0x00000044
#define ASIZ_mm_context 0x00000004
-#define AOFF_mm_start_code 0x00000040
+#define AOFF_mm_start_code 0x00000048
#define ASIZ_mm_start_code 0x00000004
-#define AOFF_mm_end_code 0x00000044
+#define AOFF_mm_end_code 0x0000004c
#define ASIZ_mm_end_code 0x00000004
-#define AOFF_mm_start_data 0x00000048
+#define AOFF_mm_start_data 0x00000050
#define ASIZ_mm_start_data 0x00000004
-#define AOFF_mm_end_data 0x0000004c
+#define AOFF_mm_end_data 0x00000054
#define ASIZ_mm_end_data 0x00000004
-#define AOFF_mm_start_brk 0x00000050
+#define AOFF_mm_start_brk 0x00000058
#define ASIZ_mm_start_brk 0x00000004
-#define AOFF_mm_brk 0x00000054
+#define AOFF_mm_brk 0x0000005c
#define ASIZ_mm_brk 0x00000004
-#define AOFF_mm_start_stack 0x00000058
+#define AOFF_mm_start_stack 0x00000060
#define ASIZ_mm_start_stack 0x00000004
-#define AOFF_mm_arg_start 0x0000005c
+#define AOFF_mm_arg_start 0x00000064
#define ASIZ_mm_arg_start 0x00000004
-#define AOFF_mm_arg_end 0x00000060
+#define AOFF_mm_arg_end 0x00000068
#define ASIZ_mm_arg_end 0x00000004
-#define AOFF_mm_env_start 0x00000064
+#define AOFF_mm_env_start 0x0000006c
#define ASIZ_mm_env_start 0x00000004
-#define AOFF_mm_env_end 0x00000068
+#define AOFF_mm_env_end 0x00000070
#define ASIZ_mm_env_end 0x00000004
-#define AOFF_mm_rss 0x0000006c
+#define AOFF_mm_rss 0x00000074
#define ASIZ_mm_rss 0x00000004
-#define AOFF_mm_total_vm 0x00000070
+#define AOFF_mm_total_vm 0x00000078
#define ASIZ_mm_total_vm 0x00000004
-#define AOFF_mm_locked_vm 0x00000074
+#define AOFF_mm_locked_vm 0x0000007c
#define ASIZ_mm_locked_vm 0x00000004
-#define AOFF_mm_def_flags 0x00000078
+#define AOFF_mm_def_flags 0x00000080
#define ASIZ_mm_def_flags 0x00000004
-#define AOFF_mm_cpu_vm_mask 0x0000007c
+#define AOFF_mm_cpu_vm_mask 0x00000084
#define ASIZ_mm_cpu_vm_mask 0x00000004
-#define AOFF_mm_swap_cnt 0x00000080
+#define AOFF_mm_swap_cnt 0x00000088
#define ASIZ_mm_swap_cnt 0x00000004
-#define AOFF_mm_swap_address 0x00000084
+#define AOFF_mm_swap_address 0x0000008c
#define ASIZ_mm_swap_address 0x00000004
-#define AOFF_mm_segments 0x00000088
+#define AOFF_mm_segments 0x00000090
#define ASIZ_mm_segments 0x00000004
#define AOFF_thread_uwinmask 0x00000000
#define ASIZ_thread_uwinmask 0x00000004
-/* $Id: page.h,v 1.44 1999/06/23 03:53:11 davem Exp $
+/* $Id: page.h,v 1.45 1999/07/03 08:58:05 davem Exp $
* page.h: Various defines and such for MMU operations on the Sparc for
* the Linux kernel.
*
#define ASIZ_mm_map_count 0x00000004
#define AOFF_mm_mmap_sem 0x00000028
#define ASIZ_mm_mmap_sem 0x00000038
-#define AOFF_mm_context 0x00000060
+#define AOFF_mm_page_table_lock 0x00000060
+#define ASIZ_mm_page_table_lock 0x00000001
+#define AOFF_mm_context 0x00000068
#define ASIZ_mm_context 0x00000008
-#define AOFF_mm_start_code 0x00000068
+#define AOFF_mm_start_code 0x00000070
#define ASIZ_mm_start_code 0x00000008
-#define AOFF_mm_end_code 0x00000070
+#define AOFF_mm_end_code 0x00000078
#define ASIZ_mm_end_code 0x00000008
-#define AOFF_mm_start_data 0x00000078
+#define AOFF_mm_start_data 0x00000080
#define ASIZ_mm_start_data 0x00000008
-#define AOFF_mm_end_data 0x00000080
+#define AOFF_mm_end_data 0x00000088
#define ASIZ_mm_end_data 0x00000008
-#define AOFF_mm_start_brk 0x00000088
+#define AOFF_mm_start_brk 0x00000090
#define ASIZ_mm_start_brk 0x00000008
-#define AOFF_mm_brk 0x00000090
+#define AOFF_mm_brk 0x00000098
#define ASIZ_mm_brk 0x00000008
-#define AOFF_mm_start_stack 0x00000098
+#define AOFF_mm_start_stack 0x000000a0
#define ASIZ_mm_start_stack 0x00000008
-#define AOFF_mm_arg_start 0x000000a0
+#define AOFF_mm_arg_start 0x000000a8
#define ASIZ_mm_arg_start 0x00000008
-#define AOFF_mm_arg_end 0x000000a8
+#define AOFF_mm_arg_end 0x000000b0
#define ASIZ_mm_arg_end 0x00000008
-#define AOFF_mm_env_start 0x000000b0
+#define AOFF_mm_env_start 0x000000b8
#define ASIZ_mm_env_start 0x00000008
-#define AOFF_mm_env_end 0x000000b8
+#define AOFF_mm_env_end 0x000000c0
#define ASIZ_mm_env_end 0x00000008
-#define AOFF_mm_rss 0x000000c0
+#define AOFF_mm_rss 0x000000c8
#define ASIZ_mm_rss 0x00000008
-#define AOFF_mm_total_vm 0x000000c8
+#define AOFF_mm_total_vm 0x000000d0
#define ASIZ_mm_total_vm 0x00000008
-#define AOFF_mm_locked_vm 0x000000d0
+#define AOFF_mm_locked_vm 0x000000d8
#define ASIZ_mm_locked_vm 0x00000008
-#define AOFF_mm_def_flags 0x000000d8
+#define AOFF_mm_def_flags 0x000000e0
#define ASIZ_mm_def_flags 0x00000008
-#define AOFF_mm_cpu_vm_mask 0x000000e0
+#define AOFF_mm_cpu_vm_mask 0x000000e8
#define ASIZ_mm_cpu_vm_mask 0x00000008
-#define AOFF_mm_swap_cnt 0x000000e8
+#define AOFF_mm_swap_cnt 0x000000f0
#define ASIZ_mm_swap_cnt 0x00000008
-#define AOFF_mm_swap_address 0x000000f0
+#define AOFF_mm_swap_address 0x000000f8
#define ASIZ_mm_swap_address 0x00000008
-#define AOFF_mm_segments 0x000000f8
+#define AOFF_mm_segments 0x00000100
#define ASIZ_mm_segments 0x00000008
-#define ASIZ_mm 0x00000100
+#define ASIZ_mm 0x00000108
#define AOFF_thread_ksp 0x00000000
#define ASIZ_thread_ksp 0x00000008
#define AOFF_thread_wstate 0x00000008
#define ASIZ_mm_map_count 0x00000004
#define AOFF_mm_mmap_sem 0x00000028
#define ASIZ_mm_mmap_sem 0x00000038
-#define AOFF_mm_context 0x00000060
+#define AOFF_mm_page_table_lock 0x00000060
+#define ASIZ_mm_page_table_lock 0x00000001
+#define AOFF_mm_context 0x00000068
#define ASIZ_mm_context 0x00000008
-#define AOFF_mm_start_code 0x00000068
+#define AOFF_mm_start_code 0x00000070
#define ASIZ_mm_start_code 0x00000008
-#define AOFF_mm_end_code 0x00000070
+#define AOFF_mm_end_code 0x00000078
#define ASIZ_mm_end_code 0x00000008
-#define AOFF_mm_start_data 0x00000078
+#define AOFF_mm_start_data 0x00000080
#define ASIZ_mm_start_data 0x00000008
-#define AOFF_mm_end_data 0x00000080
+#define AOFF_mm_end_data 0x00000088
#define ASIZ_mm_end_data 0x00000008
-#define AOFF_mm_start_brk 0x00000088
+#define AOFF_mm_start_brk 0x00000090
#define ASIZ_mm_start_brk 0x00000008
-#define AOFF_mm_brk 0x00000090
+#define AOFF_mm_brk 0x00000098
#define ASIZ_mm_brk 0x00000008
-#define AOFF_mm_start_stack 0x00000098
+#define AOFF_mm_start_stack 0x000000a0
#define ASIZ_mm_start_stack 0x00000008
-#define AOFF_mm_arg_start 0x000000a0
+#define AOFF_mm_arg_start 0x000000a8
#define ASIZ_mm_arg_start 0x00000008
-#define AOFF_mm_arg_end 0x000000a8
+#define AOFF_mm_arg_end 0x000000b0
#define ASIZ_mm_arg_end 0x00000008
-#define AOFF_mm_env_start 0x000000b0
+#define AOFF_mm_env_start 0x000000b8
#define ASIZ_mm_env_start 0x00000008
-#define AOFF_mm_env_end 0x000000b8
+#define AOFF_mm_env_end 0x000000c0
#define ASIZ_mm_env_end 0x00000008
-#define AOFF_mm_rss 0x000000c0
+#define AOFF_mm_rss 0x000000c8
#define ASIZ_mm_rss 0x00000008
-#define AOFF_mm_total_vm 0x000000c8
+#define AOFF_mm_total_vm 0x000000d0
#define ASIZ_mm_total_vm 0x00000008
-#define AOFF_mm_locked_vm 0x000000d0
+#define AOFF_mm_locked_vm 0x000000d8
#define ASIZ_mm_locked_vm 0x00000008
-#define AOFF_mm_def_flags 0x000000d8
+#define AOFF_mm_def_flags 0x000000e0
#define ASIZ_mm_def_flags 0x00000008
-#define AOFF_mm_cpu_vm_mask 0x000000e0
+#define AOFF_mm_cpu_vm_mask 0x000000e8
#define ASIZ_mm_cpu_vm_mask 0x00000008
-#define AOFF_mm_swap_cnt 0x000000e8
+#define AOFF_mm_swap_cnt 0x000000f0
#define ASIZ_mm_swap_cnt 0x00000008
-#define AOFF_mm_swap_address 0x000000f0
+#define AOFF_mm_swap_address 0x000000f8
#define ASIZ_mm_swap_address 0x00000008
-#define AOFF_mm_segments 0x000000f8
+#define AOFF_mm_segments 0x00000100
#define ASIZ_mm_segments 0x00000008
-#define ASIZ_mm 0x00000100
+#define ASIZ_mm 0x00000108
#define AOFF_thread_ksp 0x00000000
#define ASIZ_thread_ksp 0x00000008
#define AOFF_thread_wstate 0x00000008
#define ASIZ_mm_map_count 0x00000004
#define AOFF_mm_mmap_sem 0x00000028
#define ASIZ_mm_mmap_sem 0x00000040
-#define AOFF_mm_context 0x00000068
+#define AOFF_mm_page_table_lock 0x00000068
+#define ASIZ_mm_page_table_lock 0x0000000c
+#define AOFF_mm_context 0x00000078
#define ASIZ_mm_context 0x00000008
-#define AOFF_mm_start_code 0x00000070
+#define AOFF_mm_start_code 0x00000080
#define ASIZ_mm_start_code 0x00000008
-#define AOFF_mm_end_code 0x00000078
+#define AOFF_mm_end_code 0x00000088
#define ASIZ_mm_end_code 0x00000008
-#define AOFF_mm_start_data 0x00000080
+#define AOFF_mm_start_data 0x00000090
#define ASIZ_mm_start_data 0x00000008
-#define AOFF_mm_end_data 0x00000088
+#define AOFF_mm_end_data 0x00000098
#define ASIZ_mm_end_data 0x00000008
-#define AOFF_mm_start_brk 0x00000090
+#define AOFF_mm_start_brk 0x000000a0
#define ASIZ_mm_start_brk 0x00000008
-#define AOFF_mm_brk 0x00000098
+#define AOFF_mm_brk 0x000000a8
#define ASIZ_mm_brk 0x00000008
-#define AOFF_mm_start_stack 0x000000a0
+#define AOFF_mm_start_stack 0x000000b0
#define ASIZ_mm_start_stack 0x00000008
-#define AOFF_mm_arg_start 0x000000a8
+#define AOFF_mm_arg_start 0x000000b8
#define ASIZ_mm_arg_start 0x00000008
-#define AOFF_mm_arg_end 0x000000b0
+#define AOFF_mm_arg_end 0x000000c0
#define ASIZ_mm_arg_end 0x00000008
-#define AOFF_mm_env_start 0x000000b8
+#define AOFF_mm_env_start 0x000000c8
#define ASIZ_mm_env_start 0x00000008
-#define AOFF_mm_env_end 0x000000c0
+#define AOFF_mm_env_end 0x000000d0
#define ASIZ_mm_env_end 0x00000008
-#define AOFF_mm_rss 0x000000c8
+#define AOFF_mm_rss 0x000000d8
#define ASIZ_mm_rss 0x00000008
-#define AOFF_mm_total_vm 0x000000d0
+#define AOFF_mm_total_vm 0x000000e0
#define ASIZ_mm_total_vm 0x00000008
-#define AOFF_mm_locked_vm 0x000000d8
+#define AOFF_mm_locked_vm 0x000000e8
#define ASIZ_mm_locked_vm 0x00000008
-#define AOFF_mm_def_flags 0x000000e0
+#define AOFF_mm_def_flags 0x000000f0
#define ASIZ_mm_def_flags 0x00000008
-#define AOFF_mm_cpu_vm_mask 0x000000e8
+#define AOFF_mm_cpu_vm_mask 0x000000f8
#define ASIZ_mm_cpu_vm_mask 0x00000008
-#define AOFF_mm_swap_cnt 0x000000f0
+#define AOFF_mm_swap_cnt 0x00000100
#define ASIZ_mm_swap_cnt 0x00000008
-#define AOFF_mm_swap_address 0x000000f8
+#define AOFF_mm_swap_address 0x00000108
#define ASIZ_mm_swap_address 0x00000008
-#define AOFF_mm_segments 0x00000100
+#define AOFF_mm_segments 0x00000110
#define ASIZ_mm_segments 0x00000008
-#define ASIZ_mm 0x00000108
+#define ASIZ_mm 0x00000118
#define AOFF_thread_ksp 0x00000000
#define ASIZ_thread_ksp 0x00000008
#define AOFF_thread_wstate 0x00000008
-/* $Id: atomic.h,v 1.18 1997/08/07 03:38:31 davem Exp $
+/* $Id: atomic.h,v 1.19 1999/07/03 22:11:17 davem Exp $
* atomic.h: Thankfully the V9 is at least reasonable for this
* stuff.
*
#define atomic_read(v) ((v)->counter)
#define atomic_set(v, i) (((v)->counter) = i)
-extern __inline__ void atomic_add(int i, atomic_t *v)
-{
- __asm__ __volatile__("
-1: lduw [%1], %%g5
- add %%g5, %0, %%g7
- cas [%1], %%g5, %%g7
- sub %%g5, %%g7, %%g5
- brnz,pn %%g5, 1b
- nop"
- : /* No outputs */
- : "HIr" (i), "r" (__atomic_fool_gcc(v))
- : "g5", "g7", "memory");
-}
-
-extern __inline__ void atomic_sub(int i, atomic_t *v)
-{
- __asm__ __volatile__("
-1: lduw [%1], %%g5
- sub %%g5, %0, %%g7
- cas [%1], %%g5, %%g7
- sub %%g5, %%g7, %%g5
- brnz,pn %%g5, 1b
- nop"
- : /* No outputs */
- : "HIr" (i), "r" (__atomic_fool_gcc(v))
- : "g5", "g7", "memory");
-}
-
-/* Same as above, but return the result value. */
-extern __inline__ int atomic_add_return(int i, atomic_t *v)
-{
- unsigned long oldval;
- __asm__ __volatile__("
-1: lduw [%2], %%g5
- add %%g5, %1, %%g7
- cas [%2], %%g5, %%g7
- sub %%g5, %%g7, %%g5
- brnz,pn %%g5, 1b
- add %%g7, %1, %0"
- : "=&r" (oldval)
- : "HIr" (i), "r" (__atomic_fool_gcc(v))
- : "g5", "g7", "memory");
- return (int)oldval;
-}
-
-extern __inline__ int atomic_sub_return(int i, atomic_t *v)
-{
- unsigned long oldval;
- __asm__ __volatile__("
-1: lduw [%2], %%g5
- sub %%g5, %1, %%g7
- cas [%2], %%g5, %%g7
- sub %%g5, %%g7, %%g5
- brnz,pn %%g5, 1b
- sub %%g7, %1, %0"
- : "=&r" (oldval)
- : "HIr" (i), "r" (__atomic_fool_gcc(v))
- : "g5", "g7", "memory");
- return (int)oldval;
-}
+#define atomic_add_return(__i, __v) \
+({ register atomic_t *__V asm("g1"); \
+ register int __I asm("g2"); \
+ __V = (__v); __I = (__i); \
+ __asm__ __volatile__("sethi %%hi(__atomic_add), %%g3\n\t" \
+ "jmpl %%g3 + %%lo(__atomic_add), %%g3\n\t" \
+ " nop\n1:" \
+ : "=&r" (__I) \
+ : "0" (__I), "r" (__V) \
+ : "g3", "g5", "g7", "cc", "memory"); \
+ __I; \
+})
+
+#define atomic_sub_return(__i, __v) \
+({ register atomic_t *__V asm("g1"); \
+ register int __I asm("g2"); \
+ __V = (__v); __I = (__i); \
+ __asm__ __volatile__("sethi %%hi(__atomic_sub), %%g3\n\t" \
+ "jmpl %%g3 + %%lo(__atomic_sub), %%g3\n\t" \
+ " nop\n1:" \
+ : "=&r" (__I) \
+ : "0" (__I), "r" (__V) \
+ : "g3", "g5", "g7", "cc", "memory"); \
+ __I; \
+})
+
+#define atomic_add(i, v) atomic_add_return(i, v)
+#define atomic_sub(i, v) atomic_sub_return(i, v)
#define atomic_dec_return(v) atomic_sub_return(1,(v))
#define atomic_inc_return(v) atomic_add_return(1,(v))
* irq-safe write-lock, but readers can get non-irqsafe
* read-locks.
*/
-typedef unsigned long rwlock_t;
+typedef unsigned int rwlock_t;
#define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
#define read_lock(lock) do { } while(0)
#ifndef SPIN_LOCK_DEBUG
-typedef unsigned long rwlock_t;
+typedef unsigned int rwlock_t;
#define RW_LOCK_UNLOCKED 0
-extern __inline__ void read_lock(rwlock_t *rw)
-{
- __asm__ __volatile__("
-1: ldx [%0], %%g5
- brlz,pn %%g5, 2f
-4: add %%g5, 1, %%g7
- casx [%0], %%g5, %%g7
- cmp %%g5, %%g7
- bne,pn %%xcc, 1b
- membar #StoreLoad | #StoreStore
- .subsection 2
-2: ldx [%0], %%g5
- brlz,pt %%g5, 2b
- membar #LoadLoad
- b,a,pt %%xcc, 4b
- .previous
-" : /* no outputs */
- : "r" (rw)
- : "g5", "g7", "cc", "memory");
-}
+#define read_lock(__rw_lck) \
+do { register rwlock_t *__X asm("g1"); \
+ __asm__ __volatile__("sethi %%hi(__read_lock), %%g3\n\t" \
+ "jmpl %%g3 + %%lo(__read_lock), %%g3\n\t" \
+ " nop\n1:" \
+ : : "r" (__X = (__rw_lck)) \
+ : "g3", "g5", "g7", "cc", "memory"); \
+} while(0)
-extern __inline__ void read_unlock(rwlock_t *rw)
-{
- __asm__ __volatile__("
-1: ldx [%0], %%g5
- sub %%g5, 1, %%g7
- casx [%0], %%g5, %%g7
- cmp %%g5, %%g7
- bne,pn %%xcc, 1b
- membar #StoreLoad | #StoreStore
-" : /* no outputs */
- : "r" (rw)
- : "g5", "g7", "cc", "memory");
-}
+#define read_unlock(__rw_lck) \
+do { register rwlock_t *__X asm("g1"); \
+ __asm__ __volatile__("sethi %%hi(__read_unlock), %%g3\n\t" \
+ "jmpl %%g3 + %%lo(__read_unlock), %%g3\n\t" \
+ " nop\n1:" \
+ : : "r" (__X = (__rw_lck)) \
+ : "g3", "g5", "g7", "cc", "memory"); \
+} while(0)
-extern __inline__ void write_lock(rwlock_t *rw)
-{
- __asm__ __volatile__("
- sethi %%uhi(0x8000000000000000), %%g3
- sllx %%g3, 32, %%g3
-1: ldx [%0], %%g5
- brlz,pn %%g5, 5f
-4: or %%g5, %%g3, %%g7
- casx [%0], %%g5, %%g7
- cmp %%g5, %%g7
- bne,pn %%xcc, 1b
- andncc %%g7, %%g3, %%g0
- bne,pn %%xcc, 7f
- membar #StoreLoad | #StoreStore
- .subsection 2
-7: ldx [%0], %%g5
- andn %%g5, %%g3, %%g7
- casx [%0], %%g5, %%g7
- cmp %%g5, %%g7
- bne,pn %%xcc, 7b
- membar #StoreLoad | #StoreStore
-5: ldx [%0], %%g5
- brnz,pt %%g5, 5b
- membar #LoadLoad
- b,a,pt %%xcc, 4b
- .previous
-" : /* no outputs */
- : "r" (rw)
- : "g3", "g5", "g7", "memory", "cc");
-}
+#define write_lock(__rw_lck) \
+do { register rwlock_t *__X asm("g1"); \
+ __asm__ __volatile__("sethi %%hi(__write_lock), %%g3\n\t" \
+ "jmpl %%g3 + %%lo(__write_lock), %%g3\n\t" \
+ " nop\n1:" \
+ : : "r" (__X = (__rw_lck)) \
+ : "g2", "g3", "g5", "g7", "cc", "memory"); \
+} while(0)
-extern __inline__ void write_unlock(rwlock_t *rw)
-{
- __asm__ __volatile__("
- sethi %%uhi(0x8000000000000000), %%g3
- sllx %%g3, 32, %%g3
-1: ldx [%0], %%g5
- andn %%g5, %%g3, %%g7
- casx [%0], %%g5, %%g7
- cmp %%g5, %%g7
- bne,pn %%xcc, 1b
- membar #StoreLoad | #StoreStore
-" : /* no outputs */
- : "r" (rw)
- : "g3", "g5", "g7", "memory", "cc");
-}
+#define write_unlock(__rw_lck) \
+do { register rwlock_t *__X asm("g1"); \
+ __asm__ __volatile__("sethi %%hi(__write_unlock), %%g3\n\t" \
+ "jmpl %%g3 + %%lo(__write_unlock), %%g3\n\t" \
+ " nop\n1:" \
+ : : "r" (__X = (__rw_lck)) \
+ : "g2", "g3", "g5", "g7", "cc", "memory"); \
+} while(0)
#define read_lock_irq(lock) do { __cli(); read_lock(lock); } while (0)
#define read_unlock_irq(lock) do { read_unlock(lock); __sti(); } while (0)
{
struct file * file = NULL;
- if (p->files && fd < p->files->max_fds)
+ if (fd < p->files->max_fds)
file = p->files->fd[fd];
return file;
}
struct file * file = NULL;
struct files_struct *files = current->files;
- read_lock(&files->file_lock);
if (fd < files->max_fds)
file = files->fd[fd];
- read_unlock(&files->file_lock);
+ return file;
+}
+
+extern inline struct file * frip(unsigned int fd)
+{
+ struct file * file = NULL;
+
+ if (fd < current->files->max_fds)
+ file = xchg(¤t->files->fd[fd], NULL);
return file;
}
struct files_struct *files = current->files;
read_lock(&files->file_lock);
- if (fd < files->max_fds) {
- file = files->fd[fd];
- if (file)
- atomic_inc(&file->f_count);
- }
+ file = fcheck(fd);
+ if (file)
+ get_file(file);
read_unlock(&files->file_lock);
return file;
}
extern void vmtruncate(struct inode * inode, unsigned long offset);
extern int handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access);
extern int make_pages_present(unsigned long addr, unsigned long end);
+extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
extern int pgt_cache_water[2];
extern int check_pgt_cache(void);
/* The rest is for the kernel only */
#ifdef __KERNEL__
+#include <linux/wait.h>
#include <asm/system.h>
#include <asm/ptrace.h>
#include <asm/spinlock.h>
O_TARGET := kernel.o
O_OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \
module.o exit.o itimer.o info.o time.o softirq.o resource.o \
- sysctl.o acct.o capability.o
+ sysctl.o acct.o capability.o ptrace.o
OX_OBJS += signal.o
break;
while (set) {
if (set & 1) {
- struct file * file = files->fd[i];
- if (file) {
- files->fd[i] = NULL;
+ struct file * file = xchg(&files->fd[i], NULL);
+ if (file)
filp_close(file, files);
- }
}
i++;
set >>= 1;
static inline void __exit_files(struct task_struct *tsk)
{
- struct files_struct * files = tsk->files;
+ struct files_struct * files = xchg(&tsk->files, NULL);
if (files) {
- tsk->files = NULL;
if (atomic_dec_and_test(&files->count)) {
close_files(files);
/*
tmp->vm_next = NULL;
file = tmp->vm_file;
if (file) {
- atomic_inc(&file->f_count);
+ get_file(file);
if (tmp->vm_flags & VM_DENYWRITE)
file->f_dentry->d_inode->i_writecount--;
atomic_set(&newf->count, 1);
newf->max_fds = NR_OPEN;
newf->fd = new_fds;
+ read_lock(&oldf->file_lock);
newf->close_on_exec = oldf->close_on_exec;
i = copy_fdset(&newf->open_fds, &oldf->open_fds);
old_fds = oldf->fd;
for (; i != 0; i--) {
struct file *f = *old_fds++;
- *new_fds = f;
if (f)
- atomic_inc(&f->f_count);
- new_fds++;
+ get_file(f);
+ *new_fds++ = f;
}
+ read_unlock(&oldf->file_lock);
/* This is long word aligned thus could use a optimized version */
memset(new_fds, 0, (char *)newf->fd + size - (char *)new_fds);
--- /dev/null
+/*
+ * linux/kernel/ptrace.c
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ *
+ * Common interfaces for "ptrace()" which we do not want
+ * to continually duplicate across every architecture.
+ */
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+/*
+ * Access another process' address space, one page at a time.
+ */
+static int access_one_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
+{
+ pgd_t * pgdir;
+ pmd_t * pgmiddle;
+ pte_t * pgtable;
+ unsigned long page;
+
+repeat:
+ pgdir = pgd_offset(vma->vm_mm, addr);
+ if (pgd_none(*pgdir))
+ goto fault_in_page;
+ if (pgd_bad(*pgdir))
+ goto bad_pgd;
+ pgmiddle = pmd_offset(pgdir, addr);
+ if (pmd_none(*pgmiddle))
+ goto fault_in_page;
+ if (pmd_bad(*pgmiddle))
+ goto bad_pmd;
+ pgtable = pte_offset(pgmiddle, addr);
+ if (!pte_present(*pgtable))
+ goto fault_in_page;
+ page = pte_page(*pgtable);
+ if (MAP_NR(page) >= max_mapnr)
+ return 0;
+ flush_cache_page(vma, addr);
+ {
+ void *src = (void *) (page + (addr & ~PAGE_MASK));
+ void *dst = buf;
+
+ if (write) {
+ dst = src;
+ src = buf;
+ }
+ memcpy(dst, src, len);
+ }
+ flush_page_to_ram(page);
+ return len;
+
+fault_in_page:
+ /* -1: out of memory. 0 - unmapped page */
+ if (handle_mm_fault(tsk, vma, addr, write) > 0)
+ goto repeat;
+ return 0;
+
+bad_pgd:
+ printk("ptrace: bad pgd in '%s' at %08lx (%08lx)\n", tsk->comm, addr, pgd_val(*pgdir));
+ return 0;
+
+bad_pmd:
+ printk("ptrace: bad pmd in '%s' at %08lx (%08lx)\n", tsk->comm, addr, pmd_val(*pgmiddle));
+ return 0;
+}
+
+int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
+{
+ int copied;
+ struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+ if (!vma)
+ return 0;
+
+ down(&tsk->mm->mmap_sem);
+ copied = 0;
+ for (;;) {
+ unsigned long offset = addr & ~PAGE_MASK;
+ int this_len = PAGE_SIZE - offset;
+ int retval;
+
+ if (this_len > len)
+ this_len = len;
+ retval = access_one_page(tsk, vma, addr, buf, this_len, write);
+ copied += retval;
+ if (retval != this_len)
+ break;
+
+ len -= retval;
+ if (!len)
+ break;
+
+ addr += retval;
+ buf += retval;
+
+ if (addr < vma->vm_end)
+ continue;
+ if (!vma->vm_next)
+ break;
+ if (vma->vm_next->vm_start != vma->vm_end)
+ break;
+
+ vma = vma->vm_next;
+ }
+ up(&tsk->mm->mmap_sem);
+ return copied;
+}
+
+int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len)
+{
+ int copied = 0;
+ while (len) {
+ char buf[128];
+ int this_len, retval;
+
+ this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
+ retval = access_process_vm(tsk, src, buf, this_len, 0);
+ if (!retval) {
+ if (copied)
+ break;
+ return -EIO;
+ }
+ if (copy_to_user(dst, buf, retval))
+ return -EFAULT;
+ copied += retval;
+ src += retval;
+ dst += retval;
+ len -= retval;
+ }
+ return copied;
+}
+
+int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len)
+{
+ int copied = 0;
+ while (len) {
+ char buf[128];
+ int this_len, retval;
+
+ this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
+ if (copy_from_user(buf, src, this_len))
+ return -EFAULT;
+ retval = access_process_vm(tsk, dst, buf, this_len, 1);
+ if (!retval) {
+ if (copied)
+ break;
+ return -EIO;
+ }
+ copied += retval;
+ src += retval;
+ dst += retval;
+ len -= retval;
+ }
+ return copied;
+}
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
- NULL, /* follow link */
NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* get_block */
+ NULL, /* flushpage */
NULL, /* truncate */
- router_proc_perms
+ router_proc_perms, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
/*
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* get_block */
+ NULL, /* flushpage */
NULL, /* truncate */
- router_proc_perms
+ router_proc_perms, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
/*
- * Proc filesystem derectory entries.
+ * Proc filesystem directory entries.
*/
/*