This repository has been archived on 2023-08-20. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files

248 lines
5.8 KiB
C

/* $Id: tpam_memory.c,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $
*
* Turbo PAM ISDN driver for Linux. (Kernel Driver - Board Memory Access)
*
* Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* For all support questions please contact: <support@auvertech.fr>
*
*/
#include <linux/pci.h>
#include <asm/io.h>
#include "tpam.h"
/*
* Write a DWORD into the board memory.
*
* card: the board
* addr: the address (in the board memory)
* val: the value to put into the memory.
*/
void copy_to_pam_dword(tpam_card *card, u32 addr, u32 val) {
/* set the page register */
writel(addr | TPAM_PAGE_SIZE,
card->bar0 + TPAM_PAGE_REGISTER);
/* write the value */
writel(val, card->bar0 + (addr & TPAM_PAGE_SIZE));
}
/*
* Write n bytes into the board memory. The count of bytes will be rounded
* up to a multiple of 4.
*
* card: the board
* to: the destination address (in the board memory)
* from: the source address (in the kernel memory)
* n: number of bytes
*/
void copy_to_pam(tpam_card *card, u32 to, const void *from, u32 n) {
u32 page, offset, count;
/* need to write in dword ! */
while (n & 3) n++;
while (n) {
page = to | TPAM_PAGE_SIZE;
offset = to & TPAM_PAGE_SIZE;
count = n < TPAM_PAGE_SIZE - offset
? n
: TPAM_PAGE_SIZE - offset;
/* set the page register */
writel(page, card->bar0 + TPAM_PAGE_REGISTER);
/* copy the data */
memcpy_toio(card->bar0 + offset, from, count);
from += count;
to += count;
n -= count;
}
}
/*
* Read a DWORD from the board memory.
*
* card: the board
* addr: the address (in the board memory)
*
* Return: the value read into the memory.
*/
u32 copy_from_pam_dword(tpam_card *card, u32 addr) {
/* set the page register */
writel(((u32)addr) | TPAM_PAGE_SIZE,
card->bar0 + TPAM_PAGE_REGISTER);
/* read the data */
return readl(card->bar0 + (addr & TPAM_PAGE_SIZE));
}
/*
* Read n bytes from the board memory.
*
* card: the board
* to: the destination address (in the kernel memory)
* from: the source address (in the board memory)
* n: number of bytes
*/
void copy_from_pam(tpam_card *card, void *to, u32 from, u32 n) {
u32 page, offset, count;
while (n) {
page = from | TPAM_PAGE_SIZE;
offset = from & TPAM_PAGE_SIZE;
count = n < TPAM_PAGE_SIZE - offset
? n
: TPAM_PAGE_SIZE - offset;
/* set the page register */
writel(page, card->bar0 + TPAM_PAGE_REGISTER);
/* read the data */
memcpy_fromio(to, card->bar0 + offset, count);
from += count;
to += count;
n -= count;
}
}
/*
* Read n bytes from the board memory and writes them into the user memory.
*
* card: the board
* to: the destination address (in the userspace memory)
* from: the source address (in the board memory)
* n: number of bytes
*
* Return: 0 if OK, <0 if error.
*/
int copy_from_pam_to_user(tpam_card *card, void __user *to, u32 from, u32 n) {
void *page;
u32 count;
/* allocate a free page for the data transfer */
if (!(page = (void *)__get_free_page(GFP_KERNEL))) {
printk(KERN_ERR "TurboPAM(copy_from_pam_to_user): "
"get_free_page failed\n");
return -ENOMEM;
}
while (n) {
count = n < PAGE_SIZE ? n : PAGE_SIZE;
/* copy data from the board into the kernel memory */
spin_lock_irq(&card->lock);
copy_from_pam(card, page, from, count);
spin_unlock_irq(&card->lock);
/* copy it from the kernel memory into the user memory */
if (copy_to_user(to, page, count)) {
/* this can fail... */
free_page((unsigned long)page);
return -EFAULT;
}
from += count;
to += count;
n -= count;
}
/* release allocated memory */
free_page((unsigned long)page);
return 0;
}
/*
* Read n bytes from the user memory and writes them into the board memory.
*
* card: the board
* to: the destination address (in the board memory)
* from: the source address (in the userspace memory)
* n: number of bytes
*
* Return: 0 if OK, <0 if error.
*/
int copy_from_user_to_pam(tpam_card *card, u32 to, const void __user *from, u32 n) {
void *page;
u32 count;
/* allocate a free page for the data transfer */
if (!(page = (void *)__get_free_page(GFP_KERNEL))) {
printk(KERN_ERR "TurboPAM(copy_from_user_to_pam): "
"get_free_page failed\n");
return -ENOMEM;
}
while (n) {
count = n < PAGE_SIZE ? n : PAGE_SIZE;
/* copy data from the user memory into the kernel memory */
if (copy_from_user(page, from, count)) {
/* this can fail... */
free_page((unsigned long)page);
return -EFAULT;
}
/* copy it from the kernel memory into the board memory */
spin_lock_irq(&card->lock);
copy_to_pam(card, to, page, count);
spin_unlock_irq(&card->lock);
from += count;
to += count;
n -= count;
}
/* release allocated memory */
free_page((unsigned long)page);
return 0;
}
/*
* Verify if we have the permission to read or writes len bytes at the
* address address from/to the board memory.
*
* address: the start address (in the board memory)
* len: number of bytes
*
* Return: 0 if OK, <0 if error.
*/
int tpam_verify_area(u32 address, u32 len) {
if (address < TPAM_RESERVEDAREA1_START)
return (address + len <= TPAM_RESERVEDAREA1_START) ? 0 : -1;
if (address <= TPAM_RESERVEDAREA1_END)
return -1;
if (address < TPAM_RESERVEDAREA2_START)
return (address + len <= TPAM_RESERVEDAREA2_START) ? 0 : -1;
if (address <= TPAM_RESERVEDAREA2_END)
return -1;
if (address < TPAM_RESERVEDAREA3_START)
return (address + len <= TPAM_RESERVEDAREA3_START) ? 0 : -1;
if (address <= TPAM_RESERVEDAREA3_END)
return -1;
if (address < TPAM_RESERVEDAREA4_START)
return (address + len <= TPAM_RESERVEDAREA4_START) ? 0 : -1;
if (address <= TPAM_RESERVEDAREA4_END)
return -1;
return 0;
}